diff options
author | Karl Berry <karl@freefriends.org> | 2011-07-31 18:27:06 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2011-07-31 18:27:06 +0000 |
commit | dac945b204407dae96f70ec228206516093156d7 (patch) | |
tree | 02ca182689947e45dec95e17ba08b503c959bd17 /Master/texmf-dist | |
parent | c1840548792cfbc7c9f746da1d53d89b94406e72 (diff) |
l3kernel (5jun11)
git-svn-id: svn://tug.org/texlive/trunk@23282 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist')
57 files changed, 51933 insertions, 0 deletions
diff --git a/Master/texmf-dist/doc/latex/l3kernel/README b/Master/texmf-dist/doc/latex/l3kernel/README new file mode 100644 index 00000000000..9281d08f4c1 --- /dev/null +++ b/Master/texmf-dist/doc/latex/l3kernel/README @@ -0,0 +1,89 @@ + + An Experimental LaTeX3 Programming Convention + ============================================= + + 2011/05/10 + + +WHERE TO GET IT +--------------- + +The files in this distribution represent a snapshot of selected files +from the Subversion (SVN) repository of the LaTeX3 Project. + +To obtain current versions of the files, visit +<http://www.latex-project.org/code.html> which contains further +instructions. + +OVERVIEW +-------- + +The files of the expl3 bundle provide a low-level API for TeX +programmers with special syntax conventions, completely separating it +from document level syntax. Hence, the commands provided are not +intended for use at the document level nor for use in describing +design layouts in document class files. + +This API provides the foundation on which the LaTeX3 kernel and other +advanced extensions are built. Special care has been taken so that +they can be used within a LaTeX2e context as regular packages. + +While expl3 is still experimental, the bundle is now regarded as +broadly stable. The syntax conventions and functions provided are now +ready for wider use. There may still be changes to some functions, but +these will be minor when compared to the scope of expl3. + +REQUIREMENTS +------------ + +The expl3 bundle requires the e-TeX extensions and the functionality +of the \pdfstrcmp primitive. As a result, the bundle will only work +with the following engines: + + - pdfTeX v1.30 or later + - XeTeX v0.9994 or later + - LuaTeX v0.40 or later + +pdfTeX v1.30 was released in 2005, and so any recent TeX distribution +will support expl3. Both XeTeX and LuaTeX have developed more +actively over the past few years, and for this reason only recent +releases of these engines are supported. + +THE GUILTY PERSONS +------------------ + + Frank Mittelbach, Denys Duchier, Johannes Braams, Michael Downes, + David Carlisle, Alan Jeffrey, Chris Rowley, Rainer Schoepf + Javier Bezos, Morten Hoegholm, Thomas Lotze, Will Robertson, + Joseph Wright, Bruno Le Floch + + +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 +---- + +The issue tracker for LaTeX3 bugs is currently located at + + https://github.com/latex3/svn-mirror/issues + +Please report specific issues with LaTeX3 code there. More general +discussion should be directed to the LaTeX-L lists. + +===================================================================== + +--- Copyright 1998-2011 The LaTeX3 Project. All rights reserved --- + diff --git a/Master/texmf-dist/doc/latex/l3kernel/expl3.pdf b/Master/texmf-dist/doc/latex/l3kernel/expl3.pdf Binary files differnew file mode 100644 index 00000000000..875541e93ba --- /dev/null +++ b/Master/texmf-dist/doc/latex/l3kernel/expl3.pdf diff --git a/Master/texmf-dist/doc/latex/l3kernel/interface3.tex b/Master/texmf-dist/doc/latex/l3kernel/interface3.tex new file mode 100644 index 00000000000..f4c4fa4e2bf --- /dev/null +++ b/Master/texmf-dist/doc/latex/l3kernel/interface3.tex @@ -0,0 +1,89 @@ +% \iffalse meta-comment +% +%% File: interfaces3.tex Copyright (C) 1990-2011 The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +% +% \fi + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% This document will typeset the LaTeX3 interface descriptions a single +% document. This will produce quite a large file (more than 170 pages +% currently). +% +% There is also a full version of the sources (source3.tex) which additionally +% also typesets the command implementations. +% +% Do not forget to generate the index (as explained on the terminal output +% near the end of the run)! +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +\documentclass{l3doc} +\listfiles + +\begin{document} + +\title{The \LaTeX3 Interfaces} +\author{% + The \LaTeX3 Project\thanks + {% + E-mail: + \href{mailto:latex-team@latex-project.org} + {latex-team@latex-project.org}% + }% +} + +\pagenumbering{roman} +\maketitle + +% +% First load all modules and typeset the documentation parts +% + +\input{source3body} % all the individual modules + +\clearpage + +\begingroup + \def\endash{--} + \catcode`\-\active + \def-{\futurelet\temp\indexdash} + \def\indexdash{\ifx\temp-\endash\fi} + \DelayPrintIndex +\endgroup + +\end{document} + + diff --git a/Master/texmf-dist/doc/latex/l3kernel/source3.pdf b/Master/texmf-dist/doc/latex/l3kernel/source3.pdf Binary files differnew file mode 100644 index 00000000000..946105cd5c8 --- /dev/null +++ b/Master/texmf-dist/doc/latex/l3kernel/source3.pdf diff --git a/Master/texmf-dist/doc/latex/l3kernel/source3.tex b/Master/texmf-dist/doc/latex/l3kernel/source3.tex new file mode 100644 index 00000000000..927e483cce9 --- /dev/null +++ b/Master/texmf-dist/doc/latex/l3kernel/source3.tex @@ -0,0 +1,106 @@ +% \iffalse meta-comment +% +%% File: source3.tex Copyright (C) 1990-2011 The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +% +% \fi + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% This document will typeset the LaTeX3 sources as a single document. +% This will produce quite a large file (more than 400 pages). +% +% There is also a shorter version (interface3.tex) that only typesets the +% command % interface descriptions. +% +% Do not forget to generate the index (as explained on the terminal output +% near the end of the run)! +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\documentclass{l3doc} +\listfiles + +\begin{document} + +\title{The \LaTeX3 Sources} +\author{% + The \LaTeX3 Project\thanks + {% + E-mail: + \href{mailto:latex-team@latex-project.org} + {latex-team@latex-project.org}% + }% +} + +\pagenumbering{roman} +\maketitle + +% +% First load all modules and typeset the documentation parts +% + +\input{source3body} % all the individual modules + +% +% Now reload all modules and typeset the implementation parts +% + +\part{Implementation} + +\def\maketitle{} +\EnableImplementation +\DisableDocumentation +\DocInputAgain + +\clearpage +\pagestyle{headings} + +% Make TeX shut up. +\hbadness=10000 +\newcount\hbadness +\hfuzz=\maxdimen + +\PrintChanges +\clearpage + +\begingroup + \def\endash{--} + \catcode`\-\active + \def-{\futurelet\temp\indexdash} + \def\indexdash{\ifx\temp-\endash\fi} + + \DelayPrintIndex +\endgroup + +\end{document}
\ No newline at end of file diff --git a/Master/texmf-dist/doc/latex/l3kernel/source3body.tex b/Master/texmf-dist/doc/latex/l3kernel/source3body.tex new file mode 100644 index 00000000000..fbffe013ae8 --- /dev/null +++ b/Master/texmf-dist/doc/latex/l3kernel/source3body.tex @@ -0,0 +1,376 @@ +% \iffalse meta-comment +% +%% File: source3body.tex Copyright (C) 1990-2011 The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +% +% \fi + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% This file is used by +% +% source3.tex % documentation including implementation +% +% interface3.tex % only interface documentation +% +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +\begin{abstract} + +\setlength\parindent{0pt} +\setlength\parskip{\baselineskip} + +\noindent +This is the reference documentation for the \pkg{expl3} +programming environment. The \pkg{expl3} modules set up an experimental +naming scheme for \LaTeX{} commands, which allow the \LaTeX{} programmer +to systematically name functions and variables, and specify the argument +types of functions. + +The \TeX{} and \eTeX{} primitives are all given a new name according to +these conventions. However, in the main direct use of the primitives is +not required or encouraged: the \pkg{expl3} modules define an +independent low-level \LaTeX3 programming language. + +At present, the \pkg{expl3} modules are designed to be loaded on top of +\LaTeXe{}. In time, a \LaTeX3 format will be produced based on this code. +This allows the code to be used in \LaTeXe{} packages \emph{now} while a +stand-alone \LaTeX3 is developed. + +\begin{bfseries} + While \pkg{expl3} is still experimental, the bundle is now regarded as + broadly stable. The syntax conventions and functions provided are now + ready for wider use. There may still be changes to some functions, but + these will be minor when compared to the scope of \pkg{expl3}. + + New modules will be added to the distributed version of \pkg{expl3} as + they reach maturity. +\end{bfseries} + +\end{abstract} + +\clearpage + +{% + \def\\{:}% fix "newlines" in the ToC + \tableofcontents +} + +\clearpage +\pagenumbering{arabic} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% Each of the following \DocInput lines includes a file with extension +% .dtx. Each of these files may be typeset separately. For instance +% pdflatex l3box.dtx +% will typeset the source of the LaTeX3 box commands. If you use the +% Makefile, the index will be generated automatically; e.g., +% make doc F=l3box +% +% If this file is processed, each of these separate dtx files will be +% contained as a part of a single document. +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\makeatletter +\def\partname{Part} +\def\maketitle{\part{\@title}} +\let\thanks\@gobble +\let\DelayPrintIndex\PrintIndex +\let\PrintIndex\@empty +\makeatother + +\part{Introduction to \pkg{expl3} and this document} + +This document is intended to act as a comprehensive reference manual +for the \pkg{expl3} language. A general guide to the \LaTeX3 +programming language is found in \href{expl3.pdf}{expl3.pdf}. + +\section{Naming functions and variables} + +\LaTeX3 does not use \texttt{@} as a \enquote{letter} for defining +internal macros. Instead, the symbols |_| and \texttt{:} +are used in internal macro names to provide structure. The name of +each \emph{function} is divided into logical units using \texttt{_}, +while \texttt{:} separates the \emph{name} of the function from the +\emph{argument specifier} (\enquote{arg-spec}). This describes the arguments +expected by the function. In most cases, each argument is represented +by a single letter. The complete list of arg-spec letters for a function +is referred to as the \emph{signature} of the function. + +Each function name starts with the \emph{module} to which it belongs. +Thus apart from a small number of very basic functions, all \pkg{expl3} +function names contain at least one underscore to divide the module +name from the descriptive name of the function. For example, all +functions concerned with comma lists are in module \texttt{clist} and +begin \cs{clist_}. + +Every function must include an argument specifier. For functions which +take no arguments, this will be blank and the function name will end +\texttt{:}. Most functions take one or more arguments, and use the +following argument specifiers: +\begin{description} + \item[\texttt{D}] The \texttt{D} specifier means \emph{do not use}. + All of the \TeX{} primitives are initially \cs{let} to a \texttt{D} + name, and some are then given a second name. Only the kernel + team should use anything with a \texttt{D} specifier! + \item[\texttt{N} and \texttt{n}] These mean \emph{no manipulation}, + of a single token for \texttt{N} and of a set of tokens given in + braces for \texttt{n}. Both pass the argument though exactly as + given. Usually, if you use a single token for an \texttt{n} argument, + all will be well. + \item[\texttt{c}] This means \emph{csname}, and indicates that the + argument will be turned into a csname before being used. So + So \cs{foo:c} |{ArgumentOne}| will act in the same way as \cs{foo:N} + \cs{ArgumentOne}. + \item[\texttt{V} and \texttt{v}] These mean \emph{value + of variable}. The \texttt{V} and \texttt{v} specifiers are used to + get the content of a variable without needing to worry about the + underlying \TeX{} structure containing the data. A \texttt{V} + argument will be a single token (similar to \texttt{N}), for example + \cs{foo:V} \cs{MyVariable}; on the other hand, using \texttt{v} a + csname is constructed first, and then the value is recovered, for + example \cs{foo:v} |{MyVariable}|. + \item[\texttt{o}] This means \emph{expansion once}. In general, the + \texttt{V} and \texttt{v} specifiers are favoured over \texttt{o} + for recovering stored information. However, \texttt{o} is useful + for correctly processing information with delimited arguments. + \item[\texttt{x}] The \texttt{x} specifier stands for \emph{exhaustive + expansion}: the plain \TeX{} \cs{edef}. + \item[\texttt{f}] The \texttt{f} specifier stands for \emph{full + expansion}, and in contrast to \emph{x} stops at the first + non-expandable item without trying to execute it. + \item[\texttt{T} and \texttt{F}] For logic tests, there are the branch + specifiers \texttt{T} (\emph{true}) and \texttt{F} (\emph{false}). + Both specifiers treat the input in the same way as \texttt{n} (no + change), but make the logic much easier to see. + \item[\texttt{p}] The letter \texttt{p} indicates \TeX{} + \emph{parameters}. Normally this will be used for delimited + functions as \pkg{expl3} provides better methods for creating simple + sequential arguments. + \item[\texttt{w}] Finally, there is the \texttt{w} specifier for + \emph{weird} arguments. This covers everything else, but mainly + applies to delimited values (where the argument must be terminated + by some arbitrary string). +\end{description} +Notice that the argument specifier describes how the argument is +processed prior to being passed to the underlying function. For example, +\cs{foo:c} will take its argument, convert it to a control sequence and +pass it to \cs{foo:N}. + +Variables are named in a similar manner to functions, but begin with +a single letter to define the type of variable: +\begin{description} + \item[\texttt{c}] Constant: global parameters whose value should not + be changed. + \item[\texttt{g}] Parameters whose value should only be set globally. + \item[\texttt{l}] Parameters whose value should only be set locally. +\end{description} +Each variable name is then build up in a similar way to that of a +function, typically starting with the module\footnote{The module names are + not used in case of generic scratch registers defined in the data + type modules, e.g., the + \texttt{int} module contains some scratch variables called \cs{l_tmpa_int}, + \cs{l_tmpb_int}, and so on. In such a case adding the module name up front + to denote the module + and in the back to indicate the type, as in + \cs{l_int_tmpa_int} would be very unreadable.} name +and then a descriptive part. +Variables end with a short identifier to show the variable type: +\begin{description} + \item[\texttt{bool}] Either true or false. + \item[\texttt{box}] Box register. + \item[\texttt{clist}] Comma separated list. + \item[\texttt{dim}] \enquote{Rigid} lengths. + \item[\texttt{int}] Integer-valued count register. + \item[\texttt{prop}] Property list. + \item[\texttt{skip}] \enquote{Rubber} lengths. + \item[\texttt{seq}] \enquote{Sequence}: a data-type used to implement lists + (with access at both ends) and stacks. + \item[\texttt{stream}] An input or output stream (for reading from or + writing to, respectively). + \item[\texttt{tl}] Token list variables: placeholder for a token list. + \item[\texttt{toks}] Token register. +\end{description} + +\subsection{Terminological inexactitude} + +A word of warning. In this document, and others referring to the \pkg{expl3} +programming modules, we often refer to \enquote{variables} and +\enquote{functions} as if they +were actual constructs from a real programming language. In truth, \TeX{} +is a macro processor, and functions are simply macros that may or may not take +arguments and expand to their replacement text. Many of the common variables +are \emph{also} macros, and if placed into the input stream will simply expand +to their definition as well~--- a \enquote{function} with no arguments and a +\enquote{token list variable} are in truth one and the same. On the other +hand, some \enquote{variables} are actually registers that must be +initialised and their values set and retrieved with specific functions. + +The conventions of the \pkg{expl3} code are designed to clearly separate the +ideas of \enquote{macros that contain data} and +\enquote{macros that contain code}, and a +consistent wrapper is applied to all forms of \enquote{data} whether they be +macros or +actually registers. This means that sometimes we will use phrases like +\enquote{the function returns a value}, when actually we just mean +\enquote{the macro expands to something}. Similarly, the term +\enquote{execute} might be used in place of \enquote{expand} +or it might refer to the more specific case of +\enquote{processing in \TeX's stomach} +(if you are familiar with the \TeX{}book parlance). + +If in doubt, please ask; chances are we've been hasty in writing certain +definitions and need to be told to tighten up our terminology. + +\section{Documentation conventions} + +This document is typeset with the experimental \pkg{l3doc} class; +several conventions are used to help describe the features of the code. +A number of conventions are used here to make the documentation clearer. + +Each group of related functions is given in a box. For a function with +a \enquote{user} name, this might read: +\begin{function}{\ExplSyntaxOn, \ExplSyntaxOff} + \begin{syntax} + \cs{ExplSyntaxOn} \dots{} \cs{ExplSyntaxOff} + \end{syntax} + The textual description of how the function works would appear here. The + syntax of the function is shown in mono-spaced text to the right of + the box. In this example, the function takes no arguments and so the + name of the function is simply reprinted. +\end{function} + +For programming functions, which use \texttt{_} and \texttt{:} in their name +there are a few additional conventions: If two related functions are given +with identical names but different argument specifiers, these are termed +\emph{variants} of each other, and the latter functions are printed in grey to +show this more clearly. They will carry out the same function but will take +different types of argument: +\begin{function}{\seq_new:N, \seq_new:c} + \begin{syntax} + \cs{seq_new:N} \meta{sequence} + \end{syntax} + When a number of variants are described, the arguments are usually + illustrated only for the base function. Here, \meta{sequence} indicates + that \cs{seq_new:N} expects the name of a sequence. From the argument + specifier, \cs{seq_new:c} also expects a sequence name, but as a + name rather than as a control sequence. Each argument given in the + illustration should be described in the following text. +\end{function} + +Some functions are fully expandable, which allows it to be used within +an \texttt{x}-type argument (in plain \TeX{} terms, inside an \cs{edef}). +These fully expandable functions are indicated in the documentation by +a star: +\begin{function}[EXP]{\cs_to_str:N} + \begin{syntax} + \cs{cs_to_str:N} \meta{cs} + \end{syntax} + As with other functions, some text should follow which explains how + the function works. Usually, only the star will indicate that the + function is expandable. In this case, the function expects a \meta{cs}, + shorthand for a \meta{control sequence}. +\end{function} + +Conditional (\texttt{if}) functions are normally defined in three variants, +with +\texttt{T}, \texttt{F} and \texttt{TF} argument specifiers. This allows +them to be used for different \enquote{true}/\enquote{false} branches, +depending on +which outcome the conditional is being used to test. To indicate this +without repetition, this information is given in a shortened form: +\begin{function}[EXP,pTF]{\xetex_if_engine:} + \begin{syntax} + \cs{xetex_if_engine:TF} \Arg{true code} \Arg{false code} + \end{syntax} + The underlining and italic of \texttt{TF} indicates that + \cs{xetex_if_engine:T}, \cs{xetex_if_engine:F} and + \cs{xetex_if_engine:TF} are all available. Usually, the illustration + will use the \texttt{TF} variant, and so both \meta{true code} + and \meta{false code} will be shown. The two variant forms \texttt{T} and + \texttt{F} take only \meta{true code} and \meta{false code}, respectively. + Here, the star also shows that this function is expandable. + With some minor exceptions, \emph{all} conditional functions in the + \pkg{expl3} modules should be defined in this way. +\end{function} + +Variables, constants and so on are described in a similar manner: +\begin{variable}{\l_tmpa_tl} + A short piece of text will describe the variable: there is no + syntax illustration in this case. +\end{variable} + +In some cases, the function is similar to one in \LaTeXe{} or plain \TeX{}. +In these cases, the text will include an extra \enquote{\textbf{\TeX{}hackers +note}} section: +\begin{function}[EXP]{\token_to_str:N} + \begin{syntax} + \cs{token_to_str:N} \meta{token} + \end{syntax} + The normal description text. + \begin{texnote} + Detail for the experienced \TeX{} or \LaTeXe\ programmer. In this + case, it would point out that this function is the \TeX{} primitive + \cs{string}. + \end{texnote} +\end{function} + +\DisableImplementation + +\DocInput{l3bootstrap.dtx} +\DocInput{l3names.dtx} +\DocInput{l3basics.dtx} +\DocInput{l3expan.dtx} +\DocInput{l3prg.dtx} +\DocInput{l3quark.dtx} +\DocInput{l3token.dtx} +\DocInput{l3int.dtx} +\DocInput{l3skip.dtx} +\DocInput{l3tl.dtx} +\DocInput{l3seq.dtx} +\DocInput{l3clist.dtx} +\DocInput{l3prop.dtx} +\DocInput{l3box.dtx} +\DocInput{l3io.dtx} +\DocInput{l3msg.dtx} +\DocInput{l3keyval.dtx} +\DocInput{l3keys.dtx} +\DocInput{l3file.dtx} +\DocInput{l3fp.dtx} +\DocInput{l3luatex.dtx} + +\endinput diff --git a/Master/texmf-dist/makeindex/l3kernel/l3doc.ist b/Master/texmf-dist/makeindex/l3kernel/l3doc.ist new file mode 100644 index 00000000000..e1496e34d73 --- /dev/null +++ b/Master/texmf-dist/makeindex/l3kernel/l3doc.ist @@ -0,0 +1,72 @@ +%% +%% This is file `l3doc.ist', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% l3doc.dtx (with options: `docist') +%% +%% +%% EXPERIMENTAL CODE +%% +%% Do not distribute this file without also distributing the +%% source files specified above. +%% +%% Do not distribute a modified version of this file. +%% +%% +%% File: l3doc.dtx Copyright (C) 1990-2011 The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +actual '=' +quote '!' +level '#' +preamble +"\n \\begin{theindex} \n \\makeatletter\\scan@allowedfalse\n" +postamble +"\n\n \\end{theindex}\n" +item_x1 "\\efill \n \\subitem " +item_x2 "\\efill \n \\subsubitem " +delim_0 "\\pfill " +delim_1 "\\pfill " +delim_2 "\\pfill " +lethead_prefix "{\\bfseries\\hfil " +lethead_suffix "\\hfil}\\nopagebreak\n" +lethead_flag 1 +heading_prefix "{\\bfseries\\hfil " +heading_suffix "\\hfil}\\nopagebreak\n" +headings_flag 1 + +page_precedence "rnaA" +%% +%% +%% End of file `l3doc.ist'. diff --git a/Master/texmf-dist/source/latex/l3kernel/expl3.dtx b/Master/texmf-dist/source/latex/l3kernel/expl3.dtx new file mode 100644 index 00000000000..443c87b3916 --- /dev/null +++ b/Master/texmf-dist/source/latex/l3kernel/expl3.dtx @@ -0,0 +1,1099 @@ +% \iffalse meta-comment +% +%% File: expl3.dtx Copyright (C) 1990-2011 The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +% +%<*driver|package> +\RequirePackage{l3names} +\GetIdInfo$Id: expl3.dtx 2478 2011-06-19 21:34:23Z joseph $ + {L3 Experimental code bundle wrapper} +%</driver|package> +%<*driver> +\documentclass[full]{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \providecommand\acro[1]{\textsc{\MakeLowercase{#1}}} +% \newenvironment{arg-description}{% +% \begin{itemize}\def\makelabel##1{\hss\llap{\bfseries##1}}}{\end{itemize}} +% +% \title{^^A +% The \textsf{expl3} package and \LaTeX3 programming^^A +% \thanks{This file describes v\ExplFileVersion, +% last revised \ExplFileDate.}^^A +% } +% +% \author{^^A +% The \LaTeX3 Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% +% \date{Released \ExplFileDate} +% +% \maketitle +% +% \begin{documentation} +% +% \begin{abstract} +% +% This document gives an introduction to a new set of programming +% conventions that have been designed to meet the requirements of +% implementing large scale \TeX{} macro programming projects such as +% \LaTeX{}. These programming conventions are the base layer of \LaTeX3. +% +% The main features of the system described are: +% \begin{itemize} +% \item classification of the macros (or, in \LaTeX{} terminology, +% commands) into \LaTeX{} functions and \LaTeX{} parameters, and also +% into modules containing related commands; +% \item a systematic naming scheme based on these classifications; +% \item a simple mechanism for controlling the expansion of a function's +% arguments. +% \end{itemize} +% This system is being used as the basis for \TeX{} programming within +% the \LaTeX3 project. Note that the language is not intended for either +% document mark-up or style specification. Instead, it is intended that +% such features will be built on top of the conventions described here. +% +% This document is an introduction to the ideas behind the \pkg{expl3} +% programming interface. For the complete documentation of the programming +% layer provided by the \LaTeX3 Project, see the accompanying \texttt{source3} +% document. +% +% \end{abstract} +% +% \section{Introduction} +% +% The first step to develop a \LaTeX{} kernel beyond \LaTeXe{} is to +% address how the underlying system is programmed. Rather than the +% current mix of \LaTeX{} and \TeX{} macros, the \LaTeX3 system provides +% its own consistent interface to all of the functions needed to +% control \TeX{}. A key part of this work is to ensure that everything +% is documented, so that \LaTeX{} programmers and users can work +% efficiently without needing to be familiar with the internal nature +% of the kernel or with plain \TeX{}. +% +% The \pkg{expl3} bundle provides this new programming interface for +% \LaTeX. To make programming systematic, \LaTeX3 uses some very +% different conventions to \LaTeXe{} or plain TeX{}. As a result, +% programmers starting with \LaTeX3 will need to become familiar with +% the syntax of the new language. +% +% The next section shows where this language fits into a complete +% \TeX{}-based document processing system. We then describe the major +% features of the syntactic structure of command names, including the +% argument specification syntax used in function names. +% +% The practical ideas behind this argument syntax will be explained, +% together with the expansion control mechanism and the interface +% used to define variant forms of functions. +% +% As we shall demonstrate, the use of a structured naming scheme and of +% variant forms for functions greatly improves the readability of the +% code and hence also its reliability. Moreover, experience has shown +% that the longer command names which result from the new syntax do not +% make the process of \emph{writing} code significantly harder. +% +% \section{Languages and interfaces} +% +% It is possible to identify several distinct languages related to the +% various interfaces that are needed in a \TeX{}-based document processing +% system. This section looks at those we consider most important for +% the \LaTeX3 system. +% +% \begin{description} +% \item[Document mark-up] This comprises those commands (often called +% tags) that are to embedded in the document (the |.tex| file). +% +% It is generally accepted that such mark-up should be essentially +% \emph{declarative}. It may be traditional \TeX{}-based mark-up such +% as \LaTeXe{}, as described in~\cite{A-W:LLa94} and~\cite{A-W:GMS94}, +% or a mark-up language defined via \acro{HTML} or \acro{XML}. +% +% One problem with more traditional \TeX{} coding conventions (as +% described in~\cite{A-W:K-TB}) is that the names and syntax of \TeX{}'s +% primitive formatting commands are ingeniously designed to be +% \enquote{natural} when used directly by the author as document mark-up or in +% macros. Ironically, the ubiquity (and widely recognised +% superiority) of logical mark-up has meant that such explicit +% formatting commands are almost never needed in documents or in +% author-defined macros. Thus they are used almost exclusively by +% \TeX{} programmers to define higher-level commands, and their +% idiosyncratic syntax is not at all popular with this community. +% Moreover, many of them have names that could be very useful as +% document mark-up tags were they not pre-empted as primitives +% (\emph{e.g.}~\cs{box} or \cs{special}). +% +% \item[Designer interface] This relates a (human) typographic +% designer's specification for a document to a program that +% \enquote{formats +% the document}. It should ideally use a declarative language that +% facilitates expression of the relationship and spacing rules +% specified for the layout of the various document elements. +% +% This language is not embedded in document text and it will be very +% different in form to the document mark-up language. For \LaTeX, +% this level was almost completely missing from \LaTeX2.09; \LaTeXe{} +% made some improvements in this area but it is still the case that +% implementing a design specification in \LaTeX{} requires far more +% \enquote{low-level} coding than is acceptable. +% +% \item[Programmer interface] +% This language is the implementation language within which the +% basic typesetting functionality is implemented, building upon the +% primitives of \TeX{} (or a successor program). It may also be used +% to implement the previous two languages \enquote{within} \TeX{}, as in +% the +% current \LaTeX{} system. +% +% \end{description} +% +% The last layer is covered by the conventions described in this +% document, which describes a system aimed at providing a suitable +% basis for coding \LaTeX3. Its main distinguishing features are +% summarised here: +% \begin{itemize} +% \item A consistent naming scheme for all commands, including \TeX{} +% primitives. +% \item The classification of commands as \LaTeX{} functions or \LaTeX{} +% parameters, and also their division into modules according to their +% functionality. +% \item A simple mechanism for controlling argument expansion. +% \item Provision of a set of core \LaTeX{} functions that is sufficient +% for handling programming constructs such as queues, sets, stacks, +% property lists. +% \item A \TeX{} programming environment in which, for example, all +% white space is ignored. +% \end{itemize} +% +% \section{The naming scheme} +% +% \LaTeX3 does not use |@| as a \enquote{letter} for defining +% internal macros. Instead, the symbols |_| and |:| +% are used in internal macro names to provide structure. In +% contrast to the plain \TeX{} format and the \LaTeXe{} kernel, these +% extra letters are used only between parts of a macro name (no +% strange vowel replacement). +% +% While \TeX{} is actually a macro processor, by +% convention for the \pkg{expl3} programming language we distinguish between +% \emph{functions} and \emph{variables}. Functions can have arguments and they +% are either expanded or executed. Variables can be assigned values and they +% are used in arguments to functions; they are not used directly but are +% manipulated by functions (including getting and setting functions). +% Functions and variables with a related functionality (for example accessing +% counters, or manipulating token lists, \emph{etc.})\ are collected together +% into a +% \emph{module}. +% +% \subsection{Examples} +% +% Before giving the details of the naming scheme, here are a few typical +% examples to indicate the flavour of the scheme; first some variable +% names. +% \begin{quote} +% \cs{l_tmpa_box} is a local variable (hence the~|l_| prefix) +% corresponding to a box register.\\ +% \cs{g_tmpa_int} is a global variable (hence the~|g_| prefix) +% corresponding to an integer register (i.e.~a \TeX{} count +% register).\\ +% \cs{c_empty_tl} is the constant~(|c_|) token list variable +% that is always empty. +% \end{quote} +% +% Now here is an example of a typical function name. +% +% \cs{seq_push:Nn} is the function which puts the token list specified +% by its second argument onto the stack specified by its first argument. +% The different natures of the two arguments are indicated by the~|:Nn| +% suffix. The first argument must be a single token which \enquote{names} +% the stack parameter: such single-token arguments are denoted~|N|. +% The second argument is a normal \TeX{} \enquote{undelimited argument}, +% which +% may either be a single token or a balanced, brace-delimited token +% list (which we shall here call a \textit{braced token list}): the~|n| +% denotes such a \enquote{normal} argument form. The name of the function +% indicates it belongs to the |seq| module. +% +% \subsection{Formal naming syntax} +% +% We shall now look in more detail at the syntax of these names. A +% function name in \LaTeX3 will have a name consisting of three parts: +% \begin{quote} +% |\|\meta{module}|_|\meta{description}|:|\meta{arg-spec} +% \end{quote} +% while a variable will have (up to) four distinct parts to its name: +% \begin{quote} +% |\|\meta{scope}|_|\meta{module}|_|\meta{description}|_|\meta{type} +% \end{quote} +% +% The syntax of all names contains +% \begin{quote} +% \meta{module} and \meta{description} +% \end{quote} +% these both give information about the command. +% +% A \emph{module} is a collection of closely related functions and +% variables. Typical module names include~|int| for integer parameters +% and related functions,~|seq| for sequences and~|box| for boxes. +% +% Packages providing new programming functionality will add new modules +% as needed; the programmer can choose any unused name, consisting +% of letters only, for a module. In general, the module name and module +% prefix should be related: for example, the kernel module containing +% \texttt{box} functions is called \texttt{l3box}. +% +% The \emph{description} gives more detailed information about the +% function or parameter, and provides a unique name for it. It should +% consist of letters and, possibly,~|_|~characters. In general, the +% description should use |_| to divide up \enquote{words} or other easy to +% follow parts of the name. For example, the \LaTeX3 kernel provides +% \cs{if_cs_exist:N} which, as might be expected, tests if a command +% name exists. +% +% As a semi-formalized concept the letter |g| is sometimes used to +% prefix certain parts of the \meta{description} +% to mark the function as \enquote{globally acting}, \emph{e.g.}, +% \cs{int_set:Nn} is +% a local operation while \cs{int_gset:Nn} is a global operation. This +% of course goes hand in hand with when to use |l_| and |g_| +% variable prefixes. +% + %\subsubsection{Variables: scope and type} +% +% The \meta{scope} part of the name describes how the variable can be +% accessed. Variables are classified as local, global or constant. +% This \emph{scope} type appears as a code at the beginning of the name; +% the codes used are: +% \begin{arg-description} +% \item[c] constants (global variables whose value should not be +% changed); +% \item[g] variables whose value should only be set globally; +% \item[l] variables whose value should only be set locally. +% \end{arg-description} +% +% Separate functions are provided to assign data to local and global +% variables; for example, |\tl_set:Nn| and |\tl_gset:Nn| respectively +% set the value of a local or global \enquote{token list} variable. +% Note that it is a poor \TeX{} practise to intermix local and global +% assignments to a variable; otherwise you risk exhausting the save stack. +% \unskip\footnote{See \emph{The \TeX{}book}, p.\,301, for further +% information.} +% +% The \meta{type} will be in the list of available +% \emph{data-types};\footnote{Of course, if a totally new data type is +% needed then this will not be the case. However, it is hoped that only +% the kernel team will need to create new data types.} these include the +% primitive \TeX{} data-types, such as the various registers, but to +% these will be added data-types built within the \LaTeX{} programming +% system. +% +% The data types in \LaTeX3 are: +% \begin{description} +% \item[bool] either true or false (the \LaTeX3 implementation does +% not use \cs{iftrue} or \cs{iffalse}); +% \item[box] box register; +% \item[clist] comma separated list; +% \item[coffin] a \enquote{box with handles} --- a higher-level data +% type for carrying out |box| alignment operations; +% \item[dim] \enquote{rigid} lengths; +% \item[fp] floating-point values; +% \item[int] integer-valued count register; +% \item[prop] property list; +% \item[seq] sequence: a data-type used to implement lists (with +% access at both ends) and stacks; +% \item[skip] \enquote{rubber} lengths; +% \item[stream] an input or output stream (for reading from or writing +% to, respectively); +% \item[tl] \enquote{token list variables}: placeholders for token lists. +% \end{description} +% When the \meta{type} and \meta{module} are identical (as often happens in +% the more basic modules) the \meta{module} part is often omitted for +% aesthetic reasons. +% +% The name \enquote{token list} may cause confusion, and so some background is +% useful. \TeX{} works with tokens and lists of tokens, rather than +% characters. It provides two ways to store these token lists: within +% macros and as token registers (|toks|). The implementation in \LaTeX3 means +% that +% |toks| are not required, and that all operations for storing tokens can us +% the |tl| variable type. +% +% Experienced \TeX{} programmers will notice that some of the variable +% types listed are native \TeX{} registers whilst others are not. In +% general, the underlying \TeX{} implementation for a data structure may +% vary but the \emph{documented interface} will be stable. For example, +% the |prop| data type was originally implemented as a |toks|, but +% is currently built on top of the |tl| data structure. +% +% \subsubsection{Variables: guidance} +% +% Although \TeX{} provides token registers for certain programming +% tasks, \LaTeX3 is written so that token list variables can be used +% for all stored lists of tokens. The \cs{toks_\ldots} functions are +% therefore for internal use within \LaTeX3 and for supporting +% \LaTeXe, and should not be needed in new \LaTeX3-based code. +% +% Both comma lists and sequences both have similar characteristics. +% They both use special delimiters to mark out one entry from the +% next, and are both accessible at both ends. In general, it is +% easier to create comma lists `by hand' as they can be typed +% in directly. User input often takes the form of a comma separated +% list and so there are many cases where this is the obvious +% data type to use. On the other hand, sequences use special internal +% tokens to separate entries. This means that they can be used to +% contain material that comma lists cannot (such as items that may +% themselves contain commas!). In general, comma lists should be +% preferred for creating fixed lists inside programs and for +% handling user input where commas will not occur. On the other +% hand, sequences should be used to store arbitrary lists of +% data. +% +% \pkg{expl3} implements stacks using the sequence data structure. +% Thus creating stacks involves first creating a sequence, and +% then using the sequence functions which work in a stack manner +% (\cs{seq_push:Nn}, \emph{etc}.). +% +% Due to the nature of the underlying \TeX{} implementation, it is +% possible to assign values to token list variables and comma lists +% without first declaring them. However, this is \emph{not supported +% behaviour}. The \LaTeX3 coding convention is that all variables must +% be declared before use. +% +% The \pkg{expl3} package can be loaded with the |check-declarations| option +% to verify that all variables are declared before use. This has a +% performance implication and is therefore intended for testing during +% development and not for use in production documents. +% +% \subsubsection{Functions: argument specifications} +% +% Function names end with an \meta{arg-spec} after a colon. This +% gives an indication of the types of argument that a function takes, +% and provides a convenient method of naming similar functions that +% differ only in their argument forms (see the next section for +% examples). +% +% The \meta{arg-spec} consists of a (possibly empty) list of letters, +% each denoting one argument of the function. The letter, including +% its case, conveys information about the type of argument required. +% +% All functions have a base form with arguments using one of the +% following argument specifiers: +% \begin{arg-description} +% \item[n] Unexpanded token or braced token list.\\ +% This is a standard \TeX{} undelimited macro argument. +% \item[N] Single token (unlike~|n|, the argument must \emph{not} be +% surrounded by braces).\\ +% A typical example of a command taking an~|N| +% argument is~|\cs_set|, in which the command being defined must be +% unbraced. +% \item[p] Primitive \TeX{} parameter specification.\\ +% This can be something simple like~|#1#2#3|, but may use arbitrary +% delimited argument syntax such as: |#1,#2\q_stop#3|. This is used +% when defining functions. +% \item[T,F] +% These are special cases of~|n| arguments, used for the +% true and false code in conditional commands. +% \end{arg-description} +% There are two other specifiers with more general meanings: +% \begin{arg-description} +% \item[D] This means: \textbf{Do not use}. This special case is used +% for \TeX{} primitives and other commands that are provided for use +% only while bootstrapping the \LaTeX{} kernel. Programmers outside +% the kernel team should not use these functions! +% \item[w] This means that the argument syntax is \enquote{weird} in that it +% does not follow any standard rule. It is used for functions with +% arguments that take non standard forms: examples are \TeX-level +% delimited arguments and the boolean tests needed after certain +% primitive |\if|\ldots\ commands. +% \end{arg-description} +% +% In case of |n| arguments that consist of a single token the +% surrounding braces can be omitted in nearly all +% situations---functions that force the use of braces even for single +% token arguments are explicitly mentioned. However, programmers are +% encouraged to always use braces around \texttt{n} arguments, as this +% makes the relationship between function and argument clearer. +% +% Further argument specifiers are available as part of the expansion +% control system. These are discussed in the next section. +% +% \section{Expansion control} +% +% Let's take a look at some typical operations one might want to +% perform. Suppose we maintain a stack of open files and we use the +% stack |\g_ior_file_name_seq| to keep track of them (|io| is the +% file reading and writing module: it uses the module prefix +% \texttt{ior} for reading functions and variables). The basic +% operation here is to push a name onto this stack which could be +% done by the operation +% \begin{quote} +% |\seq_gpush:Nn \g_ior_file_name_seq {#1}| +% \end{quote} +% where |#1| is the filename. In other words, this operation would +% push the file name as is onto the stack. +% +% However, we might face a situation where the filename is stored in +% a variable of some sort, say |\l_ior_curr_file_tl|. In this case we +% want to retrieve the value of the variable. If we simply use +% \begin{quote} +% |\seq_gpush:Nn \g_io_file_name_seq \l_io_curr_file_tl| +% \end{quote} +% we will not get the value of the variable pushed onto the stack, +% only the variable name itself. Instead a suitable number of +% |\exp_after:wN| would be necessary (together with extra braces) to +% change the order of expansion,\footnote{\cs{exp_after:wN} is +% the \LaTeX3 name for the \TeX{} \cs{expandafter} primitive.}, \emph{i.e.} +% \begin{quote} +% |\exp_after:wN| \\ +% | \seq_gpush:Nn| \\ +% |\exp_after:wN| \\ +% | \g_io_file_name_seq| \\ +% |\exp_after:wN| \\ +% | { \l_io_curr_file_tl }| +% \end{quote} +% +% The above example is probably the simplest case but already shows +% how the code changes to something difficult to understand. +% Furthermore there is an assumption in this: that the storage bin +% reveals its contents after exactly one expansion. Relying on this +% means that you cannot do proper checking plus you have to know +% exactly how a storage bin acts in order to get the correct number +% of expansions. Therefore \LaTeX3 provides the programmer with a +% general scheme that keeps the code compact and easy to understand. +% +% To denote that some argument to a function needs special treatment one +% just uses different letters in the arg-spec part of the function to +% mark the desired behaviour. In the above example one would write +% \begin{quote} +% |\seq_gpush:NV \g_io_file_name_seq \l_io_curr_file_tl| +% \end{quote} +% to achieve the desired effect. Here the |V| (the second argument) +% is for \enquote{retrieve the value of the variable} before passing it to +% the base function. +% +% The following letters can be used to denote special treatment of +% arguments before passing it to the base function: +% \begin{description} +% \item[c] Character string used as a command name.\\ The argument (a +% token or braced token list) must, when fully expanded, produce a +% sequence of characters which is then used to construct a command +% name (\emph{via}~|\csname| \ldots |\endcsname|). This command name is the +% single token that is passed to the function as the argument. Hence +% \begin{quote} +% |\seq_gpush:cV { g_file_name_seq } \l_tmpa_tl| +% \end{quote} +% is equivalent to +% \begin{quote} +% |\seq_gpush:NV \g_file_name_seq \l_tmpa_tl"| +% \end{quote} +% Remember that \texttt{c} arguments are \emph{fully expanded} by +% \TeX{} when creating csnames. This means that (a) the entire +% argument must be expandable and (b) any variables will be +% converted to their content. So the preceding examples are also +% equivalent to +% \begin{quote} +% |\tl_new:N \g_file_seq_name_tl| \\ +% |\tl_gset:Nn \g_file_seq_name_tl { g_file_name_seq }| \\ +% |\seq_gpush:cV { \g_file_seq_name_tl } \l_tmpa_tl|. +% \end{quote} +% (Token list variables are expandable and do not require an +% accessor function. Other variable types require the appropriate +% \cs{<var>_use:N} functions to be used in this context.) +% \item[V] Value of a variable.\\ +% This means that the contents of the register in question is used as the +% argument, be it an integer, a length-type register, a token list variable +% or similar. The value is passed to the function as a braced token list. +% \item[v] Value of a register, constructed from a character string +% used as a command name.\\ +% This is a combination of |c| and |V| which first constructs a +% control sequence from the argument and then passes the value of the +% resulting register to the function. +% \item[x] Fully-expanded token or braced token list.\\ +% This means that the argument is expanded as in the replacement +% text of an~|\edef|, and the expansion is passed to the function as +% a braced token list. This means that expansion takes place until +% only unexpandable tokens are left. +% \item[o] One-level-expanded token or braced token list.\\ +% This means that the argument is expanded one level, as by +% \cs{expandafter}, and the expansion is passed to the function as a +% braced token list. Note that if the original argument is a braced +% token list then only the first token in that list is expanded. +% In general, using \texttt{V} should be preferred to using +% \texttt{o} for simple variable retrieval. +% \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. +% \end{description} +% +% \subsection{Simpler means better} +% +% Anyone who programs in \TeX{} is frustratingly familiar with the +% problem of arranging that arguments to functions are suitably expanded +% before the function is called. To illustrate how expansion control +% can bring instant relief to this problem we shall consider two +% examples copied from \texttt{latex.ltx}. +% +% \begin{verbatim} +% \global\expandafter\let +% \csname\cf@encoding \string#1\expandafter\endcsname +% \csname ?\string#1\endcsname +% \end{verbatim} +% This first piece of code is in essence simply a global |\let| whose +% two arguments firstly have to be constructed before |\let| is +% executed. The |#1| is a control sequence name such as +% |\textcurrency|. The token to be defined is obtained by +% concatenating the characters of the current font encoding stored in +% |\cf@encoding|, which has to be fully expanded, and the name of the +% symbol. The second token is the same except it uses the default +% encoding |?|. The result is a mess of interwoven |\expandafter| +% and |\csname| beloved of all \TeX{} programmers, and the code is +% essentially unreadable. +% +% Using the conventions and functionality outlined here, the task would +% be achieved with code such as this: +% \begin{verbatim} +% \cs_gset_eq:cc +% { \cf@encoding \token_to_str:N #1 } { ? \token_to_str:N #1 } +% \end{verbatim} +% The command |\cs_gset_eq:cc| is a global~|\let| that generates +% command names out of both of its arguments before making the +% definition. This produces code that is far more readable and more +% likely to be correct first time. (\cs{token_to_str:N} is the \LaTeX3 +% name for \cs{string}.) +% +% Here is the second example. +% \begin{verbatim} +% \expandafter +% \in@ +% \csname sym#3% +% \expandafter +% \endcsname +% \expandafter +% {% +% \group@list}% +% \end{verbatim} +% This piece of code is part of the definition of another function. It +% first produces two things: a token list, by expanding |\group@list| once; +% and a token whose name comes from~`|sym#3|'. Then the function~|\in@| +% is called and this tests if its first argument occurs in the token list +% of its second argument. +% +% Again we can improve enormously on the code. First we shall rename +% the function~|\in@| according to our conventions. A function such as +% this but taking two normal \enquote{\texttt{n}} arguments might reasonably be +% named |\seq_test_in:Nn|; thus the variant function we need will be +% defined with the appropriate argument types and its name will be +% |\seq_test_in:cV|. Now this code fragment will be simply: +% \begin{verbatim} +% \seq_test_in:cV { sym #3 } \l_group_seq +% \end{verbatim} +% Note that, in addition to the lack of |\expandafter|, the space after +% the~|}| will be silently ignored since all white space is ignored in +% this programming environment. +% +% \subsection{New functions from old} +% +% For many common functions the \LaTeX3 kernel will provide variants +% with a range of argument forms, and similarly it is expected that +% extension packages providing new functions will make them available in +% the all the commonly needed forms. +% +% However, there will be occasions where it is necessary to construct a +% new such variant form; therefore the expansion module provides a +% straightforward mechanism for the creation of functions with any +% required argument type, starting from a function that takes \enquote{normal} +% \TeX{} undelimited arguments. +% +% To illustrate this let us suppose you have a \enquote{base function} +% |\demo_cmd:Nnn| that takes three normal arguments, and that you need +% to construct the variant |\demo_cmd:cnx|, for which the first argument +% is used to construct the \emph{name} of a command, whilst the third +% argument must be fully expanded before being passed to +% |\demo_cmd:Nnn|. +% To produce the variant form from the base form, simply use this: +% \begin{verbatim} +% \cs_generate_variant:Nn \demo_cmd:Nnn { cnx } +% \end{verbatim} +% This defines the variant form so that you can then write, for example: +% \begin{verbatim} +% \demo_cmd:cnx { abc } { pq } { \rst \xyz } +% \end{verbatim} +% rather than \ldots\ well, something like this! +% \begin{verbatim} +% \def \tempa {{pq}}% +% \edef \tempb {\rst \xyz}% +% \expandafter +% \demo@cmd:nnn +% \csname abc% +% \expandafter +% \expandafter +% \expandafter +% \endcsname +% \expandafter +% \tempa +% \expandafter +% {% +% \tempb +% }% +% \end{verbatim} +% +% Another example: you may wish to declare a function +% |\demo_cmd_b:xcxcx|, a variant of an existing function +% |\demo_cmd_b:nnnnn|, that fully +% expands arguments 1,~3 and~5, and produces commands to pass as +% arguments 2 and~4 using~|\csname|. +% The definition you need is simply +% \begin{verbatim} +% \cs_generate_variant:Nn \demo_cmd_b:nnnnn { xcxcx } +% \end{verbatim} +% +% This extension mechanism is written so that if the same new form of +% some existing command is implemented by two extension packages then the +% two definitions will be identical and thus no conflict will occur. +% +% \section{The distribution} +% +% At present, the \pkg{expl3} modules are designed to be loaded on top +% of \LaTeXe. In time, a \LaTeX3 format will be produced based on this +% code. This allows the code to be used in \LaTeXe{} packages \emph{now} +% while a stand-alone \LaTeX3 is developed. +% +% \begin{bfseries} +% While \pkg{expl3} is still experimental, the bundle is now regarded +% as broadly stable. The syntax conventions and functions provided +% are now ready for wider use. There may still be changes to some +% functions, but these will be minor when compared to the scope of +% \pkg{expl3}. +% \end{bfseries} +% +% New modules will be added to the distributed version of \pkg{expl3} +% as they reach maturity. At present, the \pkg{expl3} bundle consists +% of a number of modules, most of which are loaded by including the +% line: +% \begin{verbatim} +% \RequirePackage{expl3} +% \end{verbatim} +% in a \LaTeXe{} package, class or other file. The \pkg{expl3} modules +% regarded as stable, and therefore suitable for basing real code on, +% are as follows: +% +% \begin{description} +% \providecommand\explpkg[2]{\item[#1]#2} +% \explpkg{l3basics}{ +% This contains the basic definition modules used +% by the other packages. +% } +% \explpkg{l3box}{ +% Primitives for dealing with boxes. +% } +% \explpkg{l3clist}{ +% Methods for manipulating comma-separated token lists. +% } +% \explpkg{l3expan}{ +% This is the argument expansion module discussed earlier in this +% document. +% } +% \explpkg{l3int}{ +% This implements the integer data-type \texttt{int}. +% } +% \explpkg{l3io}{ +% A module providing low level input and output functions. +% } +% \explpkg{l3keyval}{ +% Low-level implementation for processing lists of the form +% \texttt{\{ key1=val1 , key2=val2 \}}. +% } +% \explpkg{l3keys}{ +% Higher-level implementation of key--value methods: intended to work +% as a \LaTeX3 version of \pkg{xkeyval}/\pkg{kvoptions}, although +% with input syntax more like that of \pkg{pgfkeys}. +% } +% \explpkg{l3msg}{ +% Communicating with the user: includes low-level hooks to allow +% messages to be filtered (higher-level interface for filtering +% to be written!). +% } +% \explpkg{l3names}{ +% This sets up the basic naming scheme and renames all +% the \TeX{} primitives. +% } +% \explpkg{l3prg}{ +% Program control structures such as boolean data type |bool|, generic +% do-while loops, case-switches, sorting routines and stepwise loops. +% } +% \explpkg{l3prop}{ +% This implements the data-type for \enquote{property lists} that are used, in +% particular, for storing key/value pairs. +% } +% \explpkg{l3quark}{ +% A \enquote{quark} is a command that is defined to expand to +% itself! Therefore they must never be expanded as this will generate +% infinite recursion; they do however have many uses, \emph{e.g.}~as +% special markers and delimiters within code. +% } +% \explpkg{l3seq}{ +% This implements data-types such as queues and stacks. +% } +% \explpkg{l3skip}{ +% Implements the \enquote{rubber length} datatype \texttt{skip} and the +% \enquote{rigid length} datatype |dim|. +% } +% \explpkg{l3tl}{ +% This implements a basic data-type, called a \textit{token-list +% variable} (|tl var.|), used for storing named token lists: these are +% \TeX{} macros with no arguments. +% } +% \explpkg{l3token}{ +% Analysing token lists and token streams, including peeking ahead to +% see what's coming next and inspecting tokens to detect which kind +% they are. +% } +% \end{description} +% +% \section{Moving from \LaTeXe{} to \LaTeX3} +% +% To help programmers to use \LaTeX3 code in existing \LaTeXe{} package, +% some short notes on making the change are probably desirable. +% Suggestions for inclusion here are welcome! Some of the following +% is concerned with code, and some with coding style. +% +% \begin{itemize} +% \item \pkg{expl3} is mainly focussed on programming. This means that +% some areas still require the use of \LaTeXe{} internal macros. +% For example, you may well need \cs{@ifpackageloaded}, as there +% is currently no native \LaTeX3 package loading module. +% \item User level macros should be generated using the mechanism +% available in the \pkg{xparse} package, which is available from CTAN +% or the \LaTeX3 SVN repository. +% \item At an internal level, most functions should be generated +% \cs{long} (using \cs{cs_new:Npn}) rather than \enquote{short} (using +% \cs{cs_new_nopar:Npn}). The exceptions are: +% \begin{itemize} +% \item Functions which take no arguments; +% \item Functions which are used with pre-set arguments which +% therefore cannot be \cs{long}: this is mainly the case with +% auxiliary functions. +% \end{itemize} +% \item Where possible, declare all variables and functions (using +% \cs{cs_new:Npn}, \cs{tl_new:N}, etc.) before use. +% \item Prefer \enquote{higher-level} functions over \enquote{lower-level}, +% where +% possible. So for example use \cs{cs_if_exist:N(TF)} in preference +% \cs{if_cs_exist:N}. +% \item Use space to make code readable. In general, we recommend +% a layout such as: +% \begin{verbatim} +% \cs_new:Npn \foo_bar:Nn #1#2 +% { +% \cs_if_exist:NTF #1 +% { \foo_bar_aux_i:n {#2} } +% { \foo_bar_aux_ii:nn {#2} { literal } } +% } +% \end{verbatim} +% where spaces are used around |{| and |}| except for isolated +% |#1|, |#2|, etc. +% \item Put different code items on separate lines: readability is +% much more useful than compactness. +% \item Use long, descriptive names for functions and variables, +% and for auxiliary functions use the parent function name plus +% |aux|, |aux_i|, |aux_ii| and so on. +% \item If in doubt, ask the team via the LaTeX-L list: someone will +% soon get back to you! +% \end{itemize} +% +% \section{The \LaTeX3 Project} +% +% Development of \LaTeX3 is carried out by The \LaTeX3 Project. Over time, +% the membership of this team has naturally varied. Currently, the members +% are +% \begin{itemize} +% \item Johannes Braams +% \item David Carlisle +% \item Robin Fairbairns +% \item Morten H{\o}gholm +% \item Bruno Le Floch +% \item Thomas Lotze +% \item Frank Mittelbach +% \item Will Robertson +% \item Chris Rowley +% \item Rainer Sch{\"o}pf +% \item Joseph Wright +% \end{itemize} +% while former members are +% \begin{itemize} +% \item Michael Downes +% \item Denys Duchier +% \item Alan Jeffrey +% \item Martin Schr{\"o}der +% \end{itemize} +% +% \begin{thebibliography}{1} +% +% \bibitem{A-W:K-TB} +% Donald E Knuth +% \newblock \emph{The \TeX{}book}. +% \newblock Addison-Wesley, Reading, Massachusetts, 1984. +% +% \bibitem{A-W:GMS94} +% Goossens, Mittelbach and Samarin. +% \newblock \emph{ The \LaTeX{} Companion}. +% \newblock Addison-Wesley, Reading, Massachusetts, 1994. +% +% \bibitem{A-W:LLa94} +% Leslie Lamport. +% \newblock \emph{\LaTeX{}: A Document Preparation System}. +% \newblock Addison-Wesley, Reading, Massachusetts, second edition, 1994. +% +% \bibitem{tub:MR97-1} +% Frank Mittelbach and Chris Rowley. +% \newblock \enquote{The \LaTeX3 Project}. +% \newblock \emph{TUGboat}, +% Vol.\,18, No.\,3, pp.\,195--198, 1997. +% +% \end{thebibliography} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{expl3} implementation} +% +% \begin{macrocode} +%<*package> +% \end{macrocode} +% +% Load \pkg{etex} as otherwise we are likely to get into trouble +% with registers. Some inserts are reserved also as these have to +% be from the standard pool. +% \begin{macrocode} +\RequirePackage{etex} +\reserveinserts{32} +% \end{macrocode} +% +% We want \pkg{calc} to allow \LaTeXe{} to do \eTeX{}-like setting (which will +% be native in \LaTeX3). +% \begin{macrocode} +\RequirePackage{calc} +% \end{macrocode} +% +% Do the package identification: this will turn on code syntax. +% \begin{macrocode} +\ProvidesExplPackage + {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +% \end{macrocode} +% +% \begin{macro}{\@l@expl@check@declarations@bool} +% \begin{macro}{\@l@expl@log@functions@bool} +% A couple of package options to be provided. +% These have to be done by hand as there is no \pkg{expl3} yet: the logging +% option +% is needed before loading \pkg{l3basics}! +% \begin{macrocode} +\newcommand* \@l@expl@check@declarations@bool { 0 } +\newcommand*\@l@expl@log@functions@bool { 0 } +\DeclareOption { check-declarations } + { \def \@l@expl@check@declarations@bool { 1 } } +\DeclareOption { log-functions } + {\def \@l@expl@log@functions@bool { 1 } } +\ProcessOptions \relax +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% We already loaded \pkg{l3names} at the beginning of the \texttt{dtx} file. +% We now load the base of \LaTeX3, stopping once token list variables are +% defined. +% \begin{macrocode} +\RequirePackage{ l3basics, l3expan, l3tl } +% \end{macrocode} +% +% \begin{macro}{\tl_check_exists:N} +% When used as a package, there is an option to be picky and to +% check definitions exist. This part of the process is done now, so that +% variable types based on |tl| (for example |clist|, |seq| and |prop|) will +% inherit +% the appropriate definitions. +% \begin{macrocode} +\ifodd \@l@expl@check@declarations@bool \relax + \cs_new_protected:Npn \tl_check_exists:N #1 + { + \cs_if_exist:NF #1 + { + \msg_kernel_error:nnx { check } { non-declared-variable } + { \token_to_str:N #1 } + } + } + \cs_set_protected:Npn \tl_set:Nn #1#2 + { + \tl_check_exists:N #1 + \cs_set_nopar:Npx #1 { \exp_not:n {#2} } + } + \cs_set_protected:Npn \tl_set:Nx #1#2 + { + \tl_check_exists:N #1 + \cs_set_nopar:Npx #1 {#2} + } + \cs_set_protected:Npn \tl_gset:Nn #1#2 + { + \tl_check_exists:N #1 + \cs_gset_nopar:Npx #1 { \exp_not:n {#2} } + } + \cs_set_protected:Npn \tl_gset:Nx #1#2 + { + \tl_check_exists:N #1 + \cs_gset_nopar:Npx #1 {#2} + } + \cs_set_protected:Npn \tl_set_eq:NN #1#2 + { + \tl_check_exists:N #1 + \tl_check_exists:N #2 + \cs_set_eq:NN #1 #2 + } + \cs_set_protected:Npn \tl_gset_eq:NN #1#2 + { + \tl_check_exists:N #1 + \tl_check_exists:N #2 + \cs_gset_eq:NN #1 #2 + } +\fi +% \end{macrocode} +%\end{macro} +% +% The rest of the code can now be loaded. +% \begin{macrocode} +\RequirePackage{ + l3seq, + l3int, + l3quark, + l3prg, + l3clist, + l3token, + l3prop, + l3msg, + l3io, + l3file, + l3skip, + l3box, + l3keyval, + l3keys, + l3fp, + l3luatex +} +% \end{macrocode} +% +% Depreciated, but loaded for the moment. +% \begin{macrocode} +\RequirePackage{l3toks} +% \end{macrocode} +% +% The error message for variables cannot be created before now: this means that +% \pkg{expl3} itself may cause some odd errors. +% \begin{macrocode} +\bool_if:nT { \@l@expl@check@declarations@bool } + { + \msg_kernel_new:nnnn { check } { non-declared-variable } + { The~variable~#1~has~not~been~declared~\msg_line_context:. } + { + Checking~is~active,~and~you~have~tried~do~so~something~like: \\ + \ \ \tl_set:Nn #1 ~ + \iow_char:N \{ ~ ... ~ \iow_char:N \} \\ + without~first~having: \\ + \ \ \tl_new:N #1 \\ + \\ + LaTeX~will~create~the~variable~and~continue. + } + } +% \end{macrocode} +% +% \begin{macro}{\ExplSyntaxOff, \ExplSyntaxOn} +% These are redefined here to reduce unnecessary work when switching. +% The definition for \cs{ExplSyntaxOff} copies the code from earlier, +% so that category codes are restored. +% \begin{macrocode} +\cs_set_protected_nopar:Npn \ExplSyntaxOn + { + \bool_if:NF \l_expl_status_bool + { + \cs_set_protected_nopar:Npx \ExplSyntaxOff + { + \char_set_catcode:nn { 9 } { \char_value_catcode:n { 9 } } + \char_set_catcode:nn { 32 } { \char_value_catcode:n { 32 } } + \char_set_catcode:nn { 34 } { \char_value_catcode:n { 34 } } + \char_set_catcode:nn { 38 } { \char_value_catcode:n { 38 } } + \char_set_catcode:nn { 58 } { \char_value_catcode:n { 58 } } + \char_set_catcode:nn { 94 } { \char_value_catcode:n { 94 } } + \char_set_catcode:nn { 95 } { \char_value_catcode:n { 95 } } + \char_set_catcode:nn { 124 } { \char_value_catcode:n { 124 } } + \char_set_catcode:nn { 126 } { \char_value_catcode:n { 126 } } + \tex_endlinechar:D = \tex_the:D \tex_endlinechar:D \scan_stop: + \bool_set_false:N \l_expl_status_bool + \cs_set_protected_nopar:Npn \ExplSyntaxOff { } + } + } + \char_set_catcode_ignore:n { 9 } % tab + \char_set_catcode_ignore:n { 32 } % space + \char_set_catcode_other:n { 34 } % double quote + \char_set_catcode_alignment:n { 38 } % ampersand + \char_set_catcode_letter:n { 58 } % colon + \char_set_catcode_math_superscript:n { 94 } % circumflex + \char_set_catcode_letter:n { 95 } % underscore + \char_set_catcode_other:n { 124 } % pipe + \char_set_catcode_space:n { 126 } % tilde + \tex_endlinechar:D = 32 \scan_stop: + \bool_set_true:N \l_expl_status_bool + } +\cs_set_protected_nopar:Npx \ExplSyntaxOff + { + \exp_not:o \ExplSyntaxOff + \cs_set_protected_nopar:Npn \ExplSyntaxOff { } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +%</package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintIndex diff --git a/Master/texmf-dist/source/latex/l3kernel/l3alloc.dtx b/Master/texmf-dist/source/latex/l3kernel/l3alloc.dtx new file mode 100644 index 00000000000..8e175a2e74d --- /dev/null +++ b/Master/texmf-dist/source/latex/l3kernel/l3alloc.dtx @@ -0,0 +1,216 @@ +% \iffalse meta-comment +% +%% File: l3alloc.dtx Copyright (C) 1990-2011 The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +% +%<*driver|package> +\RequirePackage{l3names} +\GetIdInfo$Id: l3alloc.dtx 2478 2011-06-19 21:34:23Z joseph $ + {L3 Experimental register allocation} +%</driver|package> +%<*driver> +\documentclass[full]{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{^^A +% The \pkg{l3alloc} package\\ Register allocation^^A +% \thanks{This file describes v\ExplFileVersion, +% last revised \ExplFileDate.}^^A +% } +% +% \author{^^A +% The \LaTeX3 Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% +% \date{Released \ExplFileDate} +% +% \maketitle +% +% \begin{documentation} +% +% Note that this module is only used for generating an pkg{expl3}-based +% format. Under \LaTeX{}, the \pkg{etex} package is used for allocation +% management. +% +% 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 I/O streams for reading +% (|\tex_read:D|) and 16 I/O streams for writing (|\tex_write:D|), +% \item \TeX{} supports no more than 256 inserts. +% \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 efficiently. +% \item Registers could be allocated both globally and locally; the +% use of registers could also be globally or locally. Here we +% provide support for globally allocated registers for both +% global and local use. +% \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. +% +% \begin{function}{\alloc_new:nnnN} +% \begin{syntax} +% \cs{alloc_new:nnnN} \Arg{type} \Arg{min} \Arg{max} \meta{function} +% \end{syntax} +% Shorthand for allocating new registers. Defines \cs{<type>_new:N} as +% and allocator function of the specified \meta{type}, indexed up from +% \meta{min} to a \meta{max}, and with assignment carried out by +% the \meta{function}. This process will create two token lists, +% \cs{g_\meta{type}_allocation_tl} and \cs{c_\meta{type}_allocation_max_tl}, +% to store the current and maximum allocation numbers, respectively. +% It will also create \cs{g_\meta{type}_allocation_seq} to store allocation +% numbers which should not be used. +% \end{function} +% +% \section{Internal functions} +% +% \begin{function}{\alloc_setup_type:nnn} +% \begin{syntax} +% \cs{alloc_setup_type:nnn} \Arg{type} \Arg{min} \Arg{max} +% \end{syntax} +% Sets up the storage needed for the administration of registers of +% \Arg{type}, which will start allocating at \meta{min} and will issue +% an error if there is an attempt to allocate past the \meta{max}. +% \end{function} +% +% \begin{function}{\alloc_reg:nNN} +% \begin{syntax} +% \cs{alloc_reg:nNN} \Arg{type} \meta{function} \meta{register} +% \end{syntax} +% Preforms the allocation for a new \meta{register} of \meta{type}, +% using the allocator \meta{function} (which will be either a +% primitive \cs{tex_\ldots def:D} or \cs{tex_chardef:D}). +% \end{function} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{l3alloc} implementation} +% +% \begin{macrocode} +%<*initex> +% \end{macrocode} +% +% \begin{macro}{\alloc_new:nnnN} +% Shorthand for defining new register types and their allocators: +% \begin{macrocode} +\cs_new:Npn \alloc_new:nnnN #1#2#3#4 + { + \alloc_setup_type:nnn {#1} {#2} {#3} + \cs_new_nopar:cpn { #1 _new:N } ##1 { \alloc_reg:nNN {#1} #4 ##1 } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int]{\alloc_setup_type:nnn} +% For each type of register we need to \enquote{counters} that hold the +% last allocated global register, plus a constant for the maximum +% allocation. We also need a sequence to store the \enquote{exceptions}. +% \begin{macrocode} +\cs_new_nopar:Npn \alloc_setup_type:nnn #1#2#3 + { + \tl_new:c { g_ #1 _allocation_tl } + \tl_gset:cx { g_ #1 _allocation_tl } { \int_eval:n {#2} } + \tl_const:cx { c_ #1 _allocation_max_tl } { \int_eval:n {#3} } + \seq_new:c { g_ #1 _allocation_seq } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int]{\alloc_reg:nNN} +% This internal macro performs the actual allocation. +% \begin{macrocode} +\cs_new_nopar:Npn \alloc_reg:nNN #1#2#3 + { + \chk_if_free_cs:N #3 + \pref_global:D #2 #3 \tl_use:c { g_ #1 _allocation_tl } \scan_stop: + \iow_log:x + { + \token_to_str:N #3 ~=~ #1 ~register~ + \tl_use:c { g_ #1 _allocation_tl } + } + \alloc_next:n {#1} + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[aux]{\alloc_next:n} +% Finding the next register to use is a question of doing an increment +% then a check: if we run out of registers then it is a fatal error, so +% there is no need to unwind the change. (The check could be done +% first but that needs an additional calculation.) There is a built-in +% loop to handle reserved allocation positions. +% \begin{macrocode} +\cs_new_nopar:Npn \alloc_next:n #1 + { + \tl_gset:cx { g_ #1 _allocation_tl } + { \int_eval:n { \tl_use:c { g_ #1 _allocation_tl } + 1 } } + \int_compare:nNnTF + { \tl_use:c { g_ #1 _allocation_tl } } + > { \tl_use:c { c_ #1 _allocation_max_tl } } + { \msg_kernel_fatal:nnx { alloc } { out-of-registers } {#1} } + { + \seq_if_in:cxT { g_ #1 _allocation_seq } + { \tl_use:c { g_ #1 _allocation_tl } } + { \alloc_next:n {#1} } + } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +%</initex> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintIndex diff --git a/Master/texmf-dist/source/latex/l3kernel/l3basics.dtx b/Master/texmf-dist/source/latex/l3kernel/l3basics.dtx new file mode 100644 index 00000000000..52cc56c699a --- /dev/null +++ b/Master/texmf-dist/source/latex/l3kernel/l3basics.dtx @@ -0,0 +1,3208 @@ +% \iffalse meta-comment +% +%% File: l3basics.dtx Copyright (C) 1990-2011 The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +% +%<*driver|package> +\RequirePackage{l3names} +\GetIdInfo$Id: l3basics.dtx 2493 2011-07-04 09:50:22Z bruno $ + {L3 Experimental basic definitions} +%</driver|package> +%<*driver> +\documentclass[full]{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{^^A +% The \pkg{l3basics} package\\ Basic definitions^^A +% \thanks{This file describes v\ExplFileVersion, +% last revised \ExplFileDate.}^^A +% } +% +% \author{^^A +% The \LaTeX3 Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% +% \date{Released \ExplFileDate} +% +% \maketitle +% +% \begin{documentation} +% +% As the name suggest this package holds some basic definitions which +% are needed by most or all other packages in this set. +% +% Here we describe those functions that are 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. +% +% \section{No operation functions} +% +% \begin{function}[EXP]{\prg_do_nothing:} +% \begin{syntax} +% \cs{prg_do_nothing:} +% \end{syntax} +% An expandable function which does nothing at all: leaves nothing +% in the input stream after a single expansion. +% \end{function} +% +% \begin{function}{\scan_stop:} +% \begin{syntax} +% \cs{scan_stop:} +% \end{syntax} +% A non-expandable function which does nothing. Does not vanish on +% expansion but produces no typeset output. +% \end{function} +% +% \section{Grouping material} +% +% \begin{function}{\group_begin:, \group_end:} +% \begin{syntax} +% \cs{group_begin:} +% \cs{group_end:} +% \end{syntax} +% These functions begin and end a group for definition purposes. +% Assignments are local to groups unless carried out in a global +% manner. (A small number of exceptions to this rule will be noted +% as necessary elsewhere in this document.) Each \cs{group_begin:} +% must be matched by a \cs{group_end:}, although this does not have +% to occur within the same function. Indeed, it is often necessary +% to start a group within one function and finish it within another, +% for example when seeking to use non-standard category codes. +% \end{function} +% +% \begin{function}{\group_insert_after:N} +% \begin{syntax} +% \cs{group_insert_after:N} \meta{token} +% \end{syntax} +% Adds \meta{token} to the list of \meta{tokens} to be inserted +% when the current group level ends. The list of \meta{tokens} to be +% inserted will be empty at the beginning of a group: multiple +% applications of \cs{group_insert_after:N} may be used to build +% the inserted list one \meta{token} at a time. The current group +% level may be closed by a \cs{group_end:} function or by a token +% with category code $2$ (close-group). The later will be a ^^A{ +% |}| if standard category codes apply. +% \end{function} +% +% \section{Control sequences and functions} +% +% As \TeX{} is a macro language, creating new functions means +% creating macros. At point of use, a function is replaced by +% the replacement text (\enquote{code}) in which each parameter +% in the code (|#1|, |#2|, \emph{etc.}) is replaced the appropriate +% arguments absorbed by the function. In the following, \meta{code} +% is therefore used as a shorthand for \enquote{replacement text}. +% +% Functions which are not \enquote{protected} will be fully expanded +% inside an \texttt{x} expansion. In contrast, \enquote{protected} +% functions are not expanded within \texttt{x} expansions. +% +% \subsection{Defining functions} +% +% Functions can be created with no requirement that they are declared +% first (in contrast to variables, which must always be declared). +% Declaring a function before setting up the code means that the name +% chosen will be checked and an error raised if it is already in use. +% The name of a function can be checked at the point of definition using +% the \cs{cs_new\ldots} functions: this is recommended for all +% functions which are defined for the first time. +% +% \subsection{Defining new functions using primitive parameter text} +% +% \begin{function}{\cs_new:Npn, \cs_new:cpn, \cs_new:Npx, \cs_new:cpx} +% \begin{syntax} +% \cs{cs_new:Npn} \meta{function} \meta{parameters} \Arg{code} +% \end{syntax} +% Creates \meta{function} to expand to \meta{code} as replacement text. +% Within the \meta{code}, the \meta{parameters} (|#1|, |#2|, +% \emph{etc.}) will be replaced by those absorbed by the function. +% The definition is global and an error will result if the +% \meta{function} is already defined. +% \end{function} +% +% \begin{function} +% { +% \cs_new_nopar:Npn, \cs_new_nopar:cpn, +% \cs_new_nopar:Npx, \cs_new_nopar:cpx +% } +% \begin{syntax} +% \cs{cs_new_nopar:Npn} \meta{function} \meta{parameters} \Arg{code} +% \end{syntax} +% Creates \meta{function} to expand to \meta{code} as replacement text. +% Within the \meta{code}, the \meta{parameters} (|#1|, |#2|, +% \emph{etc.}) will be replaced by those absorbed by the function. +% When the \meta{function} is used the \meta{parameters} absorbed +% cannot contain \cs{par} tokens. The definition is global and +% an error will result if the \meta{function} is already defined. +% \end{function} +% +% \begin{function} +% { +% \cs_new_protected:Npn, \cs_new_protected:cpn, +% \cs_new_protected:Npx, \cs_new_protected:cpx +% } +% \begin{syntax} +% \cs{cs_new_protected:Npn} \meta{function} \meta{parameters} +% ~~\Arg{code} +% \end{syntax} +% Creates \meta{function} to expand to \meta{code} as replacement text. +% Within the \meta{code}, the \meta{parameters} (|#1|, |#2|, +% \emph{etc.}) will be replaced by those absorbed by the function. +% The \meta{function} will not expand within an \texttt{x}-type +% argument. The definition is global and an error will result if the +% \meta{function} is already defined. +% \end{function} +% +% \begin{function} +% { +% \cs_new_protected_nopar:Npn, \cs_new_protected_nopar:cpn , +% \cs_new_protected_nopar:Npx, \cs_new_protected_nopar:cpx +% } +% \begin{syntax} +% \cs{cs_new_protected_nopar:Npn} \meta{function} \meta{parameters} +% ~~\Arg{code} +% \end{syntax} +% Creates \meta{function} to expand to \meta{code} as replacement text. +% Within the \meta{code}, the \meta{parameters} (|#1|, |#2|, +% \emph{etc.}) will be replaced by those absorbed by the function. +% When the \meta{function} is used the \meta{parameters} absorbed +% cannot contain \cs{par} tokens. The \meta{function} will not +% expand within an \texttt{x}-type argument. The definition is global +% and an error will result if the \meta{function} is already defined. +% \end{function} +% +% \begin{function}{\cs_set:Npn, \cs_set:cpn, \cs_set:Npx, \cs_set:cpx} +% \begin{syntax} +% \cs{cs_set:Npn} \meta{function} \meta{parameters} \Arg{code} +% \end{syntax} +% Sets \meta{function} to expand to \meta{code} as replacement text. +% Within the \meta{code}, the \meta{parameters} (|#1|, |#2|, +% \emph{etc.}) will be replaced by those absorbed by the function. +% The assignment of a meaning to \meta{function} is restricted to +% the current \TeX{} group level. +% \end{function} +% +% \begin{function} +% { +% \cs_set_nopar:Npn, \cs_set_nopar:cpn, +% \cs_set_nopar:Npx, \cs_set_nopar:cpx +% } +% \begin{syntax} +% \cs{cs_set_nopar:Npn} \meta{function} \meta{parameters} \Arg{code} +% \end{syntax} +% Sets \meta{function} to expand to \meta{code} as replacement text. +% Within the \meta{code}, the \meta{parameters} (|#1|, |#2|, +% \emph{etc.}) will be replaced by those absorbed by the function. +% When the \meta{function} is used the \meta{parameters} absorbed +% cannot contain \cs{par} tokens. The assignment of a meaning +% to \meta{function} is restricted to the current \TeX{} group +% level. +% \end{function} +% +% \begin{function} +% { +% \cs_set_protected:Npn, \cs_set_protected:cpn, +% \cs_set_protected:Npx, \cs_set_protected:cpx +% } +% \begin{syntax} +% \cs{cs_set_protected:Npn} \meta{function} \meta{parameters} +% ~~\Arg{code} +% \end{syntax} +% Sets \meta{function} to expand to \meta{code} as replacement text. +% Within the \meta{code}, the \meta{parameters} (|#1|, |#2|, +% \emph{etc.}) will be replaced by those absorbed by the function. +% The assignment of a meaning to \meta{function} is restricted to +% the current \TeX{} group level. The \meta{function} will +% not expand within an \texttt{x}-type argument. +% \end{function} +% +% \begin{function} +% { +% \cs_set_protected_nopar:Npn, \cs_set_protected_nopar:cpn , +% \cs_set_protected_nopar:Npx, \cs_set_protected_nopar:cpx , +% } +% \begin{syntax} +% \cs{cs_set_protected_nopar:Npn} \meta{function} +% ~~\meta{parameters} \Arg{code} +% \end{syntax} +% Sets \meta{function} to expand to \meta{code} as replacement text. +% Within the \meta{code}, the \meta{parameters} (|#1|, |#2|, +% \emph{etc.}) will be replaced by those absorbed by the function. +% When the \meta{function} is used the \meta{parameters} absorbed +% cannot contain \cs{par} tokens. The assignment of a meaning +% to \meta{function} is restricted to the current \TeX{} group +% level. The \meta{function} will not expand within an +% \texttt{x}-type argument. +% \end{function} +% +% \begin{function}{\cs_gset:Npn, \cs_gset:cpn, \cs_gset:Npx, \cs_gset:cpx} +% \begin{syntax} +% \cs{cs_gset:Npn} \meta{function} \meta{parameters} \Arg{code} +% \end{syntax} +% Globally sets \meta{function} to expand to \meta{code} as replacement +% text. Within the \meta{code}, the \meta{parameters} (|#1|, |#2|, +% \emph{etc.}) will be replaced by those absorbed by the function. +% The assignment of a meaning to \meta{function} is \emph{not} +% restricted to the current \TeX{} group level: the assignment is +% global. +% \end{function} +% +% \begin{function} +% { +% \cs_gset_nopar:Npn, \cs_gset_nopar:cpn, +% \cs_gset_nopar:Npx , \cs_gset_nopar:cpx +% } +% \begin{syntax} +% \cs{cs_gset_nopar:Npn} \meta{function} \meta{parameters} \Arg{code} +% \end{syntax} +% Globally sets \meta{function} to expand to \meta{code} as replacement +% text. Within the \meta{code}, the \meta{parameters} (|#1|, |#2|, +% \emph{etc.}) will be replaced by those absorbed by the function. +% When the \meta{function} is used the \meta{parameters} absorbed +% cannot contain \cs{par} tokens. The assignment of a meaning to +% \meta{function} is \emph{not} restricted to the current \TeX{} +% group level: the assignment is global. +% \end{function} +% +% \begin{function} +% { +% \cs_gset_protected:Npn, \cs_gset_protected:cpn, +% \cs_gset_protected:Npx, \cs_gset_protected:cpx +% } +% \begin{syntax} +% \cs{cs_gset_protected:Npn} \meta{function} \meta{parameters} +% ~~\Arg{code} +% \end{syntax} +% Globally sets \meta{function} to expand to \meta{code} as replacement +% text. Within the \meta{code}, the \meta{parameters} (|#1|, |#2|, +% \emph{etc.}) will be replaced by those absorbed by the function. +% The assignment of a meaning to \meta{function} is \emph{not} +% restricted to the current \TeX{} group level: the assignment is +% global. The \meta{function} will not expand within an +% \texttt{x}-type argument. +% \end{function} +% +% \begin{function} +% { +% \cs_gset_protected_nopar:Npn, \cs_gset_protected_nopar:cpn, +% \cs_gset_protected_nopar:Npx, \cs_gset_protected_nopar:cpx +% } +% \begin{syntax} +% \cs{cs_gset_protected_nopar:Npn} \meta{function} +% ~~\meta{parameters} \Arg{code} +% \end{syntax} +% Globally sets \meta{function} to expand to \meta{code} as replacement +% text. Within the \meta{code}, the \meta{parameters} (|#1|, |#2|, +% \emph{etc.}) will be replaced by those absorbed by the function. +% When the \meta{function} is used the \meta{parameters} absorbed +% cannot contain \cs{par} tokens. The assignment of a meaning to +% \meta{function} is \emph{not} restricted to the current \TeX{} +% group level: the assignment is global. The \meta{function} will +% not expand within an \texttt{x}-type argument. +% \end{function} +% +% \subsection{Defining new functions using the signature} +% +% \begin{function} +% { +% \cs_new:Nn, \cs_new:cn, +% \cs_new:Nx, \cs_new:cx +% } +% \begin{syntax} +% \cs{cs_new:Nn} \meta{function} \Arg{code} +% \end{syntax} +% Creates \meta{function} to expand to \meta{code} as replacement text. +% Within the \meta{code}, the number of \meta{parameters} is detected +% automatically from the function signature. These \meta{parameters} +% (|#1|, |#2|, \emph{etc.}) will be replaced by those absorbed by the +% function. The definition is global and +% an error will result if the \meta{function} is already defined. +% \end{function} +% +% \begin{function} +% { +% \cs_new_nopar:Nn, \cs_new_nopar:cn, +% \cs_new_nopar:Nx, \cs_new_nopar:cx +% } +% \begin{syntax} +% \cs{cs_new_nopar:Nn} \meta{function} \Arg{code} +% \end{syntax} +% Creates \meta{function} to expand to \meta{code} as replacement text. +% Within the \meta{code}, the number of \meta{parameters} is detected +% automatically from the function signature. These \meta{parameters} +% (|#1|, |#2|, \emph{etc.}) will be replaced by those absorbed by the +% function. When the \meta{function} is used the \meta{parameters} +% absorbed cannot contain \cs{par} tokens. The definition is global and +% an error will result if the \meta{function} is already defined. +% \end{function} +% +% \begin{function} +% { +% \cs_new_protected:Nn, \cs_new_protected:cn, +% \cs_new_protected:Nx, \cs_new_protected:cx +% } +% \begin{syntax} +% \cs{cs_new_protected:Nn} \meta{function} \Arg{code} +% \end{syntax} +% Creates \meta{function} to expand to \meta{code} as replacement text. +% Within the \meta{code}, the number of \meta{parameters} is detected +% automatically from the function signature. These \meta{parameters} +% (|#1|, |#2|, \emph{etc.}) will be replaced by those absorbed by the +% function. The \meta{function} will not expand within an \texttt{x}-type +% argument. The definition is global and +% an error will result if the \meta{function} is already defined. +% \end{function} +% +% \begin{function} +% { +% \cs_new_protected_nopar:Nn, \cs_new_protected_nopar:cn, +% \cs_new_protected_nopar:Nx, \cs_new_protected_nopar:cx +% } +% \begin{syntax} +% \cs{cs_new_protected_nopar:Nn} \meta{function} \Arg{code} +% \end{syntax} +% Creates \meta{function} to expand to \meta{code} as replacement text. +% Within the \meta{code}, the number of \meta{parameters} is detected +% automatically from the function signature. These \meta{parameters} +% (|#1|, |#2|, \emph{etc.}) will be replaced by those absorbed by the +% function. When the \meta{function} is used the \meta{parameters} +% absorbed cannot contain \cs{par} tokens. The \meta{function} will not +% expand within an \texttt{x}-type argument. The definition is global and +% an error will result if the \meta{function} is already defined. +% \end{function} +% +% \begin{function} +% { +% \cs_set:Nn, \cs_set:cn, +% \cs_set:Nx, \cs_set:cx +% } +% \begin{syntax} +% \cs{cs_set:Nn} \meta{function} \Arg{code} +% \end{syntax} +% Sets \meta{function} to expand to \meta{code} as replacement text. +% Within the \meta{code}, the number of \meta{parameters} is detected +% automatically from the function signature. These \meta{parameters} +% (|#1|, |#2|, \emph{etc.}) will be replaced by those absorbed by the +% function. +% The assignment of a meaning to \meta{function} is restricted to +% the current \TeX{} group level. +% \end{function} +% +% \begin{function} +% { +% \cs_set_nopar:Nn, \cs_set_nopar:cn, +% \cs_set_nopar:Nx, \cs_set_nopar:cx +% } +% \begin{syntax} +% \cs{cs_set_nopar:Nn} \meta{function} \Arg{code} +% \end{syntax} +% Sets \meta{function} to expand to \meta{code} as replacement text. +% Within the \meta{code}, the number of \meta{parameters} is detected +% automatically from the function signature. These \meta{parameters} +% (|#1|, |#2|, \emph{etc.}) will be replaced by those absorbed by the +% function. When the \meta{function} is used the \meta{parameters} +% absorbed cannot contain \cs{par} tokens. +% The assignment of a meaning to \meta{function} is restricted to +% the current \TeX{} group level. +% \end{function} +% +% \begin{function} +% { +% \cs_set_protected:Nn, \cs_set_protected:cn, +% \cs_set_protected:Nx, \cs_set_protected:cx +% } +% \begin{syntax} +% \cs{cs_set_protected:Nn} \meta{function} \Arg{code} +% \end{syntax} +% Sets \meta{function} to expand to \meta{code} as replacement text. +% Within the \meta{code}, the number of \meta{parameters} is detected +% automatically from the function signature. These \meta{parameters} +% (|#1|, |#2|, \emph{etc.}) will be replaced by those absorbed by the +% function. The \meta{function} will not expand within an \texttt{x}-type +% argument. +% The assignment of a meaning to \meta{function} is restricted to +% the current \TeX{} group level. +% \end{function} +% +% \begin{function} +% { +% \cs_set_protected_nopar:Nn, \cs_set_protected_nopar:cn, +% \cs_set_protected_nopar:Nx, \cs_set_protected_nopar:cx +% } +% \begin{syntax} +% \cs{cs_set_protected_nopar:Nn} \meta{function} \Arg{code} +% \end{syntax} +% Sets \meta{function} to expand to \meta{code} as replacement text. +% Within the \meta{code}, the number of \meta{parameters} is detected +% automatically from the function signature. These \meta{parameters} +% (|#1|, |#2|, \emph{etc.}) will be replaced by those absorbed by the +% function. When the \meta{function} is used the \meta{parameters} +% absorbed cannot contain \cs{par} tokens. The \meta{function} will not +% expand within an \texttt{x}-type argument. +% The assignment of a meaning to \meta{function} is restricted to +% the current \TeX{} group level. +% \end{function} +% +% \begin{function} +% { +% \cs_gset:Nn, \cs_gset:cn, +% \cs_gset:Nx, \cs_gset:cx +% } +% \begin{syntax} +% \cs{cs_gset:Nn} \meta{function} \Arg{code} +% \end{syntax} +% Sets \meta{function} to expand to \meta{code} as replacement text. +% Within the \meta{code}, the number of \meta{parameters} is detected +% automatically from the function signature. These \meta{parameters} +% (|#1|, |#2|, \emph{etc.}) will be replaced by those absorbed by the +% function. +% The assignment of a meaning to \meta{function} is global. +% \end{function} +% +% \begin{function} +% { +% \cs_gset_nopar:Nn, \cs_gset_nopar:cn, +% \cs_gset_nopar:Nx, \cs_gset_nopar:cx +% } +% \begin{syntax} +% \cs{cs_gset_nopar:Nn} \meta{function} \Arg{code} +% \end{syntax} +% Sets \meta{function} to expand to \meta{code} as replacement text. +% Within the \meta{code}, the number of \meta{parameters} is detected +% automatically from the function signature. These \meta{parameters} +% (|#1|, |#2|, \emph{etc.}) will be replaced by those absorbed by the +% function. When the \meta{function} is used the \meta{parameters} +% absorbed cannot contain \cs{par} tokens. +% The assignment of a meaning to \meta{function} is global. +% \end{function} +% +% \begin{function} +% { +% \cs_gset_protected:Nn, \cs_gset_protected:cn, +% \cs_gset_protected:Nx, \cs_gset_protected:cx +% } +% \begin{syntax} +% \cs{cs_gset_protected:Nn} \meta{function} \Arg{code} +% \end{syntax} +% Sets \meta{function} to expand to \meta{code} as replacement text. +% Within the \meta{code}, the number of \meta{parameters} is detected +% automatically from the function signature. These \meta{parameters} +% (|#1|, |#2|, \emph{etc.}) will be replaced by those absorbed by the +% function. The \meta{function} will not expand within an \texttt{x}-type +% argument. +% The assignment of a meaning to \meta{function} is global. +% \end{function} +% +% \begin{function} +% { +% \cs_gset_protected_nopar:Nn, \cs_gset_protected_nopar:cn, +% \cs_gset_protected_nopar:Nx, \cs_gset_protected_nopar:cx +% } +% \begin{syntax} +% \cs{cs_gset_protected_nopar:Nn} \meta{function} \Arg{code} +% \end{syntax} +% Sets \meta{function} to expand to \meta{code} as replacement text. +% Within the \meta{code}, the number of \meta{parameters} is detected +% automatically from the function signature. These \meta{parameters} +% (|#1|, |#2|, \emph{etc.}) will be replaced by those absorbed by the +% function. When the \meta{function} is used the \meta{parameters} +% absorbed cannot contain \cs{par} tokens. The \meta{function} will not +% expand within an \texttt{x}-type argument. +% The assignment of a meaning to \meta{function} is global. +% \end{function} +% +% \begin{function} +% {\cs_generate_from_arg_count:NNnn, \cs_generate_from_arg_count:cNnn} +% \begin{syntax} +% \cs{cs_generate_from_arg_count:NNnn} \meta{function} +% ~~\meta{creator} \meta{number} \meta{code} +% \end{syntax} +% Uses the \meta{creator} function (which should have signature +% |Npn|, for example \cs{cs_new:Npn}) to define a \meta{function} +% which takes \meta{number} arguments and has \meta{code} as +% replacement text. The \meta{number} of arguments is an integer expression, +% evaluated as detailed for \cs{int_eval:n}. +% \end{function} +% +% \subsection{Copying control sequences} +% +% Control sequences (not just functions as defined above) can +% be set to have the same meaning using the functions described +% here. Making two control sequences equivalent means that the +% second control sequence is a \emph{copy} of the first (rather than +% a pointer to it). Thus the old and new control sequence are not +% tided together: changes to one are not reflected in the other. +% +% In the following text \enquote{cs} is used as an abbreviation for +% \enquote{control sequence}. +% +% \begin{function} +% {\cs_new_eq:NN, \cs_new_eq:Nc, \cs_new_eq:cN, \cs_new_eq:cc} +% \begin{syntax} +% \cs{cs_new_eq:NN} \meta{cs 1} \meta{cs 2} +% \end{syntax} +% Creates \meta{control sequence 1} and sets it to have the same +% meaning as \meta{control sequence 2} at the point where +% \cs{cs_new_eq:NN} is executed. The two control sequences may +% subsequently be altered without affecting the copy. The assignment +% of a meaning to \meta{control sequence 1} is global. +% \end{function} +% +% \begin{function} +% {\cs_set_eq:NN, \cs_set_eq:Nc, \cs_set_eq:cN, \cs_set_eq:cc} +% \begin{syntax} +% \cs{cs_set_eq:NN} \meta{cs 1} \meta{cs 2} +% \end{syntax} +% Sets \meta{control sequence 1} to have the same meaning as +% \meta{control sequence 2} at the point where \cs{cs_set_eq:NN} +% is executed. The two control sequences may subsequently be +% altered without affecting the copy. The assignment of a meaning +% to \meta{control sequence 1} is restricted to the current +% \TeX{} group level. +% \end{function} +% +% \begin{function} +% {\cs_gset_eq:NN, \cs_gset_eq:Nc, \cs_gset_eq:cN, \cs_gset_eq:cc} +% \begin{syntax} +% \cs{cs_gset_eq:NN} \meta{cs 1} \meta{cs 2} +% \end{syntax} +% Globally sets \meta{control sequence 1} to have the same meaning as +% \meta{control sequence 2} at the point where \cs{cs_gset_eq:NN} +% is executed. The two control sequences may subsequently be +% altered without affecting the copy. The assignment of a meaning to +% \meta{control sequence 1} is \emph{not} restricted to the current +% \TeX{} group level: the assignment is global. +% \end{function} +% +% \subsection{Deleting control sequences} +% +% There are occasions where control sequences need to be deleted. +% This is handled in a very simple manner. +% +% \begin{function}{\cs_undefine:N, \cs_undefine:c} +% \begin{syntax} +% \cs{cs_undefine:N} \meta{control sequence} +% \end{syntax} +% Sets \meta{control sequence} to be globally undefined. +% \end{function} +% +% \subsection{Showing control sequences} +% +% \begin{function}[EXP]{\cs_meaning:N, \cs_meaning:c} +% \begin{syntax} +% \cs{cs_meaning:N} \meta{control sequence} +% \end{syntax} +% This function expands to the \emph{meaning} of the \meta{control sequence} +% control sequence. This will show the \meta{replacement text} for a +% macro. +% \begin{texnote} +% This is \TeX{}'s \cs{meaning} primitive. +% \end{texnote} +% \end{function} +% +% \begin{function}{\cs_show:N, \cs_show:c} +% \begin{syntax} +% \cs{cs_show:N} \meta{control sequence} +% \end{syntax} +% Displays the definition of the \meta{control sequence} on the +% terminal. +% \begin{texnote} +% This is the \TeX{} primitive \cs{show}. +% \end{texnote} +% \end{function} +% + +% \subsection{Converting to and from control sequences} +% +% \begin{function}[EXP]{\use:c} +% \begin{syntax} +% \cs{use:c} \Arg{control sequence name} +% \end{syntax} +% Converts the given \meta{control sequence name} into a single +% control sequence token. This process requires two expansions. +% The content for \meta{control sequence name} may be literal +% material or from other expandable functions. The +% \meta{control sequence name} must, when fully expanded, consist +% of character tokens which are not active: typically, they will +% be of category code $10$ (space), $11$ (letter) +% or $12$ (other), or a mixture of these. As an example, both +% \begin{verbatim} +% \use:c { a b c } +% \end{verbatim} +% and +% \begin{verbatim} +% \tl_new:N \l_my_tl +% \tl_set:Nn \l_my_tl { a b c } +% \use:c { \tl_use:N \l_my_tl } +% \end{verbatim} +% would be equivalent to +% \begin{verbatim} +% \abc +% \end{verbatim} +% after two expansions of \cs{use:c}. +% \end{function} +% +% \begin{function}[EXP]{\cs:w, \cs_end:} +% \begin{syntax} +% \cs{cs:w} \meta{control sequence name} \cs{cs_end:} +% \end{syntax} +% Converts the given \meta{control sequence name} into a single +% control sequence token. This process requires one expansion. +% The content for \meta{control sequence name} may be literal +% material or from other expandable functions. The +% \meta{control sequence name} must, when fully expanded, consist +% of character tokens which are not active: typically, they will +% be of category code $10$ (space), $11$ (letter) +% or $12$ (other), or a mixture of these. As an example, both +% \begin{verbatim} +% \cs:w a b c \cs_end: +% \end{verbatim} +% and +% \begin{verbatim} +% \tl_new:N \l_my_tl +% \tl_set:Nn \l_my_tl { a b c } +% \cs:w \tl_use:N \l_my_tl \cs_end: +% \end{verbatim} +% would be equivalent to +% \begin{verbatim} +% \abc +% \end{verbatim} +% after one expansion of \cs{cs:w}. +% \begin{texnote} +% These are the \TeX{} primitives \cs{csname} and \cs{endcsname}. +% \end{texnote} +% \end{function} +% +% \begin{function}[EXP]{\cs_to_str:N} +% \begin{syntax} +% \cs{cs_to_str:N} \Arg{control sequence} +% \end{syntax} +% Converts the given \meta{control sequence} into a series of +% characters with category code $12$ (other), except spaces, +% of category code $10$. The sequence will \emph{not} include +% the current escape token, \emph{cf.}~\cs{token_to_str:N}. +% Full expansion of this function requires a variable number +% of expansion steps (either 3 or 4), and so an +% \texttt{f}- or \texttt{x}-type expansion will be required to +% convert the \meta{control sequence} to a sequence of characters +% in the input stream. +% \end{function} +% +% \section{Using or removing tokens and arguments} +% +% Tokens in the input can be read and used or read and discarded. +% If one or more tokens are wrapped in braces then in absorbing them +% the outer set will be removed. At the same time, the category code +% of each token is set when the token is read by a function (if it +% is read more than once, the category code is determined by the +% the situation in force when first function absorbs the token). +% +% \begin{function}[EXP]{\use:n, \use:nn, \use:nnn, \use:nnnn} +% \begin{syntax} +% \cs{use:n} \Arg{group1} +% \cs{use:nn} \Arg{group1} \Arg{group2} +% \cs{use:nnn} \Arg{group1} \Arg{group2} \Arg{group3} +% \cs{use:nnn} \Arg{group1} \Arg{group2} \Arg{group3} \Arg{group4} +% \end{syntax} +% As illustrated, these functions will absorb between one and four +% arguments, as indicated by the argument specifier. The braces +% surrounding each argument will be removed leaving the remaining +% tokens in the input stream. The category code of these tokens will +% also be fixed by this process (if it has not already been by some +% other absorption). All of these functions require only a single +% expansion to operate, so that one expansion of +% \begin{verbatim} +% \use:nn { abc } { { def } } +% \end{verbatim} +% will result in the input stream containing +% \begin{verbatim} +% abc { def } +% \end{verbatim} +% \emph{i.e.} only the outer braces will be removed. +% \end{function} +% +% \begin{function}[EXP]{\use_i:nn, \use_ii:nn} +% \begin{syntax} +% \cs{use_i:nn} \Arg{group1} \Arg{group2} +% \end{syntax} +% These functions will absorb two groups and leave only the +% first or the second in the input stream. The braces surrounding the +% arguments will be removed as part of this process. The category code +% of these tokens will also be fixed (if it has not already been by +% some other absorption). A single expansion is needed for the +% functions to take effect. +% \end{function} +% +% \begin{function}[EXP]{\use_i:nnn, \use_ii:nnn, \use_iii:nnn} +% \begin{syntax} +% \cs{use_i:nnn} \Arg{group1} \Arg{group2} \Arg{group3} +% \end{syntax} +% These functions will absorb three groups and leave only of these +% in the input stream. The braces surrounding the arguments will be +% removed as part of this process. The category code of these tokens +% will also be fixed (if it has not already been by some other +% absorption). A single expansion is needed for the functions to take +% effect. +% \end{function} +% +% \begin{function}[EXP] +% {\use_i:nnnn, \use_ii:nnnn, \use_iii:nnnn , \use_iv:nnnn} +% \begin{syntax} +% \cs{use_i:nnnn} \Arg{group1} \Arg{group2} \Arg{group3} \Arg{group4} +% \end{syntax} +% These functions will absorb four groups and leave only of these +% in the input stream. The braces surrounding the arguments will be +% removed as part of this process. The category code of these tokens +% will also be fixed (if it has not already been by some other +% absorption). A single expansion is needed for the functions to take +% effect. +% \end{function} +% +% \begin{function}[EXP]{\use_i_ii:nnn} +% \begin{syntax} +% \cs{use_i_ii:nnn} \Arg{group1} \Arg{group2} \Arg{group3} +% \end{syntax} +% This functions will absorb three groups and leave the first and +% second in the input stream. The braces surrounding the arguments +% will be removed as part of this process. The category code of +% these tokens will also be fixed (if it has not already been by +% some other absorption). A single expansion is needed for the +% functions to take effect. An example: +% \begin{verbatim} +% \use_i_ii:nnn { abc } { { def } } { ghi } +% \end{verbatim} +% will result in the input stream containing +% \begin{verbatim} +% abc { def } +% \end{verbatim} +% \emph{i.e.} the outer braces will be removed and the third group +% will be removed. +% \end{function} +% +% \begin{function}[EXP] +% { +% \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} +% \cs{use_none:n} \Arg{group1} +% \end{syntax} +% These functions absorb between one and nine groups from the +% input stream, leaving nothing on the resulting input stream. +% These functions work after a single expansion. One or more of the +% \texttt{n} arguments may be an unbraced single token +% (\emph{i.e.}~an \texttt{N} argument). +% \end{function} +% +% \begin{function}{\use:x} +% \begin{syntax} +% \cs{use:x} \Arg{expandable tokens} +% \end{syntax} +% Fully expands the \meta{expandable tokens} and inserts the +% result into the input stream at the current location. +% \end{function} +% +% \subsection{Selecting tokens from delimited arguments} +% +% A different kind of function for selecting tokens from the token +% stream are those that use delimited arguments. +% +% \begin{function}[EXP] +% { +% \use_none_delimit_by_q_nil:w, +% \use_none_delimit_by_q_stop:w, +% \use_none_delimit_by_q_recursion_stop:w +% } +% \begin{syntax} +% \cs{use_none_delimit_by_q_nil:w} \meta{balanced text} \cs{q_nil} +% \end{syntax} +% Absorb the \meta{balanced} text form the input stream delimited by +% the marker given in the function name, leaving nothing in the +% input stream. +% \end{function} +% +% \begin{function}[EXP] +% { +% \use_i_delimit_by_q_nil:nw, +% \use_i_delimit_by_q_stop:nw, +% \use_i_delimit_by_q_recursion_stop:nw +% } +% \begin{syntax} +% \cs{use_i_delimit_by_q_nil:nw} \Arg{inserted tokens} +% ~~\meta{balanced text} \cs{q_nil} +% \end{syntax} +% Absorb the \meta{balanced} text form the input stream delimited by +% the marker given in the function name, leaving \meta{inserted tokens} +% in the input stream for further processing. +% \end{function} +% +% +% \begin{function}[EXP] +% { +% \use_i_after_fi:nw, +% \use_i_after_else:nw, +% \use_i_after_or:nw, +% \use_i_after_orelse:nw +% } +% \begin{syntax} +% \cs{use_i_after_fi:nw} \Arg{inserted tokens} \cs{fi:} +% \cs{use_i_after_else:nw} \Arg{inserted tokens} \cs{else:} +% ~~\meta{balanced text} \cs{fi:} +% \cs{use_i_after_or:nw} \Arg{inserted tokens} \cs{or:} +% ~~\meta{balanced text} \cs{fi:} +% \cs{use_i_after_orelse:nw} \Arg{inserted tokens} \cs{or:} or \cs{else:} +% ~~\meta{balanced text} \cs{fi:} +% \end{syntax} +% Absorb the \meta{balanced text}, if appropriate, delimited by +% the function name given. The \meta{inserted tokens} are then placed +% in the input stream after the delimiter. Thus for example +% \begin{verbatim} +% \use_i_after_fi:nw { some tokens } \fi: +% \end{verbatim} +% will leave +% \begin{verbatim} +% \fi: some tokens +% \end{verbatim} +% in the input stream for further processing. See the discussion of the +% primitive \TeX{} conditionals for more detail on \cs{else:}, \cs{fi:} +% and \cs{or:}. +% \end{function} +% +% \subsection{Decomposing control sequences} +% +% \begin{function}[EXP]{\cs_get_arg_count_from_signature:N} +% \begin{syntax} +% \cs{cs_get_arg_count_from_signature:N} \meta{function} +% \end{syntax} +% Splits the \meta{function} into the name (\emph{i.e.}~the part +% before the colon) and the signature (\emph{i.e.}~after the colon). +% The \meta{number} of tokens in the \meta{signature} is then left in +% the input stream. If there was no \meta{signature} then the result is +% the marker value $-1$. +% \end{function} +% +% \begin{function}[EXP]{\cs_get_function_name:N} +% \begin{syntax} +% \cs{cs_get_function_name:NN} \meta{function} +% \end{syntax} +% Splits the \meta{function} into the name (\emph{i.e.}~the part +% before the colon) and the signature (\emph{i.e.}~after the colon). +% The \meta{name} is then left in the input stream without the escape +% character present made up of tokens with category code $12$ +% (other). +% \end{function} +% +% \begin{function}{[EXP]\cs_get_function_signature:N} +% \begin{syntax} +% \cs{cs_get_function_signature:NN} \meta{function} +% \end{syntax} +% Splits the \meta{function} into the name (\emph{i.e.}~the part +% before the colon) and the signature (\emph{i.e.}~after the colon). +% The \meta{signature} is then left in the input stream made up of +% tokens with category code $12$ (other). +% \end{function} +% +% \begin{function}EXP]{\cs_split_function:NN} +% \begin{syntax} +% \cs{cs_split_function:NN} \meta{function} \meta{processor} +% \end{syntax} +% Splits the \meta{function} into the name (\emph{i.e.}~the part +% before the colon) and the signature (\emph{i.e.}~after the colon). +% This information is then placed in the input stream after the +% \meta{processor} function in three parts: the \meta{name}, the +% \meta{signature} and a logic token indicating if a colon was found +% (to differentiate variables from function names). The \meta{name} +% will not include the escape character, and both the \meta{name} and +% \meta{signature} are made up of tokens with category code $12$ +% (other). The \meta{processor} should be a function with argument +% specification \texttt{:nnN} (plus any trailing arguments needed). +% \end{function} +% +% \begin{function}[EXP]{\cs_to_str:N} +% \begin{syntax} +% \cs{cs_to_str:N} \Arg{control sequence} +% \end{syntax} +% Converts the given \meta{control sequence} into a series of +% characters with category code $12$ (other), except spaces, +% of category code $10$. The sequence will \emph{not} include +% the current escape token, \emph{cf.}~\cs{token_to_str:N}. +% Full expansion of this function requires a variable number +% of expansion steps (either 3 or 4), and so an +% \texttt{f}- or \texttt{x}-type expansion will be required to +% convert the \meta{control sequence} to a sequence of characters +% in the input stream. +% \end{function} +% +% \section{Predicates and conditionals} +% \label{sec:predicates} +% +% \LaTeX3 has three concepts for conditional flow processing: +% \begin{description} +% \item[Branching conditionals] +% Functions that carry out a test and then execute, depending on its +% result, either the code supplied in the \meta{true arg} or the +% \meta{false arg}. +% These arguments are denoted with |T| and |F|, respectively. An +% example would be +% \begin{quote} +% |\cs_if_free:cTF{abc}| \Arg{true code} \Arg{false code} +% \end{quote} +% a function that will turn the first argument into a control sequence +% (since it's marked as |c|) then checks whether this control sequence +% is still free and then depending on the result carry out the code in +% the second argument (true case) or in the third argument (false +% case). +% +% These type of functions are known as \enquote{conditionals}; +% whenever a |TF| function is defined it will usually be accompanied by +% |T| and |F| functions as well. These are provided for convenience when +% the branch only needs to go a single way. Package writers are free to +% choose which types to define but the kernel definitions will always +% provide all three versions. +% +% Important to note is that these branching conditionals with \meta{true +% code} and/or \meta{false code} are always defined in a way that the +% code of the chosen alternative can operate on following tokens in +% the input stream. +% +% These conditional functions may or may not be fully expandable, but if +% they are expandable they will be accompanied by a \enquote{predicate} +% for the same test as described below. +% +% \item[Predicates] +% \enquote{Predicates} are functions that return a special type of +% boolean value which can be tested by the function \cs{if_predicate:w} +% or in the boolean expression parser. All functions of this type +% are expandable and have names that end with |_p| in the +% description part. For example, +% \begin{quote} +% |\cs_if_free_p:N| +% \end{quote} +% would be a predicate function for the same type of test as the +% conditional described above. It would return \enquote{true} if its +% argument (a single token denoted by |N|) is still free for definition. +% It would be used in constructions like +% \begin{quote} +% |\if_predicate:w \cs_if_free_p:N \l_tmpz_tl| \\ +% | |\meta{true code} \\ +% |else:| \\ +% | |\meta{false code}\\ +% |\fi:| \\ +% \end{quote} +% or in expressions utilizing the boolean logic parser: +% \begin{quote} +% |\bool_if:nTF {| \\ +% \verb" \cs_if_free_p:N \l_tmpz_tl || \cs_if_free_p:N \g_tmpz_tl " \\ +% |}| +% \Arg{true code} \Arg{false code} +% \end{quote} +% +% Like their branching cousins, predicate functions ensure that all +% underlying primitive |\else:| or |\fi:| have been removed before +% returning the boolean true or false values.\footnote{If defined +% using the interface provided.} +% +% For each predicate defined, a \enquote{predicate conditional} will +% also exist that behaves like a conditional described above. +% +% \item[Primitive conditionals] +% There is a third variety of conditional, which is the original +% concept used in plain \TeX{} and \LaTeXe{}. Their use is discouraged +% in \pkg{expl3} (although still used in low-level definitions) +% because they are more fragile and in many cases require more +% expansion control (hence more code) than the two types of +% conditionals described above. +% \end{description} +% +% \begin{variable}{\c_true_bool, \c_false_bool} +% Constants that represent |true| and |false|, respectively. Used to +% implement predicates. +% \end{variable} +% +% \subsection{Tests on control sequences} +% +% \begin{function}[EXP,pTF]{\cs_if_eq:NN} +% \begin{syntax} +% \cs{cs_if_eq_p:NN} \Arg{cs1} \Arg{cs2} +% \cs{cs_if_eq:NNTF} \Arg{cs1} \Arg{cs2} \Arg{true code} +% ~~\Arg{false code} +% \end{syntax} +% Compares the definition of two \meta{control sequences} and +% is logically \texttt{true} if the two are the same. The branching +% versions then leave either \meta{true code} or \meta{false code} +% in the input stream, as appropriate to the truth of the test and the +% variant of the function chosen. The logical truth of the test is left +% in the input stream by the predicate version. +% \end{function} +% +% \begin{function}[EXP,pTF]{\cs_if_exist:N, \cs_if_exist:c} +% \begin{syntax} +% \cs{cs_if_exist_p:N} \meta{control sequence} +% \cs{cs_if_exist:NTF} \meta{control sequence} \meta{true code} +% ~~\meta{false code} +% \end{syntax} +% Tests whether the \meta{control sequence} is currently defined +% (whether as a function or another control sequence type). Any +% valid definition of \meta{control sequence} will evaluate as +% \texttt{true}. The branching versions then leave either +% \meta{true code} or \meta{false code} in the input stream, as +% appropriate to the truth of the test and the variant of the function +% chosen. The logical truth of the test is left in the input stream by +% the predicate version. +% \end{function} +% +% \begin{function}[EXP,pTF]{\cs_if_free:N, \cs_if_free:c} +% \begin{syntax} +% \cs{cs_if_free_p:N} \meta{control sequence} +% \cs{cs_if_free:NTF} \meta{control sequence} \meta{true code} +% ~~\meta{false code} +% \end{syntax} +% Tests whether the \meta{control sequence} is currently free to +% be defined. This test will be \texttt{false} if the +% \meta{control sequence} currently exists (as defined by +% \cs{cs_if_exist:N}). The branching versions then leave either +% \meta{true code} or \meta{false code} in the input stream, as +% appropriate to the truth of the test and the variant of the function +% chosen. The logical truth of the test is left in the input stream by +% the predicate version. +% \end{function} +% +% \subsection{Testing string equality} +% +% \begin{function}[EXP,pTF] +% { +% \str_if_eq:nn, \str_if_eq:Vn, \str_if_eq:on, \str_if_eq:no, +% \str_if_eq:nV, \str_if_eq:VV, \str_if_eq:xx +% } +% \begin{syntax} +% \cs{str_if_eq_p:nn} \Arg{tl1} \Arg{tl2} +% \cs{str_if_eq:nnTF} \Arg{tl1} \Arg{tl2} \Arg{true code} \Arg{false code} +% \end{syntax} +% Compares the two \meta{token lists} on a character by character +% basis, and is \texttt{true} if the two lists contain the same +% characters in the same order. Thus for example +% \begin{verbatim} +% \str_if_eq_p:xx { abc } { \tl_to_str:n { abc } } +% \end{verbatim} +% is logically \texttt{true}. The branching versions then leave either +% \meta{true code} or \meta{false code} in the input stream, as +% appropriate to the truth of the test and the variant of the function +% chosen. The logical truth of the test is left in the input stream by +% the predicate version. All versions of these functions are fully +% expandable (including those involving an \texttt{x}-type +% expansion). +% \end{function} +% +% \subsection{Engine-specific conditionals} +% +% \begin{function}[EXP,TF]{\luatex_if_engine:} +% \begin{syntax} +% \cs{luatex_if_luatex:TF} \Arg{true code} \Arg{false code} +% \end{syntax} +% Detects is the document is being compiled using \LuaTeX{}. The +% branching versions then leave either \meta{true code} or +% \meta{false code} in the input stream, as appropriate to the truth +% of the test and the variant of the function chosen. +% \end{function} +% +% \begin{function}[EXP,TF]{\pdftex_if_engine:} +% \begin{syntax} +% \cs{pdftex_if_engine:TF} \Arg{true code} \Arg{false code} +% \end{syntax} +% Detects is the document is being compiled using \pdfTeX{}. The +% branching versions then leave either \meta{true code} or +% \meta{false code} in the input stream, as appropriate to the truth +% of the test and the variant of the function chosen. +% \end{function} +% +% \begin{function}[EXP,TF]{\xetex_if_engine:} +% \begin{syntax} +% \cs{xetex_if_engine:TF} \Arg{true code} \Arg{false code} +% \end{syntax} +% Detects is the document is being compiled using \XeTeX{}. The +% branching versions then leave either \meta{true code} or +% \meta{false code} in the input stream, as appropriate to the truth +% of the test and the variant of the function chosen. +% \end{function} +% +% \begin{variable} +% { +% \c_luatex_is_engine_bool, \c_pdftex_is_engine_bool, +% \c_xetex_is_engine_bool +% } +% Boolean versions of the engine conditionals, for use in predicate +% tests. +% \end{variable} +% +% \subsection{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}[EXP] +% {\if_true:, \if_false:, \or:, \else:, \fi:, \reverse_if:N} +% \begin{syntax} +% "\if_true:" <true code> "\else:" <false code> "\fi:" \\ +% "\if_false:" <true code> "\else:" <false code> "\fi:" \\ +% "\reverse_if:N" <primitive conditional> +% \end{syntax} +% "\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. "\or:" is used in case switches, see \pkg{l3intexpr} +% for more. +% \begin{texnote} +% These are equivalent to their corresponding \TeX\ primitive +% conditionals; |\reverse_if:N| is \eTeX's |\unless|. +% \end{texnote} +% \end{function} +% +% \begin{function}[EXP]{\if_meaning:w} +% \begin{syntax} +% "\if_meaning:w" <arg1> <arg2> <true code> "\else:" <false code> "\fi:" +% \end{syntax} +% "\if_meaning:w" executes <true code> when <arg1> and <arg2> are the same, +% otherwise it executes <false code>. +% <arg1> and <arg2> could be functions, variables, tokens; in all cases the +% \emph{unexpanded} definitions are compared. +% \begin{texnote} +% This is \TeX's |\ifx|. +% \end{texnote} +% \end{function} +% +% \begin{function}[EXP]{\if:w, \if_charcode:w,\if_catcode:w} +% \begin{syntax} +% "\if:w" <token1> <token2> <true code> "\else:" <false code> "\fi:" \\ +% "\if_catcode:w" <token1> <token2> <true code> "\else:" <false +% code> "\fi:" +% \end{syntax} +% 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}[EXP]{\if_predicate:w} +% \begin{syntax} +% "\if_predicate:w" <predicate> <true code> "\else:" <false code> "\fi:" +% \end{syntax} +% This function takes a predicate function and +% branches according to the result. (In practice this function would also +% accept a single boolean variable in place of the <predicate> but to make the +% coding clearer this should be done through "\if_bool:N".) +% \end{function} +% +% \begin{function}[EXP]{\if_bool:N} +% \begin{syntax} +% "\if_bool:N" <boolean> <true code> "\else:" <false code> "\fi:" +% \end{syntax} +% This function takes a boolean variable and +% branches according to the result. +% \end{function} +% +% \begin{function}[EXP]{\if_cs_exist:N, \if_cs_exist:w} +% \begin{syntax} +% "\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}[EXP] +% { +% \if_mode_horizontal:, \if_mode_vertical:, +% \if_mode_math:, \if_mode_inner: +% } +% \begin{syntax} +% "\if_mode_horizontal:" <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} +% +% \section{Internal kernel functions} +% +% \begin{function}{\chk_if_exist_cs:N, \chk_if_exist_cs:c} +% \begin{syntax} +% \cs{chk_if_exist_cs:N} \meta{cs} +% \end{syntax} +% This function checks that \meta{cs} exists according to the +% criteria for \cs{cs_if_exist_p:N}, and if not raises a kernel-level +% error. +% \end{function} +% +% \begin{function}{\chk_if_free_cs:N, \chk_if_free_cs:c} +% \begin{syntax} +% \cs{chk_if_free_cs:N} \meta{cs} +% \end{syntax} +% This function checks that \meta{cs} is free according to the +% criteria for \cs{cs_if_free_p:N}, and if not raises a kernel-level +% error. +% \end{function} +% +% \begin{function}{\pref_global:D, \pref_long:D, \pref_protected:D} +% \begin{syntax} +% \cs{pref_global:D} \cs{cs_set_nopar:Npn} +% \end{syntax} +% Prefix functions that can be used in front of some definition +% functions (namely \ldots). The result of prefixing a function +% definition with \cs{pref_global:D} makes the definition global, +% \cs{pref_long:D} change the argument scanning mechanism so that it +% allows \cs{par} tokens in the argument of the prefixed function, +% and \cs{pref_protected:D} makes the definition robust inside +% \texttt{x}-type expansions. +% +% None of these internal functions should be used by a programmer since +% the necessary combinations are all available as separate function, +% \emph{e.g.} \cs{cs_set:Npn} is internally implemented as \cs{pref_long:D} +% \c{cs_set_nopar:Npn}. +% \begin{texnote} +% These prefixes are the primitives \tn{global}, \tn{long}, and +% \cs{protected}. +% \end{texnote} +% \end{function} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{l3basics} implementation} +% +% \begin{macrocode} +%<*initex|package> +% \end{macrocode} +% +% \begin{macrocode} +%<*package> +\ProvidesExplPackage + {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +\package_check_loaded_expl: +%</package> +% \end{macrocode} +% +% \subsection{Renaming some \TeX{} primitives (again)} +% +% 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 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 \cs{tex\ldots:D} name in the cases where no good alternative exists.} +% +% \begin{macro}{\cs_set_eq:NwN} +% A pretty basic requirement: \cs{let} one control sequence to another. +% \begin{macrocode}> +\tex_let:D \cs_set_eq:NwN \tex_let:D +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\if_true:} +% \begin{macro}{\if_false:} +% \begin{macro}{\or:} +% \begin{macro}{\else:} +% \begin{macro}{\fi:} +% \begin{macro}{\reverse_if:N} +% \begin{macro}{\if:w} +% \begin{macro}{\if_bool:N} +% \begin{macro}{\if_predicate:w} +% \begin{macro}{\if_charcode:w} +% \begin{macro}{\if_catcode:w} +% Then some conditionals. +% \begin{macrocode} +\cs_set_eq:NwN \if_true: \tex_iftrue:D +\cs_set_eq:NwN \if_false: \tex_iffalse:D +\cs_set_eq:NwN \or: \tex_or:D +\cs_set_eq:NwN \else: \tex_else:D +\cs_set_eq:NwN \fi: \tex_fi:D +\cs_set_eq:NwN \reverse_if:N \etex_unless:D +\cs_set_eq:NwN \if:w \tex_if:D +\cs_set_eq:NwN \if_bool:N \tex_ifodd:D +\cs_set_eq:NwN \if_predicate:w \tex_ifodd:D +\cs_set_eq:NwN \if_charcode:w \tex_if:D +\cs_set_eq: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} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\if_meaning:w} +% \begin{macrocode} +\cs_set_eq:NwN \if_meaning:w \tex_ifx:D +% \end{macrocode} +% \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} +\cs_set_eq:NwN \if_mode_math: \tex_ifmmode:D +\cs_set_eq:NwN \if_mode_horizontal: \tex_ifhmode:D +\cs_set_eq:NwN \if_mode_vertical: \tex_ifvmode:D +\cs_set_eq: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} +\cs_set_eq:NwN \if_cs_exist:N \etex_ifdefined:D +\cs_set_eq:NwN \if_cs_exist:w \etex_ifcsname:D +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\exp_after:wN} +% \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} +\cs_set_eq:NwN \exp_after:wN \tex_expandafter:D +\cs_set_eq:NwN \exp_not:N \tex_noexpand:D +\cs_set_eq:NwN \exp_not:n \etex_unexpanded:D +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\token_to_meaning:N} +% \begin{macro}{\token_to_str:N} +% \begin{macro}{\cs:w} +% \begin{macro}{\cs_end:} +% \begin{macro}{\cs_meaning:N} +% \begin{macro}{\cs_show:N} +% \begin{macrocode} +\cs_set_eq:NwN \token_to_meaning:N \tex_meaning:D +\cs_set_eq:NwN \token_to_str:N \tex_string:D +\cs_set_eq:NwN \cs:w \tex_csname:D +\cs_set_eq:NwN \cs_end: \tex_endcsname:D +\cs_set_eq:NwN \cs_meaning:N \tex_meaning:D +\cs_set_eq:NwN \cs_show:N \tex_show:D +% \end{macrocode} +% \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} +\cs_set_eq:NwN \scan_stop: \tex_relax:D +\cs_set_eq:NwN \group_begin: \tex_begingroup:D +\cs_set_eq:NwN \group_end: \tex_endgroup:D +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\if_int_compare:w} +% \begin{macro}{\int_to_roman:w} +% \begin{macrocode} +\cs_set_eq:NwN \if_int_compare:w \tex_ifnum:D +\cs_set_eq:NwN \int_to_roman:w \tex_romannumeral:D +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\group_insert_after:N} +% \begin{macrocode} +\cs_set_eq:NwN \group_insert_after:N \tex_aftergroup:D +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\pref_global:D} +% \begin{macro}{\pref_long:D} +% \begin{macro}{\pref_protected:D} +% \begin{macrocode} +\cs_set_eq:NwN \pref_global:D \tex_global:D +\cs_set_eq:NwN \pref_long:D \tex_long:D +\cs_set_eq:NwN \pref_protected:D \etex_protected:D +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\exp_args:Nc} +% Discussed in \pkg{l3expan}, but needed much earlier. +% \begin{macrocode} +\tex_long:D \tex_def:D \exp_args:Nc #1#2 { \exp_after:wN #1 \cs:w #2 \cs_end: } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\token_to_str:c} +% \begin{macro}{\cs_meaning:c} +% \begin{macro}{\cs_show:c} +%% A small number of variants by hand. +% \begin{macrocode} +\tex_def:D \cs_meaning:c { \exp_args:Nc \cs_meaning:N } +\tex_def:D \token_to_str:c { \exp_args:Nc \token_to_str:N } +\tex_def:D \cs_show:c { \exp_args:Nc \cs_show:N } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection {Defining functions} +% +% We start by providing functions for the typical definition +% functions. First the local ones. +% +% \begin{macro}{\cs_set_nopar:Npn} +% \begin{macro}{\cs_set_nopar:Npx} +% \begin{macro}{\cs_set:Npn} +% \begin{macro}{\cs_set:Npx} +% \begin{macro}{\cs_set_protected_nopar:Npn} +% \begin{macro}{\cs_set_protected_nopar:Npx} +% \begin{macro}{\cs_set_protected:Npn} +% \begin{macro}{\cs_set_protected: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} +\cs_set_eq:NwN \cs_set_nopar:Npn \tex_def:D +\cs_set_eq:NwN \cs_set_nopar:Npx \tex_edef:D +\pref_protected:D \cs_set_nopar:Npn \cs_set:Npn + { \pref_long:D \cs_set_nopar:Npn } +\pref_protected:D \cs_set_nopar:Npn \cs_set:Npx + { \pref_long:D \cs_set_nopar:Npx } +\pref_protected:D \cs_set_nopar:Npn \cs_set_protected_nopar:Npn + { \pref_protected:D \cs_set_nopar:Npn } +\pref_protected:D \cs_set_nopar:Npn \cs_set_protected_nopar:Npx + { \pref_protected:D \cs_set_nopar:Npx } +\cs_set_protected_nopar:Npn \cs_set_protected:Npn + { \pref_protected:D \pref_long:D \cs_set_nopar:Npn } +\cs_set_protected_nopar:Npn \cs_set_protected:Npx + { \pref_protected:D \pref_long:D \cs_set_nopar:Npx } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\cs_gset_nopar:Npn} +% \begin{macro}{\cs_gset_nopar:Npx} +% \begin{macro}{\cs_gset:Npn} +% \begin{macro}{\cs_gset:Npx} +% \begin{macro}{\cs_gset_protected_nopar:Npn} +% \begin{macro}{\cs_gset_protected_nopar:Npx} +% \begin{macro}{\cs_gset_protected:Npn} +% \begin{macro}{\cs_gset_protected:Npx} +% Global versions of the above functions. +% \begin{macrocode} +\cs_set_eq:NwN \cs_gset_nopar:Npn \tex_gdef:D +\cs_set_eq:NwN \cs_gset_nopar:Npx \tex_xdef:D +\cs_set_protected_nopar:Npn \cs_gset:Npn + { \pref_long:D \cs_gset_nopar:Npn } +\cs_set_protected_nopar:Npn \cs_gset:Npx + { \pref_long:D \cs_gset_nopar:Npx } +\cs_set_protected_nopar:Npn \cs_gset_protected_nopar:Npn + { \pref_protected:D \cs_gset_nopar:Npn } +\cs_set_protected_nopar:Npn \cs_gset_protected_nopar:Npx + { \pref_protected:D \cs_gset_nopar:Npx } +\cs_set_protected_nopar:Npn \cs_gset_protected:Npn + { \pref_protected:D \pref_long:D \cs_gset_nopar:Npn } +\cs_set_protected_nopar:Npn \cs_gset_protected:Npx + { \pref_protected:D \pref_long:D \cs_gset_nopar:Npx } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Selecting tokens} +% +% \begin{macro}{\use:c} +% This macro grabs its argument and returns a csname from it. +% \begin{macrocode} +\cs_set:Npn \use:c #1 { \cs:w #1 \cs_end: } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\use:x} +% \begin{macro}[aux]{\cs_tmp:w} +% Fully expands its argument and passes it to the input stream. +% Uses |\cs_tmp:| as a scratch register but does not affect it. +% \begin{macrocode} +\cs_set_protected:Npn \use:x #1 + { + \group_begin: + \cs_set:Npx \cs_tmp:w {#1} + \exp_after:wN + \group_end: + \cs_tmp:w + } +\cs_set:Npn \cs_tmp:w { } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\use:n} +% \begin{macro}{\use:nn} +% \begin{macro}{\use:nnn} +% \begin{macro}{\use:nnnn} +% These macro grabs its arguments and returns it back to the input +% (with outer braces removed). +% \begin{macrocode} +\cs_set:Npn \use:n #1 {#1} +\cs_set:Npn \use:nn #1#2 {#1#2} +\cs_set:Npn \use:nnn #1#2#3 {#1#2#3} +\cs_set:Npn \use:nnnn #1#2#3#4 {#1#2#3#4} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\use_i:nn} +% \begin{macro}{\use_ii:nn} +% The equivalent to \LaTeXe{}'s \cs{@firstoftwo} and \cs{@secondoftwo}. +% \begin{macrocode} +\cs_set:Npn \use_i:nn #1#2 {#1} +\cs_set:Npn \use_ii:nn #1#2 {#2} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\use_i:nnn} +% \begin{macro}{\use_ii:nnn} +% \begin{macro}{\use_iii:nnn} +% \begin{macro}{\use_i_ii:nnn} +% \begin{macro}{\use_i:nnnn} +% \begin{macro}{\use_ii:nnnn} +% \begin{macro}{\use_iii:nnnn} +% \begin{macro}{\use_iv:nnnn} +% We also need something for picking up arguments from a longer +% list. +% \begin{macrocode} +\cs_set:Npn \use_i:nnn #1#2#3 {#1} +\cs_set:Npn \use_ii:nnn #1#2#3 {#2} +\cs_set:Npn \use_iii:nnn #1#2#3 {#3} +\cs_set:Npn \use_i_ii:nnn #1#2#3 {#1#2} +\cs_set:Npn \use_i:nnnn #1#2#3#4 {#1} +\cs_set:Npn \use_ii:nnnn #1#2#3#4 {#2} +\cs_set:Npn \use_iii:nnnn #1#2#3#4 {#3} +\cs_set:Npn \use_iv:nnnn #1#2#3#4 {#4} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\use_none_delimit_by_q_nil:w} +% \begin{macro}{\use_none_delimit_by_q_stop:w} +% \begin{macro}{\use_none_delimit_by_q_recursion_stop:w} +% Functions that gobble everything until they see either \cs{q_nil} or +% \cs{q_stop}, respectively. +% \begin{macrocode} +\cs_set:Npn \use_none_delimit_by_q_nil:w #1 \q_nil { } +\cs_set:Npn \use_none_delimit_by_q_stop:w #1 \q_stop { } +\cs_set:Npn \use_none_delimit_by_q_recursion_stop:w #1 \q_recursion_stop { } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\use_i_delimit_by_q_nil:nw} +% \begin{macro}{\use_i_delimit_by_q_stop:nw} +% \begin{macro}{\use_i_delimit_by_q_recursion_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} +\cs_set:Npn \use_i_delimit_by_q_nil:nw #1#2 \q_nil {#1} +\cs_set:Npn \use_i_delimit_by_q_stop:nw #1#2 \q_stop {#1} +\cs_set:Npn \use_i_delimit_by_q_recursion_stop:nw #1#2 \q_recursion_stop {#1} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\use_i_after_fi:nw} +% \begin{macro}{\use_i_after_else:nw} +% \begin{macro}{\use_i_after_or:nw} +% \begin{macro}{\use_i_after_orelse:nw} +% Returns the first argument after ending the conditional. +% \begin{macrocode} +\cs_set:Npn \use_i_after_fi:nw #1 \fi: { \fi: #1 } +\cs_set:Npn \use_i_after_else:nw #1 \else: #2 \fi: { \fi: #1 } +\cs_set:Npn \use_i_after_or:nw #1 \or: #2 \fi: { \fi: #1 } +\cs_set:Npn \use_i_after_orelse:nw #1#2#3 \fi: { \fi: #1 } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \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} +% \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} +\cs_set:Npn \use_none:n #1 { } +\cs_set:Npn \use_none:nn #1#2 { } +\cs_set:Npn \use_none:nnn #1#2#3 { } +\cs_set:Npn \use_none:nnnn #1#2#3#4 { } +\cs_set:Npn \use_none:nnnnn #1#2#3#4#5 { } +\cs_set:Npn \use_none:nnnnnn #1#2#3#4#5#6 { } +\cs_set:Npn \use_none:nnnnnnn #1#2#3#4#5#6#7 { } +\cs_set:Npn \use_none:nnnnnnnn #1#2#3#4#5#6#7#8 { } +\cs_set:Npn \use_none:nnnnnnnnn #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} +% +% \subsection{Conditional processing and definitions} +% +% Underneath any predicate function (|_p|) or other conditional forms +% (|TF|, etc.) is a built-in logic saying that it after all of the +% testing and processing must return the \meta{state} this leaves +% \TeX{} in. Therefore, a simple user interface could be something like +% \begin{verbatim} +% \if_meaning:w #1#2 \prg_return_true: \else: +% \if_meaning:w #1#3 \prg_return_true: \else: +% \prg_return_false: +% \fi: \fi: +% \end{verbatim} +% Usually, a \TeX{} programmer would have to insert a number of +% |\exp_after:wN|s to ensure the state value is returned at exactly +% the point where the last conditional is finished. However, that +% obscures the code and forces the \TeX{} programmer to prove that +% he/she knows the $2^{n}-1$ table. We therefore provide the simpler +% interface. +% +% \begin{macro}{\prg_return_true:} +% \begin{macro}{\prg_return_false:} +% The idea here is that \cs{int_to_roman:w} will expand fully any +% \cs{else:} and the \cs{fi:} that are waiting to be discarded, +% before reaching the \cs{c_zero} which will leave the expansion null. +% The code can then leave either the first or second argument in the +% input stream. This means that all of the branching code has to contain +% at least two tokens: see how the logical tests are actually implemented +% to see this. +% \begin{macrocode} +\cs_set_nopar:Npn \prg_return_true: + { \exp_after:wN \use_i:nn \int_to_roman:w } +\cs_set_nopar:Npn \prg_return_false: + { \exp_after:wN \use_ii:nn \int_to_roman:w} +% \end{macrocode} +% An extended state space could be implemented by including a more +% elaborate function in place of \cs{use_i:nn}/\cs{use_ii:nn}. Provided +% two arguments are absorbed then the code will work. +% \end{macro} +% \end{macro} +% +% \begin{macro}{\prg_set_conditional:Npnn,\prg_new_conditional:Npnn, +% \prg_set_protected_conditional:Npnn,\prg_new_protected_conditional:Npnn} +% The user functions for the types using parameter text from the +% programmer. Call aux function to grab parameters, split the base +% function into name and signature and then use, \emph{e.g.}, |\cs_set:Npn| +% to define it with. +% \begin{macrocode} +\cs_set_protected:Npn \prg_set_conditional:Npnn #1 + { + \prg_get_parm_aux:nw + { + \cs_split_function:NN #1 \prg_generate_conditional_aux:nnNNnnnn + \cs_set:Npn { parm } + } + } +\cs_set_protected:Npn \prg_new_conditional:Npnn #1 + { + \prg_get_parm_aux:nw + { + \cs_split_function:NN #1 \prg_generate_conditional_aux:nnNNnnnn + \cs_new:Npn { parm } + } + } +\cs_set_protected:Npn \prg_set_protected_conditional:Npnn #1 + { + \prg_get_parm_aux:nw{ + \cs_split_function:NN #1 \prg_generate_conditional_aux:nnNNnnnn + \cs_set_protected:Npn { parm } + } + } +\cs_set_protected:Npn \prg_new_protected_conditional:Npnn #1 + { + \prg_get_parm_aux:nw + { + \cs_split_function:NN #1 \prg_generate_conditional_aux:nnNNnnnn + \cs_new_protected:Npn { parm } + } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\prg_set_conditional:Nnn,\prg_new_conditional:Nnn, +% \prg_set_protected_conditional:Nnn,\prg_new_protected_conditional:Nnn} +% The user functions for the types automatically inserting the +% correct parameter text based on the signature. Call aux function +% after calculating number of arguments, split the base function +% into name and signature and then use, \emph{e.g.}, |\cs_set:Npn| to +% define it with. +% \begin{macrocode} +\cs_set_protected:Npn \prg_set_conditional:Nnn #1 + { + \exp_args:Nnf \prg_get_count_aux:nn + { + \cs_split_function:NN #1 \prg_generate_conditional_aux:nnNNnnnn + \cs_set:Npn { count } + } + { \cs_get_arg_count_from_signature:N #1 } + } +\cs_set_protected:Npn \prg_new_conditional:Nnn #1 + { + \exp_args:Nnf \prg_get_count_aux:nn + { + \cs_split_function:NN #1 \prg_generate_conditional_aux:nnNNnnnn + \cs_new:Npn { count} + } + { \cs_get_arg_count_from_signature:N #1 } + } + +\cs_set_protected:Npn \prg_set_protected_conditional:Nnn #1{ + \exp_args:Nnf \prg_get_count_aux:nn{ + \cs_split_function:NN #1 \prg_generate_conditional_aux:nnNNnnnn + \cs_set_protected:Npn {count} + }{\cs_get_arg_count_from_signature:N #1} +} + +\cs_set_protected:Npn \prg_new_protected_conditional:Nnn #1 + { + \exp_args:Nnf \prg_get_count_aux:nn + { + \cs_split_function:NN #1 \prg_generate_conditional_aux:nnNNnnnn + \cs_new_protected:Npn {count} + } + { \cs_get_arg_count_from_signature:N #1 } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\prg_set_eq_conditional:NNn,\prg_new_eq_conditional:NNn} +% The obvious setting-equal functions. +% \begin{macrocode} +\cs_set_protected:Npn \prg_set_eq_conditional:NNn #1#2#3 + { \prg_set_eq_conditional_aux:NNNn \cs_set_eq:cc #1#2 {#3} } +\cs_set_protected:Npn \prg_new_eq_conditional:NNn #1#2#3 + { \prg_set_eq_conditional_aux:NNNn \cs_new_eq:cc #1#2 {#3} } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[aux]{\prg_get_parm_aux:nw,\prg_get_count_aux:nn} +% For the |Npnn| type we must grab the parameter text before +% continuing. We make this a very generic function that takes one +% argument before reading everything up to a left brace. Something +% similar for the |Nnn| type. +% \begin{macrocode} +\cs_set:Npn \prg_get_count_aux:nn #1#2 { #1 {#2} } +\cs_set:Npn \prg_get_parm_aux:nw #1#2# { #1 {#2} } +% \end{macrocode} +% \end{macro} +% \begin{macro}[aux]{\prg_generate_conditional_parm_aux:nnNNnnnn, +% \prg_generate_conditional_parm_aux:nw} +% The workhorse here is going through a list of desired forms, \emph{i.e.}, +% |p|, |TF|, |T| and |F|. The first three arguments come from splitting up +% the base form of the conditional, which gives the name, signature +% and a boolean to signal whether or not there was a colon in the +% name. For the time being, we do not use this piece of information +% but could well throw an error. The fourth argument is how to +% define this function, the fifth is the text |parm| or |count| for +% which version to use to define the functions, the sixth is the +% parameters to use (possibly empty) or number of arguments, the +% seventh is the list of forms to define, the eight is the +% replacement text which we will augment when defining the forms. +% \begin{macrocode} +\cs_set_protected:Npn \prg_generate_conditional_aux:nnNNnnnn #1#2#3#4#5#6#7#8 + { + \prg_generate_conditional_aux:nnw {#5} + { + #4 {#1} {#2} {#6} {#8} + } + #7 , ? , \q_recursion_stop + } +% \end{macrocode} +% Looping through the list of desired forms. First is the text |parm| +% or |count|, second is five arguments packed together and third is +% the form. Use text and form to call the correct type. +% \begin{macrocode} +\cs_set_protected:Npn \prg_generate_conditional_aux:nnw #1#2#3 , + { + \if:w ?#3 + \exp_after:wN \use_none_delimit_by_q_recursion_stop:w + \fi: + \use:c { prg_generate_#3_form_#1:Nnnnn } #2 + \prg_generate_conditional_aux:nnw {#1} {#2} + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[aux] +% { +% \prg_generate_p_form_parm:Nnnnn, +% \prg_generate_TF_form_parm:Nnnnn, +% \prg_generate_T_form_parm:Nnnnn, +% \prg_generate_F_form_parm:Nnnnn +% } +% How to generate the various forms. The |parm| types here takes the +% following arguments: 1: how to define (an N-type), 2: name, 3: +% signature, 4: parameter text (or empty), 5: replacement. Remember that +% the logic-returning functions expect two arguments to be present after +% \cs{c_zero}: notice the construction of the different variants +% relies on this, and that the |TF| variant will be slightly faster +% than the |T| version. +% \begin{macrocode} +\cs_set_protected:Npn \prg_generate_p_form_parm:Nnnnn #1#2#3#4#5 + { + \exp_args:Nc #1 { #2 _p: #3 } #4 + { + #5 \c_zero + \c_true_bool \c_false_bool + } + } +\cs_set_protected:Npn \prg_generate_T_form_parm:Nnnnn #1#2#3#4#5 + { + \exp_args:Nc #1 { #2 : #3 T } #4 + { + #5 \c_zero + \use:n \use_none:n + } + } +\cs_set_protected:Npn \prg_generate_F_form_parm:Nnnnn #1#2#3#4#5 + { + \exp_args:Nc #1 { #2 : #3 F } #4 + { + #5 \c_zero + { } + } + } +\cs_set_protected:Npn \prg_generate_TF_form_parm:Nnnnn #1#2#3#4#5 + { + \exp_args:Nc #1 { #2 : #3 TF } #4 + { #5 \c_zero } + } +% \end{macrocode} +% \end{macro} +% \begin{macro}[aux] +% { +% \prg_generate_p_form_count:Nnnnn, +% \prg_generate_TF_form_count:Nnnnn, +% \prg_generate_T_form_count:Nnnnn, +% \prg_generate_F_form_count:Nnnnn +% } +% The |count| form is similar, but of course requires a number rather +% than a primitive argument specification. +% \begin{macrocode} +\cs_set_protected:Npn \prg_generate_p_form_count:Nnnnn #1#2#3#4#5 + { + \cs_generate_from_arg_count:cNnn { #2 _p: #3 } #1 {#4} + { + #5 \c_zero + \c_true_bool \c_false_bool + } + } +\cs_set_protected:Npn \prg_generate_T_form_count:Nnnnn #1#2#3#4#5 + { + \cs_generate_from_arg_count:cNnn { #2 : #3 T } #1 {#4} + { + #5 \c_zero + \use:n \use_none:n + } + } +\cs_set_protected:Npn \prg_generate_F_form_count:Nnnnn #1#2#3#4#5 + { + \cs_generate_from_arg_count:cNnn { #2 : #3 F } #1 {#4} + { + #5 \c_zero + { } + } + } +\cs_set_protected:Npn \prg_generate_TF_form_count:Nnnnn #1#2#3#4#5 + { + \cs_generate_from_arg_count:cNnn { #2 : #3 TF } #1 {#4} + { #5 \c_zero } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[aux]{\prg_set_eq_conditional_aux:NNNn, +% \prg_set_eq_conditional_aux:NNNw} +% \begin{macrocode} +\cs_set_protected:Npn \prg_set_eq_conditional_aux:NNNn #1#2#3#4 + { \prg_set_eq_conditional_aux:NNNw #1#2#3#4 , ? , \q_recursion_stop } +% \end{macrocode} +% Manual clist loop over argument |#4|. +% \begin{macrocode} +\cs_set_protected:Npn \prg_set_eq_conditional_aux:NNNw #1#2#3#4 , + { + \if:w ? #4 \scan_stop: + \exp_after:wN \use_none_delimit_by_q_recursion_stop:w + \fi: + #1 + { \exp_args:NNc \cs_split_function:NN #2 { prg_conditional_form_#4:nnn } } + { \exp_args:NNc \cs_split_function:NN #3 { prg_conditional_form_#4:nnn } } + \prg_set_eq_conditional_aux:NNNw #1 {#2} {#3} + } +% \end{macrocode} +% \begin{macrocode} +\cs_set:Npn \prg_conditional_form_p:nnn #1#2#3 { #1 _p : #2 } +\cs_set:Npn \prg_conditional_form_TF:nnn #1#2#3 { #1 : #2 TF } +\cs_set:Npn \prg_conditional_form_T:nnn #1#2#3 { #1 : #2 T } +\cs_set:Npn \prg_conditional_form_F:nnn #1#2#3 { #1 : #2 F } +% \end{macrocode} +% \end{macro} +% +% All that is left is to define the canonical boolean true and false. +% 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 +% |00| and |01|, so they could be used in logical +% operations. Later again they were changed to being numerical +% constants with values of $1$ for true and $0$ for false. We need +% this from the get-go. +% +% \begin{macro}{\c_true_bool} +% \begin{macro}{\c_false_bool} +% Here are the canonical boolean values. +% \begin{macrocode} +\tex_chardef:D \c_true_bool = 1~ +\tex_chardef:D \c_false_bool = 0~ +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Dissecting a control sequence} +% +% \begin{macro}{\cs_to_str:N} +% \begin{macro}[aux]{\cs_to_str_aux:w} +% This converts a control sequence into the character string of its +% name, removing the leading escape character. This turns out to be +% a non-trivial matter as there a different cases: +% \begin{itemize} +% \item The usual case of a printable escape character; +% \item the case of a non-printable escape characters, e.g., when +% the value of |\tex_escapechar:D| is negative; +% \item when the escape character is a space. +% \end{itemize} +% One approach to solve this is to test how many tokens result from +% |\token_to_str:N \a|. If there are two tokens, then the escape +% character is printable, while if it is non-printable then only +% one is present. +% +% However, there is an additional complication: the control +% sequence itself may start with a space. Clearly that should \emph{not} be +% lost in the process of converting to a string. So the approach adopted is +% a little more intricate still. When the escape character is printable, +% \verb*|\token_to_str:N \ | yields the escape character itself and a space. +% The escape sequence will terminate the expansion started by +% \cs{int_to_roman:w}, which is a negative number and so will not +% gobble the escape character even if it's a number. The \cs{tex_if:D} +% test will then be \texttt{false}, and the na\"ive approach of gobbling +% the first character of the \cs{token_to_str:N} version of the control +% sequence will work, even if the first character is a space. +% The second case is that the escape character is itself a space. In this +% case, the escape character space is consumed terminating the first +% \cs{int_to_roman:w}, and \cs{cs_to_str_aux:w} is expanded. This +% inserts a space, making the \cs{if:w} test \texttt{true}. The +% second \cs{int_to_roman:w} will then execute the \cs{token_to_str:N}, +% with the escape-character space being consumed by the +% \cs{int_to_roman:w}, and thus leaving the control sequence name in the +% input stream. The final case is where the escape character is not +% printable. +% The flow here starts with the \verb*|\token_to_str:N \ | giving just a +% space, which terminates the first \cs{int_to_roman:w} but leaves no +% token for the \cs{if:w} test. This means that the \cs{int_to_roman:w} +% is executed before the test is finished. The result is that the +% \cs{fi:}, expanded before the \cs{tex_if:D} is finished, becomes +% \cs{scan_stop:} \cs{fi:}, and the \cs{scan_stop:} is then used in +% the \cs{if:w} test. +% In this case, \cs{token_to_str:N} is therefore used with no gobbling at +% all, which is exactly what is needed in this case. +% \begin{macrocode} +\cs_set_nopar:Npn \cs_to_str:N + { + \if:w \int_to_roman:w - `0 \token_to_str:N \ % + \cs_to_str_aux:w + \fi: + \exp_after:wN \use_none:n \token_to_str:N + } +\cs_set_nopar:Npn \cs_to_str_aux:w #1 \use_none:n + { ~ \int_to_roman:w - `0 \fi: } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\cs_split_function:NN} +% \begin{macro}[aux]{\cs_split_function_aux:w} +% \begin{macro}[aux]{\cs_split_function_auxii:w} +% This function takes a function name and splits it into name with +% the escape char removed and argument specification. In addition to +% this, a third argument, a boolean \meta{true} or \meta{false} is +% returned with \meta{true} for when there is a colon in the function +% and \meta{false} if there is not. Lastly, the second argument of +% |\cs_split_function:NN| is supposed to be a function +% taking three variables, one for name, one for signature, and one +% for the boolean. For example, +% |\cs_split_function:NN\foo_bar:cnx\use_i:nnn| as input +% becomes |\use_i:nnn {foo_bar}{cnx}\c_true_bool|. +% +% Can't use a literal |:| because it has the wrong catcode here, so +% it's transformed from |@| with |\tex_lowercase:D|. +% \begin{macrocode} +\group_begin: + \tex_lccode:D `\@ = `\: \scan_stop: + \tex_catcode:D `\@ = 12~ +\tex_lowercase:D + { + \group_end: +% \end{macrocode} +% First ensure that we actually get a properly evaluated str as we +% don't know how many expansions |\cs_to_str:N| requires. Insert +% extra colon to catch the error cases. +% \begin{macrocode} + \cs_set:Npn \cs_split_function:NN #1#2 + { + \exp_after:wN \cs_split_function_aux:w + \int_to_roman:w - `\q \cs_to_str:N #1 @ a \q_stop #2 + } +% \end{macrocode} +% If no colon in the name, |#2| is |a| with catcode 11 and |#3| is +% empty. If colon in the name, then either |#2| is a colon or the +% first letter of the signature. The letters here have catcode 12. +% If a colon was given we need to a) split off the colon and quark at +% the end and b) ensure we return the name, signature and boolean true +% We can't use |\quark_if_no_value:NTF| yet but this is very safe +% anyway as all tokens have catcode~12. +% \begin{macrocode} + \cs_set:Npn \cs_split_function_aux:w #1 @ #2#3 \q_stop #4 + { + \if_meaning:w a #2 + \exp_after:wN \use_i:nn + \else: + \exp_after:wN\use_ii:nn + \fi: + { #4 {#1} { } \c_false_bool } + { \cs_split_function_auxii:w #2#3 \q_stop #4 {#1} } + } + \cs_set:Npn \cs_split_function_auxii:w #1 @a \q_stop #2#3 + { #2{#3}{#1}\c_true_bool } +% \end{macrocode} +% End of lowercase +% \begin{macrocode} + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\cs_get_function_name:N, \cs_get_function_signature:N} +% Now returning the name is trivial: just discard the last two +% arguments. Similar for signature. +% \begin{macrocode} +\cs_set:Npn \cs_get_function_name:N #1 + { \cs_split_function:NN #1 \use_i:nnn } +\cs_set:Npn \cs_get_function_signature:N #1 + { \cs_split_function:NN #1 \use_ii:nnn } +% \end{macrocode} +% \end{macro} +% +% \subsection{Exist or free} +% +% A control sequence is said to \emph{exist} (to be used) if has an entry in +% the hash table and its meaning is different from the primitive +% |\tex_relax:D| token. A control sequence is said to be \emph{free} +% (to be defined) if it does not already exist. +% +% \begin{macro}[pTF]{\cs_if_exist:N,\cs_if_exist:c} +% Two versions for checking existence. For the |N| form we firstly +% check for |\scan_stop:| and then if it is in the hash +% table. There is no problem when inputting something like |\else:| +% or |\fi:| as \TeX{} will only ever skip input in case the token +% tested against is |\scan_stop:|. +% \begin{macrocode} +\prg_set_conditional:Npnn \cs_if_exist:N #1 { p , T , F , TF } + { + \if_meaning:w #1 \scan_stop: + \prg_return_false: + \else: + \if_cs_exist:N #1 + \prg_return_true: + \else: + \prg_return_false: + \fi: + \fi: + } +% \end{macrocode} +% For the |c| form we firstly check if it is in the hash table and +% then for |\scan_stop:| so that we do not add it to the hash table +% unless it was already there. Here we have to be careful as the text +% to be skipped if the first test is false may contain tokens that +% disturb the scanner. Therefore, we ensure that the second test is +% performed after the first one has concluded completely. +% \begin{macrocode} +\prg_set_conditional:Npnn \cs_if_exist:c #1 { p , T , F , TF } + { + \if_cs_exist:w #1 \cs_end: + \exp_after:wN \use_i:nn + \else: + \exp_after:wN \use_ii:nn + \fi: + { + \exp_after:wN \if_meaning:w \cs:w #1 \cs_end: \scan_stop: + \prg_return_false: + \else: + \prg_return_true: + \fi: + } + \prg_return_false: + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[pTF]{\cs_if_free:N,\cs_if_free:c} +% The logical reversal of the above. +% \begin{macrocode} +\prg_set_conditional:Npnn \cs_if_free:N #1 { p , T , F , TF } + { + \if_meaning:w #1 \scan_stop: + \prg_return_true: + \else: + \if_cs_exist:N #1 + \prg_return_false: + \else: + \prg_return_true: + \fi: + \fi: + } +\prg_set_conditional:Npnn \cs_if_free:c #1 { p , T , F , TF } + { + \if_cs_exist:w #1 \cs_end: + \exp_after:wN \use_i:nn + \else: + \exp_after:wN \use_ii:nn + \fi: + { + \exp_after:wN \if_meaning:w \cs:w #1 \cs_end: \scan_stop: + \prg_return_true: + \else: + \prg_return_false: + \fi: + } + { \prg_return_true: } + } +% \end{macrocode} +% \end{macro} +% +% \subsection{Defining and checking (new) functions} +% +% \begin{macro}{\c_minus_one, \c_zero, \c_sixteen} +% \begin{macro}{\c_six, \c_seven, \c_twelve} +% We need the constants |\c_minus_one| and |\c_sixteen| now for +% writing information to the log and the terminal and |\c_zero| +% which is used by some functions in the \textsf{l3alloc} module. The +% rest are defined in the \textsf{l3int} module -- at least for the +% ones that can be defined with |\tex_chardef:D| or +% |\tex_mathchardef:D|. For other constants 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} +%<*package> +\cs_set_eq:NwN \c_minus_one \m@ne +%</package> +%<*initex> +\tex_countdef:D \c_minus_one = 10 ~ +\c_minus_one = -1 ~ +%</initex> +\tex_chardef:D \c_sixteen = 16~ +\tex_chardef:D \c_zero = 0~ +\tex_chardef:D \c_six = 6~ +\tex_chardef:D \c_seven = 7~ +\tex_chardef:D \c_twelve = 12~ +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\c_max_register_int} +% This is here as this particular integer is needed both in package +% mode and to bootstrap \pkg{l3alloc} +% \begin{macrocode} +\tex_mathchardef:D \c_max_register_int = 32 767 \scan_stop: +% \end{macrocode} +% \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 +% if their argument doesn't already exist, they are called +% |\..._new|. The second type of defining functions doesn't check +% 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 +% only temporary, they will be redefined later on. +% +% \begin{macro}{\iow_log:x} +% \begin{macro}{\iow_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. +% These will be redefined later by \pkg{l3io}. +% \begin{macrocode} +\cs_set_protected_nopar:Npn \iow_log:x + { \tex_immediate:D \tex_write:D \c_minus_one } +\cs_set_protected_nopar:Npn \iow_term:x + { \tex_immediate:D \tex_write:D \c_sixteen } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\msg_kernel_error:nnxx} +% \begin{macro}{\msg_kernel_error:nnx} +% \begin{macro}{\msg_kernel_error:nn} +% If an internal error occurs before \LaTeX3 has loaded \pkg{l3msg} then +% the code should issue a usable if terse error message and halt. This +% can only happen if a coding error is made by the team, so this is +% a reasonable response. +% \begin{macrocode} +\cs_set_protected_nopar:Npn \msg_kernel_error:nnxx #1#2#3#4 + { + \tex_errmessage:D + { + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!~! ^^J + Argh,~internal~LaTeX3~error! ^^J ^^J + Module ~ #1 , ~ message~name~"#2": ^^J + Arguments~'#3'~and~'#4' ^^J ^^J + This~is~one~for~The~LaTeX3~Project:~bailing~out + } + \tex_end:D + } +\cs_set_protected_nopar:Npn \msg_kernel_error:nnx #1#2#3 + { \msg_kernel_error:nnxx {#1} {#2} {#3} { } } +\cs_set_protected_nopar:Npn \msg_kernel_error:nn #1#2 + { \msg_kernel_error:nnxx {#1} {#2} { } { } } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\msg_line_context:} +% Another one from \pkg{l3msg} which will be altered later. +% \begin{macrocode} +\cs_set_nopar:Npn \msg_line_context: + { on~line~\tex_the:D \tex_inputlineno:D } +% \end{macrocode} +% \end{macro} +% +% \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. +% \begin{macrocode} +\cs_set:Npn \cs_record_meaning:N #1 { } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\chk_if_free_cs:N, \chk_if_free_cs:c} +% This command is called by |\cs_new_nopar:Npn| and |\cs_new_eq:NN| +% \emph{etc.}\ +% to make sure that the argument sequence is not already in use. If +% it is, an error is signalled. It checks if \meta{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} +\cs_set_protected_nopar:Npn \chk_if_free_cs:N #1 + { + \cs_if_free:NF #1 + { + \msg_kernel_error:nnxx { kernel } { command-already-defined } + { \token_to_str:N #1 } { \token_to_meaning:N #1 } + } +} +%<*package> +\tex_ifodd:D \@l@expl@log@functions@bool + \cs_set_protected_nopar:Npn \chk_if_free_cs:N #1 + { + \cs_if_free:NF #1 + { + \msg_kernel_error:nnxx { kernel } { command-already-defined } + { \token_to_str:N #1 } { \token_to_meaning:N #1 } + } + \iow_log:x { Defining~\token_to_str:N #1~ \msg_line_context: } + } +\fi: +%</package> +\cs_set_protected_nopar:Npn \chk_if_free_cs:c + { \exp_args:Nc \chk_if_free_cs:N } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\chk_if_exist_cs:N, \chk_if_exist_cs:c} +% This function issues a warning message when the control sequence +% in its argument does not exist. +% \begin{macrocode} +\cs_set_protected_nopar:Npn \chk_if_exist_cs:N #1 + { + \cs_if_exist:NF #1 + { + \msg_kernel_error:nnxx { kernel } { command-not-defined } + { \token_to_str:N #1 } { \token_to_meaning:N #1 } + } + } +\cs_set_protected_nopar:Npn \chk_if_exist_cs:c + { \exp_args:Nc \chk_if_exist_cs:N } +% \end{macrocode} +% \end{macro} +% +% \subsection{More new definitions} +% +% \begin{macro}{\cs_new_nopar:Npn} +% \begin{macro}{\cs_new_nopar:Npx} +% \begin{macro}{\cs_new:Npn} +% \begin{macro}{\cs_new:Npx} +% \begin{macro}{\cs_new_protected_nopar:Npn} +% \begin{macro}{\cs_new_protected_nopar:Npx} +% \begin{macro}{\cs_new_protected:Npn} +% \begin{macro}{\cs_new_protected:Npx} +% Global versions of the above functions. +% \begin {macrocode} +\cs_set:Npn \cs_tmp:w #1#2 + { + \cs_set_protected_nopar:Npn #1 ##1 + { + \chk_if_free_cs:N ##1 + #2 ##1 + } + } +\cs_tmp:w \cs_new_nopar:Npn \cs_gset_nopar:Npn +\cs_tmp:w \cs_new_nopar:Npx \cs_gset_nopar:Npx +\cs_tmp:w \cs_new:Npn \cs_gset:Npn +\cs_tmp:w \cs_new:Npx \cs_gset:Npx +\cs_tmp:w \cs_new_protected_nopar:Npn \cs_gset_protected_nopar:Npn +\cs_tmp:w \cs_new_protected_nopar:Npx \cs_gset_protected_nopar:Npx +\cs_tmp:w \cs_new_protected:Npn \cs_gset_protected:Npn +\cs_tmp:w \cs_new_protected:Npx \cs_gset_protected:Npx +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\cs_set_nopar:cpn} +% \begin{macro}{\cs_set_nopar:cpx} +% \begin{macro}{\cs_gset_nopar:cpn} +% \begin{macro}{\cs_gset_nopar:cpx} +% \begin{macro}{\cs_new_nopar:cpn} +% \begin{macro}{\cs_new_nopar:cpx} +% Like |\cs_set_nopar:Npn| and |\cs_new_nopar: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. +% +% |\cs_set_nopar:cpn|\meta{string}\meta{rep-text} will turn \meta{string} +% into a csname and then assign \m {rep-text} to it by using +% |\cs_set_nopar:Npn|. This means that there might be a parameter +% string between the two arguments. +% \begin{macrocode} +\cs_set:Npn \cs_tmp:w #1#2 + { \cs_new_protected_nopar:Npn #1 { \exp_args:Nc #2 } } +\cs_tmp:w \cs_set_nopar:cpn \cs_set_nopar:Npn +\cs_tmp:w \cs_set_nopar:cpx \cs_set_nopar:Npx +\cs_tmp:w \cs_gset_nopar:cpn \cs_gset_nopar:Npn +\cs_tmp:w \cs_gset_nopar:cpx \cs_gset_nopar:Npx +\cs_tmp:w \cs_new_nopar:cpn \cs_new_nopar:Npn +\cs_tmp:w \cs_new_nopar:cpx \cs_new_nopar:Npx +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\cs_set:cpn} +% \begin{macro}{\cs_set:cpx} +% \begin{macro}{\cs_gset:cpn} +% \begin{macro}{\cs_gset:cpx} +% \begin{macro}{\cs_new:cpn} +% \begin{macro}{\cs_new:cpx} +% Variants of the |\cs_set:Npn| versions which make a csname out +% of the first arguments. We may also do this globally. +% \begin{macrocode} +\cs_tmp:w \cs_set:cpn \cs_set:Npn +\cs_tmp:w \cs_set:cpx \cs_set:Npx +\cs_tmp:w \cs_gset:cpn \cs_gset:Npn +\cs_tmp:w \cs_gset:cpx \cs_gset:Npx +\cs_tmp:w \cs_new:cpn \cs_new:Npn +\cs_tmp:w \cs_new:cpx \cs_new:Npx +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\cs_set_protected_nopar:cpn} +% \begin{macro}{\cs_set_protected_nopar:cpx} +% \begin{macro}{\cs_gset_protected_nopar:cpn} +% \begin{macro}{\cs_gset_protected_nopar:cpx} +% \begin{macro}{\cs_new_protected_nopar:cpn} +% \begin{macro}{\cs_new_protected_nopar:cpx} +% Variants of the |\cs_set_protected_nopar:Npn| versions which make a csname +% out of the first arguments. We may also do this globally. +% \begin{macrocode} +\cs_tmp:w \cs_set_protected_nopar:cpn \cs_set_protected_nopar:Npn +\cs_tmp:w \cs_set_protected_nopar:cpx \cs_set_protected_nopar:Npx +\cs_tmp:w \cs_gset_protected_nopar:cpn \cs_gset_protected_nopar:Npn +\cs_tmp:w \cs_gset_protected_nopar:cpx \cs_gset_protected_nopar:Npx +\cs_tmp:w \cs_new_protected_nopar:cpn \cs_new_protected_nopar:Npn +\cs_tmp:w \cs_new_protected_nopar:cpx \cs_new_protected_nopar:Npx +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\cs_set_protected:cpn} +% \begin{macro}{\cs_set_protected:cpx} +% \begin{macro}{\cs_gset_protected:cpn} +% \begin{macro}{\cs_gset_protected:cpx} +% \begin{macro}{\cs_new_protected:cpn} +% \begin{macro}{\cs_new_protected:cpx} +% Variants of the |\cs_set_protected:Npn| versions which make a csname +% out of the first arguments. We may also do this globally. +% \begin{macrocode} +\cs_tmp:w \cs_set_protected:cpn \cs_set_protected:Npn +\cs_tmp:w \cs_set_protected:cpx \cs_set_protected:Npx +\cs_tmp:w \cs_gset_protected:cpn \cs_gset_protected:Npn +\cs_tmp:w \cs_gset_protected:cpx \cs_gset_protected:Npx +\cs_tmp:w \cs_new_protected:cpn \cs_new_protected:Npn +\cs_tmp:w \cs_new_protected:cpx \cs_new_protected:Npx +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}[aux]{\use_0_parameter:} +% \begin{macro}[aux]{\use_1_parameter:} +% \begin{macro}[aux]{\use_2_parameter:} +% \begin{macro}[aux]{\use_3_parameter:} +% \begin{macro}[aux]{\use_4_parameter:} +% \begin{macro}[aux]{\use_5_parameter:} +% \begin{macro}[aux]{\use_6_parameter:} +% \begin{macro}[aux]{\use_7_parameter:} +% \begin{macro}[aux]{\use_8_parameter:} +% \begin{macro}[aux]{\use_9_parameter:} +% For using parameters, \emph{i.e.}, when you need to define a function to +% process three parameters. See \textsf{xparse} for an application. +% \begin{macrocode} +\cs_new_nopar:cpn { use_0_parameter: } { } +\cs_new_nopar:cpn { use_1_parameter: } { {##1} } +\cs_new_nopar:cpn { use_2_parameter: } { {##1} {##2} } +\cs_new_nopar:cpn { use_3_parameter: } { {##1} {##2} {##3} } +\cs_new_nopar:cpn { use_4_parameter: } { {##1} {##2} {##3} {##4} } +\cs_new_nopar:cpn { use_5_parameter: } { {##1} {##2} {##3} {##4} {##5} } +\cs_new_nopar:cpn { use_6_parameter: } { {##1} {##2} {##3} {##4} {##5} {##6} } +\cs_new_nopar:cpn { use_7_parameter: } + { {##1} {##2} {##3} {##4} {##5}{##6} {##7} } +\cs_new_nopar:cpn { use_8_parameter: } + { {##1} {##2} {##3} {##4} {##5} {##6} {##7} {##8} } +\cs_new_nopar:cpn{ 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} +% +% \subsection{Copying definitions} +% +% \begin{macro}{\cs_set_eq:NN} +% \begin{macro}{\cs_set_eq:cN} +% \begin{macro}{\cs_set_eq:Nc} +% \begin{macro}{\cs_set_eq:cc} +% These macros allow us to copy the definition of a control sequence +% to another control sequence. +% +% The |=| sign allows us to define funny char tokens like |=| +% itself or \verb*| | with this function. For the definition of +% |\c_space_char{~}| to work we need the |~| after the |=|. +% +% |\cs_set_eq:NN| is long to avoid problems with a literal argument +% of |\par|. While |\cs_new_eq:NN| will probably never be correct +% with a first argument of |\par|, define it long in order to throw +% an \enquote{already defined} error rather than +% \enquote{runaway argument}. +% \begin{macrocode} +\cs_new_protected:Npn \cs_set_eq:NN #1 { \cs_set_eq:NwN #1 =~ } +\cs_new_protected_nopar:Npn \cs_set_eq:cN { \exp_args:Nc \cs_set_eq:NN } +\cs_new_protected_nopar:Npn \cs_set_eq:Nc { \exp_args:NNc \cs_set_eq:NN } +\cs_new_protected_nopar:Npn \cs_set_eq:cc { \exp_args:Ncc \cs_set_eq:NN } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\cs_new_eq:NN} +% \begin{macro}{\cs_new_eq:cN} +% \begin{macro}{\cs_new_eq:Nc} +% \begin{macro}{\cs_new_eq:cc} +% \begin{macrocode} +\cs_new_protected:Npn \cs_new_eq:NN #1 + { + \chk_if_free_cs:N #1 + \pref_global:D \cs_set_eq:NN #1 + } +\cs_new_protected_nopar:Npn \cs_new_eq:cN { \exp_args:Nc \cs_new_eq:NN } +\cs_new_protected_nopar:Npn \cs_new_eq:Nc { \exp_args:NNc \cs_new_eq:NN } +\cs_new_protected_nopar:Npn \cs_new_eq:cc { \exp_args:Ncc \cs_new_eq:NN } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\cs_gset_eq:NN} +% \begin{macro}{\cs_gset_eq:cN} +% \begin{macro}{\cs_gset_eq:Nc} +% \begin{macro}{\cs_gset_eq:cc} +% \begin{macrocode} +\cs_new_protected_nopar:Npn \cs_gset_eq:NN { \pref_global:D \cs_set_eq:NN } +\cs_new_protected_nopar:Npn \cs_gset_eq:Nc { \exp_args:NNc \cs_gset_eq:NN } +\cs_new_protected_nopar:Npn \cs_gset_eq:cN { \exp_args:Nc \cs_gset_eq:NN } +\cs_new_protected_nopar:Npn \cs_gset_eq:cc { \exp_args:Ncc \cs_gset_eq:NN } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Undefining functions} +% +% \begin{macro}{\cs_undefine:N , \cs_undefine:c} +% 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} +\cs_new_protected_nopar:Npn \cs_undefine:N #1 + { \cs_gset_eq:NN #1 \c_undefined:D } +\cs_new_protected_nopar:Npn \cs_undefine:c #1 + { \cs_gset_eq:cN {#1} \c_undefined:D } +% \end{macrocode} +% \end{macro} +% +% \subsection{Defining functions from a given number of arguments} +% +% \begin{macro}{\cs_get_arg_count_from_signature:N} +% \begin{macro}[aux]{\cs_get_arg_count_from_signature_aux:nnN} +% \begin{macro}[aux]{\cs_get_arg_count_from_signature_auxii:w} +% Counting the number of tokens in the signature, i.e., the number +% of arguments the function should take. If there is no signature, +% we return that there is $-1$ arguments to signal an error. +% Otherwise we insert the string |9876543210| after the signature. +% If the signature is empty, the number we want is $0$ so we remove +% the first nine tokens and return the tenth. Similarly, if the +% signature is |nnn| we want to remove the nine tokens |nnn987654| +% and return $3$. Therefore, we simply remove the first nine tokens +% and then return the tenth. +% \begin{macrocode} +\cs_new:Npn \cs_get_arg_count_from_signature:N #1 + { \cs_split_function:NN #1 \cs_get_arg_count_from_signature_aux:nnN } +\cs_new:Npn \cs_get_arg_count_from_signature_aux:nnN #1#2#3 + { + \if_predicate:w #3 + \exp_after:wN \use_i:nn + \else: + \exp_after:wN\use_ii:nn + \fi: + { + \exp_after:wN \cs_get_arg_count_from_signature_auxii:w + \use_none:nnnnnnnnn #2 9876543210 \q_stop + } + { -1 } +} +\cs_new:Npn \cs_get_arg_count_from_signature_auxii:w #1#2 \q_stop {#1} +% \end{macrocode} +% A variant form we need right away. +% \begin{macrocode} +\cs_new_nopar:Npn \cs_get_arg_count_from_signature:c + { \exp_args:Nc \cs_get_arg_count_from_signature:N } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}[aux]{\cs_generate_from_arg_count:NNnn} +% \begin{macro}[aux]{\cs_generate_from_arg_count_error_msg:Nn} +% We provide a constructor function for defining functions with a +% given number of arguments. For this we need to choose the correct +% parameter text and then use that when defining. Since \TeX{} +% supports from zero to nine arguments, we use a simple switch to +% choose the correct parameter text, ensuring the result is returned +% after finishing the conditional. If it is not between zero and +% nine, we throw an error. +% +% 1: function to define, 2: with what to define it, 3: the number of +% args it requires and 4: the replacement text +% \begin{macrocode} +\cs_new_protected:Npn \cs_generate_from_arg_count:NNnn #1#2#3#4 + { + \if_case:w \int_eval:w #3 \int_eval_end: + \use_i_after_orelse:nw {#2#1} + \or: + \use_i_after_orelse:nw {#2#1 ##1} + \or: + \use_i_after_orelse:nw {#2#1 ##1##2} + \or: + \use_i_after_orelse:nw {#2#1 ##1##2##3} + \or: + \use_i_after_orelse:nw {#2#1 ##1##2##3##4} + \or: + \use_i_after_orelse:nw {#2#1 ##1##2##3##4##5} + \or: + \use_i_after_orelse:nw {#2#1 ##1##2##3##4##5##6} + \or: + \use_i_after_orelse:nw {#2#1 ##1##2##3##4##5##6##7} + \or: + \use_i_after_orelse:nw {#2#1 ##1##2##3##4##5##6##7##8} + \or: + \use_i_after_orelse:nw {#2#1 ##1##2##3##4##5##6##7##8##9} + \else: + \use_i_after_fi:nw + { + \cs_generate_from_arg_count_error_msg:Nn #1 {#3} + \use_none:n + } + \fi: + {#4} + } +% \end{macrocode} +% A variant form we need right away. +% \begin{macrocode} +\cs_new_nopar:Npn \cs_generate_from_arg_count:cNnn + { \exp_args:Nc \cs_generate_from_arg_count:NNnn } +% \end{macrocode} +% The error message. Elsewhere we use the value of $-1$ to signal a +% missing colon in a function, so provide a hint for help on this. +% \begin{macrocode} +\cs_new:Npn \cs_generate_from_arg_count_error_msg:Nn #1#2 + { + \msg_kernel_error:nnxx { kernel } { bad-number-of-arguments } + { \token_to_str:N #1 } { \int_eval:n {#2} } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Using the signature to define functions} +% +% We can now combine some of the tools we have to provide a simple +% interface for defining functions. We define some simpler functions +% with user interface |\cs_set:Nn \foo_bar:nn {#1,#2}|, \emph{i.e.}, the +% number of arguments is read from the signature. +% +% +% \begin{macro}{\cs_set:Nn} +% \begin{macro}{\cs_set:Nx} +% \begin{macro}{\cs_set_nopar:Nn} +% \begin{macro}{\cs_set_nopar:Nx} +% \begin{macro}{\cs_set_protected:Nn} +% \begin{macro}{\cs_set_protected:Nx} +% \begin{macro}{\cs_set_protected_nopar:Nn} +% \begin{macro}{\cs_set_protected_nopar:Nx} +% \begin{macro}{\cs_gset:Nn} +% \begin{macro}{\cs_gset:Nx} +% \begin{macro}{\cs_gset_nopar:Nn} +% \begin{macro}{\cs_gset_nopar:Nx} +% \begin{macro}{\cs_gset_protected:Nn} +% \begin{macro}{\cs_gset_protected:Nx} +% \begin{macro}{\cs_gset_protected_nopar:Nn} +% \begin{macro}{\cs_gset_protected_nopar:Nx} +% We want to define |\cs_set:Nn| as +% \begin{verbatim} +% \cs_set_protected:Npn \cs_set:Nn #1#2 +% { +% \cs_generate_from_arg_count:NNnn #1 \cs_set:Npn +% { \cs_get_arg_count_from_signature:N #1 } {#2} +% } +% \end{verbatim} +% In short, to define |\cs_set:Nn| we need just use |\cs_set:Npn|, +% everything else is the same for each variant. Therefore, we can +% make it simpler by temporarily defining a function to do this for +% us. +% \begin{macrocode} +\cs_set:Npn \cs_tmp:w #1#2#3 + { + \cs_set_protected:cpx { cs_ #1 : #2 } ##1##2 + { + \exp_not:N \cs_generate_from_arg_count:NNnn ##1 + \exp_after:wN \exp_not:N \cs:w cs_#1 : #3 \cs_end: + { \exp_not:N\cs_get_arg_count_from_signature:N ##1 }{##2} + } + } +% \end{macrocode} +% Then we define the 32 variants beginning with |N|. +% \begin{macrocode} +\cs_tmp:w { set } { Nn } { Npn } +\cs_tmp:w { set } { Nx } { Npx } +\cs_tmp:w { set_nopar } { Nn } { Npn } +\cs_tmp:w { set_nopar } { Nx } { Npx } +\cs_tmp:w { set_protected } { Nn } { Npn } +\cs_tmp:w { set_protected } { Nx } { Npx } +\cs_tmp:w { set_protected_nopar } { Nn } { Npn } +\cs_tmp:w { set_protected_nopar } { Nx } { Npx } +\cs_tmp:w { gset } { Nn } { Npn } +\cs_tmp:w { gset } { Nx } { Npx } +\cs_tmp:w { gset_nopar } { Nn } { Npn } +\cs_tmp:w { gset_nopar } { Nx } { Npx } +\cs_tmp:w { gset_protected } { Nn } { Npn } +\cs_tmp:w { gset_protected } { Nx } { Npx } +\cs_tmp:w { gset_protected_nopar } { Nn } { Npn } +\cs_tmp:w { gset_protected_nopar } { Nx } { 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}{\cs_new:Nn} +% \begin{macro}{\cs_new:Nx} +% \begin{macro}{\cs_new_nopar:Nn} +% \begin{macro}{\cs_new_nopar:Nx} +% \begin{macro}{\cs_new_protected:Nn} +% \begin{macro}{\cs_new_protected:Nx} +% \begin{macro}{\cs_new_protected_nopar:Nn} +% \begin{macro}{\cs_new_protected_nopar:Nx} +% \begin{macrocode} +\cs_tmp:w { new } { Nn } { Npn } +\cs_tmp:w { new } { Nx } { Npx } +\cs_tmp:w { new_nopar } { Nn } { Npn } +\cs_tmp:w { new_nopar } { Nx } { Npx } +\cs_tmp:w { new_protected } { Nn } { Npn } +\cs_tmp:w { new_protected } { Nx } { Npx } +\cs_tmp:w { new_protected_nopar } { Nn } { Npn } +\cs_tmp:w { new_protected_nopar } { Nx } { Npx } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% Then something similar for the |c| variants. +% \begin{verbatim} +% \cs_set_protected:Npn \cs_set:cn #1#2 +% { +% \cs_generate_from_arg_count:cNnn {#1} \cs_set:Npn +% { \cs_get_arg_count_from_signature:c {#1} } {#2} +% } +% \end{verbatim} +% \begin{macrocode} +\cs_set:Npn \cs_tmp:w #1#2#3 + { + \cs_set_protected:cpx {cs_#1:#2}##1##2{ + \exp_not:N\cs_generate_from_arg_count:cNnn {##1} + \exp_after:wN \exp_not:N \cs:w cs_#1:#3 \cs_end: + { \exp_not:N \cs_get_arg_count_from_signature:c {##1} } {##2} + } + } +% \end{macrocode} +% \begin{macro}{\cs_set:cn} +% \begin{macro}{\cs_set:cx} +% \begin{macro}{\cs_set_nopar:cn} +% \begin{macro}{\cs_set_nopar:cx} +% \begin{macro}{\cs_set_protected:cn} +% \begin{macro}{\cs_set_protected:cx} +% \begin{macro}{\cs_set_protected_nopar:cn} +% \begin{macro}{\cs_set_protected_nopar:cx} +% \begin{macro}{\cs_gset:cn} +% \begin{macro}{\cs_gset:cx} +% \begin{macro}{\cs_gset_nopar:cn} +% \begin{macro}{\cs_gset_nopar:cx} +% \begin{macro}{\cs_gset_protected:cn} +% \begin{macro}{\cs_gset_protected:cx} +% \begin{macro}{\cs_gset_protected_nopar:cn} +% \begin{macro}{\cs_gset_protected_nopar:cx} +% The 32 |c| variants. +% \begin{macrocode} +\cs_tmp:w { set } { cn } { Npn } +\cs_tmp:w { set } { cx } { Npx } +\cs_tmp:w { set_nopar } { cn } { Npn } +\cs_tmp:w { set_nopar } { cx } { Npx } +\cs_tmp:w { set_protected } { cn } { Npn } +\cs_tmp:w { set_protected } { cx } { Npx } +\cs_tmp:w { set_protected_nopar } { cn } { Npn } +\cs_tmp:w { set_protected_nopar } { cx } { Npx } +\cs_tmp:w { gset } { cn } { Npn } +\cs_tmp:w { gset } { cx } { Npx } +\cs_tmp:w { gset_nopar } { cn } { Npn } +\cs_tmp:w { gset_nopar } { cx } { Npx } +\cs_tmp:w { gset_protected } { cn } { Npn } +\cs_tmp:w { gset_protected } { cx } { Npx } +\cs_tmp:w { gset_protected_nopar } { cn } { Npn } +\cs_tmp:w { gset_protected_nopar } { cx } { 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}{\cs_new:cn} +% \begin{macro}{\cs_new:cx} +% \begin{macro}{\cs_new_nopar:cn} +% \begin{macro}{\cs_new_nopar:cx} +% \begin{macro}{\cs_new_protected:cn} +% \begin{macro}{\cs_new_protected:cx} +% \begin{macro}{\cs_new_protected_nopar:cn} +% \begin{macro}{\cs_new_protected_nopar:cx} +% \begin{macrocode} +\cs_tmp:w { new } { cn } { Npn } +\cs_tmp:w { new } { cx } { Npx } +\cs_tmp:w { new_nopar } { cn } { Npn } +\cs_tmp:w { new_nopar } { cx } { Npx } +\cs_tmp:w { new_protected } { cn } { Npn } +\cs_tmp:w { new_protected } { cx } { Npx } +\cs_tmp:w { new_protected_nopar } { cn } { Npn } +\cs_tmp:w { new_protected_nopar } { cx } { Npx } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Checking control sequence equality} +% +% \begin{macro}[pTF]{\cs_if_eq:NN,\cs_if_eq:cN,\cs_if_eq:Nc,\cs_if_eq:cc} +% Check if two control sequences are identical. +% \begin{macrocode} +\prg_new_conditional:Npnn \cs_if_eq:NN #1#2 { p , T , F , TF } + { + \if_meaning:w #1#2 + \prg_return_true: \else: \prg_return_false: \fi: + } +\cs_new_nopar:Npn \cs_if_eq_p:cN { \exp_args:Nc \cs_if_eq_p:NN } +\cs_new_nopar:Npn \cs_if_eq:cNTF { \exp_args:Nc \cs_if_eq:NNTF } +\cs_new_nopar:Npn \cs_if_eq:cNT { \exp_args:Nc \cs_if_eq:NNT } +\cs_new_nopar:Npn \cs_if_eq:cNF { \exp_args:Nc \cs_if_eq:NNF } +\cs_new_nopar:Npn \cs_if_eq_p:Nc { \exp_args:NNc \cs_if_eq_p:NN } +\cs_new_nopar:Npn \cs_if_eq:NcTF { \exp_args:NNc \cs_if_eq:NNTF } +\cs_new_nopar:Npn \cs_if_eq:NcT { \exp_args:NNc \cs_if_eq:NNT } +\cs_new_nopar:Npn \cs_if_eq:NcF { \exp_args:NNc \cs_if_eq:NNF } +\cs_new_nopar:Npn \cs_if_eq_p:cc { \exp_args:Ncc \cs_if_eq_p:NN } +\cs_new_nopar:Npn \cs_if_eq:ccTF { \exp_args:Ncc \cs_if_eq:NNTF } +\cs_new_nopar:Npn \cs_if_eq:ccT { \exp_args:Ncc \cs_if_eq:NNT } +\cs_new_nopar:Npn \cs_if_eq:ccF { \exp_args:Ncc \cs_if_eq:NNF } +% \end{macrocode} +% \end{macro} +% +% \subsection{Diagnostic wrapper functions} +% +% \begin{macro}{\kernel_register_show:N, \kernel_register_show:c} +% \begin{macrocode} +\cs_new_nopar:Npn \kernel_register_show:N #1 + { + \cs_if_exist:NTF #1 + { \tex_showthe:D #1 } + { + \msg_kernel_error:nnx { kernel } { variable-not-defined } + { \token_to_str:N #1 } + } + } +\cs_new_nopar:Npn \kernel_register_show:c { \exp_args:Nc \int_show:N } +% \end{macrocode} +% \end{macro} +% +% \subsection{Engine specific definitions} +% +% \begin{macro} +% { +% \c_pdftex_is_engine_bool, \c_luatex_is_engine_bool, +% \c_xetex_is_engine_bool +% } +% \begin{macro}[TF]{\xetex_if_engine:, \luatex_if_engine:, \pdftex_if_engine:} +% In some cases it will be useful to know which engine we're running. +% Don't provide a |_p| predicate because the |_bool| is used for the +% same thing. This can all be hard-coded for speed. +% \begin{macrocode} +\cs_new_eq:NN \luatex_if_engine:T \use_none:n +\cs_new_eq:NN \luatex_if_engine:F \use:n +\cs_new_eq:NN \luatex_if_engine:TF \use_ii:nn +\cs_new_eq:NN \pdftex_if_engine:T \use:n +\cs_new_eq:NN \pdftex_if_engine:F \use_none:n +\cs_new_eq:NN \pdftex_if_engine:TF \use_i:nn +\cs_new_eq:NN \xetex_if_engine:T \use_none:n +\cs_new_eq:NN \xetex_if_engine:F \use:n +\cs_new_eq:NN \xetex_if_engine:TF \use_ii:nn +\cs_new_eq:NN \c_luatex_is_engine_bool \c_false_bool +\cs_new_eq:NN \c_pdftex_is_engine_bool \c_true_bool +\cs_new_eq:NN \c_xetex_is_engine_bool \c_false_bool +\cs_if_exist:NT \xetex_XeTeXversion:D + { + \cs_set_eq:NN \pdftex_if_engine:T \use_none:n + \cs_set_eq:NN \pdftex_if_engine:F \use:n + \cs_set_eq:NN \pdftex_if_engine:TF \use_ii:nn + \cs_set_eq:NN \xetex_if_engine:T \use:n + \cs_set_eq:NN \xetex_if_engine:F \use_none:n + \cs_set_eq:NN \xetex_if_engine:TF \use_i:nn + \cs_set_eq:NN \c_pdftex_is_engine_bool \c_false_bool + \cs_set_eq:NN \c_xetex_is_engine_bool \c_true_bool + } +\cs_if_exist:NT \luatex_directlua:D + { + \cs_set_eq:NN \luatex_if_engine:T \use:n + \cs_set_eq:NN \luatex_if_engine:F \use_none:n + \cs_set_eq:NN \luatex_if_engine:TF \use_i:nn + \cs_set_eq:NN \pdftex_if_engine:T \use_none:n + \cs_set_eq:NN \pdftex_if_engine:F \use:n + \cs_set_eq:NN \pdftex_if_engine:TF \use_ii:nn + \cs_set_eq:NN \c_luatex_is_engine_bool \c_true_bool + \cs_set_eq:NN \c_pdftex_is_engine_bool \c_false_bool + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Doing nothing functions} +% +% \begin{macro}{\prg_do_nothing:} +% This does not fit anywhere else! +% \begin{macrocode} +\cs_new_nopar:Npn \prg_do_nothing: { } +% \end{macrocode} +% \end{macro} +% +% \subsection{String comparisons} +% +% \begin{macro}[pTF]{\str_if_eq:nn} +% \begin{macro}[pTF]{\str_if_eq:xx} +% Modern engines provide a direct way of comparing two token lists, +% but returning a number. This set of conditionals therefore make life +% a bit clearer. The \texttt{nn} and \texttt{xx} versions are created +% directly as this is most efficient. These should eventually +% move somewhere else. +% \begin{macrocode} +\prg_new_conditional:Npnn \str_if_eq:nn #1#2 { p , T , F , TF } + { + \if_int_compare:w \pdftex_strcmp:D { \exp_not:n {#1} } { \exp_not:n {#2} } + = \c_zero + \prg_return_true: \else: \prg_return_false: \fi: + } +\prg_new_conditional:Npnn \str_if_eq:xx #1#2 { p , T , F , TF } + { + \if_int_compare:w \pdftex_strcmp:D {#1} {#2} = \c_zero + \prg_return_true: \else: \prg_return_false: \fi: + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Deprecated functions} +% +% Deprecated on 2011-05-27, for removal by 2011-08-31. +% +% \begin{macrocode} +\cs_new_eq:NN \cs_gnew_nopar:Npn \cs_new_nopar:Npn +\cs_new_eq:NN \cs_gnew:Npn \cs_new:Npn +\cs_new_eq:NN \cs_gnew_protected_nopar:Npn \cs_new_protected_nopar:Npn +\cs_new_eq:NN \cs_gnew_protected:Npn \cs_new_protected:Npn +\cs_new_eq:NN \cs_gnew_nopar:Npx \cs_new_nopar:Npx +\cs_new_eq:NN \cs_gnew:Npx \cs_new:Npx +\cs_new_eq:NN \cs_gnew_protected_nopar:Npx \cs_new_protected_nopar:Npx +\cs_new_eq:NN \cs_gnew_protected:Npx \cs_new_protected:Npx +\cs_new_eq:NN \cs_gnew_nopar:cpn \cs_new_nopar:cpn +\cs_new_eq:NN \cs_gnew:cpn \cs_new:cpn +\cs_new_eq:NN \cs_gnew_protected_nopar:cpn \cs_new_protected_nopar:cpn +\cs_new_eq:NN \cs_gnew_protected:cpn \cs_new_protected:cpn +\cs_new_eq:NN \cs_gnew_nopar:cpx \cs_new_nopar:cpx +\cs_new_eq:NN \cs_gnew:cpx \cs_new:cpx +\cs_new_eq:NN \cs_gnew_protected_nopar:cpx \cs_new_protected_nopar:cpx +\cs_new_eq:NN \cs_gnew_protected:cpx \cs_new_protected:cpx +% \end{macrocode} +% +% \begin{macrocode} +\cs_new_eq:NN \cs_gnew_eq:NN \cs_new_eq:NN +\cs_new_eq:NN \cs_gnew_eq:cN \cs_new_eq:cN +\cs_new_eq:NN \cs_gnew_eq:Nc \cs_new_eq:Nc +\cs_new_eq:NN \cs_gnew_eq:cc \cs_new_eq:cc +% \end{macrocode} +% +% \begin{macrocode} +\cs_new_eq:NN \cs_gundefine:N \cs_undefine:N +\cs_new_eq:NN \cs_gundefine:c \cs_undefine:c +% \end{macrocode} +% +% \begin{macrocode} +\cs_new_eq:NN \group_execute_after:N \group_insert_after:N +% \end{macrocode} +% +% \begin{macrocode} +%</initex|package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintIndex diff --git a/Master/texmf-dist/source/latex/l3kernel/l3bootstrap.dtx b/Master/texmf-dist/source/latex/l3kernel/l3bootstrap.dtx new file mode 100644 index 00000000000..69aaf46357b --- /dev/null +++ b/Master/texmf-dist/source/latex/l3kernel/l3bootstrap.dtx @@ -0,0 +1,647 @@ +% \iffalse meta-comment +% +%% File: l3bootstrap.dtx Copyright (C) 2011 The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +% +%<*package> +\def\GetIdInfo$% + Id: #1 #2 #3-#4-#5 #6 #7 $#8% + {% + \def\ExplFileDate{#3/#4/#5}% + \def\ExplFileVersion{#2}% + } +\GetIdInfo$Id: l3bootstrap.dtx 2478 2011-06-19 21:34:23Z joseph $ + {L3 experimental bootstrap code} +%</package> +%<*driver> +\documentclass[full]{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{^^A +% The \pkg{l3bootstrap} package\\ Bootstrap code^^A +% \thanks{This file describes v\ExplFileVersion, +% last revised \ExplFileDate.}^^A +% } +% +% \author{^^A +% The \LaTeX3 Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% +% \date{Released \ExplFileDate} +% +% \maketitle +% +% \begin{documentation} +% +% \section{Using the \LaTeX3 modules} +% +% The modules documented in \file{source3} are designed to be used on top of +% \LaTeXe{} and are loaded all as one with the usual |\usepackage{expl3}| or +% |\RequirePackage{expl3}| instructions. These modules will also form the +% basis of the \LaTeX3 format, but work in this area is incomplete and not +% included in this documentation at present. +% +% As the modules use a coding syntax different from standard +% \LaTeXe{} it provides a few functions for setting it up. +% +% \begin{function}{\ExplSyntaxOn, \ExplSyntaxOff} +% \begin{syntax} +% \cs{ExplSyntaxOn} \meta{code} \cs{ExplSyntaxOff} +% \end{syntax} +% The \cs{ExplSyntaxOn} function switches to a category code +% regim{\'e} in which spaces are ignored and in which the colon (|:|) +% and underscore (|_|) are treated as \enquote{letters}, thus allowing +% access to the names of code functions and variables. Within this +% environment, |~| is used to input a space. The \cs{ExplSyntaxOff} +% reverts to the document category code regim{\'e}. +% \end{function} +% +% \begin{function}{\ExplSyntaxNamesOn, \ExplSyntaxNamesOff} +% \begin{syntax} +% \cs{ExplSyntaxNamesOn} \meta{code} \cs{ExplSyntaxNamesOff} +% \end{syntax} +% The \cs{ExplSyntaxOn} function switches to a category code +% regim{\'e} in which the colon (|:|) and underscore (|_|) are treated as +% \enquote{letters}, thus allowing access to the names of code functions +% and variables. In contrast to \cs{ExplSyntaxOn}, using +% \cs{ExplSyntaxNamesOn} does not cause spaces to be ignored. +% The \cs{ExplSyntaxNamesOff} reverts to the document category code +% regim{\'e}. +% \end{function} +% +% \begin{function}{\ProvidesExplPackage, \ProvidesExplClass, \ProvidesExplFile} +% \begin{syntax} +% |\RequirePackage{expl3}| \\ +% \cs{ProvidesExplPackage} \Arg{package} \Arg{date} \Arg{version} +% ~~\Arg{description} +% \end{syntax} +% These functions act broadly in the same way as the \LaTeXe{} kernel +% functions \cs{ProvidesPackage}, \cs{ProvidesClass} and +% \cs{ProvidesFile}. However, they also implicitly switch +% \cs{ExplSyntaxOn} for the remainder of the code with the file. At the +% end of the file, \cs{ExplSyntaxOff} will be called to reverse this. +% (This is the same concept as \LaTeXe{} provides in turning on +% \cs{makeatletter} within package and class code.) +% \end{function} +% +% \begin{function}{\GetIdInfo} +% \begin{syntax} +% |\RequirePackage{l3names}| +% \cs{GetIdInfo} |$Id:| \meta{SVN info field} |$| \Arg{description} +% \end{syntax} +% Extracts all information from a SVN field. Spaces are not +% ignored in these fields. The information pieces are stored in +% separate control sequences with \cs{ExplFileName} for the part of the +% file name leading up to the period, \cs{ExplFileDate} for date, +% \cs{ExplFileVersion} for version and \cs{ExplFileDescription} for the +% description. +% \end{function} +% +% To summarize: Every single package using this syntax should identify +% itself using one of the above methods. Special care is taken so that +% every package or class file loaded with \cs{RequirePackage} or alike +% are loaded with usual \LaTeXe{} category codes and the \LaTeX3 category code +% scheme is reloaded when needed afterwards. See implementation for +% details. If you use the \cs{GetIdInfo} command you can use the +% information when loading a package with +% \begin{verbatim} +% \ProvidesExplPackage{\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +% \end{verbatim} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{Bootstrap code} +% +% \begin{macrocode} +%<*initex|package> +% \end{macrocode} +% +% \subsection{Format-specific code} +% +% The very first thing to do is to bootstrap the \IniTeX{} system so +% that everything else will actually work. \TeX{} does not start with +% some pretty basic character codes set up. +% \begin{macrocode} +%<*initex> +\catcode `\{ = 1 \relax +\catcode `\} = 2 \relax +\catcode `\# = 6 \relax +\catcode `\^ = 7 \relax +%</initex> +% \end{macrocode} +% +% Tab characters should not show up in the code, but to be on the +% safe side. +% \begin{macrocode} +%<*initex> +\catcode `\^^I = 10 \relax +%</initex> +% \end{macrocode} +% +% For \LuaTeX{} the extra primitives need to be enabled before +% they can be use. No \cs{ifdefined} yet, so do it the old-fashioned +% way. The primitive \cs{strcmp} is simulated using some \Lua{} +% code, which currently has to be applied to every job as the \Lua{} +% code is not part of the format. Thanks to Taco Hoekwater for this +% code. The odd \cs{csname} business is needed so that the later +% deletion code will work. +% \begin{macrocode} +%<*initex> +\begingroup\expandafter\expandafter\expandafter\endgroup +\expandafter\ifx\csname directlua\endcsname\relax +\else + \directlua + { + tex.enableprimitives('',tex.extraprimitives ()) + lua.bytecode[1] = function () + function strcmp (A, B) + if A == B then + tex.write("0") + elseif A < B then + tex.write("-1") + else + tex.write("1") + end + end + end + lua.bytecode[1]() + } + \everyjob\expandafter + {\csname\detokenize{luatex_directlua:D}\endcsname{lua.bytecode[1]()}} + \long\edef\pdfstrcmp#1#2% + {% + \expandafter\noexpand\csname\detokenize{luatex_directlua:D}\endcsname + {% + strcmp% + (% + "\noexpand\luaescapestring{#1}",% + "\noexpand\luaescapestring{#2}"% + )% + }% + } +\fi +%</initex> +% \end{macrocode} +% +% \subsection{Package-specific code} +% +% The package starts by identifying itself: the information itself is +% taken from the SVN |Id| string at the start of the source file. +% \begin{macrocode} +%<*package> +\ProvidesPackage{l3bootstrap} + [% + \ExplFileDate\space v\ExplFileVersion\space + L3 Experimental bootstrap code% + ] +%</package> +% \end{macrocode} +% +% For \LuaTeX{} the functionality of the \cs{pdfstrcmp} primitive +% needs to be provided: the \pkg{pdftexmcds} package is used to +% do this if necessary. At present, there is also a need to deal +% with some low-level allocation stuff that could usefully be added +% to \texttt{lualatex.ini}. As it is currently not, load Heiko +% Oberdiek's \pkg{luatex} package instead. +% \begin{macrocode} +%<*package> +\def\@tempa% + {% + \def\@tempa{}% + \RequirePackage{luatex}% + \RequirePackage{pdftexcmds}% + \let\pdfstrcmp\pdf@strcmp + } +\begingroup\expandafter\expandafter\expandafter\endgroup +\expandafter\ifx\csname directlua\endcsname\relax +\else + \expandafter\@tempa +\fi +%</package> +% \end{macrocode} +% +% \begin{macro}{\ExplSyntaxOff, \ExplSyntaxOn} +% Experimental syntax switching is set up here for the package-loading +% process. These are redefined in \pkg{expl3} for the package and in +% \pkg{l3final} for the format. +% \begin{macrocode} +%<*package> +\protected\edef\ExplSyntaxOff + {% + \catcode 9 = \the\catcode 9\relax + \catcode 32 = \the\catcode 32\relax + \catcode 34 = \the\catcode 34\relax + \catcode 38 = \the\catcode 38\relax + \catcode 58 = \the\catcode 58\relax + \catcode 94 = \the\catcode 94\relax + \catcode 95 = \the\catcode 95\relax + \catcode 124 = \the\catcode 124\relax + \catcode 126 = \the\catcode 126\relax + \endlinechar = \the\endlinechar\relax + \chardef\csname\detokenize{l_expl_status_bool}\endcsname = 0 \relax + } +\protected\edef\ExplSyntaxOn + { + \catcode 9 = 9 \relax + \catcode 32 = 9 \relax + \catcode 34 = 12 \relax + \catcode 58 = 11 \relax + \catcode 94 = 7 \relax + \catcode 95 = 11 \relax + \catcode 124 = 12 \relax + \catcode 126 = 10 \relax + \endlinechar = 32 \relax + \chardef\csname\detokenize{l_expl_status_bool}\endcsname = 1 \relax + } +%</package> +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\l_expl_status_bool} +% The status for experimental code syntax: this is off at present. This +% code is used by both the package and the format. +% \begin{macrocode} +\expandafter\chardef\csname\detokenize{l_expl_status_bool}\endcsname = 0 \relax +% \end{macrocode} +%\end{macro} +% +% \subsection{Dealing with package-mode meta-data} +% +% \begin{macro}{\GetIdInfo} +% \begin{macro}[aux] +% { +% \GetIdInfoFull, \GetIdInfoAuxI, \GetIdInfoAuxII, \GetIdInfoAuxIII, +% \GetIdInfoAuxCVS, \GetIdInfoAuxSVN +% } +% Functions for collecting up meta-data from the SVN information +% used by the \LaTeX3 Project. +% \begin{macrocode} +%<*package> +\protected\def\GetIdInfo + { + \begingroup + \catcode 32 = 10 \relax + \GetIdInfoAuxI + } +\protected\def\GetIdInfoAuxI$#1$#2% + { + \def\tempa{#1}% + \def\tempb{Id}% + \ifx\tempa\tempb + \def\tempa + {% + \endgroup + \def\ExplFileDate{0000/00/00}% + \def\ExplFileDescription{#2}% + \def\ExplFileName{[unknown~name]}% + \def\ExplFileVersion{000}% + }% + \else + \def\tempa + {% + \endgroup + \GetIdInfoAuxII$#1${#2}% + }% + \fi + \tempa + } +\protected\def\GetIdInfoAuxII$#1 #2.#3 #4 #5 #6 #7 #8$#9% + {% + \def\ExplFileName{#2}% + \def\ExplFileVersion{#4}% + \def\ExplFileDescription{#9}% + \GetIdInfoAuxIII#5\relax#3\relax#5\relax#6\relax + } +\protected\def\GetIdInfoAuxIII#1#2#3#4#5#6\relax + {% + \ifx#5/% + \expandafter\GetIdInfoAuxCVS + \else + \expandafter\GetIdInfoAuxSVN + \fi + } +\protected\def\GetIdInfoAuxCVS#1,v\relax#2\relax#3\relax + {\def\ExplFileDate{#2}} +\protected\def\GetIdInfoAuxSVN#1\relax#2-#3-#4\relax#5Z\relax + {\def\ExplFileDate{#2/#3/#4}} +%</package> +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\ProvidesExplPackage, \ProvidesExplClass, \ProvidesExplFile} +% For other packages and classes building on this one it is convenient +% not to need \cs{ExplSyntaxOn} each time. +% \begin{macrocode} +%<*package> +\protected\def\ProvidesExplPackage#1#2#3#4% + {% + \ProvidesPackage{#1}[#2 v#3 #4]% + \ExplSyntaxOn + } +\protected\def\ProvidesExplClass#1#2#3#4% + {% + \ProvidesClass{#1}[#2 v#3 #4]% + \ExplSyntaxOn + } +\protected\def\ProvidesExplFile#1#2#3#4% + {% + \ProvidesFile{#1}[#2 v#3 #4]% + \ExplSyntaxOn + } +%</package> +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@pushfilename, \@popfilename} +% The idea here is to use \LaTeXe{}'s \cs{@pushfilename} and +% \cs{@popfilename} to track the current syntax status. This can be +% achieved by saving the current status flag at each push to a stack, +% then recovering it at the pop stage and checking if the code +% environment should still be active. +% \begin{macrocode} +%<*package> +\edef\@pushfilename + {% + \edef\expandafter\noexpand + \csname\detokenize{l_expl_status_stack_tl}\endcsname + {% + \noexpand\ifodd\expandafter\noexpand + \csname\detokenize{l_expl_status_bool}\endcsname + 1% + \noexpand\else + 0% + \noexpand\fi + \expandafter\noexpand + \csname\detokenize{l_expl_status_stack_tl}\endcsname + }% + \ExplSyntaxOff + \unexpanded\expandafter{\@pushfilename}% + } +\edef\@popfilename + {% + \unexpanded\expandafter{\@popfilename}% + \noexpand\if a\expandafter\noexpand\csname + \detokenize{l_expl_status_stack_tl}\endcsname a% + \ExplSyntaxOff + \noexpand\else + \noexpand\expandafter + \expandafter\noexpand\csname + \detokenize{expl_status_pop:w}\endcsname + \expandafter\noexpand\csname + \detokenize{l_expl_status_stack_tl}\endcsname + \noexpand\@nil + \noexpand\fi + } +%</package> +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\l_expl_status_stack_tl} +% As \pkg{expl3} itself cannot be loaded with the code environment +% already active, at the end of the package \cs{ExplSyntaxOff} can +% safely be called. +% \begin{macrocode} +%<*package> +\@namedef{\detokenize{l_expl_status_stack_tl}}{0} +%</package> +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[aux]{\expl_status_pop:w} +% The pop auxiliary function removes the first item from the stack, +% saves the rest of the stack and then does the test. As +% \cs{ExplSyntaxOff} is already defined as a protected macro, there +% is no need for \cs{noexpand} here. +% \begin{macrocode} +%<*package> +\expandafter\edef\csname\detokenize{expl_status_pop:w}\endcsname#1#2\@nil + {% + \def\expandafter\noexpand + \csname\detokenize{l_expl_status_stack_tl}\endcsname{#2}% + \noexpand\ifodd#1\space + \noexpand\expandafter\noexpand\ExplSyntaxOn + \noexpand\else + \noexpand\expandafter\ExplSyntaxOff + \noexpand\fi + } +%</package> +% \end{macrocode} +% \end{macro} +% +% We want the \pkg{expl3} bundle to be loaded \enquote{as one}; +% this command is +% used to ensure that one of the |l3| packages isn't loaded on its own. +% \begin{macrocode} +%<*package> +\expandafter\protected\expandafter\def + \csname\detokenize{package_check_loaded_expl:}\endcsname + {% + \@ifpackageloaded{expl3} + {} + {% + \PackageError{expl3} + {Cannot load the expl3 modules separately} + {% + The expl3 modules cannot be loaded separately;\MessageBreak + please \string\usepackage\string{expl3\string} instead. + }% + }% + } +%</package> +% \end{macrocode} +% +% \subsection{The \cs{pdfstrcmp} primitive in \XeTeX{}} +% +% Only \pdfTeX{} has a primitive called \cs{pdfstrcmp}. The \XeTeX{} +% version is just \cs{strcmp}, so there is some shuffling to do. +% \begin{macrocode} +\begingroup\expandafter\expandafter\expandafter\endgroup + \expandafter\ifx\csname pdfstrcmp\endcsname\relax + \let\pdfstrcmp\strcmp +\fi +% \end{macrocode} +% +% \subsection{Engine requirements} +% +% The code currently requires functionality equivalent to \cs{pdfstrcmp} +% in addition to \eTeX{}. The former is therefore used as a test for +% a suitable engine. +% \begin{macrocode} +\begingroup\expandafter\expandafter\expandafter\endgroup +\expandafter\ifx\csname pdfstrcmp\endcsname\relax +%<*package> + \PackageError{l3names}{Required primitive not found: \protect\pdfstrcmp} + {% + LaTeX3 requires the e-TeX primitives and + \string\pdfstrcmp.\MessageBreak + These are available in engine versions: \MessageBreak + - pdfTeX 1.30 \MessageBreak + - XeTeX 0.9994 \MessageBreak + - LuaTeX 0.60 \MessageBreak + or later. \MessageBreak + \MessageBreak + Loading of expl3 will abort! + } +%</package> +%<*initex> + \newlinechar`\^^J\relax + \errhelp{% + LaTeX3 requires the e-TeX primitives and + \string\pdfstrcmp. ^^J + These are available in engine versions: ^^J + - pdfTeX 1.30 ^^J + - XeTeX 0.9994 ^^J + - LuaTeX 0.60 ^^J + or later. ^^J + For pdfTeX and XeTeX the '-etex' command-line switch is also + needed.^^J + ^^J + Format building will abort! + } +%</initex> + \expandafter\endinput +\fi +% \end{macrocode} +% +% \subsection{The \LaTeX3 code environment} +% +% \begin{macro}{\ExplSyntaxNamesOn, \ExplSyntaxNamesOff} +% These can be set up early, as they are not used anywhere in the +% package or format itself. Using an \cs{edef} here makes the +% definitions that bit clearer later. +% \begin{macrocode} +\protected\edef\ExplSyntaxNamesOn + {% + \expandafter\noexpand + \csname\detokenize{char_set_catcode_letter:n}\endcsname{58}% + \expandafter\noexpand + \csname\detokenize{char_set_catcode_letter:n}\endcsname{95}% + } +\protected\edef\ExplSyntaxNamesOff + {% + \expandafter\noexpand + \csname\detokenize{char_set_catcode_math_subscript:n}\endcsname{58}% + \expandafter\noexpand + \csname\detokenize{char_set_catcode_other:n}\endcsname{95}% + } +% \end{macrocode} +% \end{macro} +% +% The code environment is now set up for the format: the package deals +% with this using \cs{ProvidesExplPackage}. +% \begin{macrocode} +%<*initex> +\catcode 9 = 9 \relax +\catcode 32 = 9 \relax +\catcode 34 = 12 \relax +\catcode 58 = 11 \relax +\catcode 94 = 7 \relax +\catcode 95 = 11 \relax +\catcode 124 = 12 \relax +\catcode 126 = 10 \relax +\endlinechar = 32 \relax +%</initex> +% \end{macrocode} +% +% \begin{macro}{\ExplSyntaxOn, \ExplSyntaxOff} +% The idea here is that multiple \cs{ExplSyntaxOn} calls are not +% going to mess up category codes, and that multiple calls to +% \cs{ExplSyntaxOff} are also not wasting time. +% \begin{macrocode} +%<*initex> +\protected \def \ExplSyntaxOn + { + \bool_if:NF \l_expl_status_bool + { + \cs_set_protected_nopar:Npx \ExplSyntaxOff + { + \char_set_catcode:nn { 9 } { \char_value_catcode:n { 9 } } + \char_set_catcode:nn { 32 } { \char_value_catcode:n { 32 } } + \char_set_catcode:nn { 34 } { \char_value_catcode:n { 34 } } + \char_set_catcode:nn { 38 } { \char_value_catcode:n { 38 } } + \char_set_catcode:nn { 58 } { \char_value_catcode:n { 58 } } + \char_set_catcode:nn { 94 } { \char_value_catcode:n { 94 } } + \char_set_catcode:nn { 95 } { \char_value_catcode:n { 95 } } + \char_set_catcode:nn { 124 } { \char_value_catcode:n { 124 } } + \char_set_catcode:nn { 126 } { \char_value_catcode:n { 126 } } + \tex_endlinechar:D = + \tex_the:D \tex_endlinechar:D \scan_stop: + \bool_set_false:N \l_expl_status_bool + \cs_set_protected_nopar:Npn \ExplSyntaxOff { } + } + } + \char_set_catcode_ignore:n { 9 } % tab + \char_set_catcode_ignore:n { 32 } % space + \char_set_catcode_other:n { 34 } % double quote + \char_set_catcode_alignment:n { 38 } % ampersand + \char_set_catcode_letter:n { 58 } % colon + \char_set_catcode_math_superscript:n { 94 } % circumflex + \char_set_catcode_letter:n { 95 } % underscore + \char_set_catcode_other:n { 124 } % pipe + \char_set_catcode_space:n { 126 } % tilde + \tex_endlinechar:D = 32 \scan_stop: + \bool_set_true:N \l_expl_status_bool + } +\protected \def \ExplSyntaxOff { } +%</initex> +% \end{macrocode} +% \end{macro} +% +% \begin{variable}{\l_expl_status_bool} +% A flag to show the current syntax status. +% \begin{macrocode} +%<*initex> +\chardef \l_expl_status_bool = 0 ~ +%</initex> +% \end{macrocode} +% \end{variable} +% +% \begin{macrocode} +%</initex|package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintIndex
\ No newline at end of file diff --git a/Master/texmf-dist/source/latex/l3kernel/l3box.dtx b/Master/texmf-dist/source/latex/l3kernel/l3box.dtx new file mode 100644 index 00000000000..1947f85b356 --- /dev/null +++ b/Master/texmf-dist/source/latex/l3kernel/l3box.dtx @@ -0,0 +1,1237 @@ +% \iffalse meta-comment +% +%% File: l3box.dtx Copyright (C) 2005-2011 The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +% +%<*driver|package> +\RequirePackage{l3names} +\GetIdInfo$Id: l3box.dtx 2478 2011-06-19 21:34:23Z joseph $ + {L3 Experimental boxes} +%</driver|package> +%<*driver> +\documentclass[full]{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{^^A +% The \pkg{l3box} package\\ Boxes^^A +% \thanks{This file describes v\ExplFileVersion, +% last revised \ExplFileDate.}^^A +% } +% +% \author{^^A +% The \LaTeX3 Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% +% \date{Released \ExplFileDate} +% +% \maketitle +% +% \begin{documentation} +% +% 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_|. +% +% \section{Creating and initialising boxes} +% +% \begin{function}{\box_new:N, \box_new:c} +% \begin{syntax} +% \cs{box_new:N} \meta{box} +% \end{syntax} +% Creates a new \meta{box} or raises an error if the name is +% already taken. The declaration is global. The \meta{box} will +% initially be void. +% \end{function} +% +% \begin{function}{\box_clear:N, \box_clear:c} +% \begin{syntax} +% \cs{box_clear:N} \meta{box} +% \end{syntax} +% Clears the content of the \meta{box} by setting the box equal to +% \cs{c_void_box} within the current \TeX{} group level. +% \end{function} +% +% \begin{function}{\box_gclear:N, \box_gclear:c} +% \begin{syntax} +% \cs{box_gclear:N} \meta{box} +% \end{syntax} +% Clears the content of the \meta{box} by setting the box equal to +% \cs{c_void_box} globally. +% \end{function} +% +% \begin{function}{\box_clear_new:N, \box_clear_new:c} +% \begin{syntax} +% \cs{box_clear_new:N} \meta{box} +% \end{syntax} +% If the \meta{box} is not defined, globally creates it. If the \meta{box} +% is defined, +% clears the content of the \meta{box} by setting the box equal to +% \cs{c_void_box} within the current \TeX{} group level. +% \end{function} +% +% \begin{function}{\box_gclear_new:N, \box_gclear_new:c} +% \begin{syntax} +% \cs{box_gclear_new:N} \meta{box} +% \end{syntax} +% If the \meta{box} is not defined, globally creates it. If the \meta{box} +% is defined, +% clears the content of the \meta{box} by setting the box equal to +% \cs{c_void_box} globally. +% \end{function} +% +% \begin{function} +% {\box_set_eq:NN, \box_set_eq:cN, \box_set_eq:Nc, \box_set_eq:cc} +% \begin{syntax} +% \cs{box_set_eq:NN} \meta{box1} \meta{box2} +% \end{syntax} +% Sets the content of \meta{box1} equal to that of \meta{box2}. This +% assignment is restricted to the current \TeX{} group level. +% \end{function} +% +% \begin{function} +% {\box_gset_eq:NN, \box_gset_eq:cN, \box_gset_eq:Nc, \box_gset_eq:cc} +% \begin{syntax} +% \cs{box_gset_eq:NN} \meta{box1} \meta{box2} +% \end{syntax} +% Sets the content of \meta{box1} equal to that of \meta{box2} globally. +% \end{function} +% +% \begin{function} +% { +% \box_set_eq_clear:NN, \box_set_eq_clear:cN, +% \box_set_eq_clear:Nc, \box_set_eq_clear:cc +% } +% \begin{syntax} +% \cs{box_set_eq_clear:NN} \meta{box1} \meta{box2} +% \end{syntax} +% Sets the content of \meta{box1} within the current \TeX{} group +% equal to that of \meta{box2}, then clears \meta{box2} globally. +% \end{function} +% +% \begin{function} +% { +% \box_gset_eq_clear:NN, \box_gset_eq_clear:cN, +% \box_gset_eq_clear:Nc, \box_gset_eq_clear:cc +% } +% \begin{syntax} +% \cs{box_gset_eq_clear:NN} \meta{box1} \meta{box2} +% \end{syntax} +% Sets the content of \meta{box1} equal to that of \meta{box2}, then +% clears \meta{box2}. These assignments are global. +% \end{function} +% +% \section{Using boxes} +% +% \begin{function}{\box_use:N, \box_use:c} +% \begin{syntax} +% \cs{box_use:N} \meta{box} +% \end{syntax} +% Inserts the current content of the \meta{box} onto the current +% list for typesetting. +% \begin{texnote} +% This is the \TeX{} primitive \cs{copy}. +% \end{texnote} +% \end{function} +% +% \begin{function}{\box_use_clear:N, \box_use_clear:c} +% \begin{syntax} +% \cs{box_use_clear:N} \meta{box} +% \end{syntax} +% Inserts the current content of the \meta{box} onto the current +% list for typesetting, then globally clears the content of the +% \meta{box}. +% \begin{texnote} +% This is the \TeX{} primitive \cs{box}. +% \end{texnote} +% \end{function} +% +% \begin{function}{\box_move_right:nn, \box_move_left:nn} +% \begin{syntax} +% \cs{box_move_right:nn} \Arg{dimexpr} \Arg{box function} +% \end{syntax} +% This function operates in vertical mode, and inserts the +% material specified by the \meta{box function} +% such that its reference point is displaced horizontally by the given +% \meta{dimexpr} from the reference point for typesetting, to the right +% or left as appropriate. The \meta{box function} should be +% a box opeeration such as |\box_use:N \<box>| or a \enquote{raw} +% box specification such as |\vbox:n { xyz }|. +% \end{function} +% +% \begin{function}{\box_move_up:nn, \box_move_down:nn} +% \begin{syntax} +% \cs{box_move_up:nn} \Arg{dimexpr} \Arg{box function} +% \end{syntax} +% This function operates in horizontal mode, and inserts the +% material specified by the \meta{box function} +% such that its reference point is displaced vertical by the given +% \meta{dimexpr} from the reference point for typesetting, up +% or down as appropriate. The \meta{box function} should be +% a box opeeration such as |\box_use:N \<box>| or a \enquote{raw} +% box specification such as |\vbox:n { xyz }|. +% \end{function} +% +% \section{Measuring and setting box dimensions} +% +% \begin{function}{\box_dp:N, \box_dp:c} +% \begin{syntax} +% \cs{box_dp:N} \meta{box} +% \end{syntax} +% Calculates the depth (below the baseline) of the \meta{box} +% and leaves this in the input stream. The output of this function +% is suitable for use in a \meta{dimension expression} for +% calculations. +% \begin{texnote} +% This is the \TeX{} primitive \cs{dp}. +% \end{texnote} +% \end{function} +% +% \begin{function}{\box_ht:N, \box_ht:c} +% \begin{syntax} +% \cs{box_ht:N} \meta{box} +% \end{syntax} +% Calculates the height (above the baseline) of the \meta{box} +% and leaves this in the input stream. The output of this function +% is suitable for use in a \meta{dimension expression} for +% calculations. +% \begin{texnote} +% This is the \TeX{} primitive \cs{ht}. +% \end{texnote} +% \end{function} +% +% \begin{function}{\box_wd:N, \box_wd:c} +% \begin{syntax} +% \cs{box_wd:N} \meta{box} +% \end{syntax} +% Calculates the width of the \meta{box} and leaves this in the +% input stream. The output of this function is suitable for use in a +% \meta{dimension expression} for calculations. +% \begin{texnote} +% This is the \TeX{} primitive \cs{wd}. +% \end{texnote} +% \end{function} +% +% \begin{function}{\box_set_dp:Nn, \box_set_dp:cn} +% \begin{syntax} +% \cs{box_set_dp:Nn} \meta{box} \Arg{dimension expression} +% \end{syntax} +% Set the depth (below the baseline) of the \meta{box} to the value of +% the \Arg{dimension expression}. This is a global assignment. +% \end{function} +% +% \begin{function}{\box_set_ht:Nn, \box_set_ht:cn} +% \begin{syntax} +% \cs{box_set_ht:Nn} \meta{box} \Arg{dimension expression} +% \end{syntax} +% Set the height (above the baseline) of the \meta{box} to the value of +% the \Arg{dimension expression}. This is a global assignment. +% \end{function} +% +% \begin{function}{\box_set_wd:Nn, \box_set_wd:cn} +% \begin{syntax} +% \cs{box_set_wd:Nn} \meta{box} \Arg{dimension expression} +% \end{syntax} +% Set the width of the \meta{box} to the value of the +% \Arg{dimension expression}. This is a global assignment. +% \end{function} +% +% \section{Box conditionals} +% +% \begin{function}[EXP,pTF]{\box_if_empty:N, \box_if_empty:c} +% \begin{syntax} +% \cs{box_if_empty_p:N} \meta{box} +% \cs{box_if_empty:NTF} \meta{box} \Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if \meta{box} is a empty (equal to \cs{c_empty_box}). +% The branching versions then leave either +% \meta{true code} or \meta{false code} in the input stream, as +% appropriate to the truth of the test and the variant of the function +% chosen. The logical truth of the test is left in the input stream by +% the predicate version. +% \end{function} +% +% \begin{function}[EXP,pTF]{\box_if_horizontal:N, \box_if_horizontal:c} +% \begin{syntax} +% \cs{box_if_horizontal_p:N} \meta{box} +% \cs{box_if_horizontal:NTF} \meta{box} \Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if \meta{box} is a horizontal box. The branching +% versions then leave either \meta{true code} or \meta{false code} +% in the input stream, as appropriate to the truth of the test and +% the variant of the function chosen. The logical truth of the test +% is left in the input stream by the predicate version. +% \end{function} +% +% \begin{function}[EXP,pTF]{\box_if_vertical:N, \box_if_vertical:c} +% \begin{syntax} +% \cs{box_if_vertical_p:N} \meta{box} +% \cs{box_if_vertical:NTF} \meta{box} \Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if \meta{box} is a vertical box. The branching +% versions then leave either \meta{true code} or \meta{false code} +% in the input stream, as appropriate to the truth of the test and +% the variant of the function chosen. The logical truth of the test +% is left in the input stream by the predicate version. +% \end{function} +% +% \section{The last box inserted} +% +% \begin{variable}{\l_last_box} +% This is a box containing the last item added to the current partial +% list, except in the case of the main vertical list (main galley), in +% which case this box is always void. Notice that although this is +% not a constant, it is \emph{not} settable by the programmer but is +% instead varied by \TeX{}. +% \begin{texnote} +% This is the \TeX{} primitive \cs{lastbox} renamed. +% \end{texnote} +% \end{variable} +% +% \section{Constant boxes} +% +% \begin{variable}{\c_empty_box} +% This is a permanently empty box, which is neither set as horizontal +% nor vertical. +% \end{variable} +% +% \section{Scratch boxes} +% +% \begin{variable}{\l_tmpa_tl, \l_tmpb_tl} +% Scratch boxes for local assignment. These are never used by +% the kernel code, and so are safe for use with any \LaTeX3-defined +% function. However, they may be overwritten by other non-kernel +% code and so should only be used for short-term storage. +% \end{variable} +% +% \section{Viewing box contents} +% +% \begin{function}{\box_show:N, \box_show:c} +% \begin{syntax} +% \cs{box_show:N} \meta{box} +% \end{syntax} +% Writes the contents of \meta{box} to the log file. +% \begin{texnote} +% This is the \TeX{} primitive \cs{showbox}. +% \end{texnote} +% \end{function} +% +% \section{Horizontal mode boxes} +% +% \begin{function}{\hbox:n} +% \begin{syntax} +% \cs{hbox:n} \Arg{contents} +% \end{syntax} +% Typesets the \meta{contents} into a horizontal box of natural +% width and then includes this box in the current list for typesetting. +% \begin{texnote} +% This is the \TeX{} primitive \cs{hbox}. +% \end{texnote} +% \end{function} +% +% \begin{function}{\hbox_to_wd:nn} +% \begin{syntax} +% \cs{hbox_to_wd:nn} \Arg{dimexpr} \Arg{contents} +% \end{syntax} +% Typesets the \meta{contents} into a horizontal box of width +% \meta{dimexpr} and then includes this box in the current list for +% typesetting. +% \end{function} +% +% \begin{function}{\hbox_to_zero:n} +% \begin{syntax} +% \cs{hbox_to_zero:n} \Arg{contents} +% \end{syntax} +% Typesets the \meta{contents} into a horizontal box of zero width +% and then includes this box in the current list for typesetting. +% \end{function} +% +% \begin{function}{\hbox_set:Nn, \hbox_set:cn} +% \begin{syntax} +% \cs{hbox_set:Nn} \meta{box} \Arg{contents} +% \end{syntax} +% Typesets the \meta{contents} at natural width and then stores the +% result inside the \meta{box}. The assignment is local. +% \end{function} +% +% \begin{function}{\hbox_gset:Nn, \hbox_gset:cn} +% \begin{syntax} +% \cs{hbox_gset:Nn} \meta{box} \Arg{contents} +% \end{syntax} +% Typesets the \meta{contents} at natural width and then stores the +% result inside the \meta{box}. The assignment is global. +% \end{function} +% +% \begin{function}{\hbox_set_to_wd:Nnn, \hbox_set_to_wd:cnn} +% \begin{syntax} +% \cs{hbox_set_to_wd:Nnn} \meta{box} \Arg{dimexpr} \Arg{contents} +% \end{syntax} +% Typesets the \meta{contents} to the width given by the \meta{dimexpr} +% and then stores the result inside the \meta{box}. The assignment is +% local. +% \end{function} +% +% \begin{function}{\hbox_gset_to_wd:Nnn, \hbox_gset_to_wd:cnn} +% \begin{syntax} +% \cs{hbox_gset_to_wd:Nnn} \meta{box} \Arg{dimexpr} \Arg{contents} +% \end{syntax} +% Typesets the \meta{contents} to the width given by the \meta{dimexpr} +% and then stores the result inside the \meta{box}. The assignment is +% global. +% \end{function} +% +% \begin{function}{\hbox_overlap_right:n} +% \begin{syntax} +% \cs{hbox_overlap_right:n} \Arg{contents} +% \end{syntax} +% Typesets the \meta{contents} into a horizontal box of zero width +% such that material will protrude to the right of the insertion +% point. +% \end{function} +% +% \begin{function}{\hbox_overlap_left:n} +% \begin{syntax} +% \cs{hbox_overlap_left:n} \Arg{contents} +% \end{syntax} +% Typesets the \meta{contents} into a horizontal box of zero width +% such that material will protrude to the left of the insertion +% point. +% \end{function} +% +% \begin{function} +% { +% \hbox_set_inline_begin:N, \hbox_set_inline_begin:c, +% \hbox_set_inline_end: +% } +% \begin{syntax} +% \cs{hbox_set_inline_begin:N} \meta{box} \meta{contents} +% ~~\cs{hbox_set_inline_end:} +% \end{syntax} +% Typesets the \meta{contents} at natural width and then stores the +% result inside the \meta{box}. The assignment is local. In contrast +% to \cs{hbox_set:Nn} this function does not absorb the argument +% when finding the \meta{content}, and so can be used in circumstances +% where the \meta{content} may not be a simple argument. +% \end{function} +% +% \begin{function} +% { +% \hbox_gset_inline_begin:N, \hbox_gset_inline_begin:c, +% \hbox_gset_inline_end: +% } +% \begin{syntax} +% \cs{hbox_gset_inline_begin:N} \meta{box} \meta{contents} +% ~~\cs{hbox_gset_inline_end:} +% \end{syntax} +% Typesets the \meta{contents} at natural width and then stores the +% result inside the \meta{box}. The assignment is global. In contrast +% to \cs{hbox_set:Nn} this function does not absorb the argument +% when finding the \meta{content}, and so can be used in circumstances +% where the \meta{content} may not be a simple argument. +% \end{function} +% +% \begin{function}{\hbox_unpack:N, \hbox_unpack:c} +% \begin{syntax} +% \cs{hbox_unpack:N} \meta{box} +% \end{syntax} +% Unpacks the content of the horizontal \meta{box}, retaining any stretching +% or shrinking applied when the \meta{box} was set. +% \begin{texnote} +% This is the \TeX{} primitive \cs{unhcopy}. +% \end{texnote} +% \end{function} +% +% \begin{function}{\hbox_unpack_clear:N, \hbox_unpack_clear:c} +% \begin{syntax} +% \cs{hbox_unpack_clear:N} \meta{box} +% \end{syntax} +% Unpacks the content of the horizontal \meta{box}, retaining any stretching +% or shrinking applied when the \meta{box} was set. The \meta{box} is +% then cleared globally. +% \begin{texnote} +% This is the \TeX{} primitive \cs{unhbox}. +% \end{texnote} +% \end{function} +% +% \section{Vertical mode boxes} +% +% Vertical boxes inherit their baseline from their contents. The +% standard case is that the baseline of the box is at the same position +% as that of the last item added to the box. This means that the box +% will have no depth unless the last item added to it had depth. As a +% result most vertical boxes have a large height value and small or +% zero depth. The exception are |_top| boxes, where the reference point +% is that of the first item added. These tend to have a large depth and +% small height, although the later will typically be non-zero. +% +% \begin{function}{\vbox:n} +% \begin{syntax} +% \cs{vbox:n} \Arg{contents} +% \end{syntax} +% Typesets the \meta{contents} into a vertical box of natural height +% and includes this box in the current list for typesetting. +% \begin{texnote} +% This is the \TeX{} primitive \cs{vbox}. +% \end{texnote} +% \end{function} +% +% \begin{function}{\vbox_top:n} +% \begin{syntax} +% \cs{vbox_top:n} \Arg{contents} +% \end{syntax} +% Typesets the \meta{contents} into a vertical box of natural height +% and includes this box in the current list for typesetting. The +% baseline of the box will tbe equal to that of the \emph{first} +% item added to the box. +% \begin{texnote} +% This is the \TeX{} primitive \cs{vtop}. +% \end{texnote} +% \end{function} +% +% \begin{function}{\vbox_to_ht:nn} +% \begin{syntax} +% \cs{vbox_to_ht:n} \Arg{contents} \Arg{dimexpr} +% \end{syntax} +% Typesets the \meta{contents} into a vertical box of height +% \meta{dimexpr} and then includes this box in the current list for +% typesetting. +% \end{function} +% +% \begin{function}{\vbox_to_zero:n} +% \begin{syntax} +% \cs{vbox_to_zero:n} \Arg{contents} +% \end{syntax} +% Typesets the \meta{contents} into a vertical box of zero height +% and then includes this box in the current list for typesetting. +% \end{function} +% +% \begin{function}{\vbox_set:Nn, \vbox_set:cn} +% \begin{syntax} +% \cs{vbox_set:Nn} \meta{box} \Arg{contents} +% \end{syntax} +% Typesets the \meta{contents} at natural height and then stores the +% result inside the \meta{box}. The assignment is local. +% \end{function} +% +% \begin{function}{\vbox_gset:Nn, \vbox_gset:cn} +% \begin{syntax} +% \cs{vbox_gset:Nn} \meta{box} \Arg{contents} +% \end{syntax} +% Typesets the \meta{contents} at natural height and then stores the +% result inside the \meta{box}. The assignment is global. +% \end{function} +% +% \begin{function}{\vbox_set_top:Nn, \vbox_set_top:cn} +% \begin{syntax} +% \cs{vbox_set_top:Nn} \meta{box} \Arg{contents} +% \end{syntax} +% Typesets the \meta{contents} at natural height and then stores the +% result inside the \meta{box}. The baseline of the box will tbe equal +% to that of the \emph{first} item added to the box. The assignment is +% local. +% \end{function} +% +% \begin{function}{\vbox_gset_top:Nn, \vbox_gset_top:cn} +% \begin{syntax} +% \cs{vbox_gset_top:Nn} \meta{box} \Arg{contents} +% \end{syntax} +% Typesets the \meta{contents} at natural height and then stores the +% result inside the \meta{box}. The baseline of the box will tbe equal +% to that of the \emph{first} item added to the box. The assignment is +% global. +% \end{function} +% +% \begin{function}{\vbox_set_to_ht:Nnn, \vbox_set_to_ht:cnn} +% \begin{syntax} +% \cs{vbox_set_to_ht:Nnn} \meta{box} \Arg{dimexpr} \Arg{contents} +% \end{syntax} +% Typesets the \meta{contents} to the height given by the +% \meta{dimexpr} and then stores the result inside the \meta{box}. +% The assignment is local. +% \end{function} +% +% \begin{function}{\vbox_gset_to_ht:Nnn, \vbox_gset_to_ht:cnn} +% \begin{syntax} +% \cs{vbox_gset_to_ht:Nnn} \meta{box} \Arg{dimexpr} \Arg{contents} +% \end{syntax} +% Typesets the \meta{contents} to the height given by the +% \meta{dimexpr} and then stores the result inside the \meta{box}. +% The assignment is global. +% \end{function} +% +% \begin{function} +% { +% \vbox_set_inline_begin:N, \vbox_set_inline_begin:c, +% \vbox_set_inline_end: +% } +% \begin{syntax} +% \cs{vbox_set_inline_begin:N} \meta{box} \meta{contents} +% ~~\cs{vbox_set_inline_end:} +% \end{syntax} +% Typesets the \meta{contents} at natural height and then stores the +% result inside the \meta{box}. The assignment is local. In contrast +% to \cs{vbox_set:Nn} this function does not absorb the argument +% when finding the \meta{content}, and so can be used in circumstances +% where the \meta{content} may not be a simple argument. +% \end{function} +% +% \begin{function} +% { +% \vbox_gset_inline_begin:N, \vbox_gset_inline_begin:c, +% \vbox_gset_inline_end: +% } +% \begin{syntax} +% \cs{vbox_gset_inline_begin:N} \meta{box} \meta{contents} +% ~~\cs{vbox_set_inline_end:} +% \end{syntax} +% Typesets the \meta{contents} at natural height and then stores the +% result inside the \meta{box}. The assignment is global. In contrast +% to \cs{vbox_set:Nn} this function does not absorb the argument +% when finding the \meta{content}, and so can be used in circumstances +% where the \meta{content} may not be a simple argument. +% \end{function} +% +% \begin{function}{\vbox_set_split_to_ht:NNn} +% \begin{syntax} +% \cs{vbox_set_split_to_ht:NNn} \meta{box1} \meta{box2} \Arg{dimexpr} +% \end{syntax} +% Sets \meta{box1} to contain material to the height given by the +% \meta{dimexpr} by removing content from the top of \meta{box2} +% (which must be a vertical box). +% \begin{texnote} +% This is the \TeX{} primitive \cs{vsplit}. +% \end{texnote} +% \end{function} +% +% \begin{function}{\vbox_unpack:N, \vbox_unpack:c} +% \begin{syntax} +% \cs{vbox_unpack:N} \meta{box} +% \end{syntax} +% Unpacks the content of the vertical \meta{box}, retaining any stretching +% or shrinking applied when the \meta{box} was set. +% \begin{texnote} +% This is the \TeX{} primitive \cs{unvcopy}. +% \end{texnote} +% \end{function} +% +% \begin{function}{\vbox_unpack_clear:N, \vbox_unpack_clear:c} +% \begin{syntax} +% \cs{vbox_unpack:N} \meta{box} +% \end{syntax} +% Unpacks the content of the vertical \meta{box}, retaining any stretching +% or shrinking applied when the \meta{box} was set. The \meta{box} +% is then cleared globally. +% \begin{texnote} +% This is the \TeX{} primitive \cs{unvbox}. +% \end{texnote} +% \end{function} +% +% \section{Primitive box conditionals} +% +% \begin{function}[EXP]{\if_hbox:N} +% \begin{syntax} +% \cs{if_hbox:N} \meta{box} +% ~~\meta{true code} +% \cs{else:} +% ~~\meta{false code} +% \cs{fi:} +% \end{syntax} +% Tests is \meta{box} is a horizontal box. +% \begin{texnote} +% This is the \TeX{} primitive \cs{ifhbox}. +% \end{texnote} +% \end{function} +% +% \begin{function}[EXP]{\if_vbox:N} +% \begin{syntax} +% \cs{if_vbox:N} \meta{box} +% ~~\meta{true code} +% \cs{else:} +% ~~\meta{false code} +% \cs{fi:} +% \end{syntax} +% Tests is \meta{box} is a vertical box. +% \begin{texnote} +% This is the \TeX{} primitive \cs{ifvbox}. +% \end{texnote} +% \end{function} +% +% \begin{function}[EXP]{\if_box_empty:N} +% \begin{syntax} +% \cs{if_box_empty:N} \meta{box} +% ~~\meta{true code} +% \cs{else:} +% ~~\meta{false code} +% \cs{fi:} +% \end{syntax} +% Tests is \meta{box} is an empty (void) box. +% \begin{texnote} +% This is the \TeX{} primitive \cs{ifvoid}. +% \end{texnote} +% \end{function} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{l3box} implementation} +% +% \begin{macrocode} +%<*initex|package> +% \end{macrocode} +% +% \begin{macrocode} +%<*package> +\ProvidesExplPackage + {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +\package_check_loaded_expl: +%<*initex|package> +% \end{macrocode} +% +% The code in this module is very straight forward so I'm not going to +% comment it very extensively. +% +% \subsection{Creating and initialising boxes} +% +% \TestFiles{m3box001.lvt} +% +% \begin{macro}{\box_new:N,\box_new:c} +% Defining a new \meta{box} register: remember that box $255$ is not +% generally available. +% \begin{macrocode} +%<*initex> +\alloc_new:nnnN { box } \c_zero \c_max_register_int \tex_mathchardef:D +\seq_put_right:Nn \g_box_allocation_seq {255} +%</initex> +%<*package> +\cs_new_protected:Npn \box_new:N #1 + { + \chk_if_free_cs:N #1 + \newbox #1 + } +%</package> +\cs_generate_variant:Nn \box_new:N { c } +% \end{macrocode} +% +% \begin{macro}{\box_clear:N, \box_clear:c} +% \begin{macro}{\box_gclear:N, \box_gclear:c} +% \testfile* +% Clear a \meta{box} register. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \box_clear:N #1 + { \box_set_eq:NN #1 \c_empty_box } +\cs_new_protected_nopar:Npn \box_gclear:N #1 + { \box_gset_eq:NN #1 \c_empty_box } +\cs_generate_variant:Nn \box_clear:N { c } +\cs_generate_variant:Nn \box_gclear:N { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\box_clear_new:N, \box_clear_new:c} +% \begin{macro}{\box_gclear_new:N, \box_gclear_new:c} +% \testfile* +% Clear or new. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \box_clear_new:N #1 + { + \cs_if_exist:NTF #1 + { \box_set_eq:NN #1 \c_empty_box } + { \box_new:N #1 } + } +\cs_new_protected_nopar:Npn \box_gclear_new:N #1 + { + \cs_if_exist:NTF #1 + { \box_gset_eq:NN #1 \c_empty_box } + { \box_new:N #1 } + } +\cs_generate_variant:Nn \box_clear_new:N { c } +\cs_generate_variant:Nn \box_gclear_new:N { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro} +% {\box_set_eq:NN, \box_set_eq:cN, \box_set_eq:Nc, \box_set_eq:cc} +% \testfile* +% \begin{macro} +% {\box_gset_eq:NN, \box_gset_eq:cN, \box_gset_eq:Nc, \box_gset_eq:cc} +% \testfile* +% Assigning the contents of a box to be another box. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \box_set_eq:NN #1#2 + { \tex_setbox:D #1 \tex_copy:D #2 } +\cs_new_protected_nopar:Npn \box_gset_eq:NN + { \pref_global:D \box_set_eq:NN } +\cs_generate_variant:Nn \box_set_eq:NN { cN , Nc , cc } +\cs_generate_variant:Nn \box_gset_eq:NN { cN , Nc , cc } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro} +% { +% \box_set_eq_clear:NN, \box_set_eq_clear:cN, +% \box_set_eq_clear:Nc, \box_set_eq_clear:cc +% } +% \testfile* +% \begin{macro} +% { +% \box_gset_eq_clear:NN, \box_gset_eq_clear:cN, +% \box_gset_eq_clear:Nc, \box_gset_eq_clear:cc +% } +% \testfile* +% Assigning the contents of a box to be another box. +% This clears the second box globally (that's how \TeX{} does it). +% \begin{macrocode} +\cs_new_protected_nopar:Npn \box_set_eq_clear:NN #1#2 + { \tex_setbox:D #1 \tex_box:D #2 } +\cs_new_protected_nopar:Npn \box_gset_eq_clear:NN + { \pref_global:D \box_set_eq_clear:NN } +\cs_generate_variant:Nn \box_set_eq_clear:NN { cN , Nc , cc } +\cs_generate_variant:Nn \box_gset_eq_clear:NN { cN , Nc , cc } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Measuring and setting box dimensions} +% +% \begin{macro}{\box_ht:N,\box_ht:c} +% \begin{macro}{\box_dp:N,\box_dp:c} +% \begin{macro}{\box_wd:N,\box_wd:c} +% \testfile* +% Accessing the height, depth, and width of a \meta{box} register. +% \begin{macrocode} +\cs_new_eq:NN \box_ht:N \tex_ht:D +\cs_new_eq:NN \box_dp:N \tex_dp:D +\cs_new_eq:NN \box_wd:N \tex_wd:D +\cs_generate_variant:Nn \box_ht:N { c } +\cs_generate_variant:Nn \box_dp:N { c } +\cs_generate_variant:Nn \box_wd:N { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\box_set_ht:Nn, \box_set_ht:cn} +% \begin{macro}{\box_set_dp:Nn, \box_set_dp:cn} +% \begin{macro}{\box_set_wd:Nn, \box_set_wd:cn} +% Measuring is easy: all primitive work. These primitives are not +% expandable, so the derived functions are not either. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \box_set_dp:Nn #1#2 + { \box_dp:N #1 \dim_eval:w #2 \dim_eval_end: } +\cs_new_protected_nopar:Npn \box_set_ht:Nn #1#2 + { \box_ht:N #1 \dim_eval:w #2 \dim_eval_end: } +\cs_new_protected_nopar:Npn \box_set_wd:Nn #1#2 + { \box_wd:N #1 \dim_eval:w #2 \dim_eval_end: } +\cs_generate_variant:Nn \box_set_ht:Nn { c } +\cs_generate_variant:Nn \box_set_dp:Nn { c } +\cs_generate_variant:Nn \box_set_wd:Nn { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Using boxes} +% +% \begin{macro}{\box_use_clear:N, \box_use_clear:c} +% \begin{macro}{\box_use:N, \box_use:c} +% Using a \meta{box}. These are just \TeX{} primitives with meaningful +% names. +% \begin{macrocode} +\cs_new_eq:NN \box_use_clear:N \tex_box:D +\cs_new_eq:NN \box_use:N \tex_copy:D +\cs_generate_variant:Nn \box_use_clear:N { c } +\cs_generate_variant:Nn \box_use:N { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\box_move_left:nn,\box_move_right:nn} +% \begin{macro}{\box_move_up:nn,\box_move_down:nn} +% \testfile* +% Move box material in different directions. +% \begin{macrocode} +\cs_new_protected:Npn \box_move_left:nn #1#2 + { \tex_moveleft:D \dim_eval:w #1 \dim_eval_end: #2 } +\cs_new_protected:Npn \box_move_right:nn #1#2 + { \tex_moveright:D \dim_eval:w #1 \dim_eval_end: #2 } +\cs_new_protected:Npn \box_move_up:nn #1#2 + { \tex_raise:D \dim_eval:w #1 \dim_eval_end: #2 } +\cs_new_protected:Npn \box_move_down:nn #1#2 + { \tex_lower:D \dim_eval:w #1 \dim_eval_end: #2 } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Box conditionals} +% +% \begin{macro}{\if_hbox:N} +% \begin{macro}{\if_vbox:N} +% \begin{macro}{\if_box_empty:N} +% \testfile* +% The primitives for testing if a \meta{box} is empty/void or which +% type of box it is. +% \begin{macrocode} +\cs_new_eq:NN \if_hbox:N \tex_ifhbox:D +\cs_new_eq:NN \if_vbox:N \tex_ifvbox:D +\cs_new_eq:NN \if_box_empty:N \tex_ifvoid:D +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}[pTF]{\box_if_horizontal:N,\box_if_horizontal:c} +% \testfile* +% \begin{macro}[pTF]{\box_if_vertical:N,\box_if_vertical:c} +% \testfile* +% \begin{macrocode} +\prg_new_conditional:Npnn \box_if_horizontal:N #1 { p , T , F , TF } + { \if_hbox:N #1 \prg_return_true: \else: \prg_return_false: \fi: } +\prg_new_conditional:Npnn \box_if_vertical:N #1 { p , T , F , TF } + { \if_vbox:N #1 \prg_return_true: \else: \prg_return_false: \fi: } +\cs_generate_variant:Nn \box_if_horizontal_p:N { c } +\cs_generate_variant:Nn \box_if_horizontal:NT { c } +\cs_generate_variant:Nn \box_if_horizontal:NF { c } +\cs_generate_variant:Nn \box_if_horizontal:NTF { c } +\cs_generate_variant:Nn \box_if_vertical_p:N { c } +\cs_generate_variant:Nn \box_if_vertical:NT { c } +\cs_generate_variant:Nn \box_if_vertical:NF { c } +\cs_generate_variant:Nn \box_if_vertical:NTF { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[pTF]{\box_if_empty:N, \box_if_empty:c} +% \testfile* +% Testing if a \meta{box} is empty/void. +% \begin{macrocode} +\prg_new_conditional:Npnn \box_if_empty:N #1 { p , T , F , TF } + { \if_box_empty:N #1 \prg_return_true: \else: \prg_return_false: \fi: } +\cs_generate_variant:Nn \box_if_empty_p:N { c } +\cs_generate_variant:Nn \box_if_empty:NT { c } +\cs_generate_variant:Nn \box_if_empty:NF { c } +\cs_generate_variant:Nn \box_if_empty:NTF { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{The last box inserted} +% +% \begin{variable}{\l_last_box} +% A different name for this read-only primitive. +% \begin{macrocode} +\cs_new_eq:NN \l_last_box \tex_lastbox:D +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\box_set_to_last:N, \box_set_to_last:c} +% \begin{macro}{\box_gset_to_last:N, \box_gset_to_last:c} +% \testfile* +% Set a box to the previous box. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \box_set_to_last:N #1 + { \tex_setbox:D #1 \l_last_box } +\cs_new_protected_nopar:Npn \box_gset_to_last:N + { \pref_global:D \box_set_to_last:N } +\cs_generate_variant:Nn \box_set_to_last:N { c } +\cs_generate_variant:Nn \box_gset_to_last:N { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Constant boxes} +% +% \begin{variable}{\c_empty_box} +% \begin{macrocode} +%<*package> +\cs_new_eq:NN \c_empty_box \voidb@x +%</package> +%<*initex> +\box_new:N \c_empty_box +%</initex> +% \end{macrocode} +% \end{variable} +% +% \subsection{Scratch boxes} +% +% \begin{variable}{\l_tmpa_box, \l_tmpb_box} +% \begin{macrocode} +%<*package> +\cs_new_eq:NN \l_tmpa_box \@tempboxa +%</package> +%<*initex> +\box_new:N \l_tmpa_box +%</initex> +\box_new:N \l_tmpb_box +% \end{macrocode} +% \end{variable} +% +% \subsection{Viewing box contents} +% +% \begin{macro}{\box_show:N,\box_show:c} +% \testfile* +% Show the contents of a box and write it into the log file. +% \begin{macrocode} +\cs_new_eq:NN \box_show:N \tex_showbox:D +\cs_generate_variant:Nn \box_show:N { c } +% \end{macrocode} +% \end{macro} +% +% \subsection{Horizontal mode boxes} +% +% \begin{macro}{\hbox:n} +% \testfile{m3box002.lvt} +% Put a horizontal box directly into the input stream. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \hbox:n { \tex_hbox:D \scan_stop: } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\hbox_set:Nn,\hbox_set:cn} +% \begin{macro}{\hbox_gset:Nn,\hbox_gset:cn} +% \testfile* +% \begin{macrocode} +\cs_new_protected:Npn \hbox_set:Nn #1#2 { \tex_setbox:D #1 \tex_hbox:D {#2} } +\cs_new_protected_nopar:Npn \hbox_gset:Nn { \pref_global:D \hbox_set:Nn } +\cs_generate_variant:Nn \hbox_set:Nn { c } +\cs_generate_variant:Nn \hbox_gset:Nn { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\hbox_set_to_wd:Nnn,\hbox_set_to_wd:cnn} +% \begin{macro}{\hbox_gset_to_wd:Nnn,\hbox_gset_to_wd:cnn} +% \testfile* +% Storing material in a horizontal box with a specified width. +% \begin{macrocode} +\cs_new_protected:Npn \hbox_set_to_wd:Nnn #1#2#3 + { \tex_setbox:D #1 \tex_hbox:D to \dim_eval:w #2 \dim_eval_end: {#3} } +\cs_new_protected_nopar:Npn \hbox_gset_to_wd:Nnn + { \pref_global:D \hbox_set_to_wd:Nnn } +\cs_generate_variant:Nn \hbox_set_to_wd:Nnn { c } +\cs_generate_variant:Nn \hbox_gset_to_wd:Nnn {cnn} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\hbox_set_inline_begin:N, \hbox_set_inline_begin:c} +% \begin{macro}{\hbox_gset_inline_begin:N, \hbox_gset_inline_begin:c} +% \begin{macro}{\hbox_set_inline_end:} +% \begin{macro}{\hbox_gset_inline_end:} +% \testfile* +% Storing material in a horizontal box. This type is useful in +% environment definitions. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \hbox_set_inline_begin:N #1 + { \tex_setbox:D #1 \tex_hbox:D \c_group_begin_token } +\cs_new_protected_nopar:Npn \hbox_gset_inline_begin:N + { \pref_global:D \hbox_set_inline_begin:N } +\cs_generate_variant:Nn \hbox_set_inline_begin:N { c } +\cs_generate_variant:Nn \hbox_gset_inline_begin:N { c } +\cs_new_eq:NN \hbox_set_inline_end: \c_group_end_token +\cs_new_eq: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} +% \testfile* +% Put a horizontal box directly into the input stream. +% \begin{macrocode} +\cs_new_protected:Npn \hbox_to_wd:nn #1#2 + { \tex_hbox:D to \dim_eval:w #1 \dim_eval_end: {#2} } +\cs_new_protected:Npn \hbox_to_zero:n #1 { \tex_hbox:D to \c_zero_skip {#1} } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\hbox_overlap_left:n,} +% \begin{macro}{\hbox_overlap_right:n} +% Put a zero-sized box with the contents pushed against one side (which +% makes it stick out on the other) directly into the input stream. +% \begin{macrocode} +\cs_new_protected:Npn \hbox_overlap_left:n #1 + { \hbox_to_zero:n { \tex_hss:D #1 } } +\cs_new_protected:Npn \hbox_overlap_right:n #1 + { \hbox_to_zero:n { #1 \tex_hss:D } } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\hbox_unpack:N, \hbox_unpack:c} +% \begin{macro}{\hbox_unpack_clear:N, \hbox_unpack_clear:c} +% \testfile* +% Unpacking a box and if requested also clear it. +% \begin{macrocode} +\cs_new_eq:NN \hbox_unpack:N \tex_unhcopy:D +\cs_new_eq:NN \hbox_unpack_clear:N \tex_unhbox:D +\cs_generate_variant:Nn \hbox_unpack:N { c } +\cs_generate_variant:Nn \hbox_unpack_clear:N { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Vertical mode boxes} +% +% \begin{macro}{\vbox:n} +% \TestFiles{m3box003.lvt} +% \begin{macro}{\vbox:n\vbox_top:n} +% \TestFiles{m3box003.lvt} +% Put a vertical box directly into the input stream. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \vbox:n { \tex_vbox:D \scan_stop: } +\cs_new_protected_nopar:Npn \vbox_top:n { \tex_vtop:D \scan_stop: } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\vbox_to_ht:nn,\vbox_to_zero:n} +% \begin{macro}{\vbox_to_ht:nn,\vbox_to_zero:n} +% \testfile* +% Put a vertical box directly into the input stream. +% \begin{macrocode} +\cs_new_protected:Npn \vbox_to_ht:nn #1#2 + { \tex_vbox:D to \dim_eval:w #1 \dim_eval_end: {#2} } +\cs_new_protected:Npn \vbox_to_zero:n #1 { \tex_vbox:D to \c_zero_dim {#1} } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\vbox_set:Nn, \vbox_set:cn} +% \begin{macro}{\vbox_gset:Nn, \vbox_gset:cn} +% \testfile* +% Storing material in a vertical box with a natural height. +% \begin{macrocode} +\cs_new_protected:Npn \vbox_set:Nn #1#2 { \tex_setbox:D #1 \tex_vbox:D {#2} } +\cs_new_protected_nopar:Npn \vbox_gset:Nn { \pref_global:D \vbox_set:Nn } +\cs_generate_variant:Nn \vbox_set:Nn { c } +\cs_generate_variant:Nn \vbox_gset:Nn { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\vbox_set_top:Nn, \vbox_set_top:cn} +% \begin{macro}{\vbox_gset_top:Nn, \vbox_gset_top:cn} +% \testfile* +% Storing material in a vertical box with a natural height and reference +% point at the baseline of the first object in the box. +% \begin{macrocode} +\cs_new_protected:Npn \vbox_set_top:Nn #1#2 + { \tex_setbox:D #1 \tex_vtop:D {#2} } +\cs_new_protected_nopar:Npn \vbox_gset_top:Nn + { \pref_global:D \vbox_set_top:Nn } +\cs_generate_variant:Nn \vbox_set_top:Nn { c } +\cs_generate_variant:Nn \vbox_gset_top:Nn { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\vbox_set_to_ht:Nnn,\vbox_set_to_ht:cnn} +% \begin{macro}{\vbox_gset_to_ht:Nnn,\vbox_gset_to_ht:cnn} +% \testfile* +% Storing material in a vertical box with a specified height. +% \begin{macrocode} +\cs_new_protected:Npn \vbox_set_to_ht:Nnn #1#2#3 + { \tex_setbox:D #1 \tex_vbox:D to \dim_eval:w #2 \dim_eval_end: {#3} } +\cs_new_protected_nopar:Npn \vbox_gset_to_ht:Nnn + { \pref_global:D \vbox_set_to_ht:Nnn } +\cs_generate_variant:Nn \vbox_set_to_ht:Nnn { c } +\cs_generate_variant:Nn \vbox_gset_to_ht:Nnn { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\vbox_set_inline_begin:N, \vbox_set_inline_begin:c} +% \begin{macro}{\vbox_gset_inline_begin:N, \vbox_gset_inline_begin:c} +% \begin{macro}{\vbox_set_inline_end:} +% \begin{macro}{\vbox_gset_inline_end:} +% \testfile* +% Storing material in a vertical box. This type is useful in +% environment definitions. +% \begin{macrocode} +\cs_new_nopar:Npn \vbox_set_inline_begin:N #1 + { \tex_setbox:D #1 \tex_vbox:D \c_group_begin_token } +\cs_new_protected_nopar:Npn \vbox_gset_inline_begin:N + { \pref_global:D \vbox_set_inline_begin:N } +\cs_generate_variant:Nn \vbox_set_inline_begin:N { c } +\cs_generate_variant:Nn \vbox_gset_inline_begin:N { c } +\cs_new_eq:NN \vbox_set_inline_end: \c_group_end_token +\cs_new_eq:NN \vbox_gset_inline_end: \c_group_end_token +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\vbox_unpack:N, \vbox_unpack:c} +% \begin{macro}{\vbox_unpack_clear:N, \vbox_unpack_clear:c} +% \testfile* +% Unpacking a box and if requested also clear it. +% \begin{macrocode} +\cs_new_eq:NN \vbox_unpack:N \tex_unvcopy:D +\cs_new_eq:NN \vbox_unpack_clear:N \tex_unvbox:D +\cs_generate_variant:Nn \vbox_unpack:N { c } +\cs_generate_variant:Nn \vbox_unpack_clear:N { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\vbox_set_split_to_ht:NNn} +% \testfile* +% Splitting a vertical box in two. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \vbox_set_split_to_ht:NNn #1#2#3 + { \tex_setbox:D #1 \tex_vsplit:D #2 to \dim_eval:w #3 \dim_eval_end: } +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +%</initex|package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintIndex diff --git a/Master/texmf-dist/source/latex/l3kernel/l3clist.dtx b/Master/texmf-dist/source/latex/l3kernel/l3clist.dtx new file mode 100644 index 00000000000..d031b15f552 --- /dev/null +++ b/Master/texmf-dist/source/latex/l3kernel/l3clist.dtx @@ -0,0 +1,1437 @@ +% \iffalse meta-comment +% +%% File: l3clist.dtx Copyright (C) 2004-2011 Frank Mittelbach, +%% The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +% +%<*driver|package> +\RequirePackage{l3names} +\GetIdInfo$Id: l3clist.dtx 2498 2011-07-09 17:51:47Z joseph $ + {L3 Experimental comma separated lists} +%</driver|package> +%<*driver> +\documentclass[full]{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{^^A +% The \pkg{l3clist} package\\ Comma separated lists^^A +% \thanks{This file describes v\ExplFileVersion, +% last revised \ExplFileDate.}^^A +% } +% +% \author{^^A +% The \LaTeX3 Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% +% \date{Released \ExplFileDate} +% +% \maketitle +% +% \begin{documentation} +% +% Comma lists contain ordered data where items can be added to the left +% or right end of the sequence. This gives an ordered list which can +% then be utilised with the \cs{clist_map_function:NN} function. Comma +% Comma lists cannot contain empty items, thus +% \begin{verbatim} +% \clist_new:N \l_my_clist +% \clist_put_right:Nn \l_my_clist { } +% \clist_if_empty:NTF \l_my_clist { true } { false } +% \end{verbatim} +% will leave \texttt{true} in the input stream. +% +% \section{Creating and initialising comma lists} +% +% \begin{function}{\clist_new:N, \clist_new:c} +% \begin{syntax} +% \cs{clist_new:N} \meta{comma list} +% \end{syntax} +% Creates a new \meta{comma list} or raises an error if the name is +% already taken. The declaration is global. The \meta{comma list} will +% initially contain no items. +% \end{function} +% +% \begin{function}{\clist_clear:N, \clist_clear:c} +% \begin{syntax} +% \cs{clist_clear:N} \meta{comma list} +% \end{syntax} +% Clears all items from the \meta{comma list} within the scope of +% the current \TeX{} group. +% \end{function} +% +% \begin{function}{\clist_gclear:N, \clist_gclear:c} +% \begin{syntax} +% \cs{clist_gclear:N} \meta{comma list} +% \end{syntax} +% Clears all entries from the \meta{comma list} globally. +% \end{function} +% +% \begin{function}{\clist_clear_new:N, \clist_clear_new:c} +% \begin{syntax} +% \cs{clist_clear_new:N} \meta{comma list} +% \end{syntax} +% If the \meta{comma list} already exists, clears it within the scope +% of the current \TeX{} group. If the \meta{comma list} is not defined, +% it will be created (using \cs{clist_new:N}). Thus the comma list is +% guaranteed to be available and clear within the current \TeX{} +% group. The \meta{comma list} will exist globally, but the content +% outside of the current \TeX{} group is not specified. +% \end{function} +% +% \begin{function}{\clist_gclear_new:N, \clist_gclear_new:c} +% \begin{syntax} +% \cs{clist_gclear_new:N} \meta{comma list} +% \end{syntax} +% If the \meta{comma list} already exists, clears it globally. If the +% \meta{comma list} is not defined, it will be created (using +% \cs{clist_new:N}). Thus the comma list is guaranteed to be available +% and globally clear. +% \end{function} +% +% \begin{function} +% {\clist_set_eq:NN, \clist_set_eq:cN, \clist_set_eq:Nc, \clist_set_eq:cc} +% \begin{syntax} +% \cs{clist_set_eq:NN} \meta{comma list1} \meta{comma list2} +% \end{syntax} +% Sets the content of \meta{comma list1} equal to that of +% \meta{comma list2}. This assignment is restricted to the current +% \TeX{} group level. +% \end{function} +% +% \begin{function} +% { +% \clist_gset_eq:NN, \clist_gset_eq:cN, +% \clist_gset_eq:Nc, \clist_gset_eq:cc +% } +% \begin{syntax} +% \cs{clist_gset_eq:NN} \meta{comma list1} \meta{comma list2} +% \end{syntax} +% Sets the content of \meta{comma list1} equal to that of +% \meta{comma list2}. This assignment is global and so is not +% limited by the current \TeX{} group level. +% \end{function} +% +% \begin{function}{\clist_concat:NNN, \clist_concat:ccc} +% \begin{syntax} +% \cs{clist_concat:NNN} \meta{comma list1} \meta{comma list2} +% ~~\meta{comma list3} +% \end{syntax} +% Concatenates the content of \meta{comma list2} and \meta{comma list3} +% together and saves the result in \meta{comma list1}. The items in +% \meta{comma list2} will be placed at the left side of the new comma list. +% This operation is local to the current \TeX{} group and will +% remove any existing content in \meta{comma list1}. +% \end{function} +% +% \begin{function}{\clist_gconcat:NNN, \clist_gconcat:ccc} +% \begin{syntax} +% \cs{clist_gconcat:NNN} \meta{comma list1} \meta{comma list2} +% ~~\meta{comma list3} +% \end{syntax} +% Concatenates the content of \meta{comma list2} and \meta{comma list3} +% together and saves the result in \meta{comma list1}. The items in +% \meta{comma list2} will be placed at the left side of the new comma list. +% This operation is global and will remove any existing content in +% \meta{comma list1}. +% \end{function} +% +% \section{Appending items to comma lists} +% +% \begin{function}{ +% \clist_put_left:Nn, \clist_put_left:NV, +% \clist_put_left:No, \clist_put_left:Nx, +% \clist_put_left:cn, \clist_put_left:cV, +% \clist_put_left:co, \clist_put_left:cx +% } +% \begin{syntax} +% \cs{clist_put_left:Nn} \meta{comma list} \Arg{item} +% \end{syntax} +% Appends the \meta{item} to the left of the \meta{comma list}. +% The assignment is restricted to the current \TeX{} group. +% \end{function} +% +% \begin{function}{ +% \clist_gput_left:Nn, \clist_gput_left:NV, +% \clist_gput_left:No, \clist_gput_left:Nx, +% \clist_gput_left:cn, \clist_gput_left:cV, +% \clist_gput_left:co, \clist_gput_left:cx +% } +% \begin{syntax} +% \cs{clist_gput_left:Nn} \meta{comma list} \Arg{item} +% \end{syntax} +% Appends the \meta{item} to the left of the \meta{comma list}. +% The assignment is global. +% \end{function} +% +% \begin{function}{ +% \clist_put_right:Nn, \clist_put_right:NV, +% \clist_put_right:No, \clist_put_right:Nx, +% \clist_put_right:cn, \clist_put_right:cV, +% \clist_put_right:co, \clist_put_right:cx +% } +% \begin{syntax} +% \cs{clist_put_right:Nn} \meta{comma list} \Arg{item} +% \end{syntax} +% Appends the \meta{item} to the right of the \meta{comma list}. +% The assignment is restricted to the current \TeX{} group. +% \end{function} +% +% \begin{function}{ +% \clist_gput_right:Nn, \clist_gput_right:NV, +% \clist_gput_right:No, \clist_gput_right:Nx, +% \clist_gput_right:cn, \clist_gput_right:cV, +% \clist_gput_right:co, \clist_gput_right:cx +% } +% \begin{syntax} +% \cs{clist_gput_right:Nn} \meta{comma list} \Arg{item} +% \end{syntax} +% Appends the \meta{item} to the right of the \meta{comma list}. +% The assignment is global. +% \end{function} +% +% \section{Comma lists as stacks} +% +% \begin{function}{\clist_get:NN, \clist_get:cN} +% \begin{syntax} +% \cs{clist_get:NN} \meta{comma list} \meta{token list variable} +% \end{syntax} +% Stores the left-most item from a \meta{comma list} in the +% \meta{token list variable} without removing it from the +% \meta{comma list}. The \meta{token list variable} is assigned locally. +% \end{function} +% +% \begin{function}{\clist_get:NN, \clist_get:cN} +% \begin{syntax} +% \cs{clist_get:NN} \meta{comma list} \meta{token list variable} +% \end{syntax} +% Stores the right-most item from a \meta{comma list} in the +% \meta{token list variable} without removing it from the +% \meta{comma list}. The \meta{token list variable} is assigned locally. +% \end{function} +% +% \begin{function}{\clist_pop:NN, \clist_pop:cN} +% \begin{syntax} +% \cs{clist_pop:NN} \meta{comma list} \meta{token list variable} +% \end{syntax} +% Pops the left-most item from a \meta{comma list} into the +% \meta{token list variable}, \emph{i.e.}~removes the item from the +% comma list and stores it in the \meta{token list variable}. +% Both of the variables are assigned locally. +% \end{function} +% +% \begin{function}{\clist_gpop:NN, \clist_gpop:cN} +% \begin{syntax} +% \cs{clist_gpop:NN} \meta{comma list} \meta{token list variable} +% \end{syntax} +% Pops the left-most item from a \meta{comma list} into the +% \meta{token list variable}, \emph{i.e.}~removes the item from the +% comma list and stores it in the \meta{token list variable}. +% The \meta{comma list} is modified globally, while the assignment of +% the \meta{token list variable} is local. +% \end{function} +% +% \begin{function} +% { +% \clist_push:Nn, \clist_push:NV, \clist_push:No, \clist_push:Nx, +% \clist_push:cn, \clist_push:cV, \clist_push:co, \clist_push:cx +% } +% \begin{syntax} +% \cs{clist_push:Nn} \meta{sequence} \Arg{item} +% \end{syntax} +% Adds the \Arg{item} to the top of the \meta{comma list}. +% The assignment is restricted to the current \TeX{} group. +% \end{function} +% +% \begin{function} +% { +% \clist_gpush:Nn, \clist_gpush:NV, \clist_gpush:No, \clist_gpush:Nx, +% \clist_gpush:cn, \clist_gpush:cV, \clist_gpush:co, \clist_gpush:cx +% } +% \begin{syntax} +% \cs{clist_gpush:Nn} \meta{sequence} \Arg{item} +% \end{syntax} +% Pushes the \meta{item} onto the end of the top of the +% \meta{comma list}. The assignment is global. +% \end{function} +% +% \section{Using comma lists} +% +% \begin{function}[EXP]{\clist_use:N, \clist_use:c} +% \begin{syntax} +% \cs{clist_use:N} \meta{comma list} +% \end{syntax} +% Places the \meta{comma list} directly into the input stream, thus +% treating it as a \meta{token list}. +% \end{function} +% +% \section{Modifying comma lists} +% +% While comma lists are normally used as ordered lists, it may be +% necessary to modify the content. The functions here may be used +% to update comma lists, while retaining the order of the unaffected +% entries. +% +% \begin{function}{\clist_remove_duplicates:N, \clist_remove_duplicates:c} +% \begin{syntax} +% \cs{clist_remove_duplicates:N} \meta{comma list} +% \end{syntax} +% Removes duplicate items from the \meta{comma list}, leaving the +% left most copy of each item in the \meta{comma list}. The \meta{item} +% comparison takes place on a token basis, as for \cs{tl_if_eq:nn(TF)}. +% The removal is local to the current \TeX{} group. +% \begin{texnote} +% This function iterates through every item in the \meta{comma list} and +% does a comparison with the \meta{items} already checked. It is therefore +% relatively slow with large comma lists. +% \end{texnote} +% \end{function} +% +% \begin{function}{\clist_gremove_duplicates:N, \clist_gremove_duplicates:c} +% \begin{syntax} +% \cs{clist_gremove_duplicates:N} \meta{comma list} +% \end{syntax} +% Removes duplicate items from the \meta{comma list}, leaving the +% left most copy of each item in the \meta{comma list}. The \meta{item} +% comparison takes place on a token basis, as for \cs{tl_if_eq:nn(TF)}. +% The removal is applied globally. +% \begin{texnote} +% This function iterates through every item in the \meta{comma list} and +% does a comparison with the \meta{items} already checked. It is therefore +% relatively slow with large comma lists. +% \end{texnote} +% \end{function} +% +% \begin{function}{\clist_remove_all:Nn, \clist_remove_all:cn} +% \begin{syntax} +% \cs{clist_remove_all:Nn} \meta{comma list} \Arg{item} +% \end{syntax} +% Removes every occurrence of \meta{item} from the \meta{comma list}. +% The \meta{item} comparison takes place on a token basis, as for +% \cs{tl_if_eq:nn(TF)}. The removal is local to the current \TeX{} group. +% \end{function} +% +% \begin{function}{\clist_gremove_all:Nn, \clist_gremove_all:cn} +% \begin{syntax} +% \cs{clist_gremove_all:Nn} \meta{comma list} \Arg{item} +% \end{syntax} +% Removes each occurrence of \meta{item} from the \meta{comma list}. +% The \meta{item} comparison takes place on a token basis, as for +% \cs{tl_if_eq:nn(TF)}. The removal is applied globally. +% \end{function} +% +% \begin{function}{\clist_trim_spaces:N, \clist_trim_spaces:c} +% \begin{syntax} +% \cs{clist_trim_spaces:N} \meta{comma list} +% \end{syntax} +% Removes leading and trailing spaces from each \meta{item} in the +% \meta{comma list} within the current \TeX{} group. This space-removal +% process takes place as described for \cs{tl_trim_spaces:n}. +% \end{function} +% +% \begin{function}{\clist_gtrim_spaces:N, \clist_gtrim_spaces:c} +% \begin{syntax} +% \cs{clist_gtrim_spaces:N} \meta{comma list} +% \end{syntax} +% Removes leading and trailing spaces from each \meta{item} in the +% \meta{comma list} globally. This space-removal +% process takes place as described for \cs{tl_trim_spaces:n}. +% \end{function} +% +% \begin{function}[EXP]{\clist_trim_spaces:n} +% \begin{syntax} +% \cs{clist_trim_spaces:N} \meta{comma list} +% \end{syntax} +% Removes leading and trailing spaces from each \meta{item} in the +% \meta{comma list}, leaving the resulting modified list in the +% input stream. +% \end{function} +% +% \section{Comma list conditionals} +% +% \begin{function}[EXP,pTF]{\clist_if_empty:N, \clist_if_empty:c} +% \begin{syntax} +% \cs{clist_if_empty_p:N} \meta{comma list} +% \cs{clist_if_empty:NTF} \meta{comma list} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the \meta{comma list} is empty (containing no items). The +% branching versions then leave either \meta{true code} or +% \meta{false code} in the input stream, as appropriate to the truth of +% the test and the variant of the function chosen. The logical truth of +% the test is left in the input stream by the predicate version. +% \end{function} +% +% \begin{function}[EXP,pTF] +% {\clist_if_eq:NN, \clist_if_eq:Nc, \clist_if_eq:cN, \clist_if_eq:cc} +% \begin{syntax} +% \cs{clist_if_eq_p:NN} \Arg{clist1} \Arg{clist2} +% \cs{clist_if_eq:NNTF} \Arg{clist1} \Arg{clist2} \Arg{true code} +% ~~\Arg{false code} +% \end{syntax} +% Compares the content of two \meta{comma lists} and +% is logically \texttt{true} if the two contain the same list of +% entries in the same order. The branching versions then leave either +% \meta{true code} or \meta{false code} in the input stream, as +% appropriate to the truth of the test and the variant of the function +% chosen. The logical truth of the test is left in the input stream by +% the predicate version. +% \end{function} +% +% \begin{function}[TF]{ +% \clist_if_in:Nn, \clist_if_in:NV, \clist_if_in:No, +% \clist_if_in:cn, \clist_if_in:cV, \clist_if_in:co, +% \clist_if_in:nn, \clist_if_in:nV, \clist_if_in:no +% } +% \begin{syntax} +% \cs{clist_if_in:NnTF} \meta{comma list} \Arg{item} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the \meta{item} is present in the \meta{comma list}. +% Either the \meta{true code} or \meta{false code} is left in the input +% stream, as appropriate to the truth of the test and the variant of the +% function +% chosen. +% \end{function} +% +% \section{Mapping to comma lists} +% +% \begin{function}[EXP] +% {\clist_map_function:NN, \clist_map_function:cN, \clist_map_function:nN} +% \begin{syntax} +% \cs{clist_map_function:NN} \meta{comma list} \meta{function} +% \end{syntax} +% Applies \meta{function} to every \meta{item} stored in the +% \meta{comma list}. The \meta{function} will receive one argument for +% each iteration. The \meta{items} are returned from left to right. +% The function \cs{clist_map_inline:Nn} is in general more efficient +% than \cs{clist_map_function:NN}. +% One mapping may be nested inside another. +% \end{function} +% +% \begin{function} +% {\clist_map_inline:Nn, \clist_map_inline:cn, \clist_map_inline:nn} +% \begin{syntax} +% \cs{clist_map_inline:Nn} \meta{comma list} \Arg{inline function} +% \end{syntax} +% Applies \meta{inline function} to every \meta{item} stored +% within the \meta{comma list}. The \meta{inline function} should +% consist of code which will receive the \meta{item} as |#1|. +% One in line mapping can be nested inside another. The \meta{items} +% are returned from left to right. +% \end{function} +% +% \begin{function} +% {\clist_map_variable:NNn, \clist_map_variable:cNn, \clist_map_variable:nNn} +% \begin{syntax} +% \cs{clist_map_variable:NNn} \meta{comma list} +% ~~\meta{tl~var.} \Arg{function using tl~var.} +% \end{syntax} +% Stores each entry in the \meta{comma list} in turn in the +% \meta{tl~var.}\ and applies the \meta{function using tl~var.} +% The \meta{function} will usually consist of code making use of +% the \meta{tl~var.}, but this is not enforced. One variable +% mapping can be nested inside another. The \meta{items} +% are returned from left to right. +% \end{function} +% +% \begin{function}[EXP]{\clist_map_break:} +% \begin{syntax} +% \cs{clist_map_break:} +% \end{syntax} +% Used to terminate a \cs{clist_map_\ldots} function before all +% entries in the \meta{comma list} have been processed. This will +% normally take place within a conditional statement, for example +% \begin{verbatim} +% \clist_map_inline:Nn \l_my_clist +% { +% \str_if_eq:nnTF { #1 } { bingo } +% { \clist_map_break: } +% { +% % Do something useful +% } +% } +% \end{verbatim} +% Use outside of a \cs{clist_map_\ldots} scenario will lead to low +% level \TeX{} errors. +% \begin{texnote} +% When the mapping is broken, additional tokens may be inserted by the +% internal macro \cs{clist_break_point:n} before further items are taken +% from the input stream. This will depend on the design of the mapping +% function. +% \end{texnote} +% \end{function} +% +% \begin{function}[EXP]{\clist_map_break:n} +% \begin{syntax} +% \cs{clist_map_break:n} \Arg{tokens} +% \end{syntax} +% Used to terminate a \cs{clist_map_\ldots} function before all +% entries in the \meta{comma list} have been processed, inserting +% the \meta{tokens} after the mapping has ended. This will +% normally take place within a conditional statement, for example +% \begin{verbatim} +% \clist_map_inline:Nn \l_my_clist +% { +% \str_if_eq:nnTF { #1 } { bingo } +% { \clist_map_break:n { <tokens> } } +% { +% % Do something useful +% } +% } +% \end{verbatim} +% Use outside of a \cs{clist_map_\ldots} scenario will lead to low +% level \TeX{} errors. +% \begin{texnote} +% When the mapping is broken, additional tokens may be inserted by the +% internal macro \cs{clist_break_point:n} before the \meta{tokens} are +% inserted into the input stream. +% This will depend on the design of the mapping function. +% \end{texnote} +% \end{function} +% +% \section{Comma lists as stacks} +% +% Comma lists can be used as stacks, where data is pushed to and popped +% from the top of the comma list. (The left of a comma list is the top, for +% performance reasons.) The stack functions for comma lists are not +% intended to be mixed with the general ordered data functions detailed +% in the previous section: a comma list should either be used as an +% ordered data type or as a stack, but not in both ways. +% +% \begin{function}{\clist_get:NN, \clist_get:cN} +% \begin{syntax} +% \cs{clist_get:NN} \meta{comma list} \meta{token list variable} +% \end{syntax} +% Reads the top item from a \meta{comma list} into the +% \meta{token list variable} without removing it from the +% \meta{comma list}. The \meta{token list variable} is assigned locally. +% If \meta{comma list} is empty an error will be raised. +% \end{function} +% +% \begin{function}{\clist_pop:NN, \clist_pop:cN} +% \begin{syntax} +% \cs{clist_pop:NN} \meta{comma list} \meta{token list variable} +% \end{syntax} +% Pops the top item from a \meta{comma list} into the +% \meta{token list variable}. Both of the variables are assigned +% locally. If \meta{comma list} is empty an error will be raised. +% \end{function} +% +% \begin{function}{\clist_gpop:NN, \clist_gpop:cN} +% \begin{syntax} +% \cs{clist_gpop:NN} \meta{comma list} \meta{token list variable} +% \end{syntax} +% Pops the top item from a \meta{comma list} into the +% \meta{token list variable}. The \meta{comma list} is modified globally, +% while the \meta{token list variable} is assigned locally. If +% \meta{comma list} is empty an error will be raised. +% \end{function} +% +% \begin{function}{ +% \clist_push:Nn, \clist_push:NV, \clist_push:No, \clist_push:Nx, +% \clist_push:cn, \clist_push:cV, \clist_push:co, \clist_push:cx +% } +% \begin{syntax} +% \cs{clist_push:Nn} \meta{comma list} \Arg{item} +% \end{syntax} +% Adds the \Arg{item} to the top of the \meta{comma list}. +% The assignment is restricted to the current \TeX{} group. +% \end{function} +% +% \begin{function}{ +% \clist_gpush:Nn, \clist_gpush:NV, \clist_gpush:No, \clist_gpush:Nx, +% \clist_gpush:cn, \clist_gpush:cV, \clist_gpush:co, \clist_gpush:cx +% } +% \begin{syntax} +% \cs{clist_gpush:Nn} \meta{comma list} \Arg{item} +% \end{syntax} +% Pushes the \meta{item} onto the end of the top of the +% \meta{comma list}. The assignment is global. +% \end{function} +% +% \section{Viewing comma lists} +% +% \begin{function}{\clist_show:N, \clist_show:c} +% \begin{syntax} +% \cs{clist_show:N} \meta{comma list} +% \end{syntax} +% Displays the entries in the \meta{comma list} in the terminal. +% \end{function} +% +% \section{Experimental comma list functions} +% +% This section contains functions which may or may not be retained, depending +% on how useful they are found to be. +% +% \begin{function}[EXP]{\clist_length:N, \clist_length:c,\clist_length:n} +% \begin{syntax} +% \cs{clist_length:N} \meta{comma list} +% \end{syntax} +% Leaves the number of items in the \meta{comma list} in the input +% stream as an \meta{integer denotation}. The total number of items +% in a \meta{comma list} will include those which are empty and duplicates, +% \emph{i.e.}~every item in a \meta{comma list} is unique. +% \end{function} +% +% \begin{function}[EXP]{\clist_item:Nn, \clist_item:cn, \clist_item:nn} +% \begin{syntax} +% \cs{clist_item:Nn} \meta{comma list} \Arg{integer expression} +% \end{syntax} +% Indexing items in the \meta{comma list} from $0$ at the top (left), this +% function will evaluate the \meta{integer expression} and leave the +% appropriate item from the comma list in the input stream. If the +% \meta{integer expression} is negative, indexing occurs from the +% bottom (right) of the comma list. When the \meta{integer expression} +% is larger than the number of items in the \meta{comma list} (as +% calculated by \cs{clist_length:N}) then the function will expand to +% nothing. +% \end{function} +% +% \begin{function} +% { +% \clist_set_from_seq:NN, \clist_set_from_seq:cN, +% \clist_set_from_seq:Nc, \clist_set_from_seq:cc +% } +% \begin{syntax} +% \cs{clist_set_from_seq:NN} \meta{comma list} \meta{sequence} +% \end{syntax} +% Sets the \meta{comma list} within the current \TeX{} group to be equal +% to the content of the \meta{sequence}. +% \end{function} +% +% \begin{function} +% { +% \clist_gset_from_seq:NN, \clist_gset_from_seq:cN, +% \clist_gset_from_seq:Nc, \clist_gset_from_seq:cc +% } +% \begin{syntax} +% \cs{clist_gset_from_seq:NN} \meta{comma list} \meta{sequence} +% \end{syntax} +% Sets the \meta{comma list} globally to equal to the content of the +% \meta{sequence}. +% \end{function} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{l3clist} implementation} +% +% \TestFiles{m3clist002} +% +% \begin{macrocode} +%<*initex|package> +% \end{macrocode} +% +% \begin{macrocode} +%<*package> +\ProvidesExplPackage + {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +\package_check_loaded_expl: +%</package> +% \end{macrocode} +% +% \begin{variable}{\l_clist_tmpa_tl, \l_clist_tmpb_tl} +% Scratch space for various internal uses. +% \begin{macrocode} +\tl_new:N \l_clist_tmpa_tl +\tl_new:N \l_clist_tmpb_tl +% \end{macrocode} +% \end{variable} +% +% \subsection{Allocation and initialisation} +% +% \begin{macro}{\clist_new:N,\clist_new:c} +% \UnitTested +% Internally, comma lists are just token lists. +% \begin{macrocode} +\cs_new_eq:NN \clist_new:N \tl_new:N +\cs_new_eq:NN \clist_new:c \tl_new:c +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\clist_clear:N, \clist_clear:c} +% \UnitTested +% \begin{macro}{\clist_gclear:N, \clist_gclear:c} +% \UnitTested +% Clearing comma lists is just the same as clearing token lists. +% \begin{macrocode} +\cs_new_eq:NN \clist_clear:N \tl_clear:N +\cs_new_eq:NN \clist_clear:c \tl_clear:c +\cs_new_eq:NN \clist_gclear:N \tl_gclear:N +\cs_new_eq:NN \clist_gclear:c \tl_gclear:c +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\clist_clear_new:N, \clist_clear_new:c} +% \UnitTested +% \begin{macro}{\clist_gclear_new:N, \clist_gclear_new:c} +% \UnitTested +% Once again a copy from the token list functions. +% \begin{macrocode} +\cs_new_eq:NN \clist_clear_new:N \tl_clear_new:N +\cs_new_eq:NN \clist_clear_new:c \tl_clear_new:c +\cs_new_eq:NN \clist_gclear_new:N \tl_gclear_new:N +\cs_new_eq:NN \clist_gclear_new:c \tl_gclear_new:c +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro} +% {\clist_set_eq:NN, \clist_set_eq:cN, \clist_set_eq:Nc, \clist_set_eq:cc} +% \UnitTested +% \begin{macro} +% { +% \clist_gset_eq:NN, \clist_gset_eq:cN, +% \clist_gset_eq:Nc, \clist_gset_eq:cc +% } +% \UnitTested +% Once again, these are simple copies from the token list functions. +% \begin{macrocode} +\cs_new_eq:NN \clist_set_eq:NN \tl_set_eq:NN +\cs_new_eq:NN \clist_set_eq:Nc \tl_set_eq:Nc +\cs_new_eq:NN \clist_set_eq:cN \tl_set_eq:cN +\cs_new_eq:NN \clist_set_eq:cc \tl_set_eq:cc +\cs_new_eq:NN \clist_gset_eq:NN \tl_gset_eq:NN +\cs_new_eq:NN \clist_gset_eq:Nc \tl_gset_eq:Nc +\cs_new_eq:NN \clist_gset_eq:cN \tl_gset_eq:cN +\cs_new_eq:NN \clist_gset_eq:cc \tl_gset_eq:cc +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\clist_concat:NNN, \clist_concat:ccc} +% \UnitTested +% \begin{macro}{\clist_gconcat:NNN, \clist_gconcat:ccc} +% \UnitTested +% \begin{macro}[aux]{\clist_concat_aux:NNNN} +% Concatenating sequences is not quite as easy as it seems, as there is +% the danger that |#1| may be the same as either |#2| or |#3|. Also, +% there needs to be the correct addition of a comma to the output. So +% a little work to do. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \clist_concat:NNN + { \clist_concat_aux:NNNN \tl_set:Nx } +\cs_new_protected_nopar:Npn \clist_gconcat:NNN + { \clist_concat_aux:NNNN \tl_gset:Nx } +\cs_new_protected_nopar:Npn \clist_concat_aux:NNNN #1#2#3#4 + { + #1 #2 + { + \clist_if_empty:NTF #3 + { \exp_not:o #4 } + { + \exp_not:o #3 + \clist_if_empty:NF #4 + { + , + \exp_not:o #4 + } + } + } + } +\cs_generate_variant:Nn \clist_concat:NNN { ccc } +\cs_generate_variant:Nn \clist_gconcat:NNN { ccc } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Appending items to comma lists} +% +% \begin{macro} +% { +% \clist_put_left:Nn, \clist_put_left:NV, +% \clist_put_left:No, \clist_put_left:Nx, +% \clist_put_left:cn, \clist_put_left:cV, +% \clist_put_left:co, \clist_put_left:cx +% } +% \UnitTested +% \begin{macro} +% { +% \clist_gput_left:Nn, \clist_gput_left:NV, +% \clist_gput_left:No, \clist_gput_left:Nx, +% \clist_gput_left:cn, \clist_gput_left:cV, +% \clist_gput_left:co, \clist_gput_left:cx +% } +% \UnitTested +% Comma lists cannot hold empty values: there are therefore a couple +% of sanity checks to avoid accumulating commas. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \clist_put_left:Nn + { \clist_put_aux:NNnnNn \tl_set:Nn \tl_put_left:Nn { } , } +\cs_new_protected_nopar:Npn \clist_gput_left:Nn + { \clist_put_aux:NNnnNn \tl_gset:Nn \tl_gput_left:Nn { } , } +\cs_new_protected:Npn \clist_put_aux:NNnnNn #1#2#3#4#5#6 + { + \clist_if_empty:NTF #5 + { #1 #5 {#6} } + { \tl_if_empty:nF {#6} { #2 #5 { #3 #6 #4 } } } + } +\cs_generate_variant:Nn \clist_put_left:Nn { NV , No , Nx } +\cs_generate_variant:Nn \clist_put_left:Nn { c , cV , co , cx } +\cs_generate_variant:Nn \clist_gput_left:Nn { NV , No , Nx } +\cs_generate_variant:Nn \clist_gput_left:Nn { c , cV , co , cx } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro} +% { +% \clist_put_right:Nn, \clist_put_right:NV, +% \clist_put_right:No, \clist_put_right:Nx, +% \clist_put_right:cn, \clist_put_right:cV, +% \clist_put_right:co, \clist_put_right:cx +% } +% \begin{macro} +% { +% \clist_gput_right:Nn, \clist_gput_right:NV, +% \clist_gput_right:No, \clist_gput_right:Nx, +% \clist_gput_right:cn, \clist_gput_right:cV, +% \clist_gput_right:co, \clist_gput_right:cx +% } +% The same for the right side. +% \begin{macrocode} +\cs_new_protected:Npn \clist_put_right:Nn + { \clist_put_aux:NNnnNn \tl_set:Nn \tl_put_right:Nn , { } } +\cs_new_protected_nopar:Npn \clist_gput_right:Nn + { \clist_put_aux:NNnnNn \tl_gset:Nn \tl_gput_right:Nn , { } } +\cs_generate_variant:Nn \clist_put_right:Nn { NV , No , Nx } +\cs_generate_variant:Nn \clist_put_right:Nn { c , cV , co , cx } +\cs_generate_variant:Nn \clist_gput_right:Nn { NV , No , Nx } +\cs_generate_variant:Nn \clist_gput_right:Nn { c , cV , co , cx } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Comma lists as stacks} +% +% \begin{macro}{\clist_get:NN, \clist_get:cN} +% \UnitTested +% \begin{macro}[aux]{\clist_get_aux:wN} +% Getting an item from the left of a comma list is pretty easy: just +% trim off the first item using the comma. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \clist_get:NN #1#2 + { \exp_after:wN \clist_get_aux:wN #1 , \q_stop #2 } +\cs_new_protected:Npn \clist_get_aux:wN #1 , #2 \q_stop #3 + { \tl_set:Nn #3 {#1} } +\cs_generate_variant:Nn \clist_get:NN { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\clist_pop:NN, \clist_pop:cN} +% \UnitTested +% \begin{macro}{\clist_gpop:NN, \clist_gpop:cN} +% \UnitTested +% \begin{macro}[aux]{\clist_pop_aux:NNN} +% \begin{macro}[aux]{\clist_pop_aux:wNNN} +% The aim here is to get the popped item as |#1| in the auxiliary, with +% |#2| containing either the remainder of the list \emph{or} \cs{q_nil} +% if there were insufficient items. That keeps the number of auxiliary +% functions down. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \clist_pop:NN + { \clist_pop_aux:NNN \tl_set:Nn } +\cs_new_protected_nopar:Npn \clist_gpop:NN + { \clist_pop_aux:NNN \tl_gset:Nn } +\cs_new_protected_nopar:Npn \clist_pop_aux:NNN #1#2#3 + { \exp_after:wN \clist_pop_aux:wNNN #2 , \q_nil , \q_nil , \q_stop #1#2#3 } +\cs_new_protected:Npn \clist_pop_aux:wNNN #1 , #2 , \q_nil , #3 \q_stop #4#5#6 + { + \quark_if_nil:nTF {#2} + { #4 #5 { } } + { #4 #5 {#2} } + \tl_set:Nn #6 {#1} + } +\cs_generate_variant:Nn \clist_pop:NN { c } +\cs_generate_variant:Nn \clist_gpop:NN { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{ +% \clist_push:Nn, \clist_push:NV, \clist_push:No, \clist_push:Nx, +% \clist_push:cn, \clist_push:cV, \clist_push:co, \clist_push:cx +% } +% \UnitTested +% \begin{macro}{ +% \clist_gpush:Nn, \clist_gpush:NV, \clist_gpush:No, \clist_gpush:Nx, +% \clist_gpush:cn, \clist_gpush:cV, \clist_gpush:co, \clist_gpush:cx +% } +% \UnitTested +% Pushing to a sequence is the same as adding on the left. +% \begin{macrocode} +\cs_new_eq:NN \clist_push:Nn \clist_put_left:Nn +\cs_new_eq:NN \clist_push:NV \clist_put_left:NV +\cs_new_eq:NN \clist_push:No \clist_put_left:No +\cs_new_eq:NN \clist_push:Nx \clist_put_left:Nx +\cs_new_eq:NN \clist_push:cn \clist_put_left:cn +\cs_new_eq:NN \clist_push:cV \clist_put_left:cV +\cs_new_eq:NN \clist_push:co \clist_put_left:co +\cs_new_eq:NN \clist_push:cx \clist_put_left:cx +\cs_new_eq:NN \clist_gpush:Nn \clist_gput_left:Nn +\cs_new_eq:NN \clist_gpush:NV \clist_gput_left:NV +\cs_new_eq:NN \clist_gpush:No \clist_gput_left:No +\cs_new_eq:NN \clist_gpush:Nx \clist_gput_left:Nx +\cs_new_eq:NN \clist_gpush:cn \clist_gput_left:cn +\cs_new_eq:NN \clist_gpush:cV \clist_gput_left:cV +\cs_new_eq:NN \clist_gpush:co \clist_gput_left:co +\cs_new_eq:NN \clist_gpush:cx \clist_gput_left:cx +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Using comma lists} +% +% \begin{macro}{\clist_use:N, \clist_use:c} +% \UnitTested +% The approach is the same as for \cs{tl_use:N}. +% \begin{macrocode} +\cs_new_eq:NN \clist_use:N \tl_use:N +\cs_new_eq:NN \clist_use:c \tl_use:c +% \end{macrocode} +% \end{macro} +% +% \subsection{Modifying comma lists} +% +% \begin{variable}{\l_clist_remove_clist} +% An internal comma list for the removal routines. +% \begin{macrocode} +\clist_new:N \l_clist_remove_clist +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\clist_remove_duplicates:N, \clist_remove_duplicates:c} +% \UnitTested +% \begin{macro}{\clist_gremove_duplicates:N, \clist_gremove_duplicates:c} +% \UnitTested +% \begin{macro}[aux]{\clist_remove_duplicates_aux:NN} +% Removing duplicates means making a new list then copying it. +% \begin{macrocode} +\cs_new_protected:Npn \clist_remove_duplicates:N + { \clist_remove_duplicates_aux:NN \clist_set_eq:NN } +\cs_new_protected:Npn \clist_gremove_duplicates:N + { \clist_remove_duplicates_aux:NN \clist_gset_eq:NN } +\cs_new_protected:Npn \clist_remove_duplicates_aux:NN #1#2 + { + \clist_clear:N \l_clist_remove_clist + \clist_map_inline:Nn #2 + { + \clist_if_in:NnF \l_clist_remove_clist {##1} + { \clist_put_right:Nn \l_clist_remove_clist {##1} } + } + #1 #2 \l_clist_remove_clist + } +\cs_generate_variant:Nn \clist_remove_duplicates:N { c } +\cs_generate_variant:Nn \clist_gremove_duplicates:N { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\clist_remove_all:Nn, \clist_remove_all:cn} +% \UnitTested +% \begin{macro}{\clist_gremove_all:Nn, \clist_gremove_all:cn} +% \UnitTested +% \begin{macro}[aux]{\clist_remove_all_aux:NNn} +% \begin{macro}[aux]{\clist_remove_all_aux:w} +% Removing an item from a comma list is done without looping over +% the entire list, as the performance of that approach is very bad for +% long lists. Instead, a delimited function is needed. For this to work +% correctly, there is a need to add an additional comma at the start of +% the list, and to remove it again once the removal is complete. Of +% course, the list can end up empty, which is the reason for the test +% before copying back to the parent. +% \begin{macrocode} +\cs_new_protected:Npn \clist_remove_all:Nn + { \clist_remove_all_aux:NNn \clist_set_eq:NN } +\cs_new_protected:Npn \clist_gremove_all:Nn + { \clist_remove_all_aux:NNn \clist_gset_eq:NN } +\cs_new_protected:Npn \clist_remove_all_aux:NNn #1#2#3 + { + \clist_if_empty:NF #2 + { + \clist_clear:N \l_clist_remove_clist + \cs_set_protected:Npn \clist_remove_all_aux:w + ##1 , #3 , ##2 \q_stop + { + \tl_put_right:Nn \l_clist_remove_clist {##1} + \quark_if_no_value:nF {##2} + { \clist_remove_all_aux:w , ##2 \q_stop } + } + \exp_after:wN \clist_remove_all_aux:w + \exp_after:wN , #2 , #3 , \q_no_value \q_stop + \tl_if_empty:NF \l_clist_remove_clist + { + \exp_after:wN \tl_set:No \exp_after:wN + \l_clist_remove_clist \exp_after:wN + { \exp_after:wN \use_none:n \l_clist_remove_clist } + } + #1 #2 \l_clist_remove_clist + } + } +\cs_new_protected:Npn \clist_remove_all_aux:w { } +\cs_generate_variant:Nn \clist_remove_all:Nn { c } +\cs_generate_variant:Nn \clist_gremove_all:Nn { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\clist_trim_spaces:n} +% \begin{macro} +% { +% \clist_trim_spaces:N, \clist_trim_spaces:c, +% \clist_gtrim_spaces:N, \clist_gtrim_spaces:c +% } +% \begin{macro}{\clist_trim_spaces_aux_i:n} +% \begin{macro}{\clist_trim_spaces_aux_ii:n} +% Here, the basic plan is to use \cs{tl_trim_spaces:n} to do the work: +% the only issue is to make sure that the number of commas at the end of +% the process is correct. +% \begin{macrocode} +\cs_new:Npn \clist_trim_spaces:n #1 + { + \exp_args:Nf \clist_trim_spaces_aux_i:n + { \clist_map_function:nN {#1} \clist_trim_spaces_aux_ii:n } + } +\cs_new:Npn \clist_trim_spaces_aux_i:n #1 { \use_ii:nn #1 } +\cs_new:Npn \clist_trim_spaces_aux_ii:n #1 + { , \tl_trim_spaces:n {#1} } +\cs_new_protected:Npn \clist_trim_spaces:N #1 + { \tl_set:Nf #1 { \exp_args:No \clist_trim_spaces:n #1 } } +\cs_new_protected:Npn \clist_gtrim_spaces:N #1 + { \tl_gset:Nf #1 { \exp_args:No \clist_trim_spaces:n #1 } } +\cs_generate_variant:Nn \clist_trim_spaces:N { c } +\cs_generate_variant:Nn \clist_gtrim_spaces:N { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Comma list conditionals} +% +% \begin{macro}[aux]{\clist_tmp:w} +% A temporary function for comparison. +% \begin{macrocode} +\cs_new_protected:Npn \clist_tmp:w { } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[pTF]{\clist_if_empty:N, \clist_if_empty:c} +% \UnitTested +% Simple copies from the token list variable material. +% \begin{macrocode} +\prg_new_eq_conditional:NNn \clist_if_empty:N \tl_if_empty:N { p , T , F , TF } +\prg_new_eq_conditional:NNn \clist_if_empty:c \tl_if_empty:c { p , T , F , TF } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[pTF] +% {\clist_if_eq:NN, \clist_if_eq:Nc, \clist_if_eq:cN, \clist_if_eq:cc} +% \UnitTested +% Simple copies from the token list variable material. +% \begin{macrocode} +\prg_new_eq_conditional:NNn \clist_if_eq:NN \tl_if_eq:NN { p , T , F , TF } +\prg_new_eq_conditional:NNn \clist_if_eq:Nc \tl_if_eq:Nc { p , T , F , TF } +\prg_new_eq_conditional:NNn \clist_if_eq:cN \tl_if_eq:cN { p , T , F , TF } +\prg_new_eq_conditional:NNn \clist_if_eq:cc \tl_if_eq:cc { p , T , F , TF } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[TF] +% { +% \clist_if_in:Nn, \clist_if_in:NV, \clist_if_in:No, +% \clist_if_in:cn, \clist_if_in:cV, \clist_if_in:co +% } +% \UnitTested +% \begin{macrocode} +\prg_new_protected_conditional:Npnn \clist_if_in:Nn #1#2 + { T , F , TF } + { + \cs_set_protected:Npn \clist_tmp:w ##1 , #2 , ##2##3 \q_stop + { + \if_meaning:w \q_no_value ##2 + \prg_return_false: + \else: + \prg_return_true: + \fi: + } + \exp_last_unbraced:NNo \clist_tmp:w , #1 , #2 , \q_no_value \q_stop + } +\prg_new_protected_conditional:Npnn \clist_if_in:nn #1#2 + { T , F , TF } + { + \cs_set_protected:Npn \clist_tmp:w ##1 , #2 , ##2##3 \q_stop + { + \if_meaning:w \q_no_value ##2 + \prg_return_false: + \else: + \prg_return_true: + \fi: + } + \clist_tmp:w , #1 , #2 , \q_no_value \q_stop + } +\cs_generate_variant:Nn \clist_if_in:NnT { NV , No } +\cs_generate_variant:Nn \clist_if_in:NnT { c , cV , co } +\cs_generate_variant:Nn \clist_if_in:NnF { NV , No } +\cs_generate_variant:Nn \clist_if_in:NnF { c , cV , co } +\cs_generate_variant:Nn \clist_if_in:NnTF { NV , No } +\cs_generate_variant:Nn \clist_if_in:NnTF { c , cV , co } +\cs_generate_variant:Nn \clist_if_in:nnT { nV , no } +\cs_generate_variant:Nn \clist_if_in:nnF { nV , no } +\cs_generate_variant:Nn \clist_if_in:nnTF { nV , no } +% \end{macrocode} +% \end{macro} +% +% \subsection{Mapping to comma lists} +% +% \begin{macro}{\clist_map_function:NN, \clist_map_function:cN} +% \UnitTested +% \begin{macro}{\clist_map_function:nN} +% \UnitTested +% \begin{macro}[aux]{\clist_map_function_aux:Nw} +% Mapping to comma lists is pretty simple, if not massively efficient. +% \begin{macrocode} +\cs_new_nopar:Npn \clist_map_function:NN #1#2 + { + \clist_if_empty:NF #1 + { + \exp_last_unbraced:NNo \clist_map_function_aux:Nw #2 #1 + , \q_recursion_tail , \q_recursion_stop + } + } +\cs_new:Npn \clist_map_function:nN #1#2 + { + \tl_if_empty:nF {#1} + { + \clist_map_function_aux:Nw #2 #1 + , \q_recursion_tail , \q_recursion_stop + } + } +\cs_new:Npn \clist_map_function_aux:Nw #1#2 , + { + \quark_if_recursion_tail_stop:n {#2} + #1 {#2} + \clist_map_function_aux:Nw #1 + } +\cs_generate_variant:Nn \clist_map_function:NN { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{variable}{\g_clist_map_inline_int} +% For the nesting of mappings. +% \begin{macrocode} +\int_new:N \g_clist_map_inline_int +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\clist_map_inline:Nn, \clist_map_inline:cn} +% \UnitTested +% \begin{macro}{\clist_map_inline:nn} +% \UnitTested +% Inline mapping is done by creating a suitable function +% \enquote{on the fly}: +% this is done globally to avoid any issues with \TeX{}'s groups. +% \begin{macrocode} +\cs_new_protected:Npn \clist_map_inline:Nn #1#2 + { + \int_gincr:N \g_clist_map_inline_int + \cs_gset:cpn { clist_map_inline_ \int_use:N \g_clist_map_inline_int :n } + ##1 + {#2} + \exp_args:NNc \clist_map_function:NN #1 + { clist_map_inline_ \int_use:N \g_clist_map_inline_int :n } + \int_gdecr:N \g_clist_map_inline_int + } +\cs_new_protected:Npn \clist_map_inline:nn #1#2 + { + \int_gincr:N \g_clist_map_inline_int + \cs_gset:cpn { clist_map_inline_ \int_use:N \g_clist_map_inline_int :n } + ##1 + {#2} + \exp_args:Nnc \clist_map_function:nN {#1} + { clist_map_inline_ \int_use:N \g_clist_map_inline_int :n } + \int_gdecr:N \g_clist_map_inline_int + } +\cs_generate_variant:Nn \clist_map_inline:Nn { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\clist_map_variable:NNn, \clist_map_variable:cNn} +% \UnitTested +% This is just a dedicated version of the inline mapping. +% \begin{macrocode} +\cs_new_protected:Npn \clist_map_variable:NNn #1#2#3 + { + \clist_map_inline:Nn #1 + { + \tl_set:Nn #2 {##1} + #3 + } + } +\cs_new_protected:Npn \clist_map_variable:nNn #1#2#3 + { + \clist_map_inline:nn {#1} + { + \tl_set:Nn #2 {##1} + #3 + } + } +\cs_generate_variant:Nn \clist_map_variable:NNn { c } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\clist_map_break:} +% \UnitTested +% \begin{macro}{\clist_map_break:n} +% Both are simple renaming. +% \begin{macrocode} +\cs_new_eq:NN \clist_map_break: \use_none_delimit_by_q_recursion_stop:w +\cs_new_eq:NN \clist_map_break:n \use_i_delimit_by_q_recursion_stop:nw +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \section{Viewing comma lists} +% +% \begin{macro}{\clist_show:N, \clist_show:c} +% \UnitTested +% \begin{macro}[aux]{\clist_show_aux:n} +% \begin{macro}[aux]{\clist_show_aux:w} +% The aim of the mapping here is to create a token list containing the +% formatted comma list. The very first item needs the new line and \verb*|> | +% removing, which is achieved using a \texttt{w}-type auxiliary. To avoid +% a low-level \TeX{} error if there is an empty comma list, a simple test is +% used to keep the output \enquote{clean}. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \clist_show:N #1 + { + \clist_if_empty:NTF #1 + { + \iow_term:x { Comma~list~\token_to_str:N #1 \c_space_tl is~empty } + \tl_show:n { } + } + { + \iow_term:x + { + Comma~list~\token_to_str:N #1 \c_space_tl + contains~the~items~(without~outer~braces): + } + \tl_set:Nx \l_clist_show_tl + { \clist_map_function:NN #1 \clist_show_aux:n } + \etex_showtokens:D \exp_after:wN \exp_after:wN \exp_after:wN + { \exp_after:wN \clist_show_aux:w \l_clist_show_tl } + } + } +\cs_new:Npn \clist_show_aux:n #1 + { + \iow_newline: > \c_space_tl \c_space_tl + \iow_char:N \{ \exp_not:n {#1} \iow_char:N \} + } +\cs_new:Npn \clist_show_aux:w #1 > ~ { } +\cs_generate_variant:Nn \clist_show:N { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Experimental functions} +% +% \begin{macro}{\clist_length:N, \clist_length:c} +% \begin{macro}{\clist_length:n} +% \begin{macro}[aux]{\clist_length_aux:n} +% Counting the items in a comma list is done using the same approach as for +% other length functions: turn each entry into a \texttt{+1} then use +% integer evaluation to actually do the mathematics. +% \begin{macrocode} +\cs_new:Npn \clist_length:N #1 + { + \int_eval:n + { + 0 + \clist_map_function:NN #1 \clist_length_aux:n + } + } +\cs_new:Npn \clist_length:n #1 + { + \int_eval:n + { + 0 + \clist_map_function:nN {#1} \clist_length_aux:n + } + } +\cs_new:Npn \clist_length_aux:n #1 { +1 } +\cs_generate_variant:Nn \clist_length:N { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\clist_item:Nn, \clist_item:cn} +% \begin{macro}{\clist_item:nn} +% \begin{macro}[aux]{\clist_item_aux:nnn} +% The idea here is to find the offset of the item from the left, then use +% a loop to grab the correct item. If the resulting offset is too large, +% then \cs{quark_if_recursion_stop:n} will be true, +% terminating the loop and returning nothing at all. +% \begin{macrocode} +\cs_set_nopar:Npn \clist_item:Nn #1#2 + { \exp_args:No \clist_item:nn #1 {#2} } +\cs_set:Npn \clist_item:nn #1#2 + { + \int_compare:nNnTF {#2} < \c_zero + { + \exp_args:Nf \clist_item_aux:nw + { \int_eval:n { \clist_length:n {#1} + #2 } } + #1 , \q_recursion_tail \q_recursion_stop + } + { \clist_item_aux:nw {#2} #1 , \q_recursion_tail \q_recursion_stop } + } +\cs_set:Npn \clist_item_aux:nw #1#2 , #3 + { + \int_compare:nNnTF {#1} = \c_zero + { \use_i_delimit_by_q_recursion_stop:nw {#2} } + { + \quark_if_recursion_tail_stop:n {#3} + \exp_args:Nf \clist_item_aux:nw + { \int_eval:n { #1 - 1 } } + #3 + } + } +\cs_generate_variant:Nn \clist_item:Nn { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro} +% { +% \clist_set_from_seq:NN, \clist_set_from_seq:cN, +% \clist_set_from_seq:Nc, \clist_set_from_seq:cc +% } +% \begin{macro} +% { +% \clist_gset_from_seq:NN, \clist_gset_from_seq:cN, +% \clist_gset_from_seq:Nc, \clist_gset_from_seq:cc +% } +% Setting a comma list from a comma-separated list is done using a simple +% mapping. We wrap each item with braces, \cs{exp_not:n}, and a comma. The +% first comma must be removed, except in the case of an empty comma-list. +% \begin{macrocode} +\cs_new_protected:Npn \clist_set_from_seq:NN #1#2 + { + \seq_if_empty:NTF #2 + { \clist_clear:N #1 } + { + \seq_push_item_def:n { , \exp_not:n {{##1}} } + \tl_set:Nx #1 + { \exp_after:wN \use_none:n \tex_romannumeral:D -`\0 #2 } + \seq_pop_item_def: + } + } +\cs_new_protected:Npn \clist_gset_from_seq:NN #1#2 + { + \seq_if_empty:NTF #2 + { \clist_gclear:N #1 } + { + \seq_push_item_def:n { , \exp_not:n {##1} } + \tl_gset:Nx #1 + { \exp_after:wN \use_none:n \tex_romannumeral:D -`\0 #2 } + \seq_pop_item_def: + } + } +\cs_generate_variant:Nn \clist_set_from_seq:NN { Nc } +\cs_generate_variant:Nn \clist_set_from_seq:NN { c , cc } +\cs_generate_variant:Nn \clist_gset_from_seq:NN { Nc } +\cs_generate_variant:Nn \clist_gset_from_seq:NN { c , cc } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Deprecated interfaces} +% +% Deprecated on 2011-05-27, for removal by 2011-08-31. +% +% \begin{macro}{\clist_top:NN, \clist_top:cN} +% These are old stack functions. +% \begin{macrocode} +\cs_new_eq:NN \clist_top:NN \clist_get:NN +\cs_new_eq:NN \clist_top:cN \clist_get:cN +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\clist_remove_element:Nn} +% \begin{macro}{\clist_gremove_element:Nn} +% An older name for \cs{clist_remove_all:Nn}. +% \begin{macrocode} +\cs_new_eq:NN \clist_remove_element:Nn \clist_remove_all:Nn +\cs_new_eq:NN \clist_gremove_element:Nn \clist_gremove_all:Nn +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\clist_display:N, \clist_display:c} +% An older name for \cs{clist_show:N}. +% \begin{macrocode} +\cs_new_eq:NN \clist_display:N \clist_show:N +\cs_new_eq:NN \clist_display:c \clist_show:c +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +%</initex|package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintIndex
\ No newline at end of file diff --git a/Master/texmf-dist/source/latex/l3kernel/l3doc.dtx b/Master/texmf-dist/source/latex/l3kernel/l3doc.dtx new file mode 100644 index 00000000000..5039b8c0f62 --- /dev/null +++ b/Master/texmf-dist/source/latex/l3kernel/l3doc.dtx @@ -0,0 +1,2064 @@ +% \iffalse meta-comment +% +%% File: l3doc.dtx Copyright (C) 1990-2011 The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +% +%<*driver> +\def\nameofplainTeX{plain} +\ifx\fmtname\nameofplainTeX\else + \expandafter\begingroup +\fi +\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 +\generate{\file{l3doc.cls}{\from{l3doc.dtx}{class}}} +\generate{\file{l3doc.ist}{\from{l3doc.dtx}{docist}}} +\ifx\fmtname\nameofplainTeX + \expandafter\endbatchfile +\else + \expandafter\endgroup +\fi +%</driver> +% +%<*driver|class> +\RequirePackage{l3names} +%</driver|class> +% +% Need to protect the file metadata for any modules that load l3doc. +% This is restored after "\ProvideExplClass" below. +% \begin{macrocode} +%<class>\let \filenameOld \ExplFileName +%<class>\let \filedateOld \ExplFileDate +%<class>\let \fileversionOld \ExplFileVersion +%<class>\let \filedescriptionOld \ExplFileDescription +% \end{macrocode} +% +%<*driver|class> +\GetIdInfo$Id: l3doc.dtx 2478 2011-06-19 21:34:23Z joseph $ + {L3 Experimental documentation class} +%</driver|class> +% +%<*driver> +\ProvidesFile{\ExplFileName.dtx} + [\ExplFileDate\space v\ExplFileVersion\space\ExplFileDescription] +\documentclass{l3doc} +\usepackage{framed} +\begin{document} + \DocInput{l3doc.dtx} +\end{document} +%</driver> +% +% This isn't included in the typeset documentation because it's a bit ugly: +%<*class> +\ProvidesExplClass + {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +\RequirePackage{expl3,xparse} +\let \ExplFileName \filenameOld +\let \ExplFileDate \filedateOld +\let \ExplFileVersion \fileversionOld +\let \ExplFileDescription \filedescriptionOld +%</class> +% \fi +% +% \title{The \pkg{l3doc} class\thanks{This file +% has version number v\ExplFileVersion, last +% revised \ExplFileDate.}} +% \author{\Team} +% \date{\ExplFileDate} +% \maketitle +% \tableofcontents +% +% \begin{documentation} +% +% \section{Introduction} +% +% This is an ad-hoc class for documenting the \pkg{expl3} bundle, +% a collection of modules or packages that make up \LaTeX3's programming +% environment. Eventually it will replace the "ltxdoc" class for \LaTeX3, +% but not before the good ideas in \pkg{hypdoc}, \cls{xdoc2}, \pkg{docmfp}, and +% \cls{gmdoc} are incorporated. +% +% \textbf{It is even less stable than the main \pkg{expl3} packages. Use at own risk!} +% +% It is written as a `self-contained' docstrip file: executing +% "latex l3doc.dtx" +% will generate the "l3doc.cls" file and typeset this +% documentation; execute "tex l3doc.dtx" to only generate the ".cls" file. +% +% \section{Features of other packages} +% +% This class builds on the \pkg{ltxdoc} class and the \pkg{doc} package, but +% in the time since they were originally written some +% improvements and replacements have appeared that we would like to use as +% inspiration. +% +% These packages or classes are \pkg{hypdoc}, \pkg{docmfp}, \pkg{gmdoc}, +% and \pkg{xdoc}. I have summarised them below in order to work out what +% sort of features we should aim at a minimum for \pkg{l3doc}. +% +% \subsection{The \pkg{hypdoc} package} +% +% This package provides hyperlink support for the \pkg{doc} package. I have +% included it in this list to remind me that cross-referencing between +% documentation and implementation of methods is not very good. (E.g., it +% would be nice to be able to automatically hyperlink the documentation for +% a function from its implementation and vice-versa.) +% +% \subsection{The \pkg{docmfp} package} +% +% \begin{itemize} +% \item Provides "\DescribeRoutine" and the "routine" environment (etc.) +% for MetaFont and MetaPost code. +% \item Provides "\DescribeVariable" and the "variable" environment (etc.) +% for more general code. +% \item Provides "\Describe" and the "Code" environment (etc.) as a +% generalisation of the above two instantiations. +% \item Small tweaks to the DocStrip system to aid non-\LaTeX\ use. +% \end{itemize} +% +% \subsection{The \pkg{xdoc2} package} +% +% \begin{itemize} +% \item Two-sided printing. +% \item "\NewMacroEnvironment", "\NewDescribeEnvironment"; similar idea +% to \pkg{docmfp} but more comprehensive. +% \item Tons of small improvements. +% \end{itemize} +% +% \subsection{The \pkg{gmdoc} package} +% +% Radical re-implementation of \pkg{doc} as a package or class. +% \begin{itemize} +% \item Requires no "\begin{macrocode}" blocks! +% \item Automatically inserts "\begin{macro}" blocks! +% \item And a whole bunch of other little things. +% \end{itemize} +% +% \section{Problems \& Todo} +% +% Problems at the moment: (1)~not flexible in the types of things that can be documented; (2)~very nonstandard markup (e.g., the odd `"/ (...)"' tags; (3)~no obvious link between the "\begin{function}" environment for documenting things to the "\begin{macro}" function that's used analogously in the implementation. +% +% The "macro" should probably be renamed to "function" when it is used within +% an implementation section. But they should have the same syntax before that happens! +% +% Furthermore, we need another `layer' of documentation commands to +% account for `user-macro' as opposed to `code-functions'; the \pkg{expl3} +% functions should be documented differently, probably, to the \pkg{xparse} +% user macros (at least in terms of indexing). +% +% In no particular order, a list of things to do: +% \begin{itemize} +% \item Rename \env{function}/\env{macro} environments to better describe +% their use. +% \item Generalise \env{function}/\env{macro} for documenting `other things', +% such as environment names, package options, even keyval options. +% \item Use \pkg{xparse}. +% \item New function like "\part" but for files (remove awkward `File' as "\partname"). +% \item Something better to replace "\StopEventually"; I'm thinking two +% environments \env{documentation} and \env{implementation} that can +% conditionally typeset/ignore their material. +% (This has been implemented but needs further consideration.) +% \item Hyperlink documentation and implementation of macros (see +% the \textsc{dtx} file of \pkg{svn-multi} v2 as an example). +% \end{itemize} +% +% \section{Bugs} +% +% \begin{itemize} +% \item Spaces are ignored entirely within \env{function} and \env{macro} +% arguments. This is just waiting for a convenient space-trimming +% macro in \pkg{expl3}. +% \end{itemize} +% +% \section{Documentation} +% +% \subsection{Configuration} +% +% Before class options are processed, \pkg{l3doc} loads a configuration +% file "l3doc.cfg" if it exists, allowing you to customise the behaviour of +% the class without having to change the documentation source files. +% +% For example, to produce documentation on letter-sized paper instead of the +% default A4 size, create |l3doc.cfg| and include the line +% \begin{verbatim} +% \PassOptionsToClass{letterpaper}{l3doc} +% \end{verbatim} +% +% By default, \pkg{l3doc} selects the |T1| font encoding and loads the +% Latin Modern fonts. +% To prevent this, use the class option |cm-default|. +% +% \subsection{Partitioning documentation and implementation} +% +% \pkg{doc} uses the "\OnlyDocumentation"/"\AlsoImplementation" macros +% to guide the use of "\StopEventually{}", which is intended to be placed +% to partition the documentation and implementation within a single DTX file. +% +% This isn't very flexible, since it assumes that we \emph{always} want +% to print the documentation. For the \pkg{expl3} sources, I wanted to be +% be able to input DTX files in two modes: only displaying the documentation, +% and only displaying the implementation. For example: +% +% \begin{verbatim} +% \DisableImplementation +% \DocInput{l3basics,l3prg,...} +% \EnableImplementation +% \DisableDocumentation +% \DocInputAgain +% \end{verbatim} +% +% The idea being that the entire \pkg{expl3} bundle can be documented, +% with the implementation included at the back. Now, this isn't perfect, +% but it's a start. +% +% Use "\begin{documentation}...\end{documentation}" around the documentation, +% and "\begin{implementation}...\end{implementation}" around the implementation. +% The "\EnableDocumentation"/"\EnableImplementation" will cause them to be typeset +% when the DTX file is "\DocInput"; use "\DisableDocumentation"/"\DisableImplementation" +% to omit the contents of those environments. +% +% Note that \cmd\DocInput\ now takes comma-separated arguments, and \cmd\DocInputAgain\ +% can be used to re-input all DTX files previously input in this way. +% +% \subsection{Describing functions in the documentation} +% +% \DescribeEnv{function} +% \DescribeEnv{syntax} +% Two heavily-used environments are defined to describe the syntax +% of \textsf{expl3} functions and variables. +% \begin{framed} +% \vspace{-\baselineskip} +% \begin{verbatim} +% \begin{function}{ list_of , functions } +% \begin{syntax} +% "\foo_bar:" \Arg{meta} <test1> +% \end{syntax} +% <description> +% \end{function} +% \end{verbatim} +% \vspace{-2\baselineskip} +% \hrulefill +% \begin{function}{ list_of , functions } +% \begin{syntax} +% "\foo_bar:" \Arg{meta} <test1> +% \end{syntax} +% <description> +% \end{function} +% \end{framed} +% +% Function environments take an optional argument to indicate whether the function(s) it +% describes are expandable or defined in conditional forms. Use "EXP", "TF", or "pTF" +% for this; note that "pTF" implies "EXP" since predicates must always be expandable. +% As an example: +% \begin{framed} +% \vspace{-\baselineskip} +% \begin{verbatim} +% \begin{function}[pTF]{ \cs_if_exist:N } +% \begin{syntax} +% "\cs_if_exist_p:N" <cs> +% \end{syntax} +% <description> +% \end{function} +% \end{verbatim} +% \vspace{-2\baselineskip} +% \hrulefill +% \begin{function}[pTF]{ \cs_if_exist:N } +% \begin{syntax} +% "\cs_if_exist_p:N" <cs> +% \end{syntax} +% <description> +% \end{function} +% \end{framed} +% +% Note that the list of functions used to use "|" as a separator instead, +% and this syntax is still supported. +% +% In the old syntax, individual functions could be suffixed by an optional flag or +% two to indicate the same information given in the optional argument. +% This is still supported; use "/" to separate the function name +% from the flag(s) and then add any of "(EXP)", "(TF)", or "(pTF)". +% +% \DescribeEnv{variable} +% If you are documenting a variable instead of a function, use the "variable" environment instead; it behaves identically to the "function" environment above. +% +% \subsection{Describing functions in the implementation} +% +% \DescribeEnv{macro} +% The well-used environment from \LaTeXe\ for marking up the implementation +% of macros/functions remains the \env{macro} environment. +% Some changes in \pkg{l3doc}: it now accepts comma-separated lists +% of functions, to avoid a very large number of consecutive "\end{macro}" +% statements. +% \begin{verbatim} +% % \begin{macro}{\foo:N,\foo:c} +% % \begin{macrocode} +% ... code for \foo:N and \foo:c ... +% % \end{macrocode} +% % \end{macro} +% \end{verbatim} +% If you are documenting an auxiliary macro, it's generally not necessary +% to highlight it as much and you also don't need to check it for, say, +% having a test function and having a documentation chunk earlier in a "function" +% environment. In this case, write "\begin[aux]{macro}" and it will be +% marked as such; its margin call-out will be printed in grey. +% +% Similarly, an internal package function still requires documentation +% but usually will not be documented for users to see; these can be marked +% as such with "\begin[internal]{macro}". +% +% For documenting \pkg{expl3}-type conditionals, you may also pass this +% environment a "TF" option (and omit it from the function name) to denote that +% the function is provided with "T", "F", and "TF" suffixes. +% A similar "pTF" option will print both "TF" and "_p" predicate forms. +% +% +% \DescribeMacro{\TestFiles} +% \cs{TestFiles}\marg{list of files} is used to indicate which test files +% are used for the current code; they will be printed in the documentation. +% +% \DescribeMacro{\UnitTested} +% Within a "macro" environment, it is a good idea to mark whether a unit test has +% been created for the commands it defines. This is indicated by writing \cs{UnitTested} +% anywhere within "\begin{macro}" \dots "\end{macro}". +% +% If the class option "checktest" is enabled, then it is an \emph{error} to have a +% "macro" environment without a \cs{testfile} file. This is intended for large packages such +% as \pkg{expl3} that should have absolutely comprehensive tests suites and whose authors +% may not always be as sharp at adding new tests with new code as they should be. +% +% \DescribeMacro{\TestMissing} +% If a function is missing a test, this may be flagged by writing (as many times as needed) +% \cs{TestMissing}\marg{explanation of test required}. +% These missing tests will be summarised in the listing printed at the end of the +% compilation run. +% +% \DescribeEnv{variable} +% When documenting variable definitions, use the "variable" environment instead. +% It will, here, behave identically to the "macro" environment, except that if the class +% option "checktest" is enabled, variables will not be required to have a test file. +% +% \DescribeEnv{arguments} +% Within a \env{macro} environment, you may use the \env{arguments} environment +% to describe the arguments taken by the function(s). It behaves +% like a modified enumerate environment. +% \begin{verbatim} +% % \begin{macro}{\foo:nn,\foo:VV} +% % \begin{arguments} +% % \item Name of froozle to be frazzled +% % \item Name of muble to be jubled +% % \end{arguments} +% % \begin{macrocode} +% ... code for \foo:nn and \foo:VV ... +% % \end{macrocode} +% % \end{macro} +% \end{verbatim} +% +% \bigskip +% \textbf{OPTIONS FOR THE FUTURE}\qquad Any improvements to the markup +% for the \env{function} environment would be good to mirror in \env{macro}. +% +% Perhaps this would be a better syntax for describing arguments? +% \begin{verbatim} +% \begin{macro}{\foo:nn,foo:VV} +% \dArg{Name of froozle to be frazzled} +% \dArg{Name of mumble to be jumbled} +% ... +% \end{verbatim} +% I.e., get rid of the environment and do things like in, say, \pkg{fontspec}. +% +% \subsection{Keeping things consistent} +% +% Whenever a function is either documented or defined with \env{function} +% and \env{macro} respectively, its name is stored in a sequence for later +% processing. +% +% At the end of the document (i.e., after the \textsc{dtx} file has finished +% processing), the list of names is analysed to check whether all defined +% functions have been documented and vice versa. The results are printed +% in the console output. +% +% If you need to do more serious work with these lists of names, take a +% look at the implementation for the data structures and methods used to +% store and access them directly. +% +% \subsection{Documenting templates} +% +% The following macros are provided for documenting templates; might +% end up being something completely different but who knows. +% \begin{quote}\parskip=0pt\obeylines +% "\begin{TemplateInterfaceDescription}" \Arg{template type name} +% " \TemplateArgument{none}{---}" +% \textsc{or one or more of these:} +% " \TemplateArgument" \Arg{arg no} \Arg{meaning} +% \textsc{and} +% "\TemplateSemantics" +% " " \meta{text describing the template type semantics} +% "\end{TemplateInterfaceDescription}" +% \end{quote} +% +% \begin{quote}\parskip=0pt\obeylines +% "\begin{TemplateDescription}" \Arg{template type name} \Arg{name} +% \textsc{one or more of these:} +% " \TemplateKey" \marg{key name} \marg{type of key} +% " "\marg{textual description of meaning} +% " "\marg{default value if any} +% \textsc{and} +% "\TemplateSemantics" +% " " \meta{text describing special additional semantics of the template} +% "\end{TemplateDescription}" +% \end{quote} +% +% \begin{quote}\parskip=0pt\obeylines +% "\begin{InstanceDescription}" \oarg{text to specify key column width (optional)} +% \hfill\marg{template type name}\marg{instance name}\marg{template name} +% \textsc{one or more of these:} +% " \InstanceKey" \marg{key name} \marg{value} +% \textsc{and} +% "\InstanceSemantics" +% " " \meta{text describing the result of this instance} +% "\end{InstanceDescription}" +% \end{quote} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{l3doc} implementation} +% +% \begin{macrocode} +%<*class> +% \end{macrocode} +% +% The Guilty Parties. +% \begin{macrocode} +\cs_new_nopar:Npn\Team{% + The~\LaTeX3~Project\thanks{% + Frank~Mittelbach,~Denys~Duchier,~Chris~Rowley,~ + Rainer~Sch\"opf,~Johannes~Braams,~Michael~Downes,~ + David~Carlisle,~Alan~Jeffrey,~Morten~H\o{}gholm,~Thomas~Lotze,~ + Javier~Bezos,~Will~Robertson,~Joseph~Wright}} +% \end{macrocode} +% +% \subsection{Options and configuration} +% +% \begin{macrocode} +\DeclareOption{a5paper}{\@latexerr{Option not supported}{}} +% \end{macrocode} +% +% \begin{macrocode} +\bool_new:N \g_doc_full_bool +\bool_new:N \g_doc_lmodern_bool +\bool_new:N \g_doc_checkfunc_bool +\bool_new:N \g_doc_checktest_bool +% \end{macrocode} +% +% \begin{macrocode} +\DeclareOption{full}{ \bool_set_true:N \g_doc_full_bool } +\DeclareOption{onlydoc}{ \bool_set_false:N \g_doc_full_bool } +% \end{macrocode} +% +% \begin{macrocode} +\DeclareOption{check}{ \bool_set_true:N \g_doc_checkfunc_bool } +\DeclareOption{nocheck}{ \bool_set_false:N \g_doc_checkfunc_bool } +% \end{macrocode} +% +% \begin{macrocode} +\DeclareOption{checktest}{ \bool_set_true:N \g_doc_checktest_bool } +\DeclareOption{nochecktest}{ \bool_set_false:N \g_doc_checktest_bool } +% \end{macrocode} +% +% \begin{macrocode} +\DeclareOption{cm-default}{ \bool_set_false:N \g_doc_lmodern_bool } +\DeclareOption{lm-default}{ \bool_set_true:N \g_doc_lmodern_bool } +% \end{macrocode} +% +% \begin{macrocode} +\DeclareOption*{\PassOptionsToClass{\CurrentOption}{article}} +\ExecuteOptions{full,a4paper,nocheck,nochecktest,lm-default} +% \end{macrocode} +% +% Input a local configuration file, if it exists. +% +% \begin{macrocode} +\InputIfFileExists{l3doc.cfg} + { + \typeout{*************************************^^J + *~Local~config~file~l3doc.cfg~used ^^J + *************************************} + } + { \@input{l3doc.ltx} } +% \end{macrocode} +% +% \begin{macrocode} +\ProcessOptions +% \end{macrocode} +% +% +% \subsection{Class and package loading} +% +% \begin{macrocode} +\LoadClass{article} +\RequirePackage{doc} +\RequirePackage{array,alphalph,booktabs,color,fixltx2e,enumitem,textcomp,trace,underscore,csquotes} +% \end{macrocode} +% +% \begin{macrocode} +\bool_if:NT \g_doc_lmodern_bool { + \RequirePackage[T1]{fontenc} + \RequirePackage{lmodern} +} +% \end{macrocode} +% +% \begin{macrocode} +\RequirePackage{hypdoc} +% \end{macrocode} +% Just want the "comment" environment from \pkg{verbatim}: +% \begin{macrocode} +\let\doc@verbatim\verbatim +\let\enddoc@verbatim\endverbatim +\let\doc@@verbatim\@verbatim +\expandafter\let\csname doc@verbatim*\expandafter\endcsname + \csname verbatim*\endcsname +\expandafter\let\csname enddoc@verbatim*\expandafter\endcsname + \csname endverbatim*\endcsname +\expandafter\let\csname doc@@verbatim*\expandafter\endcsname + \csname @verbatim*\endcsname +\RequirePackage{verbatim} +\AtBeginDocument{% + \let\verbatim\doc@verbatim + \let\endverbatim\enddoc@verbatim + \let\@verbatim\doc@@verbatim + \expandafter\let\csname verbatim*\expandafter\endcsname + \csname doc@verbatim*\endcsname + \expandafter\let\csname endverbatim*\expandafter\endcsname + \csname enddoc@verbatim*\endcsname + \expandafter\let\csname @verbatim*\expandafter\endcsname + \csname doc@@verbatim*\endcsname +} +% \end{macrocode} +% +% \subsection{Configuration} +% +% \begin{macro}{\MakePrivateLetters} +% \begin{macrocode} +\cs_set_nopar:Npn \MakePrivateLetters { + \char_set_catcode_letter:N \@ + \char_set_catcode_letter:N \_ + \char_set_catcode_letter:N \: +} +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +\setcounter{StandardModuleDepth}{1} +\@addtoreset{CodelineNo}{part} +\cs_set_nopar:Npn \theCodelineNo { + \textcolor[gray]{0.5}{ \sffamily\tiny\arabic{CodelineNo} } +} +% \end{macrocode} +% +% +% +% \subsection{Design} +% +% Increase the text width slightly so that width the standard fonts +% 72 columns of code may appear in a |macrocode| environment. +% Increase the marginpar width slightly, for long command names. +% And increase the left margin by a similar amount. +% \begin{macrocode} +\setlength \textwidth { 385pt } +\addtolength \marginparwidth { 30pt } +\addtolength \oddsidemargin { 20pt } +\addtolength \evensidemargin { 20pt } +% \end{macrocode} +% (These were introduced when "article" was the documentclass, but +% I've left them here for now to remind me to do something about them +% later; we still have the problem of \emph{very long} command names.) +% +% Customise lists: +% \begin{macrocode} +\cs_set_eq:NN \@@oldlist\list +\cs_set_nopar:Npn \list#1#2{\@@oldlist{#1}{#2\listparindent\z@}} +\setlength \parindent { 0pt } +\setlength \itemindent { 0pt } +\setlength \parskip { \medskipamount } +% \end{macrocode} +% +% \subsection{Text markup} +% +% Make "|" and |"| be `short verb' characters, but not in +% the document preamble, where an active character may interfere +% with packages that are loaded. +% \begin{macrocode} +\AtBeginDocument { + \MakeShortVerb \" + \MakeShortVerb \| +} +% \end{macrocode} +% +% \begin{macrocode} +\providecommand*\eTeX{ + \if b\expandafter\@car\f@series\@nil\boldmath\fi + $\m@th\varepsilon$-\TeX +} +\providecommand*\IniTeX{Ini\TeX} +\providecommand*\Lua{Lua} +\providecommand*\LuaTeX{\Lua\TeX} +\providecommand*\pdfTeX{pdf\TeX} +\RequirePackage{graphicx} +\cs_if_free:NT \XeTeX { + \cs_new_protected_nopar:Npn \XeTeX + {X\kern-.125em\lower.5ex\hbox{\reflectbox{E}}\kern-.1667em\TeX} +} +% \end{macrocode} +% +% \begin{macro}{\cmd,\cs} +% |\cmd{\foo}| Prints |\foo| verbatim. It may be used inside moving +% arguments. |\cs{foo}| also prints |\foo|, for those who prefer that +% syntax. +% \begin{macrocode} +\cs_set_nopar:Npn \cmd #1 { \cs{\expandafter\cmd@to@cs\string#1} } +\cs_set_nopar:Npn \cmd@to@cs #1#2 { \char\number`#2\relax } +\DeclareRobustCommand \cs [1] { \texttt { \char`\\ #1 } } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\marg,\oarg,\parg} +% |\marg{text}| prints \marg{text}, `mandatory argument'.\\ +% |\oarg{text}| prints \oarg{text}, `optional argument'.\\ +% |\parg{te,xt}| prints \parg{te,xt}, `picture mode argument'. +% \begin{macrocode} +\providecommand\marg[1]{ \texttt{\char`\{} \meta{#1} \texttt{\char`\}} } +\providecommand\oarg[1]{ \texttt[ \meta{#1} \texttt] } +\providecommand\parg[1]{ \texttt( \meta{#1} \texttt) } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\m,\file,\env,\pkg,\cls} +% This list may change\dots this is just my preference for markup. +% \begin{macrocode} +\cs_set_eq:NN \m \meta +\cs_set_eq:NN \file \nolinkurl +\DeclareRobustCommand \env {\texttt} +\DeclareRobustCommand \pkg {\textsf} +\DeclareRobustCommand \cls {\textsf} +% \end{macrocode} +% \end{macro} +% +% \begin{environment}{texnote} +% \begin{macrocode} +\newenvironment{texnote}{ + \endgraf + \vspace{3mm} + \small\textbf{\TeX~hackers~note:} +}{ + \vspace{3mm} +} +% \end{macrocode} +% \end{environment} +% +% \begin{macro}{\tn} +% As \cs{cs}. Use this to mark up all \TeX\ and \LaTeXe\ commands; they +% then end up together in the index. TODO: hyperlinks in the index entries. +% \begin{macrocode} +\newcommand\tn[1]{ + \texttt{\bslash #1} + \index{TeX~and~LaTeX2e~commands\actualchar + \string\TeX{}~and~\string\LaTeXe{}~commands:\levelchar + #1\actualchar{\string\ttfamily\string\bslash{}#1}}} +% \end{macrocode} +% \end{macro} +% +% \begin{environment}{documentation} +% \begin{environment}{implementation} +% \begin{macro}{\EnableDocumentation,\EnableImplementation} +% \begin{macro}{\DisableDocumentation,\DisableImplementation} +% \begin{macrocode} +\cs_new:Npn \doc_implementation: { + \cs_set:Npn \variable {\macro[var]} +} +\cs_new:Npn \doc_docu: { + \cs_set_eq:NN \variable \variabledoc +} +\AtEndOfPackage{\doc_docu:} +\newenvironment{documentation}{\doc_docu:}{} +\newenvironment{implementation}{\doc_implementation:}{} +\newcommand\EnableDocumentation{% + \renewenvironment{documentation}{\doc_docu:}{}% +} +\newcommand\EnableImplementation{% + \renewenvironment{implementation}{\doc_implementation:}{}% +} +\newcommand\DisableDocumentation{% + \cs_set_eq:NN \documentation \comment + \cs_set_eq:NN \enddocumentation \endcomment +} +\newcommand\DisableImplementation{% + \cs_set_eq:NN \implementation \comment + \cs_set_eq:NN \endimplementation \endcomment +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{environment} +% \end{environment} +% +% \begin{environment}{arguments} +% This environment is designed to be used within a \env{macro} environment +% to describe the arguments of the macro/function. +% \begin{macrocode} +\newenvironment{arguments}{ + \enumerate[ + nolistsep, + label=\texttt{\#\arabic*}~:, + labelsep=*, + ] +}{ + \endenumerate +} +% \end{macrocode} +% \end{environment} +% +% \begin{environment}{function} +% \begin{environment}{variabledoc} +% Environment for documenting function(s). +% Stick the function names in a box. Use a "|" as delimiter and +% allow |<...>| to be used as markup for |\meta{...}|. +% Ignore spaces and sanitize with catcodes before reading argument. +% \begin{macrocode} +\char_set_catcode_active:N \< +\DeclareDocumentCommand \function { O{} } { + + \phantomsection + + \bool_gset_false:N \l_doc_meta_TF_bool + \bool_gset_false:N \l_doc_meta_pTF_bool + \bool_gset_false:N \l_doc_meta_EXP_bool + + \cs_set_nopar:Npn \KV_key_no_value_elt:n ##1 { \use:c {doc_meta_opt_##1:} } + \keyval_parse:NNn \KV_key_no_value_elt:n \use_none:nn {#1} + + \char_set_catcode_active:N \< + \cs_set_eq:NN < \doc_open_meta:n + + \group_begin: + \MakePrivateLetters + \char_set_catcode_other:N \| + \char_set_catcode_other:N \\ + \char_set_catcode_space:N \~ + \char_set_catcode_ignore:N \ % space + \char_set_catcode_ignore:N \^^M + \char_set_catcode_ignore:N \^^I + \function_aux:n +} +\char_set_catcode_other:N \< +\cs_set_eq:NN \variabledoc \function +% \end{macrocode} +% +% \begin{macrocode} +\cs_set:Nn \doc_meta_opt_TF: { + \bool_gset_true:N \l_doc_meta_TF_bool +} +\cs_set:Nn \doc_meta_opt_EXP: { + \bool_gset_true:N \l_doc_meta_EXP_bool +} +\cs_set:Nn \doc_meta_opt_pTF: { + \bool_gset_true:N \l_doc_meta_pTF_bool + \bool_gset_true:N \l_doc_meta_TF_bool + \bool_gset_true:N \l_doc_meta_EXP_bool +} +% \end{macrocode} +% +% \begin{macro}{\function_aux:n} +% \begin{arguments} +% \item Vertical bar--separated list of functions with optional metadata; +% input has already been sanitised by catcode changes before reading +% the argument. +% \end{arguments} +% Because vertical bars are odd delimiters to choose, we also now iterate over commas! +% \begin{macrocode} +\group_begin: +\char_set_catcode_other:N \| +\cs_gset_nopar:Npn \function_aux:n #1 { + \cs_set_nopar:Npn \nextnewline{\cs_gset_nopar:Npn\nextnewline{\\}} + \tl_gset_eq:NN \g_doc_macro_tl \c_empty_tl + \bigskip\endgraf\noindent\ttfamily + \tabular[b]{ | l @{} c | } + \hline + \clist_map_inline:nn {#1} {\doc_showmacro:w ##1 | \q_stop} \\ + \hline + \endtabular + \group_end: +} +\group_end: +% \end{macrocode} +% \end{macro} +% \end{environment} +% \end{environment} +% +% \begin{macro}{\doc_showmacro:w} +% This function reads in a "|"-separated list, passing each item to +% the auxiliary function "\doc_showmacro_aux:w". +% \begin{macrocode} +\group_begin: +\char_set_catcode_other:N \| +\cs_gset_nopar:Npn \doc_showmacro:w #1 | { + \tl_if_blank:nTF {#1} { + \use_none:n + }{ + \doc_showmacro_aux:w #1 / \q_stop + \peek_meaning:NTF \q_stop { \use_none:n } { \doc_showmacro:w } + } +} +\group_end: +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +\bool_new:N \l_doc_meta_TF_bool +\bool_new:N \l_doc_meta_pTF_bool +\bool_new:N \l_doc_meta_EXP_bool +% \end{macrocode} +% +% \begin{macro}{\doc_showmacro_aux:w} +% This macro is passed one of: +% \begin{quote} +% "\abc:cnx / (EXP) / \q_stop" \\ +% "\abc:cnx / \q_stop" \\ +% \end{quote} +% We also have some code here to print out every documented macro at the end +% of the document. +% \begin{arguments} +% \item Function/macro/variable name \item Metadata tags (if any) +% \end{arguments} +% \begin{macrocode} +\cs_new_nopar:Npn \doc_showmacro_aux:w #1 / #2 \q_stop { + + \tl_if_in:nnT {#2} { (TF) } { + \bool_gset_true:N \l_doc_meta_TF_bool + } + + \tl_if_in:nnT {#2} { (EXP) } { + \bool_gset_true:N \l_doc_meta_EXP_bool + } + + \tl_if_in:nnT {#2} { (pTF) } { + \bool_gset_true:N \l_doc_meta_TF_bool + \bool_gset_true:N \l_doc_meta_pTF_bool + \bool_gset_true:N \l_doc_meta_EXP_bool + } + + \bool_if:NT \l_doc_meta_pTF_bool { + \tl_set:Nx \l_doc_pTF_name_tl { \doc_predicate_from_base:w #1 \q_nil } + \doc_special_main_index:o { \l_doc_pTF_name_tl } + \seq_gput_right:Nx \g_doc_functions_seq { \tl_to_str:N \l_doc_pTF_name_tl } + } + + \bool_if:NTF \l_doc_meta_TF_bool { + \doc_special_main_index:o { #1 TF } + \seq_gput_right:Nx \g_doc_functions_seq { \tl_to_str:n { #1 TF } } + \seq_gput_right:Nx \g_doc_functions_seq { \tl_to_str:n { #1 T } } + \seq_gput_right:Nx \g_doc_functions_seq { \tl_to_str:n { #1 F } } + }{ + \doc_special_main_index:o { #1 } + \seq_gput_right:Nx \g_doc_functions_seq { \tl_to_str:n { #1 } } + } + + \bool_if:NTF \l_doc_meta_pTF_bool { + \bool_gset_false:N \l_doc_meta_TF_bool + \exp_after:wN \doc_showmacro_aux_ii:w \l_doc_pTF_name_tl ::\q_stop + \bool_gset_true:N \l_doc_meta_TF_bool + \doc_showmacro_aux_ii:w #1::\q_stop + }{ + \doc_showmacro_aux_ii:w #1::\q_stop + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\doc_showmacro_aux_ii:w} +% This macro is passed arguments in the following ways: +% \begin{quote} +% "\doc_showmacro_aux_ii:w "^^A +% \makebox[\widthof{\texttt{123456}}]{\meta{name}}^^A +% " ::\q_stop" \\ +% "\doc_showmacro_aux_ii:w \foo ::\q_stop" \\ +% "\doc_showmacro_aux_ii:w \foo: ::\q_stop" \\ +% "\doc_showmacro_aux_ii:w \foo:Z ::\q_stop" \\ +% \end{quote} +% Notice that for "\foo", "#2" and "#3" are empty,\\ +% for "\foo:", "#2" is empty, and "#3" is `":"'\\ +% for "\foo:Z", "#2" is `"Z"' and "#3" is `":"' . +% \begin{arguments} +% \item Function name \item Possible arg.\ spec. \item Possible colon +% \end{arguments} +% \begin{macrocode} +\cs_set_nopar:Npn \doc_showmacro_aux_ii:w #1:#2:#3 \q_stop { + \nextnewline + \str_if_eq:xxTF {#1} {\g_doc_macro_tl} { + \doc_typeset_aux:n + }{ + \tl_gset:Nn \g_doc_macro_tl {#1} + \use:n + } + { \g_doc_macro_tl } + #3 + #2 + \bool_if:NT \l_doc_meta_TF_bool { \doc_typeset_TF: } + & + \bool_if:NT \l_doc_meta_EXP_bool { + \hspace{\tabcolsep} + $\star$ + } + \tl_set:Nx \g_doc_macro_tl { \tl_to_str:N \g_doc_macro_tl } + \exp_args:NNf \tl_replace_all_in:Nnn \g_doc_macro_tl {\token_to_str:N _} {/} + \exp_args:NNf \tl_replace_all_in:Nnn \g_doc_macro_tl {\@backslashchar} {} + \bool_if:NT \g_doc_full_bool { + \exp_args:Nf\label{doc/function/\g_doc_macro_tl#3#2} + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{environment}{syntax} +% Syntax block placed next to the list of functions to illustrate their use. +% \begin{macrocode} +\dim_new:N \g_doc_syntax_dim +\dim_set:Nn \g_doc_syntax_dim {0.7\textwidth} +\newenvironment{syntax}{ + \minipage[b]{\g_doc_syntax_dim} + \cs_set_nopar:Npn \meta@font@select{\rmfamily\itshape} % (Will: I HATE italic cmtt!) + \small\ttfamily\raggedright + \obeyspaces\obeylines +}{ + \endminipage + \hfil\break + \global\@ignoretrue +} +% \end{macrocode} +% \end{environment} +% +% Perhaps these belong in \file{l3token}? +% \begin{macrocode} +\tl_map_inline:nn {0123456789} { \cs_gset_eq:cN {char_other_#1} #1 } +% \end{macrocode} +% +% \begin{macro}{\doc_open_meta:n,\doc_close_meta:n} +% This code turns all numbers within "<...>" markup to be set as subscripts. +% You can use escaped numbers to get the real thing (e.g., "\1" = `1'). +% \begin{macrocode} +\group_begin: + \tl_map_inline:nn {0123456789} { \char_set_catcode_active:N #1 } + \cs_new:Npn \doc_open_meta:n { + \group_begin: + \tl_map_function:nN {0123456789} \doc_assign_num:n + \doc_close_meta:w + } + \cs_new:Npn \Arg { + \texttt{ \char`\{ } + \group_begin: + \tl_map_function:nN {0123456789} \doc_assign_num:n + \doc_close_Arg:n + } +\group_end: +\cs_new_nopar:Npn \doc_close_meta:w #1> { \meta {#1} \group_end: } +\cs_new_nopar:Npn \doc_close_Arg:n #1 { + \meta {#1} + \group_end: + \texttt{ \char`\} } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\doc_assign_num:n} +% This function takes a numeral (`0'), defines its escaped self to be equal +% to itself ("\0" $\to$ `0'), makes it active, and turns itself into a subscript +% instead (`0' $\to$ `${}_0$'). +% \begin{macrocode} +\cs_new_nopar:Npn \doc_assign_num:n #1 { + \cs_set_eq:cc { \string #1 } { char_other_\string #1 } + \char_set_catcode_active:N #1 + \cs_set_nopar:Npn #1 { \unskip \, $ {} \sb { \use:c { char_other_\string #1 } } $ } +} +% \end{macrocode} +% \end{macro} +% +% \begin{environment}{macro} +% We want to extend the old definition to allow comma-separated lists of +% macros, rather than one at a time. keyval processing is very rudimentary; +% awaiting a more robust solution. +% \begin{macrocode} +\renewcommand \macro [1][] { + + \int_compare:nNnTF \currentgrouplevel=2 + { \int_gzero:N \g_doc_nested_macro_int } + { \int_incr:N \g_doc_nested_macro_int } + + \bool_set_false:N \l_doc_macro_aux_bool + \bool_set_false:N \l_doc_macro_internal_bool + \bool_set_false:N \l_doc_macro_TF_bool + \bool_set_false:N \l_doc_macro_pTF_bool + \bool_set_false:N \l_doc_macro_var_bool + \bool_set_false:N \l_doc_tested_bool + + \cs_set_eq:NN \doc_macroname_prefix:n \use:n + \cs_set_eq:NN \doc_macroname_suffix: \c_empty_tl + + \cs_set_nopar:Npn \KV_key_no_value_elt:n ##1 { \use:c {doc_macro_opt_##1:} } + \keyval_parse:NNn \KV_key_no_value_elt:n \use_none:nn {#1} + + \cs_set_eq:NN \testfile \doc_print_testfile:n + + \group_begin: + \MakePrivateLetters + \char_set_catcode_letter:N \\ + \char_set_catcode_ignore:N \ % space + \char_set_catcode_ignore:N \^^M + \char_set_catcode_ignore:N \^^I + \doc_macro_aux:n +} +% \end{macrocode} +% After changing the catcodes, parse the arguments: +% \begin{macrocode} +\cs_new_nopar:Npn \doc_macro_aux:n #1 { + \group_end: + \cs_set:Npn \l_doc_macro_input_clist {#1} + \bool_if:NTF \l_doc_macro_pTF_bool + { + \clist_map_inline:nn {#1} + { + \tl_if_blank:nF {##1} + { + \exp_args:Nf \doc_macro_single + { \doc_predicate_from_base:w ##1 \q_nil } + } + } + \bool_set_true:N \l_doc_macro_TF_bool + \clist_map_inline:nn {#1} + { \tl_if_blank:nF {##1} { \doc_macro_single {##1} } } + \bool_set_false:N \l_doc_macro_TF_bool + } + { + \clist_map_inline:nn {#1} + { \tl_if_blank:nF {##1} { \doc_macro_single {##1} } } + } +} +% \end{macrocode} +% +% \begin{macrocode} +\bool_new:N \l_doc_macro_internal_bool +\bool_new:N \l_doc_macro_aux_bool +\bool_new:N \l_doc_macro_TF_bool +\bool_new:N \l_doc_macro_pTF_bool +\bool_new:N \l_doc_macro_var_bool +\cs_set_nopar:Npn \doc_macro_opt_aux: { \bool_set_true:N \l_doc_macro_aux_bool } +\cs_set_nopar:Npn \doc_macro_opt_internal: { \bool_set_true:N \l_doc_macro_internal_bool } +\cs_set_nopar:Npn \doc_macro_opt_TF: { \bool_set_true:N \l_doc_macro_TF_bool } +\cs_set_nopar:Npn \doc_macro_opt_pTF: { \bool_set_true:N \l_doc_macro_pTF_bool } +\cs_set_nopar:Npn \doc_macro_opt_var: { \bool_set_true:N \l_doc_macro_var_bool } +% \end{macrocode} +% \end{environment} +% +% \begin{macrocode} +\cs_set:Npn \doc_predicate_from_base:w #1:#2 \q_nil {#1_p:#2} +% \end{macrocode} +% +% \begin{environment}{doc_macro_single} +% Let's start to mess around with "doc"'s "macro" environment. See \file{doc.dtx} +% for a full explanation of the original environment. It's +% rather \emph{enthusiastically} commented. +% \begin{arguments} +% \item Macro/function/whatever name; input has already been sanitised. +% \end{arguments} +% \begin{macrocode} +\int_new:N \l_doc_macro_int +\cs_set_nopar:Npn \doc_macro_single #1 { + \int_incr:N \l_doc_macro_int + \tl_set:Nx \saved@macroname { \token_to_str:N #1 } + \topsep\MacroTopsep + \trivlist + \cs_set_nopar:Npn \makelabel ##1 { \llap{##1} } + \if@inlabel + \cs_set_eq:NN \@tempa \@empty + \count@ \macro@cnt + \loop \ifnum\count@>\z@ + \cs_set_nopar:Npx \@tempa{\@tempa\hbox{\strut}} + \advance\count@\m@ne + \repeat + \cs_set_nopar:Npx \makelabel ##1 { + \llap{\vtop to\baselineskip {\@tempa\hbox{##1}\vss}} + } + \advance \macro@cnt \@ne + \else + \macro@cnt \@ne + \fi + + \bool_if:NT \l_doc_macro_aux_bool { + \cs_set_eq:NN \doc_macroname_prefix:n \doc_typeset_aux:n + } + \bool_if:NT \l_doc_macro_TF_bool { + \cs_set_eq:NN \doc_macroname_suffix: \doc_typeset_TF: + } + + \bool_if:NF \l_doc_macro_aux_bool { + \tl_gset:Nx \l_doc_macro_tl { \tl_to_str:n {#1} } + \exp_args:NNf \tl_greplace_all_in:Nnn \l_doc_macro_tl {\token_to_str:N _} {/} + \exp_args:NNf \tl_greplace_all_in:Nnn \l_doc_macro_tl {\@backslashchar} {} + } + + \use:x { + \exp_not:N \item [ \exp_not:N \doc_print_macroname:n { + \tl_to_str:n {#1} + }] + } + \global\advance \c@CodelineNo \@ne + + \bool_if:NF \l_doc_macro_aux_bool { + \bool_if:NTF \l_doc_macro_TF_bool { + \seq_gput_right:Nx \g_doc_macros_seq { \tl_to_str:n { #1 TF } } + \seq_gput_right:Nx \g_doc_macros_seq { \tl_to_str:n { #1 T } } + \seq_gput_right:Nx \g_doc_macros_seq { \tl_to_str:n { #1 F } } + }{ + \seq_gput_right:Nx \g_doc_macros_seq { \tl_to_str:n {#1} } + } + } + \bool_if:NTF \l_doc_macro_TF_bool { + \SpecialMainIndex{#1 TF}\nobreak + \DoNotIndex{#1 TF} + }{ + \SpecialMainIndex{#1}\nobreak + \DoNotIndex{#1} + } + + \global\advance \c@CodelineNo \m@ne + \ignorespaces +} +% \end{macrocode} +% +% \begin{macro}{\doc_print_macroname:n} +% \begin{macrocode} +\tl_clear:N \l_doc_macro_tl +\cs_set_nopar:Npn \doc_print_macroname:n #1 { + \strut + \int_compare:nTF { \tl_elt_count:n {#1} <= 28 } + { \MacroFont } { \MacroLongFont } + + % INEFFICIENT: (!) + \exp_args:NNx \seq_if_in:NnTF \g_doc_functions_seq + { #1 \bool_if:NT \l_doc_macro_TF_bool { \tl_to_str:n {TF} } } + { + \hyperref [doc/function/\l_doc_macro_tl] + } + { \use:n } + { + \doc_macroname_prefix:n {#1} \doc_macroname_suffix: \ % space! + } +} +% \end{macrocode} +% \end{macro} +% \end{environment} +% +% \begin{macro}{\MacroLongFont} +% \begin{macrocode} +\providecommand \MacroLongFont { + \fontfamily{lmtt}\fontseries{lc}\small +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\doc_typeset_TF:,\doc_typeset_aux:n} +% Used by \cs{doc_macro_single} and \cs{doc_showmacro_aux_ii:w} to typeset +% conditionals and auxiliary functions. +% \begin{macrocode} +\cs_set_nopar:Npn \doc_typeset_TF: { + \itshape TF% + \makebox[0pt][r]{% + \color[gray]{0.5} + \underline { \phantom{\itshape TF} \kern-0.1em } + } +} +\cs_set_nopar:Npn \doc_typeset_aux:n #1 { + {\color[gray]{0.5} #1} +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\doc_print_testfile:n} +% Used to show that a macro has a test, somewhere. +% \begin{macrocode} +\DeclareDocumentCommand \doc_print_testfile:n {m} { + \bool_set_true:N \l_doc_tested_bool + \tl_if_eq:nnF {#1} {*} { + \seq_if_in:NnF \g_doc_testfiles_seq {#1} + { + \par{\footnotesize(\textit{ + The~ test~ suite~ for~ this~ command,~ and~ others~ in~ this~ file,~ is~ \textsf{#1}}. + )\par} + \seq_gput_right:Nn \g_doc_testfiles_seq {#1} + } + } +} +\seq_new:N \g_doc_testfiles_seq +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\TestFiles} +% \begin{macrocode} +\DeclareDocumentCommand \TestFiles {m} { + \par + {\itshape + The~ following~ test~ files~ are~ used~ for~ this~ code:~ \textsf{#1}. + } + \par\ignorespaces +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\UnitTested} +% \begin{macrocode} +\DeclareDocumentCommand \UnitTested {} { + \testfile* +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\TestMissing} +% \begin{macrocode} +\cs_generate_variant:Nn \prop_gput:Nnn {NVx} +\prop_new:N \g_doc_missing_tests_prop +\DeclareDocumentCommand \TestMissing {m} { + \prop_if_in:NVTF \g_doc_missing_tests_prop \l_doc_macro_input_clist + { + \prop_get:NVN \g_doc_missing_tests_prop \l_doc_macro_input_clist \l_tmpa_tl + \prop_gput:NVx \g_doc_missing_tests_prop \l_doc_macro_input_clist + { + *~ \l_tmpa_tl + ^^J \exp_not:n {\space\space\space\space\space\space} + *~ #1 + } + } + { \prop_gput:NVn \g_doc_missing_tests_prop \l_doc_macro_input_clist {#1} } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\endmacro} +% \begin{macrocode} +\int_new:N \g_doc_nested_macro_int +\cs_set:Nn \doc_texttt_comma:n {\,,~\texttt{#1}} +\cs_set:Npn \endmacro { + \int_compare:nT {\g_doc_nested_macro_int<1} + { + \par\nobreak{\footnotesize(\emph{ + End~ definition~ for~ + \prg_case_int:nnn { \clist_length:N \l_doc_macro_input_clist } + { + {1} { \texttt{ \clist_use:N \l_doc_macro_input_clist }. } + {2} + { + \tl_set:Nx \l_clist_first_tl { \clist_item:Nn \l_doc_macro_input_clist {0} } + \tl_set:Nx \l_clist_last_tl { \clist_item:Nn \l_doc_macro_input_clist {1} } + \texttt{\l_clist_first_tl}\,~ and~ \texttt{\l_clist_last_tl}\,. + } + {3} + { + \tl_set:Nx \l_clist_first_tl { \clist_item:Nn \l_doc_macro_input_clist {0} } + \tl_set:Nx \l_clist_mid_tl { \clist_item:Nn \l_doc_macro_input_clist {1} } + \tl_set:Nx \l_clist_last_tl { \clist_item:Nn \l_doc_macro_input_clist {2} } + \texttt{\l_clist_first_tl}\,,~ + \texttt{\l_clist_mid_tl}\,,~ + and~ \texttt{\l_clist_last_tl}\,. + } + } + { + \tl_set:Nx \l_clist_first_tl { \clist_item:Nn \l_doc_macro_input_clist {0} } + \texttt{\l_clist_first_tl}\,~and~others. + } + \bool_if:nT { + !\l_doc_macro_aux_bool && + !\l_doc_macro_internal_bool && + \int_compare_p:n {\g_doc_nested_macro_int<1} + } + { + \int_compare:nNnTF \l_doc_macro_int=1 {~This~} {~These~} + \bool_if:NTF \l_doc_macro_var_bool{variable}{function} + \int_compare:nNnTF \l_doc_macro_int=1 {~is~}{s~are~} + documented~on~page~ + \exp_args:Nx\pageref{doc/function/\l_doc_macro_tl}. + } + })\par} + } + \bool_if:nT + { \g_doc_checktest_bool && + !( \l_doc_macro_aux_bool || \l_doc_macro_var_bool ) && + !\l_doc_tested_bool + } + { + \seq_gput_right:Nx \g_doc_not_tested_seq + { + \l_doc_macro_input_clist + \bool_if:NT \l_doc_macro_pTF_bool {~(pTF)} + \bool_if:NT \l_doc_macro_TF_bool {~(TF)} + } + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\DescribeOption} +% For describing package options. Due to Joseph Wright. +% Name/usage might change soon. +% \begin{macrocode} +\newcommand*{\DescribeOption}{ + \leavevmode + \@bsphack + \begingroup + \MakePrivateLetters + \Describe@Option +} +\newcommand*{\Describe@Option}[1]{ + \endgroup + \marginpar{ + \raggedleft + \PrintDescribeEnv{#1} + } + \SpecialOptionIndex{#1} + \@esphack + \ignorespaces +} +\newcommand*{\SpecialOptionIndex}[1]{ + \@bsphack + \begingroup + \HD@target + \let\HDorg@encapchar\encapchar + \edef\encapchar usage{ + \HDorg@encapchar hdclindex{\the\c@HD@hypercount}{usage} + } + \index{ + #1\actualchar{\protect\ttfamily#1}~(option) + \encapchar usage + } + \index{ + options:\levelchar#1\actualchar{\protect\ttfamily#1} + \encapchar usage + } + \endgroup + \@esphack +} +% \end{macrocode} +% \end{macro} +% +% Here are some definitions for additional markup that will help to +% structure your documentation. +% +% \begin{environment}{danger} +% \begin{environment}{ddanger} +% \begin{syntax} +% |\begin{[d]danger}|\\ +% dangerous code\\ +% |\end{[d]danger}| +% \end{syntax} +% +% \begin{danger} +% Provides a danger bend, as known from the \TeX{}book. +% \end{danger} +% The actual character from the font |manfnt|: +% \begin{macrocode} +\font\manual=manfnt +\cs_set_nopar:Npn \dbend { {\manual\char127} } +% \end{macrocode} +% +% Defines the single danger bend. Use it whenever there is a feature in your +% package that might be tricky to use. +% FIXME: Has to be fixed when in combination with a macro-definition. +% \begin{macrocode} +\newenvironment {danger} { + \begin{trivlist}\item[]\noindent + \begingroup\hangindent=2pc\hangafter=-2 + \cs_set_nopar:Npn \par{\endgraf\endgroup} + \hbox to0pt{\hskip-\hangindent\dbend\hfill}\ignorespaces +}{ + \par\end{trivlist} +} +% \end{macrocode} +% +% \begin{ddanger} +% Use the double danger bend if there is something which could cause serious +% problems when used in a wrong way. Better the normal user does not know +% about such things. +% \end{ddanger} +% \begin{macrocode} +\newenvironment {ddanger} { + \begin{trivlist}\item[]\noindent + \begingroup\hangindent=3.5pc\hangafter=-2 + \cs_set_nopar:Npn \par{\endgraf\endgroup} + \hbox to0pt{\hskip-\hangindent\dbend\kern2pt\dbend\hfill}\ignorespaces +}{ + \par\end{trivlist} +} +% \end{macrocode} +% \end{environment} +% \end{environment} +% +% \subsection{Documenting templates} +% +% \begin{macrocode} +\newenvironment{TemplateInterfaceDescription}[1] + {\subsection{The~object~type~`#1'}% + \begingroup + \@beginparpenalty\@M + \description + \def\TemplateArgument##1##2{\item[Arg:~##1]##2\par}% + \def\TemplateSemantics{\enddescription\endgroup + \subsubsection*{Semantics:}}% + } + {\par\bigskip} +% \end{macrocode} +% +% \begin{macrocode} +\newenvironment{TemplateDescription}[2] + {\subsection{The~template~`#2'~(object~type~#1)}% + \subsubsection*{Attributes:}% + \begingroup + \@beginparpenalty\@M + \description + \def\TemplateKey##1##2##3##4{\item[##1~(##2)]##3% + \ifx\TemplateKey##4\TemplateKey\else +% \hskip0ptplus3em\penalty-500\hskip 0pt plus 1filll Default:~##4% + \hfill\penalty500\hbox{}\hfill Default:~##4% + \nobreak\hskip-\parfillskip\hskip0pt\relax + \fi + \par}% + \def\TemplateSemantics{\enddescription\endgroup + \subsubsection*{Semantics~\&~Comments:}}% + } + {\par\bigskip} +% \end{macrocode} +% +% \begin{macrocode} +\newenvironment{InstanceDescription}[4][xxxxxxxxxxxxxxx] + {\subsubsection{The~instance~`#3'~(template~#2/#4)}% + \subsubsection*{Attribute~values:}% + \begingroup + \@beginparpenalty\@M + \def\InstanceKey##1##2{\>\textbf{##1}\>##2\\}% + \def\InstanceSemantics{\endtabbing\endgroup + \vskip-30pt\vskip0pt + \subsubsection*{Layout~description~\&~Comments:}}% + \tabbing + xxxx\=#1\=\kill + } + {\par\bigskip} +% \end{macrocode} +% +% \subsection{Inheriting doc} +% +% Code here is taken from \pkg{doc}, stripped of comments and translated +% into \pkg{expl3} syntax. New features are added in various places. +% +% \begin{macro}{\StopEventually,\Finale,\AlsoImplementation,\OnlyDescription} +% \begin{macrocode} +\bool_new:N \g_doc_implementation_bool +\cs_set_nopar:Npn \AlsoImplementation { + \bool_set_true:N \g_doc_implementation_bool + \cs_set:Npn \StopEventually ##1 { + \@bsphack + \cs_gset_nopar:Npn \Finale { ##1 \check@checksum } + \init@checksum + \@esphack + } +} +\AlsoImplementation +\cs_set_nopar:Npn \OnlyDescription { + \@bsphack + \bool_set_false:N \g_doc_implementation_bool + \cs_set:Npn \StopEventually ##1 { ##1 \endinput } + \@esphack +} +\cs_set_eq:NN \Finale \relax +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +\cs_set_nopar:Npn \partname{File} +% \end{macrocode} +% +% \begin{macro}{\DocInput} +% From \pkg{doc}. Now accepts comma-list input (who has commas in filenames?). +% \begin{macrocode} +\clist_new:N \g_docinput_clist +\cs_set:Npn \DocInput #1 { + \clist_map_inline:nn {#1} { + \clist_put_right:Nn \g_docinput_clist {##1} + \MakePercentIgnore + \input{##1} + \MakePercentComment + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\DocInputAgain} +% Uses "\g_docinput_clist" to re-input whatever's already been "\DocInput"-ed until now. +% May be used multiple times. +% \begin{macrocode} +\cs_set:Npn \DocInputAgain { + \clist_map_inline:Nn \g_docinput_clist { + \MakePercentIgnore + \input{##1} + \MakePercentComment + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\DocInclude} +% More or less exactly the same as |\include|, but uses |\DocInput| +% on a |dtx| file, not |\input| on a |tex| file. +% \begin{macrocode} +\cs_set_nopar:Npn \partname{File} +% \end{macrocode} +% +% \begin{macrocode} +\newcommand*{\DocInclude}[1]{% + \relax\clearpage + \docincludeaux + \IfFileExists{#1.fdd}{ + \cs_set_nopar:Npn \currentfile{#1.fdd} + }{ + \cs_set_nopar:Npn \currentfile{#1.dtx} + } + \ifnum\@auxout=\@partaux + \@latexerr{\string\include\space cannot~be~nested}\@eha + \else + \@docinclude #1 + \fi +} +% \end{macrocode} +% +% \begin{macrocode} +\cs_set_nopar:Npn \@docinclude #1 { + \clearpage + \immediate\write\@mainaux{\string\@input{#1.aux}} + \@tempswatrue + \if@partsw + \@tempswafalse + \cs_set_nopar:Npx \@tempb{#1} + \@for\@tempa:=\@partlist\do{ + \ifx\@tempa\@tempb\@tempswatrue\fi + } + \fi + \if@tempswa + \cs_set_eq:NN \@auxout\@partaux + \immediate\openout\@partaux #1.aux + \immediate\write\@partaux{\relax} + \cs_set_eq:NN \@ltxdoc@PrintIndex\PrintIndex + \cs_set_eq:NN \PrintIndex\relax + \cs_set_eq:NN \@ltxdoc@PrintChanges\PrintChanges + \cs_set_eq:NN \PrintChanges\relax + \cs_set_eq:NN \@ltxdoc@theglossary\theglossary + \cs_set_eq:NN \@ltxdoc@endtheglossary\endtheglossary + \part{\currentfile} + { + \cs_set_eq:NN \ttfamily\relax + \cs_gset_nopar:Npx \filekey{\filekey, \thepart={\ttfamily\currentfile}} + } + \DocInput{\currentfile} + \cs_set_eq:NN \PrintIndex\@ltxdoc@PrintIndex + \cs_set_eq:NN \PrintChanges\@ltxdoc@PrintChanges + \cs_set_eq:NN \theglossary\@ltxdoc@theglossary + \cs_set_eq:NN \endtheglossary\@ltxdoc@endtheglossary + \clearpage + \@writeckpt{#1} + \immediate\closeout\@partaux + \else + \@nameuse{cp@#1} + \fi + \cs_set_eq:NN \@auxout\@mainaux +} +% \end{macrocode} +% +% \begin{macrocode} +\cs_gset_nopar:Npn \codeline@wrindex #1 { + \immediate\write\@indexfile { + \string\indexentry{#1} + {\filesep\number\c@CodelineNo} + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +\cs_set_eq:NN \filesep \@empty +% \end{macrocode} +% +% \begin{macro}{\docincludeaux} +% \begin{macrocode} +\cs_set_nopar:Npn \docincludeaux { + \cs_set_nopar:Npn \thepart {\alphalph{part}} + \cs_set_nopar:Npn \filesep {\thepart-} + \cs_set_eq:NN \filekey\@gobble + \g@addto@macro\index@prologue{ + \cs_gset_nopar:Npn\@oddfoot{ + \parbox{\textwidth}{ + \strut\footnotesize + \raggedright{\bfseries File~Key:}~\filekey + } + } + \cs_set_eq:NN \@evenfoot\@oddfoot + } + \cs_gset_eq:NN \docincludeaux\relax + \cs_gset_nopar:Npn\@oddfoot{ + \expandafter\ifx\csname ver@\currentfile\endcsname\relax + File~\thepart :~{\ttfamily\currentfile}~ + \else + \GetFileInfo{\currentfile} + File~\thepart :~{\ttfamily\filename}~ + Date:~\ExplFileDate\ % space + Version~\ExplFileVersion + \fi + \hfill\thepage + } + \cs_set_eq:NN \@evenfoot \@oddfoot +} +% \end{macrocode} +% \end{macro} +% +% \subsection{At end document} +% +% Print all defined and documented macros/functions. +% +% \begin{macrocode} +\seq_new:N \g_doc_functions_seq +\seq_new:N \g_doc_macros_seq +\seq_new:N \g_doc_not_tested_seq +% \end{macrocode} +% +% \begin{macrocode} +\iow_open:Nn \g_write_func_stream { \jobname.cmds } +% \end{macrocode} +% +% \begin{macrocode} +\cs_new_nopar:Npn \doc_show_functions_defined: { + \bool_if:nT { \g_doc_implementation_bool && \g_doc_checkfunc_bool } { + \typeout{ ======================================== ^^J } + + \tl_clear:N \l_tmpa_tl + \seq_map_inline:Nn \g_doc_functions_seq { + \seq_if_in:NnT \g_doc_macros_seq {##1} { + \tl_put_right:Nn \l_tmpa_tl { ##1 ^^J } + \iow_now:Nn \g_write_func_stream { ##1 } + } + } + \iow_close:N \g_write_func_stream + \doc_functions_typeout:n { + Functions~both~documented~and~defined:^^J (In~order~of~being~documented) + } + + \seq_map_inline:Nn \g_doc_functions_seq { + \seq_if_in:NnF \g_doc_macros_seq {##1} { + \tl_put_right:Nn \l_tmpa_tl { ##1 ^^J } + } + } + \doc_functions_typeout:n { Functions~documented~but~not~defined: } + + \seq_map_inline:Nn \g_doc_macros_seq { + \seq_if_in:NnF \g_doc_functions_seq {##1} { + \tl_put_right:Nn \l_tmpa_tl { ##1 ^^J } + } + } + \doc_functions_typeout:n { Functions~defined~but~not~documented: } + + \typeout{ ======================================== } + } +} +\AtEndDocument{ \doc_show_functions_defined: } +% \end{macrocode} +% +% \begin{macrocode} +\cs_set_nopar:Npn \doc_functions_typeout:n #1 { + \tl_if_empty:NF \l_tmpa_tl { + \typeout{ + -------------------------------------- ^^J #1 ^^J + -------------------------------------- ^^J \l_tmpa_tl + } + \tl_clear:N \l_tmpa_tl + } +} +% \end{macrocode} +% +% \begin{macrocode} +\cs_new:Npn \doc_show_not_tested: { + \bool_if:NT \g_doc_checktest_bool + { + \bool_if:nT { !(\seq_if_empty_p:N \g_doc_not_tested_seq) || + !(\prop_if_empty_p:N \g_doc_missing_tests_prop) } + { + \tl_clear:N \l_tmpa_tl + \prop_if_empty:NF \g_doc_missing_tests_prop + { + \tl_put_right:Nn \l_tmpa_tl + { + ^^J^^JThe~ following~ macro(s)~ have~ incomplete~ tests:^^J + } + \prop_map_inline:Nn \g_doc_missing_tests_prop + { + \tl_put_right:Nn \l_tmpa_tl + {^^J\space\space\space\space ##1 + ^^J\space\space\space\space\space\space ##2} + } + } + \seq_if_empty:NF \g_doc_not_tested_seq + { + \tl_put_right:Nn \l_tmpa_tl + { + ^^J^^J + The~ following~ macro(s)~ do~ not~ have~ any~ tests:^^J + } + \seq_map_inline:Nn \g_doc_not_tested_seq + { + \clist_map_inline:nn {##1} + { + \tl_put_right:Nn \l_tmpa_tl {^^J\space\space\space\space ####1} + } + } + \int_set:Nn \l_tmpa_int {\etex_interactionmode:D} + \errorstopmode + \ClassError{l3doc}{\l_tmpa_tl}{} + \int_set:Nn \etex_interactionmode:D {\l_tmpa_int} + } + } + } +} +\AtEndDocument{ \doc_show_not_tested: } +% \end{macrocode} +% +% \subsection{Indexing} +% +% Fix index (for now): +% \begin{macrocode} +\g@addto@macro\theindex{\MakePrivateLetters} +\cs_set:Npn \verbatimchar {&} +% \end{macrocode} +% +% \begin{macrocode} +\setcounter{IndexColumns}{2} +% \end{macrocode} +% +% Set up the Index to use "\part" +% \begin{macrocode} +\IndexPrologue{ + \part*{Index} + \markboth{Index}{Index} + \addcontentsline{toc}{part}{Index} + The~italic~numbers~denote~the~pages~where~the~ + corresponding~entry~is~described,~ + numbers~underlined~point~to~the~definition,~ + all~others~indicate~the~places~where~it~is~used. +} +% \end{macrocode} +% +% +% \begin{macro}{\doc_special_main_index:n,\doc_special_main_index:o,\hdpgindex} +% Heiko's replacement to play nicely with |hypdoc|: +% \begin{macrocode} + +\cs_set_nopar:Npn \doc_special_main_index:n #1 { + \index{ + \@gobble#1 + \actualchar + \string\verb\quotechar*\verbatimchar#1\verbatimchar + \encapchar + hdpgindex{\thepage}{usage} + } +} +\cs_set_nopar:Npn \doc_special_main_index:o { \exp_args:No \doc_special_main_index:n } +% \end{macrocode} +% \begin{macrocode} +\cs_set_nopar:Npn \hdpgindex #1#2#3 { + \csname\ifx\\#2\\relax\else#2\fi\endcsname{ + \hyperlink{page.#1}{#3} + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +\g@addto@macro \PrintIndex { \AtEndDocument{ \typeout{^^J + ========================================^^J + Generate~the~index~by~executing^^J + \c_space_tl \c_space_tl \c_space_tl \c_space_tl + makeindex~-s~l3doc.ist~-o~\jobname.ind~\jobname.idx^^J + ========================================^^J + }} +} +% \end{macrocode} +% +% \subsection{Change history} +% +% Set the change history to use "\part". +% Allow control names to be hyphenated in here... +% \begin{macrocode} +\GlossaryPrologue{ + \part*{Change~History} + {\GlossaryParms\ttfamily\hyphenchar\font=`\-} + \markboth{Change~History}{Change~History} + \addcontentsline{toc}{part}{Change~History} +} +% \end{macrocode} +% +% \begin{macrocode} +\g@addto@macro \PrintChanges { \AtEndDocument{ \typeout{^^J + ========================================^^J + Generate~the~change~list~by~executing^^J + \c_space_tl \c_space_tl \c_space_tl \c_space_tl + makeindex~-s~gglo.ist~~-o~\jobname.gls~\jobname.glo^^J + ========================================^^J + }} +} +% \end{macrocode} +% +%^^A The standard \changes command modified slightly to better cope with +%^^A this multiple file document. +%^^A\def\changes@#1#2#3{% +%^^A \let\protect\@unexpandable@protect +%^^A \edef\@tempa{\noexpand\glossary{#2\space\currentfile\space#1\levelchar +%^^A \ifx\saved@macroname\@empty +%^^A \space +%^^A \actualchar +%^^A \generalname +%^^A \else +%^^A \expandafter\@gobble +%^^A \saved@macroname +%^^A \actualchar +%^^A \string\verb\quotechar*% +%^^A \verbatimchar\saved@macroname +%^^A \verbatimchar +%^^A \fi +%^^A :\levelchar #3}}% +%^^A \@tempa\endgroup\@esphack} +% +% \subsection{cfg} +% +% \begin{macrocode} +\bool_if:NTF \g_doc_full_bool { + \RecordChanges + \CodelineIndex + \EnableCrossrefs + \AlsoImplementation +}{ + \CodelineNumbered + \DisableCrossrefs + \OnlyDescription +} +% \end{macrocode} +% +% +% \begin{macrocode} +%</class> +% \end{macrocode} +% +% +% \subsection{Makeindex configuration} +% +% The makeindex style "l3doc.ist" is used in place of the usual +% "gind.ist" to ensure that I is used in the sequence I J K +% not I II II, which would be the default makeindex behaviour. +% +% Will: Do we need this? +% +% \begin{macrocode} +%<*docist> +actual '=' +quote '!' +level '#' +preamble +"\n \\begin{theindex} \n \\makeatletter\\scan@allowedfalse\n" +postamble +"\n\n \\end{theindex}\n" +item_x1 "\\efill \n \\subitem " +item_x2 "\\efill \n \\subsubitem " +delim_0 "\\pfill " +delim_1 "\\pfill " +delim_2 "\\pfill " +% The next lines will produce some warnings when +% running Makeindex as they try to cover two different +% versions of the program: +lethead_prefix "{\\bfseries\\hfil " +lethead_suffix "\\hfil}\\nopagebreak\n" +lethead_flag 1 +heading_prefix "{\\bfseries\\hfil " +heading_suffix "\\hfil}\\nopagebreak\n" +headings_flag 1 + +% and just for source3: +% Remove R so I is treated in sequence I J K not I II III +page_precedence "rnaA" +%</docist> +% \end{macrocode} +% +% \section{Testing} +%\ExplSyntaxOn +%\cs_set_eq:NN\g_saved_doc_functions_seq\g_doc_functions_seq +%\cs_set_eq:NN\g_saved_doc_macros_seq\g_doc_macros_seq +%\ExplSyntaxOff +% +% \begin{function}{\example_foo:N|\example_foo:c} +% \begin{syntax} +% "\example_foo:N" <arg1> +% \end{syntax} +% <0123456789> <\0\1\2\3\4\5\6\7\8\9> \Arg{arg1} ":(" +% \end{function} +% +% \begin{function}{ \foo | \foo: | \foo:x | \barrz: } +% \begin{syntax} +% "\example_foo:N" <arg1> +% \end{syntax} +% <0123456789> <\0\1\2\3\4\5\6\7\8\9> +% \end{function} +% +% \begin{function}{\foo:N / (TF) | \foo_if:c / (TF) (EXP)} +% Test. +% \end{function} +% +% \begin{function}[EXP]{\fffoo:N} +% Test. +% \end{function} +% \begin{function}[TF]{\ffffoo:N} +% Test. +% \end{function} +% \begin{function}[pTF]{\ffoo:N} +% Test. +% \end{function} +% +% \begin{function}{ \bar / (EXP) | \bar: / (EXP) | \bar:x / (EXP) | } +% \begin{syntax} +% "\example_foo:N" <arg1> +% \end{syntax} +% <0123456789> <\0\1\2\3\4\5\6\7\8\9> +% \end{function} +% +% \begin{macro}{ \foo , \foo: , \foo:x } +% Testing. +% \end{macro} +% +% \bigskip\bigskip +% +% \begin{macro}[aux]{ \foo_aux: } +% Testing. +% \end{macro} +% +% \bigskip\bigskip +% +% \begin{macro}[TF]{ \foo_if:c } +% Testing. +% \end{macro} +% +% \begin{macro}[internal]{ \foo_if:d } +% Testing. +% \end{macro} +% +% \bigskip\bigskip +% +% \begin{macro}{\aaaa_bbbb_cccc_dddd_eeee_ffff_gggg_hhhh} +% Long macro names need to be printed in a shorter font. +% \begin{macrocode} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\c_minus_one, +% \c_zero, +% \c_one, +% \c_two, +% \c_three, +% \c_four, +% \c_five, +% \c_six, +% \c_seven, +% \c_eight, +% \c_nine, +% \c_ten, +% \c_eleven, +% \c_sixteen, +% \c_thirty_two, +% \c_hundred_one, +% \c_twohundred_fifty_five, +% \c_twohundred_fifty_six, +% \c_thousand, +% \c_ten_thousand, +% \c_ten_thousand_one} +% \begin{arguments} +% \item name +% \item parameters +% \end{arguments} +% Another test. +% \end{macro} +% +% +%\ExplSyntaxOn +%\cs_set_eq:NN\g_doc_functions_seq\g_saved_doc_functions_seq +%\cs_set_eq:NN\g_doc_macros_seq\g_saved_doc_macros_seq +%\ExplSyntaxOff +% +% +% \subsection{Macros} +% \raggedright +% \ExplSyntaxOn +% \seq_map_inline:Nn \g_doc_macros_seq { `\texttt{#1}' \quad } +% \ExplSyntaxOff +% +% \subsection{Functions} +% \ExplSyntaxOn +% \seq_map_inline:Nn \g_doc_functions_seq { `\texttt{#1}' \quad } +% \ExplSyntaxOff +% +% \end{implementation} +% +% \PrintIndex +% +% \endinput diff --git a/Master/texmf-dist/source/latex/l3kernel/l3expan.dtx b/Master/texmf-dist/source/latex/l3kernel/l3expan.dtx new file mode 100644 index 00000000000..5b37fd49aaf --- /dev/null +++ b/Master/texmf-dist/source/latex/l3kernel/l3expan.dtx @@ -0,0 +1,1416 @@ +% \iffalse meta-comment +% +%% File: l3expan.dtx Copyright (C) 1990-2011 The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +% +%<*driver|package> +\RequirePackage{l3names} +\GetIdInfo$Id: l3expan.dtx 2480 2011-06-20 17:25:23Z bruno $ + {L3 Experimental argument expansion} +%</driver|package> +%<*driver> +\documentclass[full]{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{^^A +% The \pkg{l3expan} package\\ Argument expansion^^A +% \thanks{This file describes v\ExplFileVersion, +% last revised \ExplFileDate.}^^A +% } +% +% \author{^^A +% The \LaTeX3 Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% +% \date{Released \ExplFileDate} +% +% \maketitle +% +% \begin{documentation} +% +% This module provides generic methods for expanding \TeX{} arguments in a +% systematic manner. The functions in this module all have prefix |exp|. +% +% Not all possible variations are implemented for every base +% function. Instead only those that are used within the \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. +% +% \section{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 +% second are a single tokens the third argument gets +% expanded once. If |\seq_gpush:No| was not defined the example +% above could be coded in the following way: +% \begin{verbatim} +% \exp_args:NNo \seq_gpush:Nn +% \g_file_name_stack +% \l_tmpa_tl +% \end{verbatim} +% In other words, the first argument to |\exp_args:NNo| is the base +% function and the other arguments are preprocessed and then passed to +% this base function. In the example the first argument to the base +% function should be a single token which is left unchanged while the +% second argument is expanded once. From this example we can also see +% how the variants are defined. They just expand into the appropriate +% |\exp_| function followed by the desired base function, \emph{e.g.} +% \begin{quote} +% |\cs_new_nopar:Npn\seq_gpush:No{\exp_args:NNo\seq_gpush:Nn}| +% \end{quote} +% Providing variants in this way in style files is uncritical as the +% |\cs_new_nopar:Npn| function will silently accept definitions whenever the +% 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 steps above may be automated by using the function +% |\cs_generate_variant:Nn|, described next. +% +% \section{Methods for defining variants} +% +% \begin{function}{\cs_generate_variant:Nn} +% \begin{syntax} +% \cs{cs_generate_variant:Nn} \meta{parent control sequence} +% ~~\Arg{variant argument specifiers} +% \end{syntax} +% This function is used to define argument-specifier variants of the +% \meta{parent control sequence} for \LaTeX3 code-level macros. The +% \meta{parent control sequence} is first separated into the +% \meta{base name} and \meta{original argument specifier}. The +% comma-separated list of \meta{variant argument specifiers} is +% then used to define variants of the +% \meta{original argument specifier} where these are not already +% defined. For each \meta{variant} given, a function is created +% which will expand its arguments as detailed and pass them +% to the \meta{parent control sequence}. So for example +% \begin{verbatim} +% \cs_set:Npn \foo:Nn #1#2 { code here } +% \cs_generate_variant:Nn \foo:Nn { c } +% \end{verbatim} +% will create a new function \cs{foo:cn} which will expand its first +% argument into a control sequence name and pass the result to +% \cs{foo:Nn}. Similarly +% \begin{verbatim} +% \cs_generate_variant:Nn \foo:Nn { NV , cV } +% \end{verbatim} +% would generate the functions \cs{foo:NV} and \cs{foo:cV} in the +% same way. The \cs{cs_generate_variant:Nn} function can only be +% applied if the \meta{parent control sequence} is already defined. If +% the \meta{parent control sequence} is protected then the new sequence +% will also be protected. The \meta{variant} is created globally, as +% is any \cs{exp_args:N\meta{variant}} function needed to carry out +% the expansion. +% \end{function} +% +% \section{Introducing the variants} +% +% The available internal functions for argument expansion come in two +% flavours, some of them are faster then others. Therefore it is usually +% best to follow the following guidelines when defining new functions +% that are supposed to come with variant forms: +% \begin{itemize} +% \item +% Arguments that might need expansion should come first in the list of +% arguments to make processing faster. +% \item +% Arguments that should consist of single tokens should come first. +% \item +% Arguments that need full expansion (\emph{i.e.}, are denoted +% with |x|) should be avoided if possible as they can not be +% processed expandably, \emph{i.e.}, functions of this type will +% not work correctly in arguments that are itself subject to |x| +% expansion. +% \item +% In general, unless in the last position, multi-token arguments +% |n|, |f|, and |o| will need special processing which is not fast. +% Therefore it is best to use the optimized functions, namely +% those that contain only |N|, |c|, |V|, and |v|, and, in the last +% position, |o|, |f|, with possible trailing |N| or |n|, which are +% not expanded. +% \end{itemize} +% +% The |V| type returns the value of a register, which can be one of +% |tl|, |num|, |int|, |skip|, |dim|, |toks|, or built-in \TeX{} +% registers. The |v| type is the same except it first creates a +% control sequence out of its argument before returning the +% value. This recent addition to the argument specifiers may shake +% things up a bit as most places where |o| is used will be replaced by +% |V|. The documentation you are currently reading will therefore +% require a fair bit of re-writing. +% +% In general, the programmer should not need to be concerned with +% expansion control. When simply using the content of a variable, +% functions with a |V| specifier should be used. For those referred to by +% (cs)name, the |v| specifier is available for the same purpose. Only when +% specific expansion steps are needed, such as when using delimited +% arguments, should the lower-level functions with |o| specifiers be employed. +% +% 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_tl b| into a control +% sequence. Furthermore we want to store the execution of it in a +% \meta{tl~var}. In this example we assume |\l_tmpa_tl| contains +% the text string |lur|. The straightforward approach is +% \begin{quote} +% |\tl_set:No \l_tmpb_tl {\cs_set_eq:Nc \aaa { b \l_tmpa_tl b } }| +% \end{quote} +% Unfortunately this only puts +% |\exp_args:NNc \cs_set_eq:NN \aaa {b \l_tmpa_tl b}| into |\l_tmpb_tl| +% and not |\cs_set_eq:NwN \aaa = \blurb| as we probably wanted. Using +% |\tl_set:Nx| is not an option as that will die horribly. Instead +% we can do a +% \begin{quote} +% |\tl_set:Nf \l_tmpb_tl {\cs_set_eq:Nc \aaa { b \l_tmpa_tl b } }| +% \end{quote} +% which puts the desired result in |\l_tmpb_tl|. It requires +% |\toks_set:Nf| to be defined as +% \begin{quote} +% |\cs_set_nopar:Npn \tl_set:Nf { \exp_args:NNf \tl_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! +% +% \section{Manipulating the first argument} +% +% These functions are described in detail: expansion of multiple tokens follows +% the same rules but is described in a shorter fashion. +% +% \begin{function}[EXP]{\exp_args:No} +% \begin{syntax} +% \cs{exp_args:No} \meta{function} \Arg{tokens} \Arg{tokens2} ... +% \end{syntax} +% This function absorbs two arguments (the \meta{function} name and +% the \meta{tokens}). The \meta{tokens} are expanded once, and the result +% is inserted in braces into the input stream \emph{after} reinsertion +% of the \meta{function}. Thus the \meta{function} may take more than +% one argument: all others will be left unchanged. +% \end{function} +% +% \begin{function}[EXP]{\exp_args:Nc, \exp_args:cc} +% \begin{syntax} +% \cs{exp_args:Nc} \meta{function} \Arg{tokens} \Arg{tokens2} ... +% \end{syntax} +% This function absorbs two arguments (the \meta{function} name and +% the \meta{tokens}). The \meta{tokens} are expanded until only characters +% remain, and are then turned into a control sequence. (An internal error +% will occur if such a conversion is not possible). The result +% is inserted into the input stream \emph{after} reinsertion +% of the \meta{function}. Thus the \meta{function} may take more than +% one argument: all others will be left unchanged. +% +% The |:cc| variant constructs the \meta{function} name in the same +% manner as described for the \meta{tokens}. +% \end{function} +% +% \begin{function}[EXP]{\exp_args:NV} +% \begin{syntax} +% \cs{exp_args:NV} \meta{function} \meta{variable} \Arg{tokens2} ... +% \end{syntax} +% This function absorbs two arguments (the names of the \meta{function} and +% the the \meta{variable}). The content of the \meta{variable} are recovered +% and placed inside braces into the input stream \emph{after} reinsertion +% of the \meta{function}. Thus the \meta{function} may take more than +% one argument: all others will be left unchanged. +% \end{function} +% +% \begin{function}[EXP]{\exp_args:Nv} +% \begin{syntax} +% \cs{exp_args:Nv} \meta{function} \Arg{tokens} \Arg{tokens2} ... +% \end{syntax} +% This function absorbs two arguments (the \meta{function} name and +% the \meta{tokens}). The \meta{tokens} are expanded until only characters +% remain, and are then turned into a control sequence. (An internal error +% will occur if such a conversion is not possible). This control sequence +% should +% be the name of a \meta{variable}. The content of the \meta{variable} are +% recovered and placed inside braces into the input stream \emph{after} +% reinsertion of the \meta{function}. Thus the \meta{function} may take more +% than one argument: all others will be left unchanged. +% \end{function} +% +% \begin{function}[EXP]{\exp_args:Nf} +% \begin{syntax} +% \cs{exp_args:Nf} \meta{function} \Arg{tokens} \Arg{tokens2} ... +% \end{syntax} +% This function absorbs two arguments (the \meta{function} name and +% the \meta{tokens}). The \meta{tokens} are fully expanded until the +% first non-expandable token or space is found, and the result +% is inserted in braces into the input stream \emph{after} reinsertion +% of the \meta{function}. Thus the \meta{function} may take more than +% one argument: all others will be left unchanged. +% \end{function} +% +% \begin{function}{\exp_args:Nx} +% \begin{syntax} +% \cs{exp_args:Nx} \meta{function} \Arg{tokens} \Arg{tokens2} ... +% \end{syntax} +% This function absorbs two arguments (the \meta{function} name and +% the \meta{tokens}) and exhaustively expands the \meta{tokens} +% second. The result is inserted in braces into the input stream +% \emph{after} reinsertion of the \meta{function}. +% Thus the \meta{function} may take more +% than one argument: all others will be left unchanged. +% \end{function} +% +% \section{Manipulating two arguments} +% +% \begin{function}[EXP] +% { +% \exp_args:NNo, +% \exp_args:NNc, +% \exp_args:NNv, +% \exp_args:NNV, +% \exp_args:NNf, +% \exp_args:Nco, +% \exp_args:Ncf, +% \exp_args:Ncc, +% \exp_args:NVV +% } +% \begin{syntax} +% \cs{exp_args:NNc} \meta{token1} \meta{token2} \Arg{tokens} +% \end{syntax} +% These optimized functions absorb three arguments and expand the second and +% third as detailed by their argument specifier. The first argument +% of the function is then the next item on the input stream, followed +% by the expansion of the second and third arguments. +% \end{function} +% +% \begin{function}[EXP] +% { +% \exp_args:Nno, +% \exp_args:NnV, +% \exp_args:Nnf, +% \exp_args:Noo, +% \exp_args:Noc, +% \exp_args:Nff, +% \exp_args:Nfo, +% \exp_args:Nnc +% } +% \begin{syntax} +% \cs{exp_args:Noo} \meta{token} \Arg{tokens1} \Arg{tokens2} +% \end{syntax} +% These functions absorb three arguments and expand the second and +% third as detailed by their argument specifier. The first argument +% of the function is then the next item on the input stream, followed +% by the expansion of the second and third arguments. +% These functions need special (slower) processing. +% \end{function} +% +% \begin{function} +% { +% \exp_args:NNx, +% \exp_args:Nnx, +% \exp_args:Ncx, +% \exp_args:Nox, +% \exp_args:Nxo, +% \exp_args:Nxx +% } +% \begin{syntax} +% \cs{exp_args:NNx} \meta{token1} \meta{token2} \Arg{tokens} +% \end{syntax} +% These functions absorb three arguments and expand the second and +% third as detailed by their argument specifier. The first argument +% of the function is then the next item on the input stream, followed +% by the expansion of the second and third arguments. These functions +% are not expandable. +% \end{function} +% +% \section{Manipulating three arguments} +% +% \begin{function}[EXP] +% { +% \exp_args:NNNo, +% \exp_args:NNNV, +% \exp_args:Nccc, +% \exp_args:NcNc, +% \exp_args:NcNo, +% \exp_args:Ncco +% } +% \begin{syntax} +% \cs{exp_args:NNNo} \meta{token1} \meta{token2} \meta{token3} +% ~~\Arg{tokens} +% \end{syntax} +% These optimized functions absorb four arguments and expand the second, third +% and fourth as detailed by their argument specifier. The first +% argument of the function is then the next item on the input stream, +% followed by the expansion of the second argument, \emph{etc}. +% \end{function} +% +% \begin{function}[EXP] +% { +% \exp_args:NNoo, +% \exp_args:NNno, +% \exp_args:Nnno, +% \exp_args:Nnnc, +% \exp_args:Nooo, +% } +% \begin{syntax} +% \cs{exp_args:NNNo} \meta{token1} \meta{token2} \meta{token3} +% ~~\Arg{tokens} +% \end{syntax} +% These functions absorb four arguments and expand the second, third +% and fourth as detailed by their argument specifier. The first +% argument of the function is then the next item on the input stream, +% followed by the expansion of the second argument, \emph{etc}. +% These functions need special (slower) processing. +% \end{function} +% +% \begin{function} +% { +% \exp_args:NNnx, +% \exp_args:NNox, +% \exp_args:Nnnx, +% \exp_args:Nnox, +% \exp_args:Noox, +% \exp_args:Ncnx, +% \exp_args:Nccx +% } +% \begin{syntax} +% \cs{exp_args:NNnx} \meta{token1} \meta{token2} \meta{tokens1} +% ~~\Arg{tokens2} +% \end{syntax} +% These functions absorb four arguments and expand the second, third +% and fourth as detailed by their argument specifier. The first +% argument of the function is then the next item on the input stream, +% followed by the expansion of the second argument, \emph{etc.} +% \end{function} +% +% \section{Unbraced expansion} +% +% \begin{function} +% { +% \exp_last_unbraced:Nf, +% \exp_last_unbraced:NV, +% \exp_last_unbraced:No, +% \exp_last_unbraced:Nv, +% \exp_last_unbraced:NcV, +% \exp_last_unbraced:NNV, +% \exp_last_unbraced:NNo, +% \exp_last_unbraced:Nfo, +% \exp_last_unbraced:NNNV, +% \exp_last_unbraced:NNNo +% } +% \begin{syntax} +% \cs{exp_last_unbraced:Nno} \meta{token} \meta{tokens1} \meta{tokens2} +% \end{syntax} +% These functions absorb the number of arguments given by their +% specification, carry out the expansion +% indicated and leave the the results in the input stream, with the +% last argument not surrounded by the usual braces. +% Of these, \cs{exp_last_unbraced:Nfo} needs special (slower) processing. +% \end{function} +% +% \begin{function}[EXP]{\exp_last_two_unbraced:Noo} +% \begin{syntax} +% \cs{exp_last_two_unbraced:Noo} \meta{token} \meta{tokens1} \Arg{tokens2} +% \end{syntax} +% This function absorbs three arguments and expand the second and third +% once. The first argument of the function is then the next item on the +% input stream, followed by the expansion of the second and third arguments, +% which are not wrapped in braces. +% This function needs special (slower) processing. +% \end{function} +% +% \begin{function}[EXP]{\exp_after:wN} +% \begin{syntax} +% \cs{exp_after:wN} \meta{token1} \meta{token2} +% \end{syntax} +% Carries out a single expansion of \meta{token2} prior to expansion +% of \meta{token1}. If \meta{token2} is a \TeX{} primitive, it will +% be executed rather than expanded, while if \meta{token2} has not +% expansion (for example, if it is a character) then it will be left +% unchanged. It is important to notice that \meta{token1} may be +% \emph{any} single token, including group-opening and -closing +% tokens (|{| or |}"| assuming normal \TeX{} category codes). Unless +% specifically required, expansion should be carried out using an +% appropriate argument specifier variant or the appropriate +% \cs{exp_arg:N} function. +% \begin{texnote} +% This is the \TeX{} primitive \cs{expandafter} renamed. +% \end{texnote} +% \end{function} +% +% \section{Preventing expansion} +% +% \begin{function}{\exp_not:N} +% \begin{syntax} +% \cs{exp_not:N} \meta{token} +% \end{syntax} +% Prevents expansion of the \meta{token} in a context where it would otherwise +% be expanded, for example an |x|-type argument. +% \begin{texnote} +% This is the \TeX{} \cs{noexpand} primitive. +% \end{texnote} +% \end{function} +% +% \begin{function}{\exp_not:c} +% \begin{syntax} +% \cs{exp_not:c} \Arg{tokens} +% \end{syntax} +% Expands the \meta{tokens} until only unexpandable content remains, and then +% converts this into a control sequence. Further expansion of this control +% sequence is then inhibited. +% \end{function} +% +% \begin{function}{\exp_not:n} +% \begin{syntax} +% \cs{exp_not:n} \Arg{tokens} +% \end{syntax} +% Prevents expansion of the \meta{tokens} in a context where they would +% otherwise +% be expanded, for example an |x|-type argument. +% \begin{texnote} +% This is the \eTeX{} \cs{unexpanded} primitive. +% \end{texnote} +% \end{function} +% +% \begin{function}{\exp_not:V} +% \begin{syntax} +% \cs{exp_not:V} \meta{variable} +% \end{syntax} +% Recovers the content of the \meta{variable}, then prevents expansion +% of the this material in a context where it would otherwise +% be expanded, for example an |x|-type argument. +% \end{function} +% +% \begin{function}{\exp_not:v} +% \begin{syntax} +% \cs{exp_not:v} \Arg{tokens} +% \end{syntax} +% Expands the \meta{tokens} until only unexpandable content remains, and then +% converts this into a control sequence (which should be a \meta{variable} +% name). The content of the \meta{variable} is recovered, and further +% expansion is prevented in a context where it would otherwise +% be expanded, for example an |x|-type argument. +% \end{function} +% +% \begin{function}{\exp_not:o} +% \begin{syntax} +% \cs{exp_not:o} \Arg{tokens} +% \end{syntax} +% Expands the \meta{tokens} once, then prevents any further expansion in a +% context where they would otherwise +% be expanded, for example an |x|-type argument. +% \end{function} +% +% \begin{function}[EXP]{\exp_not:f} +% \begin{syntax} +% \cs{exp_not:f} \meta{tokens} +% \end{syntax} +% Expands \meta{tokens} fully until the first unexpandable token +% is found. Expansion then stops, and the result of the expansion +% (including any tokens which were not expanded) is protected from +% further expansion. +% \end{function} +% +% \begin{function}[EXP]{\exp_stop_f:} +% \begin{syntax} +% \cs{function:f} \meta{tokens} \cs{exp_stop_f:} \meta{more tokens} +% \end{syntax} +% This function terminates an \texttt{f}-type expansion. Thus if +% a function \cs{function:f} starts an \texttt{f}-type expansion +% and all of \meta{tokens} are expandable \cs{exp_stop:f} will +% terminate the expansion of tokens even if \meta{more tokens} +% are also expandable. The function itself is an implicit space +% token. Inside an \texttt{x}-type expansion, it will retain its +% form, but when typeset it produces the underlying space (\verb*| |). +% \end{function} +% +% \section{Internal functions and variables} +% +% \begin{variable}{\l_exp_tl} +% 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. +% \end{variable} +% +% \begin{function}[EXP]{\exp_eval_register:N, \exp_eval_register:c} +% \begin{syntax} +% \cs{exp_eval_register:N} \meta{variable} +% \end{syntax} +% These functions evaluates a \meta{variable} as part of a |V| or |v| +% expansion (respectively), preceeded by \cs{c_zero} which stops +% the expansion of a previous \cs{tex_romannumeral:D}. +% A \meta{variable} might exist as +% one of two things: a parameter-less non-long, non-protected macro +% or a built-in \TeX{} register such as |\count|. +% \end{function} +% +% \begin{function}{\::n, \::N, \::c, \::o, \::f, \::x, \::v, \::V, \:::} +% \begin{syntax} +% |\cs_set_nopar:Npn \exp_args:Ncof { \::c \::o \::f \::: }| +% \end{syntax} +% Internal forms for the base expansion types. These names do \emph{not} +% conform to the general \LaTeX3 approach as this makes them more readily +% visible in the log and so forth. +% \end{function} +% +% \begin{function}{\cs_generate_internal_variant:n} +% \begin{syntax} +% \cs{cs_generate_internal_variant:n} \meta{arg~spec} +% \end{syntax} +% Tests if the function |\exp_args:N|\meta{arg~spec} exists, and defines it +% if it does not. The \meta{arg~spec} should be a series of one or more +% of the letters |N|, |c|, |n|, |o|, |V|, |v|, |f| and |x|. +% \end{function} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{l3expan} implementation} +% +% \begin{macrocode} +%<*initex|package> +% \end{macrocode} +% +% We start by ensuring that the required packages are loaded. +% \begin{macrocode} +%<*package> +\ProvidesExplPackage + {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +\package_check_loaded_expl: +%</package> +% \end{macrocode} +% +% \begin{macro}{\exp_after:wN} +% \begin{macro}{\exp_not:N} +% \begin{macro}{\exp_not:n} +% These are defined in \pkg{l3basics}. +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{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 |\cs_set_nopar: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.}) +% +% The definition of expansion functions with this technique happens +% in section~\ref{sec:gendef}. +% In section~\ref{sec:handtune} some common cases are coded by a more direct +% method for efficiency, typically using calls to |\exp_after:wN|. +% +% \begin{variable}{\l_exp_tl} +% We need a scratch token list variable. +% We don't use |tl| methods so that \pkg{l3expan} can be loaded earlier. +% \begin{macrocode} +\cs_new_nopar:Npn \l_exp_tl { } +% \end{macrocode} +% \end{variable} +% +% This code uses internal functions with names that start with |\::| +% to perform the expansions. All macros are |long| as this turned out +% to be desirable since the tokens undergoing expansion may be +% arbitrary user input. +% +% An argument manipulator |\::|\meta{Z} always has signature |#1\:::#2#3| +% where |#1| holds the remaining argument manipulations to be performed, +% |\:::| serves as an end marker for the list of manipulations, |#2| +% is the carried over result of the previous expansion steps and |#3| is +% the argument about to be processed. +% +% \begin{macro}[aux]{\exp_arg_next:nnn} +% \begin{macro}[aux]{\exp_arg_next_nobrace:nnn} +% |#1| is the result of an expansion step, |#2| is the remaining +% argument manipulations and |#3| is the current result of the +% expansion chain. This auxiliary function moves |#1| back after +% |#3| in the input stream and checks if any expansion is left to +% be done by calling |#2|. In by far the most cases we will require +% to add a set of braces to the result of an argument manipulation +% so it is more effective to do it directly here. Actually, so far +% only the |c| of the final argument manipulation variants does not +% require a set of braces. +% \begin{macrocode} +\cs_new:Npn \exp_arg_next:nnn #1#2#3 { #2 \::: { #3 {#1} } } +\cs_new:Npn \exp_arg_next_nobrace:nnn #1#2#3 { #2 \::: { #3 #1 } } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[int]{\:::} +% The end marker is just another name for the identity function. +% \begin{macrocode} +\cs_new:Npn \::: #1 {#1} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int]{\::n} +% This function is used to skip an argument that doesn't need to +% be expanded. +% \begin{macrocode} +\cs_new:Npn \::n #1 \::: #2#3 { #1 \::: { #2 {#3} } } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int]{\::N} +% This function is used to skip an argument that consists of a +% single token and doesn't need to be expanded. +% \begin{macrocode} +\cs_new:Npn \::N #1 \::: #2#3 { #1 \::: {#2#3} } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int]{\::c} +% This function is used to skip an argument that is turned into +% as control sequence without expansion. +% \begin{macrocode} +\cs_new:Npn \::c #1 \::: #2#3 + { \exp_after:wN \exp_arg_next_nobrace:nnn \cs:w #3 \cs_end: {#1} {#2} } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int]{\::o} +% This function is used to expand an argument once. +% \begin{macrocode} +\cs_new:Npn \::o #1 \::: #2#3 + { \exp_after:wN \exp_arg_next:nnn \exp_after:wN {#3} {#1} {#2} } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\::f} +% \begin{macro}{\exp_stop_f:} +% This function is used to expand a token list until the first +% unexpandable token is found. The underlying |\tex_romannumeral:D -`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. We introduce |\exp_stop_f:| +% to mark such an end of expansion marker; 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 |\cs_set_eq:Nc \aaa { b \l_tmpa_tl b }| +% into |\cs_set_eq:NwN \aaa = \blurb| which then turned out to contain +% the non-expandable token |\cs_set_eq:NwN|. Since the expansion of +% |\tex_romannumeral:D -`0| is \meta{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} +\cs_new:Npn \::f #1 \::: #2#3 + { + \exp_after:wN \exp_arg_next:nnn + \exp_after:wN { \tex_romannumeral:D -`0 #3 } + {#1} {#2} + } +\use:nn { \cs_new_eq:NN \exp_stop_f: } { ~ } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[int]{\::x} +% This function is used to expand an argument fully. +% \begin{macrocode} +\cs_new_protected:Npn \::x #1 \::: #2#3 + { + \cs_set_nopar:Npx \l_exp_tl { {#3} } + \exp_after:wN \exp_arg_next:nnn \l_exp_tl {#1} {#2} + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int]{\::v} +% \begin{macro}[int]{\::V} +% These functions return the value of a register, i.e., one of +% |tl|, |num|, |int|, |skip|, |dim| and |muskip|. The |V| version +% expects a single token whereas |v| like |c| creates a csname from +% its argument given in braces and then evaluates it as if it was a +% |V|. The primitive \cs{tex_romannumeral:D} sets off an expansion +% similar to an |f| type expansion, which we will terminate using +% \cs{c_zero}. The argument is returned in braces. +% \begin{macrocode} +\cs_new:Npn \::V #1 \::: #2#3 + { + \exp_after:wN \exp_arg_next:nnn + \exp_after:wN { \tex_romannumeral:D \exp_eval_register:N #3 } + {#1} {#2} +} +\cs_new:Npn \::v # 1\::: #2#3 + { + \exp_after:wN \exp_arg_next:nnn + \exp_after:wN { \tex_romannumeral:D \exp_eval_register:c {#3} } + {#1} {#2} + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[int]{\exp_eval_register:N, \exp_eval_register:c} +% \begin{macro}[aux]{\exp_eval_error_msg:w} +% This function evaluates a register. Now a register might exist as +% one of two things: A parameter-less macro or a built-in \TeX{} +% register such as |\count|. For the \TeX{} registers we have to +% utilize a |\tex_the:D| whereas for the macros we merely have to +% expand them once. The trick is to find out when to use +% |\tex_the:D| and when not to. What we do here is try to find out +% whether the token will expand to something else when hit with +% |\exp_after:wN|. The technique is to compare the meaning of the +% register in question when it has been prefixed with |\exp_not:N| +% and the register itself. If it is a macro, the prefixed +% |\exp_not:N| will temporarily turn it into the primitive +% |\scan_stop:|. +% \begin{macrocode} +\cs_new_nopar:Npn \exp_eval_register:N #1 + { + \exp_after:wN \if_meaning:w \exp_not:N #1 #1 +% \end{macrocode} +% If the token was not a macro it may be a malformed variable from a +% |c| expansion in which case it is equal to the primitive +% |\scan_stop:|. In that case we throw an error. We could let \TeX{} +% do it for us but that would result in the rather obscure +% \begin{quote} +% |! You can't use `\relax' after \the.| +% \end{quote} +% which while quite true doesn't give many hints as to what actually +% went wrong. We provide something more sensible. +% \begin{macrocode} + \if_meaning:w \scan_stop: #1 + \exp_eval_error_msg:w + \fi: +% \end{macrocode} +% The next bit requires some explanation. The function must be +% initiated by the primitive \cs{tex_romannumeral:D} and we want to +% terminate this expansion chain by inserting the \cs{c_zero} integer +% constant. However, we have to expand the register |#1| before we do +% that. If it is a \TeX{} register, we need to execute the sequence +% |\exp_after:wN \c_zero \tex_the:D #1| and if it is a macro we +% need to execute |\exp_after:wN \c_zero #1|. We therefore issue +% the longer of the two sequences and if the register is a macro, we +% remove the |\tex_the:D|. +% \begin{macrocode} + \else: + \exp_after:wN \use_i_ii:nnn + \fi: + \exp_after:wN \c_zero \tex_the:D #1 + } +\cs_new_nopar:Npn \exp_eval_register:c #1 + { \exp_after:wN \exp_eval_register:N \cs:w #1 \cs_end: } +% \end{macrocode} +% Clean up nicely, then call the undefined control sequence. The +% result is an error message looking like this: +% \begin{verbatim} +% ! Undefined control sequence. +% \exp_eval_error_msg:w ...erroneous variable used! +% +% l.55 \tl_set:Nv \l_tmpa_tl {undefined_tl} +% \end{verbatim} +% \begin{macrocode} +\group_begin:% +\tex_catcode:D`\!=11\scan_stop:% +\tex_catcode:D`\ =11\scan_stop:% +\cs_new:Npn\exp_eval_error_msg:w#1\tex_the:D#2{% +\fi:\fi:\exp_after:wN\c_zero\erroneous variable used!}% +\group_end:% +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Hand-tuned definitions} +% \label{sec:handtune} +% +% One of the most important features of these functions is that they +% are fully expandable and therefore allow to prefix them with +% |\pref_global:D| for example. +% +% \begin{macro}{\exp_args:No} +% \begin{macro}{\exp_args:NNo} +% \begin{macro}{\exp_args:NNNo} +% Those lovely runs of expansion! +% \begin{macrocode} +\cs_new:Npn \exp_args:No #1#2 { \exp_after:wN #1 \exp_after:wN {#2} } +\cs_new:Npn \exp_args:NNo #1#2#3 + { \exp_after:wN #1 \exp_after:wN #2 \exp_after:wN {#3} } +\cs_new:Npn \exp_args:NNNo #1#2#3#4 + { \exp_after:wN #1 \exp_after:wN#2 \exp_after:wN #3 \exp_after:wN {#4} } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\exp_args:Nc} +% In \pkg{l3basics} +%\end{macro} +% +% \begin{macro}{\exp_args:cc, \exp_args:NNc, \exp_args:Ncc, \exp_args:Nccc} +% Here are the functions that turn their argument into csnames but +% are expandable. +% \begin{macrocode} +\cs_new:Npn \exp_args:cc #1#2 + { \cs:w #1 \exp_after:wN \cs_end: \cs:w #2 \cs_end: } +\cs_new:Npn \exp_args:NNc #1#2#3 + { \exp_after:wN #1 \exp_after:wN #2 \cs:w # 3\cs_end: } +\cs_new:Npn \exp_args:Ncc #1#2#3 + { \exp_after:wN #1 \cs:w #2 \exp_after:wN \cs_end: \cs:w #3 \cs_end: } +\cs_new:Npn \exp_args:Nccc #1#2#3#4 + { + \exp_after:wN #1 + \cs:w #2 \exp_after:wN \cs_end: + \cs:w #3 \exp_after:wN \cs_end: + \cs:w #4 \cs_end: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\exp_args:Nf, \exp_args:NV, \exp_args:Nv, \exp_args:Nx} +% \begin{macrocode} +\cs_new:Npn \exp_args:Nf #1#2 + { \exp_after:wN #1 \exp_after:wN { \tex_romannumeral:D -`0 #2 } } +\cs_new:Npn \exp_args:Nv #1#2 + { + \exp_after:wN #1 \exp_after:wN + { \tex_romannumeral:D \exp_eval_register:c {#2} } + } +\cs_new:Npn \exp_args:NV #1#2 + { + \exp_after:wN #1 \exp_after:wN + { \tex_romannumeral:D \exp_eval_register:N #2 } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\exp_args:NNV,\exp_args:NNv,\exp_args:NNf, +% \exp_args:NVV, +% \exp_args:Ncf,\exp_args:Nco} +% Some more hand-tuned function with three arguments. +% If we force that an |o| argument always has braces, +% we could implement \cs{exp_args:Nco} with less tokens +% and only two arguments. +% \begin{macrocode} +\cs_new:Npn \exp_args:NNf #1#2#3 + { + \exp_after:wN #1 + \exp_after:wN #2 + \exp_after:wN { \tex_romannumeral:D -`0 #3 } + } +\cs_new:Npn \exp_args:NNv #1#2#3 + { + \exp_after:wN #1 + \exp_after:wN #2 + \exp_after:wN { \tex_romannumeral:D \exp_eval_register:c {#3} } + } +\cs_new:Npn \exp_args:NNV #1#2#3 + { + \exp_after:wN #1 + \exp_after:wN #2 + \exp_after:wN { \tex_romannumeral:D \exp_eval_register:N #3 } + } +\cs_new:Npn \exp_args:Nco #1#2#3 + { + \exp_after:wN #1 + \cs:w #2 \exp_after:wN \cs_end: + \exp_after:wN {#3} + } +\cs_new:Npn \exp_args:Ncf #1#2#3 + { + \exp_after:wN #1 + \cs:w #2 \exp_after:wN \cs_end: + \exp_after:wN { \tex_romannumeral:D -`0 #3 } + } +\cs_new_nopar:Npn \exp_args:NVV #1#2#3 + { + \exp_after:wN #1 + \exp_after:wN { \tex_romannumeral:D \exp_after:wN + \exp_eval_register:N \exp_after:wN #2 \exp_after:wN } + \exp_after:wN { \tex_romannumeral:D \exp_eval_register:N #3 } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\exp_args:Ncco, +% \exp_args:NcNc, +% \exp_args:NcNo, +% \exp_args:NNNV} +% A few more that we can hand-tune. +% \begin{macrocode} +\cs_new:Npn \exp_args:NNNV #1#2#3#4 + { + \exp_after:wN #1 + \exp_after:wN #2 + \exp_after:wN #3 + \exp_after:wN { \tex_romannumeral:D \exp_eval_register:N #4 } + } +\cs_new:Npn \exp_args:NcNc #1#2#3#4 + { + \exp_after:wN #1 + \cs:w #2 \exp_after:wN \cs_end: + \exp_after:wN #3 + \cs:w #4 \cs_end: + } +\cs_new:Npn \exp_args:NcNo #1#2#3#4 + { + \exp_after:wN #1 + \cs:w #2 \exp_after:wN \cs_end: + \exp_after:wN #3 + \exp_after:wN {#4} + } +\cs_new:Npn \exp_args:Ncco #1#2#3#4 + { + \exp_after:wN #1 + \cs:w #2 \exp_after:wN \cs_end: + \cs:w #3 \exp_after:wN \cs_end: + \exp_after:wN {#4} + } +% \end{macrocode} +% \end{macro} +% +% \subsection{Definitions with the automated technique} +% \label{sec:gendef} +% +% Some of these could be done more efficiently, but the complexity of +% coding then becomes an issue. Notice that the auto-generated functions +% are all not long: they don't actually take any arguments themselves. +% +% \begin{macro}{\exp_args:Nx} +% \begin{macrocode} +\cs_new_protected_nopar:Npn \exp_args:Nx { \::x \::: } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\exp_args:NNx, +% \exp_args:Nnc, +% \exp_args:Ncx, +% \exp_args:Nfo,\exp_args:Nff, +% \exp_args:Nnf,\exp_args:Nno,\exp_args:NnV,\exp_args:Nnx, +% \exp_args:Noo,\exp_args:Noc,\exp_args:Nox, +% \exp_args:Nxo,\exp_args:Nxx} +% Here are the actual function definitions, using the helper functions +% above. +% \begin{macrocode} +\cs_new_nopar:Npn \exp_args:Nnc { \::n \::c \::: } +\cs_new_nopar:Npn \exp_args:Nfo { \::f \::o \::: } +\cs_new_nopar:Npn \exp_args:Nff { \::f \::f \::: } +\cs_new_nopar:Npn \exp_args:Nnf { \::n \::f \::: } +\cs_new_nopar:Npn \exp_args:Nno { \::n \::o \::: } +\cs_new_nopar:Npn \exp_args:NnV { \::n \::V \::: } +\cs_new_nopar:Npn \exp_args:Noc { \::o \::c \::: } +\cs_new_nopar:Npn \exp_args:Noo { \::o \::o \::: } +\cs_new_protected_nopar:Npn \exp_args:NNx { \::N \::x \::: } +\cs_new_protected_nopar:Npn \exp_args:Ncx { \::c \::x \::: } +\cs_new_protected_nopar:Npn \exp_args:Nnx { \::n \::x \::: } +\cs_new_protected_nopar:Npn \exp_args:Nox { \::o \::x \::: } +\cs_new_protected_nopar:Npn \exp_args:Nxo { \::x \::o \::: } +\cs_new_protected_nopar:Npn \exp_args:Nxx { \::x \::x \::: } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\exp_args:Nccx, +% \exp_args:Ncnx, +% \exp_args:NNno, +% \exp_args:Nnno, +% \exp_args:Nnnx, +% \exp_args:Nnox, +% \exp_args:Nooo, +% \exp_args:Noox, +% \exp_args:Nnnc, +% \exp_args:NNnx, +% \exp_args:NNoo, +% \exp_args:NNox} +% \begin{macrocode} +\cs_new_nopar:Npn \exp_args:NNno { \::N \::n \::o \::: } +\cs_new_nopar:Npn \exp_args:NNoo { \::N \::o \::o \::: } +\cs_new_nopar:Npn \exp_args:Nnnc { \::n \::n \::c \::: } +\cs_new_nopar:Npn \exp_args:Nnno { \::n \::n \::o \::: } +\cs_new_nopar:Npn \exp_args:Nooo { \::o \::o \::o \::: } +\cs_new_protected_nopar:Npn \exp_args:NNnx { \::N \::n \::x \::: } +\cs_new_protected_nopar:Npn \exp_args:NNox { \::N \::o \::x \::: } +\cs_new_protected_nopar:Npn \exp_args:Nnnx { \::n \::n \::x \::: } +\cs_new_protected_nopar:Npn \exp_args:Nnox { \::n \::o \::x \::: } +\cs_new_protected_nopar:Npn \exp_args:Nccx { \::c \::c \::x \::: } +\cs_new_protected_nopar:Npn \exp_args:Ncnx { \::c \::n \::x \::: } +\cs_new_protected_nopar:Npn \exp_args:Noox { \::o \::o \::x \::: } +% \end{macrocode} +% \end{macro} +% +% \subsection{Last-unbraced versions} +% +% \begin{macro}[aux]{\exp_arg_last_unbraced:nn} +% \begin{macro}[aux]{\::f_unbraced} +% \begin{macro}[aux]{\::o_unbraced} +% \begin{macro}[aux]{\::V_unbraced} +% \begin{macro}[aux]{\::v_unbraced} +% There are a few places where the last argument needs to be available +% unbraced. First some helper macros. +% \begin{macrocode} +\cs_new:Npn \exp_arg_last_unbraced:nn #1#2 { #2#1 } +\cs_new:Npn \::f_unbraced \::: #1#2 + { + \exp_after:wN \exp_arg_last_unbraced:nn + \exp_after:wN { \tex_romannumeral:D -`0 #2 } {#1} + } +\cs_new:Npn \::o_unbraced \::: #1#2 + { \exp_after:wN \exp_arg_last_unbraced:nn \exp_after:wN {#2} {#1} } +\cs_new:Npn \::V_unbraced \::: #1#2 + { + \exp_after:wN \exp_arg_last_unbraced:nn + \exp_after:wN { \tex_romannumeral:D \exp_eval_register:N #2 } {#1} + } +\cs_new:Npn \::v_unbraced \::: #1#2 + { + \exp_after:wN \exp_arg_last_unbraced:nn + \exp_after:wN { \tex_romannumeral:D \exp_eval_register:c {#2} } {#1} + } +% \end{macrocode} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +% +% \begin{macro}{\exp_last_unbraced:NV} +% \begin{macro}{\exp_last_unbraced:Nv} +% \begin{macro}{\exp_last_unbraced:Nf} +% \begin{macro}{\exp_last_unbraced:No} +% \begin{macro}{\exp_last_unbraced:NcV} +% \begin{macro}{\exp_last_unbraced:NNV} +% \begin{macro}{\exp_last_unbraced:NNo} +% \begin{macro}{\exp_last_unbraced:Noo} +% \begin{macro}{\exp_last_unbraced:Nfo} +% \begin{macro}{\exp_last_unbraced:NNNV} +% \begin{macro}{\exp_last_unbraced:NNNo} +% Now the business end: most of these are hand-tuned for speed, but the +% general system is in place. +% \begin{macrocode} +\cs_new:Npn \exp_last_unbraced:NV #1#2 + { \exp_after:wN #1 \tex_romannumeral:D \exp_eval_register:N #2 } +\cs_new:Npn \exp_last_unbraced:Nv #1#2 + { \exp_after:wN #1 \tex_romannumeral:D \exp_eval_register:c {#2} } +\cs_new:Npn \exp_last_unbraced:No #1#2 { \exp_after:wN #1 #2 } +\cs_new:Npn \exp_last_unbraced:Nf #1#2 + { \exp_after:wN #1 \tex_romannumeral:D -`0 #2 } +\cs_new:Npn \exp_last_unbraced:NcV #1#2#3 + { + \exp_after:wN #1 + \cs:w #2 \exp_after:wN \cs_end: + \tex_romannumeral:D \exp_eval_register:N #3 + } +\cs_new:Npn \exp_last_unbraced:NNV #1#2#3 + { + \exp_after:wN #1 + \exp_after:wN #2 + \tex_romannumeral:D \exp_eval_register:N #3 + } +\cs_new:Npn \exp_last_unbraced:NNo #1#2#3 + { \exp_after:wN #1 \exp_after:wN #2 #3 } +\cs_new_nopar:Npn \exp_last_unbraced:Noo { \::o \::o_unbraced \::: } +\cs_new_nopar:Npn \exp_last_unbraced:Nfo { \::f \::o_unbraced \::: } +\cs_new:Npn \exp_last_unbraced:NNNV #1#2#3#4 + { + \exp_after:wN #1 + \exp_after:wN #2 + \exp_after:wN #3 + \tex_romannumeral:D \exp_eval_register:N #4 + } +\cs_new:Npn \exp_last_unbraced:NNNo #1#2#3#4 + { \exp_after:wN #1 \exp_after:wN #2 \exp_after:wN #3 #4 } +% \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}{\exp_last_two_unbraced:Noo} +% If |#2| is a single token then this can be implemented as +% \begin{verbatim} +% \cs_new:Npn \exp_last_two_unbraced:Noo #1 #2 #3 +% { \exp_after:wN \exp_after:wN \exp_after:wN #1 \exp_after:wN #2 #3 } +% \end{verbatim} +% However, for robustness this is not suitable. Instead, a bit of a +% shuffle is used to ensure that |#2| can be multiple tokens. +% \begin{macrocode} +\cs_new:Npn \exp_last_two_unbraced:Noo #1#2#3 + { \exp_after:wN \exp_last_two_unbraced_aux:nnN \exp_after:wN {#3} {#2} #1 } +\cs_new:Npn \exp_last_two_unbraced_aux:nnN #1#2#3 + { \exp_after:wN #3 #2 #1 } +% \end{macrocode} +% \end{macro} +% +% \subsection{Preventing expansion} +% +% \begin{macro}{\exp_not:o} +% \begin{macro}{\exp_not:f} +% \begin{macro}{\exp_not:V} +% \begin{macro}{\exp_not:v} +% \begin{macrocode} +\cs_new:Npn \exp_not:o #1 { \etex_unexpanded:D \exp_after:wN {#1} } +\cs_new:Npn \exp_not:f #1 + { \etex_unexpanded:D \exp_after:wN { \tex_romannumeral:D -`0 #1 } } +\cs_new:Npn \exp_not:V #1 + { + \etex_unexpanded:D \exp_after:wN + { \tex_romannumeral:D \exp_eval_register:N #1 } + } +\cs_new:Npn \exp_not:v #1 + { + \etex_unexpanded:D \exp_after:wN + { \tex_romannumeral:D \exp_eval_register:c {#1} } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\exp_not:c} +% A helper function. +% \begin{macrocode} +\cs_new:Npn \exp_not:c #1 { \exp_after:wN \exp_not:N \cs:w #1 \cs_end: } +% \end{macrocode} +% \end{macro} +% +% \subsection{Defining function variants} +% +% \begin{macro}{\cs_generate_variant:Nn} +% \begin{macro}[aux]{\cs_generate_variant_aux:nnNNn} +% \begin{macro}[aux]{\cs_generate_variant_aux:Nnnw} +% \begin{macro}[aux]{\cs_generate_variant_aux:NNn} +% \begin{macro}[aux]{\cs_generate_variant_aux:N} +% \begin{arguments} +% \item Base form of a function; \emph{e.g.},~|\tl_set:Nn| +% \item One or more variant argument specifiers; e.g., |{Nx,c,cx}| +% \end{arguments} +% Split up the original base function to grab its name and signature +% consisting of $k$ letters. Then we wish to iterate through the list +% of variant argument specifiers, and for each one construct a new +% function name using the original base name, the variant signature +% consisting of $l$ letters and the last $k-l$ letters of the base +% signature. For example, for a base function |\tl_set:Nn| which +% needs a |c| variant form, we want the new signature to be |cn|. +% \begin{macrocode} +\cs_new_protected:Npn \cs_generate_variant:Nn #1 + { + \chk_if_exist_cs:N #1 + \cs_split_function:NN #1 \cs_generate_variant_aux:nnNNn + #1 + } +% \end{macrocode} +% We discard the boolean |#3| and then set off a loop through the desired +% variant forms. The original function is retained as |#4| for efficiency. +% \begin{macrocode} +\cs_new:Npn \cs_generate_variant_aux:nnNNn #1#2#3#4#5 + { \cs_generate_variant_aux:Nnnw #4 {#1}{#2} #5 , ? , \q_recursion_stop } +% \end{macrocode} +% Next is the real work to be done. We now have 1: original function, +% 2: base name, 3: base signature, 4: beginning of variant signature. +% To construct the new +% csname and the |\exp_args:Ncc| form, we need the variant signature. +% In our example, we wanted to discard the first two letters of the +% base signature because the variant form started with |cc|. This is +% the same as putting first |cc| in the signature and then +% |\use_none:nn| followed by the base signature |NNn|. We therefore +% call a small loop that outputs an |n| for each letter in the variant +% signature and use this to call the correct |\use_none:| variant. +% +% Firstly though, we check whether to terminate the loop. +% Then build the variant function once, to avoid repeating this +% relatively expensive operation. Then recurse. +% \begin{macrocode} +\cs_new:Npn \cs_generate_variant_aux:Nnnw #1#2#3#4 , + { + \if:w ? #4 + \exp_after:wN \use_none_delimit_by_q_recursion_stop:w + \fi: + \exp_args:NNc \cs_generate_variant_aux:NNn + #1 + { #2 : #4 \use:c { use_none: \cs_generate_variant_aux:N #4 ? } #3 } + {#4} + \cs_generate_variant_aux:Nnnw #1 {#2} {#3} + } +% \end{macrocode} +% Check if the variant form has already been defined. +% If not, then define it and then additionally check if +% the |\exp_args:N| form needed is defined. +% Otherwise tell that it was already defined. +% \begin{macrocode} +\cs_new:Npn \cs_generate_variant_aux:NNn #1 #2 #3 + { + \cs_if_free:NTF #2 + { + \cs_generate_variant_aux:NNpx #1 #2 + { \exp_not:c { exp_args:N #3 } \exp_not:N #1 } + \cs_generate_internal_variant:n {#3} + } + { + \iow_log:x + { + Variant~\token_to_str:N #2~% + already~defined;~ not~ changing~ it~on~line~% + \tex_the:D \tex_inputlineno:D + } + } + } +% \end{macrocode} +% The small loop for defining the required number of |n|s. Break when +% seeing a |?|. +% \begin{macrocode} +\cs_new:Npn \cs_generate_variant_aux:N #1 + { + \if:w ? #1 + \exp_after:wN \use_none:nn + \fi: + n + \cs_generate_variant_aux:N + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}[aux]{\cs_generate_variant_aux:NNpx} +% \begin{macro}[aux]{\cs_generate_variant_aux:w} +% The idea here is to pick up protected parent functions, using the +% nature of the meaning string that they generate. The test here is +% almost the same as \cs{tl_if_empty:nTF}, but has to be hard-coded as +% that function is not yet available and because it has to match both +% long and short macros. +% \begin{macrocode} +\group_begin: + \tex_lccode:D `\Z = `\d \scan_stop: + \tex_lccode:D `\? =`\\ \scan_stop: + \tex_catcode:D `\P = 12 \scan_stop: + \tex_catcode:D `\R = 12 \scan_stop: + \tex_catcode:D `\O = 12 \scan_stop: + \tex_catcode:D `\T = 12 \scan_stop: + \tex_catcode:D `\E = 12 \scan_stop: + \tex_catcode:D `\C = 12 \scan_stop: + \tex_catcode:D `\Z = 12 \scan_stop: +\tex_lowercase:D + { + \group_end: + \cs_new_nopar:Npn \cs_generate_variant_aux:NNpx #1 + { + \exp_after:wN \cs_generate_variant_aux:w + \token_to_meaning:N #1 ? PROTECTEZ \q_stop + } + \cs_new:Npn \cs_generate_variant_aux:w #1 ? PROTECTEZ #2 \q_stop + { + \if_catcode:w a \etex_detokenize:D \exp_after:wN {#1} a + \exp_after:wN \cs_new_protected_nopar:Npx + \else: + \exp_after:wN \cs_new_nopar:Npx + \fi: + } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[int]{\cs_generate_internal_variant:n} +% \begin{macro}[aux]{\cs_generate_internal_variant_aux:N} +% Test if |exp_args:N #1| is already defined +% and if not define it via the +% |\::| commands using the chars in |#1| +% \begin{macrocode} +\cs_new_protected:Npn \cs_generate_internal_variant:n #1 + { + \cs_if_free:cT { exp_args:N #1 } + { + \cs_new:cpx { exp_args:N #1 } + { \cs_generate_internal_variant_aux:N #1 : } + } + } +% \end{macrocode} +% 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} +\cs_new:Npn \cs_generate_internal_variant_aux:N #1 + { + \exp_not:c { :: #1 } + \if_meaning:w #1 : + \exp_after:wN \use_none:n + \fi: + \cs_generate_internal_variant_aux:N + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +%\subsection{Variants which cannot be created earlier} +% +% \begin{macro}[pTF] +% {\str_if_eq:Vn, \str_if_eq:on, \str_if_eq:nV, \str_if_eq:no, \str_if_eq:VV} +% These cannot come earlier as they need \cs{cs_generate_variant:Nn}. +% \begin{macrocode} +\cs_generate_variant:Nn \str_if_eq_p:nn { V , o } +\cs_generate_variant:Nn \str_if_eq_p:nn { nV , no , VV } +\cs_generate_variant:Nn \str_if_eq:nnT { V , o } +\cs_generate_variant:Nn \str_if_eq:nnT { nV , no , VV } +\cs_generate_variant:Nn \str_if_eq:nnF { V , o } +\cs_generate_variant:Nn \str_if_eq:nnF { nV , no , VV } +\cs_generate_variant:Nn \str_if_eq:nnTF { V , o } +\cs_generate_variant:Nn \str_if_eq:nnTF { nV , no , VV } +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +%</initex|package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintIndex diff --git a/Master/texmf-dist/source/latex/l3kernel/l3file.dtx b/Master/texmf-dist/source/latex/l3kernel/l3file.dtx new file mode 100644 index 00000000000..7ec9de82c5e --- /dev/null +++ b/Master/texmf-dist/source/latex/l3kernel/l3file.dtx @@ -0,0 +1,418 @@ +% \iffalse meta-comment +% +%% File: l3file.dtx Copyright (C) 2009-2011 The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +% +%<*driver|package> +\RequirePackage{l3names} +\GetIdInfo$Id: l3file.dtx 2478 2011-06-19 21:34:23Z joseph $ + {L3 Experimental file operations} +%</driver|package> +%<*driver> +\documentclass[full]{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{^^A +% The \pkg{l3file} package\\ File operations^^A +% \thanks{This file describes v\ExplFileVersion, +% last revised \ExplFileDate.}^^A +% } +% +% \author{^^A +% The \LaTeX3 Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% +% \date{Released \ExplFileDate} +% +% \maketitle +% +% \begin{documentation} +% +% In contrast to the \pkg{l3io} module, which deals with the lowest +% level of file management, the \pkg{l3file} module provides a higher +% level interface for handling file contents. This involves providing +% convenient wrappers around many of the functions in \pkg{l3io} +% to make them more generally accessible. +% +% It is important to remember that \TeX{} will attempt to locate files using +% both the operating system path and entries in the \TeX{} file database (most +% \TeX{} systems use such a database). Thus the \enquote{current path} for +% \TeX{} is somewhat broader than that for other programs. +% +% \section{File operation functions} +% +% \begin{variable}{\g_file_current_name_tl} +% Contains the name of the current \LaTeX{} file. This variable +% should not be modified: it is intended for information only. It +% will be equal to \cs{c_job_name_tl} at the start of a \LaTeX{} +% run and will be modified each time a file is read using +% \cs{file_input:n}. +% \end{variable} +% +% \begin{function}[TF]{\file_if_exist:n} +% \begin{syntax} +% \cs{file_if_exist:nTF} \Arg{file name} \Arg{true code} \Arg{false code} +% \end{syntax} +% Searches for \meta{file name} using the current \TeX{} search +% path and the additional paths controlled by +% \cs{file_path_include:n}). The branching versions then leave +% either \meta{true code} or \meta{false code} in the input stream, +% as appropriate to the truth of the test and the variant of the +% function chosen. +% \begin{texnote} +% The \meta{file name} may contain both literal items and expandable +% content, which should on full expansion be the desired file name. +% The expansion occurs when \TeX{} searches for the file. +% \end{texnote} +% \end{function} +% +% \begin{function}{\file_add_path:nN} +% \begin{syntax} +% \cs{file_add_path:nN} \Arg{file name} \meta{tl var} +% \end{syntax} +% Searches for \meta{file name} in the path as detailed for +% \cs{file_if_exist:nTF}, and if found sets the \meta{tl var} the +% fully-qualified name of the file, \emph{i.e}.~the path and file name. +% If the file is not found then the \meta{tl var} will be empty. +% \begin{texnote} +% The \meta{file name} may contain both literal items and expandable +% content, which should on full expansion be the desired file name. +% The expansion occurs when \TeX{} searches for the file. +% \end{texnote} +% \end{function} +% +% \begin{function}{\file_input:n} +% \begin{syntax} +% \cs{file_input:n} \Arg{file name} +% \end{syntax} +% Searches for \meta{file name} in the path as detailed for +% \cs{file_if_exist:nTF}, and if found reads in the file as +% additional \LaTeX{} source. All files read are recorded +% for information and the file name stack is updated by this +% function. +% \begin{texnote} +% The \meta{file name} may contain both literal items and expandable +% content, which should on full expansion be the desired file name. +% The expansion occurs when \TeX{} searches for the file. +% \end{texnote} +% \end{function} +% +% \begin{function}{\file_path_include:n} +% \begin{syntax} +% \cs{file_path_include:n} \Arg{path} +% \end{syntax} +% Adds \meta{path} to the list of those used to search for files +% by the \cs{file_input:n} and \cs{file_if_exist:n} function. The +% assignment is local. +% \end{function} +% +% \begin{function}{\file_path_remove:n} +% \begin{syntax} +% \cs{file_path_remove:n} \Arg{path} +% \end{syntax} +% Removes \meta{path} from the list of those used to search for files +% by the \cs{file_input:n} and \cs{file_if_exist:n} function. The +% assignment is local. +% \end{function} +% +% \begin{function}{\file_list:} +% \begin{syntax} +% \cs{file_list:} +% \end{syntax} +% This function will list all files loaded using \cs{file_input:n} +% in the log file. +% \end{function} +% +% \section{Internal file functions} +% +% \begin{variable}{\g_file_stack_seq} +% Stores the stack of nested files loaded using \cs{file_input:n}. This +% is needed to restore the appropriate file name to +% \cs{g_file_current_name_tl} at the end of each file. +% \end{variable} +% +% \begin{variable}{\g_file_record_seq} +% Stores the name of every file loaded using \cs{file_input:n}. In +% contrast to \cs{g_file_stack_seq}, no items are ever removed from this +% sequence. +% \end{variable} +% +% \begin{variable}{\l_file_name_tl} +% Used to return the full name of a file for internal use. +% \end{variable} +% +% \begin{variable}{\l_file_search_path_seq} +% The sequence of file paths to search when loading a file. +% \end{variable} +% +% \begin{variable}{\l_file_search_path_saved_seq} +% When loaded on top of \LaTeXe{}, there is a need to save the search +% path so that \cs{input@path} can be used as appropriate. +% \end{variable} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{l3file} implementation} +% +% \TestFiles{m3file001} +% +% \begin{macrocode} +%<*initex|package> +% \end{macrocode} +% +% \begin{macrocode} +%<*package> +\ProvidesExplPackage + {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +\package_check_loaded_expl: +%</package> +% \end{macrocode} +% +% \begin{variable}{\g_file_current_name_tl} +% The name of the current file should be available at all times. +% \begin{macrocode} +\tl_new:N \g_file_current_name_tl +% \end{macrocode} +% For the format the file name needs to be picked up at the start of the +% file. In package mode the current file name is collected from \LaTeXe{}. +% \begin{macrocode} +%<*initex> +\tex_everyjob:D \exp_after:wN + { + \tex_the:D \tex_everyjob:D + \tl_gset:Nx \g_file_current_name_tl { \tex_jobname:D } + } +%</initex> +%<*package> +\tl_gset_eq:NN \g_file_current_name_tl \@currname +%</package> +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\g_file_stack_seq} +% The input list of files is stored as a sequence stack. +% \begin{macrocode} +\seq_new:N \g_file_stack_seq +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\g_file_record_seq} +% The total list of files used is recorded separately from the current file +% stack, as nothing is ever popped from this list. +% \begin{macrocode} +\seq_new:N \g_file_record_seq +% \end{macrocode} +% The current file name should be included in the file list! +% \begin{macrocode} +%<*initex> +\tex_everyjob:D \exp_after:wN + { + \tex_the:D \tex_everyjob:D + \seq_gput_right:NV \g_file_record_seq \g_file_current_name_tl + } +%</initex> +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_file_name_tl} +% Used to return the fully-qualified name of a file. +% \begin{macrocode} +\tl_new:N \l_file_name_tl +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_file_search_path_seq} +% The current search path. +% \begin{macrocode} +\seq_new:N \l_file_search_path_seq +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_file_search_path_saved_seq} +% The current search path has to be saved for package use. +% \begin{macrocode} +%<*package> +\seq_new:N \l_file_search_path_saved_seq +%</package> +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\file_add_path:nN} +% \begin{variable}{\g_file_test_stream} +% \begin{macro}[aux]{\file_add_path_search:nN} +% The way to test if a file exists is to try to open it: if it does not +% exist then \TeX{} will report end-of-file. For files which are in the +% current directory, this is straight-forward. For other locations, a +% search has to be made looking at each potential path in turn. The first +% location is of course treated as the correct one. If nothing is found, +% |#2| is returned empty. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \file_add_path:nN #1#2 + { + \ior_open:Nn \g_file_test_stream {#1} + \ior_if_eof:NTF \g_file_test_stream + { \file_add_path_search:nN {#1} #2 } + { + \ior_close:N \g_file_test_stream + \tl_set:Nx #2 {#1} + } + } +\cs_new_protected_nopar:Npn \file_add_path_search:nN #1#2 + { + \tl_clear:N #2 +%<*package> + \cs_if_exist:NT \input@path + { + \seq_set_eq:NN \l_file_search_path_saved_seq \l_file_search_path_seq + \clist_map_inline:Nn \input@path + { \seq_put_right:Nn \l_file_search_path_seq {##1} } + } +%</package> + \seq_map_inline:Nn \l_file_search_path_seq + { + \ior_open:Nn \g_file_test_stream { ##1 #1 } + \ior_if_eof:NF \g_file_test_stream + { + \tl_set:Nx #2 { ##1 #1 } + \seq_map_break: + } + } +%<*package> + \cs_if_exist:NT \input@path + { \seq_set_eq:NN \l_file_search_path_seq \l_file_search_path_saved_seq } +%</package> + \ior_close:N \g_file_test_stream + } +% \end{macrocode} +% \end{macro} +% \end{variable} +% \end{macro} +% +% \begin{macro}[TF]{\file_if_exist:n} +% The test for the existence of a file is a wrapper around the function to +% add a path to a file. If the file was found, the path will contain +% something, whereas if the file was not located then the return value +% will be empty. +% \begin{macrocode} +\prg_new_protected_conditional:Nnn \file_if_exist:n { T , F , TF } + { + \file_add_path:nN {#1} \l_file_name_tl + \tl_if_empty:NTF \l_file_name_tl + { \prg_return_false: } + { \prg_return_true: } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\file_input:n} +% Loading a file is done in a safe way, checking first that the file +% exists and loading only if it does. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \file_input:n #1 + { + \file_add_path:nN {#1} \l_file_name_tl + \tl_if_empty:NF \l_file_name_tl + { +%<*initex> + \seq_gput_right:Nx \g_file_record_seq {#1} +%</initex> +%<*package> + \@addtofilelist {#1} +%</package> + \seq_gpush:NV \g_file_stack_seq \g_file_current_name_tl + \tl_gset:Nn \g_file_current_name_tl {#1} + \exp_after:wN \tex_input:D \l_file_name_tl ~ + \seq_gpop:NN \g_file_stack_seq \g_file_current_name_tl + } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\file_path_include:n} +% \begin{macro}{\file_path_remove:n} +% Wrapper functions to manage the search path. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \file_path_include:n #1 + { + \seq_if_in:NnF \l_file_search_path_seq {#1} + { \seq_put_right:Nn \l_file_search_path_seq {#1} } + } +\cs_new_protected_nopar:Npn \file_path_remove:n #1 + { \seq_remove_all:Nn \l_file_search_path_seq {#1} } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\file_list:} +% A function to list all files used to the log. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \file_list: + { + \seq_remove_duplicates:N \g_file_record_seq + \iow_log:n { *~File~List~* } + \seq_map_inline:Nn \g_file_record_seq { \iow_log:n {##1} } + \iow_log:n { ************* } + } +% \end{macrocode} +% \end{macro} +% +% When used as a package, there is a need to hold onto the standard +% file list as well as the new one here. +% \begin{macrocode} +%<*package> +\AtBeginDocument + { + \clist_map_inline:Nn \@filelist + { \seq_put_right:Nn \g_file_record_seq {#1} } + } +%</package> +% \end{macrocode} +% +% \begin{macrocode} +%</initex|package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintIndex
\ No newline at end of file diff --git a/Master/texmf-dist/source/latex/l3kernel/l3final.dtx b/Master/texmf-dist/source/latex/l3kernel/l3final.dtx new file mode 100644 index 00000000000..bc37e2aaee4 --- /dev/null +++ b/Master/texmf-dist/source/latex/l3kernel/l3final.dtx @@ -0,0 +1,112 @@ +% \iffalse meta-comment +% +%% File: l3final.dtx Copyright (C) 1990-2011 The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +% +%<*driver|package> +\RequirePackage{l3names} +\GetIdInfo$Id: l3final.dtx 2478 2011-06-19 21:34:23Z joseph $ + {L3 Experimental format finalisation} +%</driver|package> +%<*driver> +\documentclass[full]{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{^^A +% The \pkg{l3final} package\\ Format finalisation^^A +% \thanks{This file describes v\ExplFileVersion, +% last revised \ExplFileDate.}^^A +% } +% +% \author{^^A +% The \LaTeX3 Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% +% \date{Released \ExplFileDate} +% +% \maketitle +% +% \begin{documentation} +% +% This module is the end of the \LaTeX3 format file. Currently, there +% is not a lot happening here. +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{l3final} Implementation} +% +% \begin{macrocode} +%<*initex> +% \end{macrocode} +% +% \begin{macro}{\par} +% \TeX{} has a nasty habit of inserting a command with the name \cs{par} +% so we had better make sure that that command at least has a definition. +% \begin{macrocode} +\cs_set_eq:NN \par \tex_par:D +% \end{macrocode} +% \end{macro} +% +% The very last job is to dump the format, taking care to first leave +% the code environment. +% \begin{macrocode} +\use:n + { + \char_set_catcode_space:n { 9 } + \char_set_catcode_space:n { 32 } + \char_set_catcode_math_subscript:n { 94 } + \char_set_catcode_other:n { 58 } + \char_set_catcode_active:n { 126 } + \tex_endlinechar:D = 13 \scan_stop: + \tex_dump:D + } +% \end{macrocode} +% +% \begin{macrocode} +%</initex> +% \end{macrocode} +% +% \end{implementation} +% +%\PrintIndex diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp.dtx new file mode 100644 index 00000000000..36ac323debd --- /dev/null +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp.dtx @@ -0,0 +1,5676 @@ +% \iffalse meta-comment +% +%% File: l3fp.dtx Copyright (C) 2010,2011 The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +% +%<*driver|package> +\RequirePackage{l3names} +\GetIdInfo$Id: l3fp.dtx 2478 2011-06-19 21:34:23Z joseph $ + {L3 Experimental floating-point operations} +%</driver|package> +%<*driver> +\documentclass[full]{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{^^A +% The \pkg{l3fp} package\\ Floating-point operations^^A +% \thanks{This file describes v\ExplFileVersion, +% last revised \ExplFileDate.}^^A +% } +% +% \author{^^A +% The \LaTeX3 Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% +% \date{Released \ExplFileDate} +% +% \maketitle +% +% \begin{documentation} +% +% A floating point number is one which is stored as a mantissa and +% a separate exponent. This module implements arithmetic using radix +% $10$ floating point numbers. This means that the mantissa should +% be a real number in the range $1 \le \expandafter\mathopen\string| +% x \expandafter\mathclose\string| < 10$, with the +% exponent given as an integer between $-99$ and $99$. In the +% input, the exponent part is represented starting with an \texttt{e}. +% As this is a low-level module, error-checking is minimal. Numbers +% which are too large for the floating point unit to handle will result +% in errors, either from \TeX{} or from \LaTeX{}. The \LaTeX{} code does not +% check that the input will not overflow, hence the possibility of a +% \TeX{} error. On the other hand, numbers which are too small will be +% dropped, which will mean that extra decimal digits will simply be +% lost. +% +% When parsing numbers, any missing parts will be interpreted as +% zero. So for example +%\begin{verbatim} +% \fp_set:Nn \l_my_fp { } +% \fp_set:Nn \l_my_fp { . } +% \fp_set:Nn \l_my_fp { - } +% \end{verbatim} +% will all be interpreted as zero values without raising an error. +% +% Operations which give an undefined result (such as division by +% $0$) will not lead to errors. Instead special marker values are +% returned, which can be tested for using fr example +% \cs{fp_if_undefined:N(TF)}. In this way it is possible to work with +% asymptotic functions without first checking the input. If these +% special values are carried forward in calculations they will be +% treated as $0$. +% +% Floating point numbers are stored in the \texttt{fp} floating point +% variable type. This has a standard range of functions for +% variable management. +% +% \section{Floating-point variables} +% +% \begin{function}{\fp_new:N, \fp_new:c} +% \begin{syntax} +% \cs{fp_new:N} \meta{floating point variable} +% \end{syntax} +% Creates a new \meta{floating point variable} or raises an error if +% the name is already taken. The declaration global. The +% \meta{floating point} will initially be set to |+0.000000000e0| +% (the zero floating point). +% \end{function} +% +% \begin{function}{\fp_const:Nn, \fp_const:cn} +% \begin{syntax} +% \cs{fp_const:Nn} \meta{floating point variable} \Arg{value} +% \end{syntax} +% Creates a new constant \meta{floating point variable} or raises an +% error if the name is already taken. The value of the +% \meta{floating point variable} will be set globally to the +% \meta{value}. +% \end{function} +% +% \begin{function}{\fp_set_eq:NN, \fp_set_eq:cN, \fp_set_eq:Nc, \fp_set_eq:cc} +% \begin{syntax} +% \cs{fp_set_eq:NN} \meta{fp var1} \meta{fp var2} +% \end{syntax} +% Sets the value of \meta{floating point variable1} equal to that of +% \meta{floating point variable2}. This assignment is restricted to the +% current \TeX{} group level. +% \end{function} +% +% \begin{function} +% {\fp_gset_eq:NN, \fp_gset_eq:cN, \fp_gset_eq:Nc, \fp_gset_eq:cc} +% \begin{syntax} +% \cs{fp_gset_eq:NN} \meta{fp var1} \meta{fp var2} +% \end{syntax} +% Sets the value of \meta{floating point variable1} equal to that of +% \meta{floating point variable2}. This assignment is global and so is +% not limited by the current \TeX{} group level. +% \end{function} +% +% \begin{function}{\fp_zero:N, \fp_zero:c} +% \begin{syntax} +% \cs{fp_zero:N} \meta{floating point variable} +% \end{syntax} +% Sets the \meta{floating point variable} to |+0.000000000e0| within +% the current scope. +% \end{function} +% +% \begin{function}{\fp_gzero:N, \fp_gzero:c} +% \begin{syntax} +% \cs{fp_gzero:N} \meta{floating point variable} +% \end{syntax} +% Sets the \meta{floating point variable} to |+0.000000000e0| globally. +% \end{function} +% +% \begin{function}{\fp_set:Nn, \fp_set:cn} +% \begin{syntax} +% \cs{fp_set:Nn} \meta{floating point variable} \Arg{value} +% \end{syntax} +% Sets the \meta{floating point variable} variable to \meta{value} +% within the scope of the current \TeX{} group. +% \end{function} +% +% \begin{function}{\fp_gset:Nn, \fp_gset:cn} +% \begin{syntax} +% \cs{fp_gset:Nn} \meta{floating point variable} \Arg{value} +% \end{syntax} +% Sets the \meta{floating point variable} variable to \meta{value} +% globally. +% \end{function} +% +% \begin{function}{\fp_set_from_dim:Nn, \fp_set_from_dim:cn} +% \begin{syntax} +% \cs{fp_set_from_dim:Nn} \meta{floating point variable} \Arg{dimexpr} +% \end{syntax} +% Sets the \meta{floating point variable} to the distance represented +% by the \meta{dimension expression} in the units points. This means +% that distances given in other units are first converted to points +% before being assigned to the \meta{floating point variable}. The +% assignment is local. +% \end{function} +% +% \begin{function}{\fp_gset_from_dim:Nn, \fp_gset_from_dim:cn} +% \begin{syntax} +% \cs{fp_gset_from_dim:Nn} \meta{floating point variable} \Arg{dimexpr} +% \end{syntax} +% Sets the \meta{floating point variable} to the distance represented +% by the \meta{dimension expression} in the units points. This means +% that distances given in other units are first converted to points +% before being assigned to the \meta{floating point variable}. The +% assignment is global. +% \end{function} +% +% \begin{function}[EXP]{\fp_use:N, \fp_use:c} +% \begin{syntax} +% \cs{fp_use:N} \meta{floating point variable} +% \end{syntax} +% Inserts the value of the \meta{floating point variable} into the +% input stream. The value will be given as a real number without any +% exponent part, and will always include a decimal point. For example, +% \begin{verbatim} +% \fp_new:Nn \test +% \fp_set:Nn \test { 1.234 e 5 } +% \fp_use:N \test +% \end{verbatim} +% will insert |12345.00000| into the input stream. +% As illustrated, a floating point will always be inserted with ten +% significant digits given. Very large and very small values will +% include additional zeros for place value. +% \end{function} +% +% \begin{function}{\fp_show:N, \fp_show:c} +% \begin{syntax} +% \cs{fp_show:N} \meta{floating point variable} +% \end{syntax} +% Displays the content of the \meta{floating point variable} on the +% terminal. +% \end{function} +% +% \section{Conversion of floating point values to other formats} +% +% It is useful to be able to convert floating point variables to +% other forms. These functions are expandable, so that the material +% can be used in a variety of contexts. The \cs{fp_use:N} function +% should also be consulted in this context, as it will insert the +% value of the floating point variable as a real number. +% +% \begin{function}[EXP]{\fp_to_dim:N, \fp_to_dim:c} +% \begin{syntax} +% \cs{fp_to_dim:N} \meta{floating point variable} +% \end{syntax} +% Inserts the value of the \meta{floating point variable} +% into the input stream converted into a dimension in points. +% \end{function} +% +% \begin{function}[EXP]{\fp_to_int:N, \fp_to_int:c} +% \begin{syntax} +% \cs{fp_to_int:N} \meta{floating point variable} +% \end{syntax} +% Inserts the integer value of the \meta{floating point variable} +% into the input stream. The decimal part of the number will not be +% included, but will be used to round the integer. +% \end{function} +% +% \begin{function}[EXP]{\fp_to_tl:N, \fp_to_tl:c} +% \begin{syntax} +% \cs{fp_to_tl:N} \meta{floating point variable} +% \end{syntax} +% Inserts a representation of the \meta{floating point variable} into +% the input stream as a token list. The representation follows the +% conventions of a pocket calculator: +% \begin{center} +% \ttfamily +% \begin{tabular}{r@{.}lr@{.}l} +% \toprule +% \multicolumn{2}{l}{\rmfamily{Floating point value}} & +% \multicolumn{2}{l}{\rmfamily{Representation}} \\ +% \midrule +% 1 & 234000000000e0 & 1 & 234 \\ +% -1 & 234000000000e0 & -1 & 234 \\ +% 1 & 234000000000e3 & \multicolumn{2}{l}{1234} \\ +% 1 & 234000000000e13 & \multicolumn{2}{l}{1234e13} \\ +% 1 & 234000000000e-1 & 0 & 1234 \\ +% 1 & 234000000000e-2 & 0 & 01234 \\ +% 1 & 234000000000e-3 & 1 & 234e-3 \\ +% \bottomrule +% \end{tabular} +% \end{center} +% Notice that trailing zeros are removed in this process, and that +% numbers which do not require a decimal part do \emph{not} include +% a decimal marker. +% \end{function} +% +% \section{Rounding floating point values} +% +% The module can round floating point values to either decimal places +% or significant figures using the usual method in which exact halves +% are rounded up. +% +% \begin{function}{\fp_round_figures:Nn, \fp_round_figures:cn} +% \begin{syntax} +% \cs{fp_round_figures:Nn} \meta{floating point variable} \Arg{target} +% \end{syntax} +% Rounds the \meta{floating point variable} to the \meta{target} number +% of significant figures (an integer expression). The rounding is +% carried out locally. +% \end{function} +% +% \begin{function}{\fp_ground_figures:Nn, \fp_ground_figures:cn} +% \begin{syntax} +% \cs{fp_ground_figures:Nn} \meta{floating point variable} \Arg{target} +% \end{syntax} +% Rounds the \meta{floating point variable} to the \meta{target} number +% of significant figures (an integer expression). The rounding is +% carried out globally. +% \end{function} +% +% \begin{function}{\fp_round_places:Nn, \fp_round_places:cn} +% \begin{syntax} +% \cs{fp_round_places:Nn} \meta{floating point variable} \Arg{target} +% \end{syntax} +% Rounds the \meta{floating point variable} to the \meta{target} number +% of decimal places (an integer expression). The rounding is +% carried out locally. +% \end{function} +% +% \begin{function}{\fp_ground_places:Nn, \fp_ground_places:cn} +% \begin{syntax} +% \cs{fp_ground_places:Nn} \meta{floating point variable} \Arg{target} +% \end{syntax} +% Rounds the \meta{floating point variable} to the \meta{target} number +% of decimal places (an integer expression). The rounding is +% carried out globally. +% \end{function} +% +% \section{Floating-point conditionals} +% +% \begin{function}[EXP,pTF]{\fp_if_undefined:N} +% \begin{syntax} +% \cs{fp_if_undefined_p:N} \meta{fixed-point} +% \cs{fp_if_undefined:NTF} \meta{fixed-point} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if \meta{floating point} is undefined (\emph{i.e.}~equal to the +% special \cs{c_undefined_fp} variable). The branching versions then +% leave either \meta{true code} or \meta{false code} in the input +% stream, as appropriate to the truth of the test and the variant of +% the function chosen. The logical truth of the test is left in the +% input stream by the predicate version. +% \end{function} +% +% \begin{function}[EXP]{\fp_if_zero:N} +% \begin{syntax} +% \cs{fp_if_zero_p:N} \meta{fixed-point} +% \cs{fp_if_zero:NTF} \meta{fixed-point} \Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if \meta{floating point} is equal to zero (\emph{i.e.}~equal to +% the special \cs{c_zero_fp} variable). The branching versions then +% leave either \meta{true code} or \meta{false code} in the input +% stream, as appropriate to the truth of the test and the variant of +% the function chosen. The logical truth of the test is left in the +% input stream by the predicate version. +% \end{function} +% +% \begin{function}[TF]{\fp_compare:nNn} +% \begin{syntax} +% \cs{fp_compare:nNnTF} +% ~~\Arg{floating point1} \meta{relation} \Arg{floating point2} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% This function compared the two \meta{floating point} values, which +% may be stored as \texttt{fp} variables, using the \meta{relation}: +% \begin{center} +% \begin{tabular}{ll} +% Equal & |=| \\ +% Greater than & |>| \\ +% Less than & |<| \\ +% \end{tabular} +% \end{center} +% Either \meta{true code} or \meta{false code} is then left in the +% input stream, as appropriate to the truth of the test and the variant +% of the function chosen. The tests treat undefined floating points as +% zero as the comparison is intended for real numbers only. +% \end{function} +% +% \begin{function}[TF]{\fp_compare:n} +% \begin{syntax} +% \cs{fp_compare:nTF} +% ~~\{ \meta{floating point1} \meta{relation} \meta{floating point2} \} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% This function compared the two \meta{floating point} values, which +% may be stored as \texttt{fp} variables, using the \meta{relation}: +% \begin{center} +% \begin{tabular}{ll} +% Equal & |=| or |==| \\ +% Greater than & |>| \\ +% Greater than or equal & |>=| \\ +% Less than & |<| \\ +% Less than or equal & |<=| \\ +% Not equal & |!=| \\ +% \end{tabular} +% \end{center} +% Either \meta{true code} or \meta{false code} is then left in the +% input stream, as appropriate to the truth of the test and the variant +% of the function chosen. The tests treat undefined floating points as +% zero as the comparison is intended for real numbers only. +% \end{function} +% +% \section{Unary floating-point operations} +% +% The unary operations alter the value stored within an \texttt{fp} +% variable. +% +% \begin{function}{\fp_abs:N, \fp_abs:c} +% \begin{syntax} +% \cs{fp_abs:N} \meta{floating point variable} +% \end{syntax} +% Converts the \meta{floating point variable} to its absolute value, +% assigning the result within the current \TeX\ group. +% \end{function} +% +% \begin{function}{\fp_gabs:N, \fp_gabs:c} +% \begin{syntax} +% \cs{fp_gabs:N} \meta{floating point variable} +% \end{syntax} +% Converts the \meta{floating point variable} to its absolute value, +% assigning the result globally. +% \end{function} +% +% \begin{function}{\fp_neg:N, \fp_neg:c} +% \begin{syntax} +% \cs{fp_neg:N} \meta{floating point variable} +% \end{syntax} +% Reverse the sign of the \meta{floating point variable}, assigning the +% result within the current \TeX\ group. +% \end{function} +% +% \begin{function}{\fp_gneg:N, \fp_gneg:c} +% \begin{syntax} +% \cs{fp_gneg:N} \meta{floating point variable} +% \end{syntax} +% Reverse the sign of the \meta{floating point variable}, assigning the +% result globally. +% \end{function} +% +% \section{Floating-point arithmetic} +% +% Binary arithmetic operations act on the value stored in an +% \texttt{fp}, so for example +% \begin{verbatim} +% \fp_set:Nn \l_my_fp { 1.234 } +% \fp_sub:Nn \l_my_fp { 5.678 } +% \end{verbatim} +% sets \cs{l_my_fp} to the result of $1.234 - 5.678$ +% (\emph{i.e.}~$-4.444$). +% +% \begin{function}{\fp_add:Nn, \fp_add:cn} +% \begin{syntax} +% \cs{fp_add:Nn} \meta{floating point} \Arg{value} +% \end{syntax} +% Adds the \meta{value} to the \meta{floating point}, making the +% assignment within the current \TeX{} group level. +% \end{function} +% +% \begin{function}{\fp_gadd:Nn, \fp_gadd:cn} +% \begin{syntax} +% \cs{fp_gadd:Nn} \meta{floating point} \Arg{value} +% \end{syntax} +% Adds the \meta{value} to the \meta{floating point}, making the +% assignment globally. +% \end{function} +% +% \begin{function}{\fp_sub:Nn, \fp_sub:cn} +% \begin{syntax} +% \cs{fp_sub:Nn} \meta{floating point} \Arg{value} +% \end{syntax} +% Subtracts the \meta{value} from the \meta{floating point}, making the +% assignment within the current \TeX{} group level. +% \end{function} +% +% \begin{function}{\fp_gsub:Nn, \fp_gsub:cn} +% \begin{syntax} +% \cs{fp_gsub:Nn} \meta{floating point} \Arg{value} +% \end{syntax} +% Subtracts the \meta{value} from the \meta{floating point}, making the +% assignment globally. +% \end{function} +% +% \begin{function}{\fp_mul:Nn, \fp_mul:cn} +% \begin{syntax} +% \cs{fp_mul:Nn} \meta{floating point} \Arg{value} +% \end{syntax} +% Multiples the \meta{floating point} by the \meta{value}, making the +% assignment within the current \TeX{} group level. +% \end{function} +% +% \begin{function}{\fp_gmul:Nn, \fp_gmul:cn} +% \begin{syntax} +% \cs{fp_gmul:Nn} \meta{floating point} \Arg{value} +% \end{syntax} +% Multiples the \meta{floating point} by the \meta{value}, making the +% assignment globally. +% \end{function} +% +% \begin{function}{\fp_div:Nn, \fp_div:cn} +% \begin{syntax} +% \cs{fp_div:Nn} \meta{floating point} \Arg{value} +% \end{syntax} +% Divides the \meta{floating point} by the \meta{value}, making the +% assignment within the current \TeX{} group level. If the \meta{value} +% is zero, the \meta{floating point} will be set to +% \cs{c_undefined_fp}. The assignment is local. +% \end{function} +% +% \begin{function}{\fp_gdiv:Nn, \fp_gdiv:cn} +% \begin{syntax} +% \cs{fp_gdiv:Nn} \meta{floating point} \Arg{value} +% \end{syntax} +% Divides the \meta{floating point} by the \meta{value}, making the +% assignment globally. If the \meta{value} is zero, the +% \meta{floating point} will be set to \cs{c_undefined_fp}. +% The assignment is global. +% \end{function} +% +% \section{Floating-point power operations} +% +% \begin{function}{\fp_pow:Nn, \fp_pow:cn} +% \begin{syntax} +% \cs{fp_pow:Nn} \meta{floating point} \Arg{value} +% \end{syntax} +% Raises the \meta{floating point} to the given \meta{value}. If the +% \meta{floating point} is negative, then the \meta{value} should be +% either a positive real number or a negative integer. If the +% \meta{floating point} is positive, then the \meta{value} may be any +% real value. Mathematically invalid operations such as $0^{0}$ +% will give set the \meta{floating point} to to \cs{c_undefined_fp}. +% The assignment is local. +% \end{function} +% +% \begin{function}{\fp_gpow:Nn, \fp_gpow:cn} +% \begin{syntax} +% \cs{fp_gpow:Nn} \meta{floating point} \Arg{value} +% \end{syntax} +% Raises the \meta{floating point} to the given \meta{value}. If the +% \meta{floating point} is negative, then the \meta{value} should be +% either a positive real number or a negative integer. If the +% \meta{floating point} is positive, then the \meta{value} may be any +% real value. Mathematically invalid operations such as $0^{0}$ +% will give set the \meta{floating point} to to \cs{c_undefined_fp}. +% The assignment is global. +% \end{function} +% +% \section{Exponential and logarithm functions} +% +% \begin{function}{\fp_exp:Nn, \fp_exp:cn} +% \begin{syntax} +% \cs{fp_exp:Nn} \meta{floating point} \Arg{value} +% \end{syntax} +% Calculates the exponential of the \meta{value} and assigns this +% to the \meta{floating point}. The assignment is local. +% \end{function} +% +% \begin{function}{\fp_gexp:Nn, \fp_gexp:cn} +% \begin{syntax} +% \cs{fp_gexp:Nn} \meta{floating point} \Arg{value} +% \end{syntax} +% Calculates the exponential of the \meta{value} and assigns this +% to the \meta{floating point}. The assignment is global. +% \end{function} +% +% \begin{function}{\fp_ln:Nn, \fp_ln:cn} +% \begin{syntax} +% \cs{fp_ln:Nn} \meta{floating point} \Arg{value} +% \end{syntax} +% Calculates the natural logarithm of the \meta{value} and assigns +% this to the \meta{floating point}. The assignment is local. +% \end{function} +% +% \begin{function}{\fp_gln:Nn, \fp_gln:cn} +% \begin{syntax} +% \cs{fp_gln:Nn} \meta{floating point} \Arg{value} +% \end{syntax} +% Calculates the natural logarithm of the \meta{value} and assigns +% this to the \meta{floating point}. The assignment is global. +% \end{function} +% +% \section{Trigonometric functions} +% +% The trigonometric functions all work in radians. They accept a maximum +% input value of $100\,000\,000$, as there are issues with range +% reduction and very large input values. +% +% \begin{function}{\fp_sin:Nn, \fp_sin:cn} +% \begin{syntax} +% \cs{fp_sin:Nn} \meta{floating point} \Arg{value} +% \end{syntax} +% Assigns the sine of the \meta{value} to the \meta{floating point}. +% The \meta{value} should be given in radians. The assignment is +% local. +% \end{function} +% +% \begin{function}{\fp_gsin:Nn, \fp_gsin:cn} +% \begin{syntax} +% \cs{fp_gsin:Nn} \meta{floating point} \Arg{value} +% \end{syntax} +% Assigns the sine of the \meta{value} to the \meta{floating point}. +% The \meta{value} should be given in radians. The assignment is +% global. +% \end{function} +% +% \begin{function}{\fp_cos:Nn, \fp_cos:cn} +% \begin{syntax} +% \cs{fp_cos:Nn} \meta{floating point} \Arg{value} +% \end{syntax} +% Assigns the cosine of the \meta{value} to the \meta{floating point}. +% The \meta{value} should be given in radians. The assignment is +% local. +% \end{function} +% +% \begin{function}{\fp_gcos:Nn, \fp_gcos:cn} +% \begin{syntax} +% \cs{fp_gcos:Nn} \meta{floating point} \Arg{value} +% \end{syntax} +% Assigns the cosine of the \meta{value} to the \meta{floating point}. +% The \meta{value} should be given in radians. The assignment is +% global. +% \end{function} +% +% \begin{function}{\fp_tan:Nn, \fp_tan:cn} +% \begin{syntax} +% \cs{fp_tan:Nn} \meta{floating point} \Arg{value} +% \end{syntax} +% Assigns the tangent of the \meta{value} to the \meta{floating point}. +% The \meta{value} should be given in radians. The assignment is +% local. +% \end{function} +% +% \begin{function}{\fp_gtan:Nn, \fp_gtan:cn} +% \begin{syntax} +% \cs{fp_gtan:Nn} \meta{floating point} \Arg{value} +% \end{syntax} +% Assigns the tangent of the \meta{value} to the \meta{floating point}. +% The \meta{value} should be given in radians. The assignment is +% global. +% \end{function} +% +% \section{Constant floating point values} +% +% \begin{variable}{\c_e_fp} +% The value of the base of natural numbers, $\mathrm{e}$. +% \end{variable} +% +% \begin{variable}{\c_one_fp} +% A floating point variable with permanent value $1$: used for +% speeding up some comparisons. +% \end{variable} +% +% \begin{variable}{\c_pi_fp} +% The value of $\pi$. +% \end{variable} +% +% \begin{variable}{\c_undefined_fp} +% A special marker floating point variable representing the result of +% an operation which does not give a defined result (such as division +% by $0$). +% \end{variable} +% +% \begin{variable}{\c_zero_fp} +% A permanently zero floating point variable. +% \end{variable} +% +% \section{Notes on the floating point unit} +% +% As calculation of the elemental transcendental functions is +% computationally expensive compared to storage of results, after +% calculating a trigonometric function, exponent, \emph{etc.}~the module +% stored the result for reuse. Thus the performance of the module for +% repeated operations, most probably trigonometric functions, should be +% much higher than if the values were re-calculated every time they +% were needed. +% +% Anyone with experience of programming floating point calculations will +% know that this is a complex area. The aim of the unit is to be +% accurate enough for the likely applications in a typesetting context. +% The arithmetic operations are therefore intended to provide ten digit +% accuracy with the last digit accurate to $\pm 1$. The elemental +% transcendental functions may not provide such high accuracy in every +% case, although the design aim has been to provide $10$ digit +% accuracy for cases likely to be relevant in typesetting situations. +% A good overview of the challenges in this area can be found in +% J.-M.~Muller, \emph{Elementary functions: algorithms and +% implementation}, 2nd edition, Birkh{\"a}uer Boston, New York, USA, +% 2006. +% +% The internal representation of numbers is tuned to the needs of the +% underlying \TeX{} system. This means that the format is somewhat +% different from that used in, for example, computer floating point +% units. Programming in \TeX{} makes it most convenient to use a +% radix $10$ system, using \TeX{} \texttt{count} registers for +% storage and taking advantage where possible of delimited arguments. +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{l3fp} Implementation} +% +% \TestFiles{m3fp003.lvt} +% +% \begin{macrocode} +%<*initex|package> +% \end{macrocode} +% +% \begin{macrocode} +%<*package> +\ProvidesExplPackage + {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +\package_check_loaded_expl: +%</package> +% \end{macrocode} +% +% \subsection{Constants} +% +% \begin{variable}{\c_forty_four} +% \begin{variable}{\c_one_million} +% \begin{variable}{\c_one_hundred_million} +% \begin{variable}{\c_five_hundred_million} +% \begin{variable}{\c_one_thousand_million} +% There is some speed to gain by moving numbers into fixed positions. +% \begin{macrocode} +\int_const:Nn \c_forty_four { 44 } +\int_const:Nn \c_one_million { 1 000 000 } +\int_const:Nn \c_one_hundred_million { 100 000 000 } +\int_const:Nn \c_five_hundred_million { 500 000 000 } +\int_const:Nn \c_one_thousand_million { 1 000 000 000 } +% \end{macrocode} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% +% \begin{variable}{\c_fp_pi_by_four_decimal_int} +% \begin{variable}{\c_fp_pi_by_four_extended_int} +% \begin{variable}{\c_fp_pi_decimal_int} +% \begin{variable}{\c_fp_pi_extended_int} +% \begin{variable}{\c_fp_two_pi_decimal_int} +% \begin{variable}{\c_fp_two_pi_extended_int} +% Parts of $\pi$ for trigonometric range reduction, implemented +% as \texttt{int} variables for speed. +% \begin{macrocode} +\int_new:N \c_fp_pi_by_four_decimal_int +\int_set:Nn \c_fp_pi_by_four_decimal_int { 785 398 158 } +\int_new:N \c_fp_pi_by_four_extended_int +\int_set:Nn \c_fp_pi_by_four_extended_int { 897 448 310 } +\int_new:N \c_fp_pi_decimal_int +\int_set:Nn \c_fp_pi_decimal_int { 141 592 653 } +\int_new:N \c_fp_pi_extended_int +\int_set:Nn \c_fp_pi_extended_int { 589 793 238 } +\int_new:N \c_fp_two_pi_decimal_int +\int_set:Nn \c_fp_two_pi_decimal_int { 283 185 307 } +\int_new:N \c_fp_two_pi_extended_int +\int_set:Nn \c_fp_two_pi_extended_int { 179 586 477 } +% \end{macrocode} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% +% \begin{variable}{\c_e_fp} +% The value $\mathrm{e}$ as a \enquote{machine number}. +% \begin{macrocode} +\tl_const:Nn \c_e_fp { + 2.718281828 e 0 } +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\c_one_fp} +% The constant value $1$: used for fast comparisons. +% \begin{macrocode} +\tl_const:Nn \c_one_fp { + 1.000000000 e 0 } +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\c_pi_fp} +% The value $\pi$ as a \enquote{machine number}. +% \begin{macrocode} +\tl_const:Nn \c_pi_fp { + 3.141592654 e 0 } +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\c_undefined_fp} +% A marker for undefined values. +% \begin{macrocode} +\tl_const:Nn \c_undefined_fp { X 0.000000000 e 0 } +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\c_zero_fp} +% The constant zero value. +% \begin{macrocode} +\tl_const:Nn \c_zero_fp { + 0.000000000 e 0 } +% \end{macrocode} +% \end{variable} +% +% \subsection{Variables} +% +% \begin{variable}{\l_fp_arg_tl} +% A token list to store the formalised representation of the input +% for transcendental functions. +% \begin{macrocode} +\tl_new:N \l_fp_arg_tl +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_fp_count_int} +% A counter for things like the number of divisions possible. +% \begin{macrocode} +\int_new:N \l_fp_count_int +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_fp_div_offset_int} +% When carrying out division, an offset is used for the results to +% get the decimal part correct. +% \begin{macrocode} +\int_new:N \l_fp_div_offset_int +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_fp_exp_integer_int} +% \begin{variable}{\l_fp_exp_decimal_int} +% \begin{variable}{\l_fp_exp_extended_int} +% \begin{variable}{\l_fp_exp_exponent_int} +% Used for the calculation of exponent values. +% \begin{macrocode} +\int_new:N \l_fp_exp_integer_int +\int_new:N \l_fp_exp_decimal_int +\int_new:N \l_fp_exp_extended_int +\int_new:N \l_fp_exp_exponent_int +% \end{macrocode} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% +% \begin{variable}{\l_fp_input_a_sign_int} +% \begin{variable}{\l_fp_input_a_integer_int} +% \begin{variable}{\l_fp_input_a_decimal_int} +% \begin{variable}{\l_fp_input_a_exponent_int} +% \begin{variable}{\l_fp_input_b_sign_int} +% \begin{variable}{\l_fp_input_b_integer_int} +% \begin{variable}{\l_fp_input_b_decimal_int} +% \begin{variable}{\l_fp_input_b_exponent_int} +% Storage for the input: two storage areas as there are at most two +% inputs. +% \begin{macrocode} +\int_new:N \l_fp_input_a_sign_int +\int_new:N \l_fp_input_a_integer_int +\int_new:N \l_fp_input_a_decimal_int +\int_new:N \l_fp_input_a_exponent_int +\int_new:N \l_fp_input_b_sign_int +\int_new:N \l_fp_input_b_integer_int +\int_new:N \l_fp_input_b_decimal_int +\int_new:N \l_fp_input_b_exponent_int +% \end{macrocode} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% +% \begin{variable}{\l_fp_input_a_extended_int} +% \begin{variable}{\l_fp_input_b_extended_int} +% For internal use, \enquote{extended} floating point numbers are +% needed. +% \begin{macrocode} +\int_new:N \l_fp_input_a_extended_int +\int_new:N \l_fp_input_b_extended_int +% \end{macrocode} +% \end{variable} +% \end{variable} +% +% \begin{variable}{\l_fp_mul_a_i_int} +% \begin{variable}{\l_fp_mul_a_ii_int} +% \begin{variable}{\l_fp_mul_a_iii_int} +% \begin{variable}{\l_fp_mul_a_iv_int} +% \begin{variable}{\l_fp_mul_a_v_int} +% \begin{variable}{\l_fp_mul_a_vi_int} +% \begin{variable}{\l_fp_mul_b_i_int} +% \begin{variable}{\l_fp_mul_b_ii_int} +% \begin{variable}{\l_fp_mul_b_iii_int} +% \begin{variable}{\l_fp_mul_b_iv_int} +% \begin{variable}{\l_fp_mul_b_v_int} +% \begin{variable}{\l_fp_mul_b_vi_int} +% Multiplication requires that the decimal part is split into parts +% so that there are no overflows. +% \begin{macrocode} +\int_new:N \l_fp_mul_a_i_int +\int_new:N \l_fp_mul_a_ii_int +\int_new:N \l_fp_mul_a_iii_int +\int_new:N \l_fp_mul_a_iv_int +\int_new:N \l_fp_mul_a_v_int +\int_new:N \l_fp_mul_a_vi_int +\int_new:N \l_fp_mul_b_i_int +\int_new:N \l_fp_mul_b_ii_int +\int_new:N \l_fp_mul_b_iii_int +\int_new:N \l_fp_mul_b_iv_int +\int_new:N \l_fp_mul_b_v_int +\int_new:N \l_fp_mul_b_vi_int +% \end{macrocode} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% +% \begin{variable}{\l_fp_mul_output_int} +% \begin{variable}{\l_fp_mul_output_tl} +% Space for multiplication results. +% \begin{macrocode} +\int_new:N \l_fp_mul_output_int +\tl_new:N \l_fp_mul_output_tl +% \end{macrocode} +% \end{variable} +% \end{variable} +% +% \begin{variable}{\l_fp_output_sign_int} +% \begin{variable}{\l_fp_output_integer_int} +% \begin{variable}{\l_fp_output_decimal_int} +% \begin{variable}{\l_fp_output_exponent_int} +% Output is stored in the same way as input. +% \begin{macrocode} +\int_new:N \l_fp_output_sign_int +\int_new:N \l_fp_output_integer_int +\int_new:N \l_fp_output_decimal_int +\int_new:N \l_fp_output_exponent_int +% \end{macrocode} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% +% \begin{variable}{\l_fp_output_extended_int} +% Again, for calculations an extended part. +% \begin{macrocode} +\int_new:N \l_fp_output_extended_int +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_fp_round_carry_bool} +% To indicate that a digit needs to be carried forward. +% \begin{macrocode} +\bool_new:N \l_fp_round_carry_bool +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_fp_round_decimal_tl} +% A temporary store when rounding, to build up the decimal part without +% needing to do any maths. +% \begin{macrocode} +\tl_new:N \l_fp_round_decimal_tl +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_fp_round_position_int} +% \begin{variable}{\l_fp_round_target_int} +% Used to check the position for rounding. +% \begin{macrocode} +\int_new:N \l_fp_round_position_int +\int_new:N \l_fp_round_target_int +% \end{macrocode} +% \end{variable} +% \end{variable} +% +% \begin{variable}{\l_fp_sign_tl} +% There are places where the sign needs to be set up \enquote{early}, +% so that the registers can be re-used. +% \begin{macrocode} +\tl_new:N \l_fp_sign_tl +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_fp_split_sign_int} +% When splitting the input it is fastest to use a fixed name for the +% sign part, and to transfer it after the split is complete. +% \begin{macrocode} +\int_new:N \l_fp_split_sign_int +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_fp_tmp_int} +% A scratch \texttt{int}: used only where the value is not carried +% forward. +% \begin{macrocode} +\int_new:N \l_fp_tmp_int +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_fp_tmp_tl} +% A scratch token list variable for expanding material. +% \begin{macrocode} +\tl_new:N \l_fp_tmp_tl +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_fp_trig_octant_int} +% To track which octant the trigonometric input is in. +% \begin{macrocode} +\int_new:N \l_fp_trig_octant_int +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_fp_trig_sign_int} +% \begin{variable}{\l_fp_trig_decimal_int} +% \begin{variable}{\l_fp_trig_extended_int} +% Used for the calculation of trigonometric values. +% \begin{macrocode} +\int_new:N \l_fp_trig_sign_int +\int_new:N \l_fp_trig_decimal_int +\int_new:N \l_fp_trig_extended_int +% \end{macrocode} +% \end{variable} +% \end{variable} +% \end{variable} +% +% \subsection{Parsing numbers} +% +% \begin{macro}{\fp_read:N} +% \begin{macro}[aux]{\fp_read_aux:w} +% Reading a stored value is made easier as the format is designed to +% match the delimited function. This is always used to read the first +% value (register |a|). +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_read:N #1 + { \exp_after:wN \fp_read_aux:w #1 \q_stop } +\cs_new_protected_nopar:Npn \fp_read_aux:w #1#2 . #3 e #4 \q_stop + { + \if:w #1 - + \l_fp_input_a_sign_int \c_minus_one + \else: + \l_fp_input_a_sign_int \c_one + \fi: + \l_fp_input_a_integer_int #2 \scan_stop: + \l_fp_input_a_decimal_int #3 \scan_stop: + \l_fp_input_a_exponent_int #4 \scan_stop: + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\fp_split:Nn} +% \begin{macro}[aux]{\fp_split_sign:} +% \begin{macro}[aux]{\fp_split_exponent:} +% \begin{macro}[aux]{\fp_split_aux_i:w} +% \begin{macro}[aux]{\fp_split_aux_ii:w} +% \begin{macro}[aux]{\fp_split_aux_iii:w} +% \begin{macro}[aux]{\fp_split_decimal:w} +% \begin{macro}[aux]{\fp_split_decimal_aux:w} +% The aim here is to use as much of \TeX{}'s mechanism as possible to pick +% up the numerical input without any mistakes. In particular, negative +% numbers have to be filtered out first in case the integer part is +% $0$ (in which case \TeX{} would drop the |-| sign). That process +% has to be done in a loop for cases where the sign is repeated. +% Finding an exponent is relatively easy, after which the next phase is +% to find the integer part, which will terminate with a |.|, and trigger +% the decimal-finding code. The later will allow the decimal to be too +% long, truncating the result. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_split:Nn #1#2 + { + \tl_set:Nx \l_fp_tmp_tl {#2} + \tl_set_rescan:Nno \l_fp_tmp_tl { \char_set_catcode_ignore:n { 32 } } + { \l_fp_tmp_tl } + \l_fp_split_sign_int \c_one + \fp_split_sign: + \use:c { l_fp_input_ #1 _sign_int } \l_fp_split_sign_int + \exp_after:wN \fp_split_exponent:w \l_fp_tmp_tl e e \q_stop #1 + } +\cs_new_protected_nopar:Npn \fp_split_sign: + { + \if_int_compare:w \pdftex_strcmp:D + { \exp_after:wN \tl_head:w \l_fp_tmp_tl ? \q_stop } { - } + = \c_zero + \tl_set:Nx \l_fp_tmp_tl + { + \exp_after:wN + \tl_tail:w \l_fp_tmp_tl \prg_do_nothing: \q_stop + } + \l_fp_split_sign_int -\l_fp_split_sign_int + \exp_after:wN \fp_split_sign: + \else: + \if_int_compare:w \pdftex_strcmp:D + { \exp_after:wN \tl_head:w \l_fp_tmp_tl ? \q_stop } { + } + = \c_zero + \tl_set:Nx \l_fp_tmp_tl + { + \exp_after:wN + \tl_tail:w \l_fp_tmp_tl \prg_do_nothing: \q_stop + } + \exp_after:wN \exp_after:wN \exp_after:wN \fp_split_sign: + \fi: + \fi: + } +\cs_new_protected_nopar:Npn \fp_split_exponent:w #1 e #2 e #3 \q_stop #4 + { + \use:c { l_fp_input_ #4 _exponent_int } + \int_eval:w 0 #2 \scan_stop: + \tex_afterassignment:D \fp_split_aux_i:w + \use:c { l_fp_input_ #4 _integer_int } + \int_eval:w 0 #1 . . \q_stop #4 + } +\cs_new_protected_nopar:Npn \fp_split_aux_i:w #1 . #2 . #3 \q_stop + { \fp_split_aux_ii:w #2 000000000 \q_stop } +\cs_new_protected_nopar:Npn \fp_split_aux_ii:w #1#2#3#4#5#6#7#8#9 + { \fp_split_aux_iii:w {#1#2#3#4#5#6#7#8#9} } +\cs_new_protected_nopar:Npn \fp_split_aux_iii:w #1#2 \q_stop + { + \l_fp_tmp_int 1 #1 \scan_stop: + \exp_after:wN \fp_split_decimal:w + \int_use:N \l_fp_tmp_int 000000000 \q_stop + } +\cs_new_protected_nopar:Npn \fp_split_decimal:w #1#2#3#4#5#6#7#8#9 + { \fp_split_decimal_aux:w {#2#3#4#5#6#7#8#9} } +\cs_new_protected_nopar:Npn \fp_split_decimal_aux:w #1#2#3 \q_stop #4 + { + \use:c { l_fp_input_ #4 _decimal_int } #1#2 \scan_stop: + \if_int_compare:w + \int_eval:w + \use:c { l_fp_input_ #4 _integer_int } + + \use:c { l_fp_input_ #4 _decimal_int } + \scan_stop: + = \c_zero + \use:c { l_fp_input_ #4 _sign_int } \c_one + \fi: + \if_int_compare:w + \use:c { l_fp_input_ #4 _integer_int } < \c_one_thousand_million + \else: + \exp_after:wN \fp_overflow_msg: + \fi: + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\fp_standardise:NNNN} +% \begin{macro}[aux]{\fp_standardise_aux:NNNN} +% \begin{macro}[aux]{\fp_standardise_aux:} +% \begin{macro}[aux]{\fp_standardise_aux:w} +% The idea here is to shift the input into a known exponent range. This +% is done using \TeX{} tokens where possible, as this is faster than +% arithmetic. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_standardise:NNNN #1#2#3#4 + { + \if_int_compare:w + \int_eval:w #2 + #3 = \c_zero + #1 \c_one + #4 \c_zero + \exp_after:wN \use_none:nnnn + \else: + \exp_after:wN \fp_standardise_aux:NNNN + \fi: + #1#2#3#4 + } +\cs_new_protected_nopar:Npn \fp_standardise_aux:NNNN #1#2#3#4 + { + \cs_set_protected_nopar:Npn \fp_standardise_aux: + { + \if_int_compare:w #2 = \c_zero + \tex_advance:D #3 \c_one_thousand_million + \exp_after:wN \fp_standardise_aux:w + \int_use:N #3 \q_stop + \exp_after:wN \fp_standardise_aux: + \fi: + } + \cs_set_protected_nopar:Npn + \fp_standardise_aux:w ##1##2##3##4##5##6##7##8##9 \q_stop + { + #2 ##2 \scan_stop: + #3 ##3##4##5##6##7##8##9 0 \scan_stop: + \tex_advance:D #4 \c_minus_one + } + \fp_standardise_aux: + \cs_set_protected_nopar:Npn \fp_standardise_aux: + { + \if_int_compare:w #2 > \c_nine + \tex_advance:D #2 \c_one_thousand_million + \exp_after:wN \use_i:nn \exp_after:wN + \fp_standardise_aux:w \int_use:N #2 + \exp_after:wN \fp_standardise_aux: + \fi: + } + \cs_set_protected_nopar:Npn + \fp_standardise_aux:w ##1##2##3##4##5##6##7##8##9 + { + #2 ##1##2##3##4##5##6##7##8 \scan_stop: + \tex_advance:D #3 \c_one_thousand_million + \tex_divide:D #3 \c_ten + \tl_set:Nx \l_fp_tmp_tl + { + ##9 + \exp_after:wN \use_none:n \int_use:N #3 + } + #3 \l_fp_tmp_tl \scan_stop: + \tex_advance:D #4 \c_one + } + \fp_standardise_aux: + \if_int_compare:w #4 < \c_one_hundred + \if_int_compare:w #4 > -\c_one_hundred + \else: + #1 \c_one + #2 \c_zero + #3 \c_zero + #4 \c_zero + \fi: + \else: + \exp_after:wN \fp_overflow_msg: + \fi: + } +\cs_new_protected_nopar:Npn \fp_standardise_aux: { } +\cs_new_protected_nopar:Npn \fp_standardise_aux:w { } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Internal utilities} +% +% \begin{macro}{\fp_level_input_exponents:} +% \begin{macro}[aux]{\fp_level_input_exponents_a:} +% \begin{macro}[aux]{\fp_level_input_exponents_a:NNNNNNNNN} +% \begin{macro}[aux]{\fp_level_input_exponents_b:} +% \begin{macro}[aux]{\fp_level_input_exponents_b:NNNNNNNNN} +% The routines here are similar to those used to standardise the +% exponent. However, the aim here is different: the two exponents need +% to end up the same. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_level_input_exponents: + { + \if_int_compare:w \l_fp_input_a_exponent_int > \l_fp_input_b_exponent_int + \exp_after:wN \fp_level_input_exponents_a: + \else: + \exp_after:wN \fp_level_input_exponents_b: + \fi: + } +\cs_new_protected_nopar:Npn \fp_level_input_exponents_a: + { + \if_int_compare:w \l_fp_input_a_exponent_int > \l_fp_input_b_exponent_int + \tex_advance:D \l_fp_input_b_integer_int \c_one_thousand_million + \exp_after:wN \use_i:nn \exp_after:wN + \fp_level_input_exponents_a:NNNNNNNNN + \int_use:N \l_fp_input_b_integer_int + \exp_after:wN \fp_level_input_exponents_a: + \fi: + } +\cs_new_protected_nopar:Npn \fp_level_input_exponents_a:NNNNNNNNN + #1#2#3#4#5#6#7#8#9 + { + \l_fp_input_b_integer_int #1#2#3#4#5#6#7#8 \scan_stop: + \tex_advance:D \l_fp_input_b_decimal_int \c_one_thousand_million + \tex_divide:D \l_fp_input_b_decimal_int \c_ten + \tl_set:Nx \l_fp_tmp_tl + { + #9 + \exp_after:wN \use_none:n + \int_use:N \l_fp_input_b_decimal_int + } + \l_fp_input_b_decimal_int \l_fp_tmp_tl \scan_stop: + \tex_advance:D \l_fp_input_b_exponent_int \c_one + } +\cs_new_protected_nopar:Npn \fp_level_input_exponents_b: + { + \if_int_compare:w \l_fp_input_b_exponent_int > \l_fp_input_a_exponent_int + \tex_advance:D \l_fp_input_a_integer_int \c_one_thousand_million + \exp_after:wN \use_i:nn \exp_after:wN + \fp_level_input_exponents_b:NNNNNNNNN + \int_use:N \l_fp_input_a_integer_int + \exp_after:wN \fp_level_input_exponents_b: + \fi: + } +\cs_new_protected_nopar:Npn \fp_level_input_exponents_b:NNNNNNNNN + #1#2#3#4#5#6#7#8#9 + { + \l_fp_input_a_integer_int #1#2#3#4#5#6#7#8 \scan_stop: + \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million + \tex_divide:D \l_fp_input_a_decimal_int \c_ten + \tl_set:Nx \l_fp_tmp_tl + { + #9 + \exp_after:wN \use_none:n + \int_use:N \l_fp_input_a_decimal_int + } + \l_fp_input_a_decimal_int \l_fp_tmp_tl \scan_stop: + \tex_advance:D \l_fp_input_a_exponent_int \c_one + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}[aux]{\fp_tmp:w} +% Used for output of results, cutting down on \cs{exp_after:wN}. +% This is just a place holder definition. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_tmp:w #1#2 { } +% \end{macrocode} +% \end{macro} +% +% \subsection{Operations for \texttt{fp} variables} +% +% The format of \texttt{fp} variables is tightly defined, so that +% they can be read quickly by the internal code. The format is a single +% sign token, a single number, the decimal point, nine decimal numbers, +% an |e| and finally the exponent. This final part may vary in length. +% When stored, floating points will always be stored with a value in +% the integer position unless the number is zero. +% +% \begin{macro}{\fp_new:N, \fp_new:c} +% \UnitTested +% Fixed-points always have a value, and of course this has to be +% initialised globally. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_new:N #1 + { + \tl_new:N #1 + \tl_gset_eq:NN #1 \c_zero_fp + } +\cs_generate_variant:Nn \fp_new:N { c } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\fp_const:Nn, \fp_const:cn} +% A simple wrapper. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_const:Nn #1#2 + { + \fp_new:N #1 + \fp_gset:Nn #1 {#2} + } +\cs_generate_variant:Nn \fp_const:Nn { c } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\fp_zero:N, \fp_zero:c} +% \UnitTested +% \begin{macro}{\fp_gzero:N, \fp_gzero:c} +% \UnitTested +% Zeroing fixed-points is pretty obvious. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_zero:N #1 + { \tl_set_eq:NN #1 \c_zero_fp } +\cs_new_protected_nopar:Npn \fp_gzero:N #1 + { \tl_gset_eq:NN #1 \c_zero_fp } +\cs_generate_variant:Nn \fp_zero:N { c } +\cs_generate_variant:Nn \fp_gzero:N { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\fp_set:Nn, \fp_set:cn} +% \UnitTested +% \begin{macro}{\fp_gset:Nn, \fp_gset:cn} +% \UnitTested +% \begin{macro}[aux]{\fp_set_aux:NNn} +% To trap any input errors, a very simple version of the parser is run +% here. This will pick up any invalid characters at this stage, saving +% issues later. The splitting approach is the same as the more +% advanced function later. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_set:Nn { \fp_set_aux:NNn \tl_set:Nn } +\cs_new_protected_nopar:Npn \fp_gset:Nn { \fp_set_aux:NNn \tl_gset:Nn } +\cs_new_protected_nopar:Npn \fp_set_aux:NNn #1#2#3 + { + \group_begin: + \fp_split:Nn a {#3} + \fp_standardise:NNNN + \l_fp_input_a_sign_int + \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int + \l_fp_input_a_exponent_int + \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million + \cs_set_protected_nopar:Npx \fp_tmp:w + { + \group_end: + #1 \exp_not:N #2 + { + \if_int_compare:w \l_fp_input_a_sign_int < \c_zero + - + \else: + + + \fi: + \int_use:N \l_fp_input_a_integer_int + . + \exp_after:wN \use_none:n + \int_use:N \l_fp_input_a_decimal_int + e + \int_use:N \l_fp_input_a_exponent_int + } + } + \fp_tmp:w + } +\cs_generate_variant:Nn \fp_set:Nn { c } +\cs_generate_variant:Nn \fp_gset:Nn { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% +% \begin{macro}{\fp_set_from_dim:Nn, \fp_set_from_dim:cn} +% \UnitTested +% \begin{macro}{\fp_gset_from_dim:Nn, \fp_gset_from_dim:cn} +% \UnitTested +% \begin{macro}[aux]{\fp_set_from_dim_aux:NNn} +% \begin{macro}[aux]{\fp_set_from_dim_aux:w} +% \begin{variable}{\l_fp_tmp_dim} +% \begin{variable}{\l_fp_tmp_skip} +% Here, dimensions are converted to fixed-points \emph{via} a +% temporary variable. This ensures that they always convert as points. +% The code is then essentially the same as for \cs{fp_set:Nn}, but with +% the dimension passed so that it will be striped of the |pt| on the +% way through. The passage through a skip is used to remove any rubber +% part. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_set_from_dim:Nn + { \fp_set_from_dim_aux:NNn \tl_set:Nx } +\cs_new_protected_nopar:Npn \fp_gset_from_dim:Nn + { \fp_set_from_dim_aux:NNn \tl_gset:Nx } +\cs_new_protected_nopar:Npn \fp_set_from_dim_aux:NNn #1#2#3 + { + \group_begin: + \l_fp_tmp_skip \etex_glueexpr:D #3 \scan_stop: + \l_fp_tmp_dim \l_fp_tmp_skip + \fp_split:Nn a + { + \exp_after:wN \fp_set_from_dim_aux:w + \dim_use:N \l_fp_tmp_dim + } + \fp_standardise:NNNN + \l_fp_input_a_sign_int + \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int + \l_fp_input_a_exponent_int + \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million + \cs_set_protected_nopar:Npx \fp_tmp:w + { + \group_end: + #1 \exp_not:N #2 + { + \if_int_compare:w \l_fp_input_a_sign_int < \c_zero + - + \else: + + + \fi: + \int_use:N \l_fp_input_a_integer_int + . + \exp_after:wN \use_none:n + \int_use:N \l_fp_input_a_decimal_int + e + \int_use:N \l_fp_input_a_exponent_int + } + } + \fp_tmp:w + } +\cs_set_protected_nopar:Npx \fp_set_from_dim_aux:w + { + \cs_set_nopar:Npn \exp_not:N \fp_set_from_dim_aux:w + ##1 \tl_to_str:n { pt } {##1} + } +\fp_set_from_dim_aux:w +\cs_generate_variant:Nn \fp_set_from_dim:Nn { c } +\cs_generate_variant:Nn \fp_gset_from_dim:Nn { c } +\dim_new:N \l_fp_tmp_dim +\skip_new:N \l_fp_tmp_skip +% \end{macrocode} +% \end{variable} +% \end{variable} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\fp_set_eq:NN, \fp_set_eq:cN, \fp_set_eq:Nc, \fp_set_eq:cc} +% \UnitTested +% \begin{macro}{\fp_gset_eq:NN, \fp_gset_eq:cN, \fp_gset_eq:Nc, \fp_gset_eq:cc} +% \UnitTested +% Pretty simple, really. +% \begin{macrocode} +\cs_new_eq:NN \fp_set_eq:NN \tl_set_eq:NN +\cs_new_eq:NN \fp_set_eq:cN \tl_set_eq:cN +\cs_new_eq:NN \fp_set_eq:Nc \tl_set_eq:Nc +\cs_new_eq:NN \fp_set_eq:cc \tl_set_eq:cc +\cs_new_eq:NN \fp_gset_eq:NN \tl_gset_eq:NN +\cs_new_eq:NN \fp_gset_eq:cN \tl_gset_eq:cN +\cs_new_eq:NN \fp_gset_eq:Nc \tl_gset_eq:Nc +\cs_new_eq:NN \fp_gset_eq:cc \tl_gset_eq:cc +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\fp_show:N, \fp_show:c} +% \UnitTested +% Simple showing of the underlying variable. +% \begin{macrocode} +\cs_new_eq:NN \fp_show:N \tl_show:N +\cs_new_eq:NN \fp_show:c \tl_show:c +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\fp_use:N, \fp_use:c} +% \UnitTested +% \begin{macro}[aux]{\fp_use_aux:w} +% \begin{macro}[aux]{\fp_use_none:w} +% \begin{macro}[aux]{\fp_use_small:w} +% \begin{macro}[aux]{\fp_use_large:w} +% \begin{macro}[aux]{\fp_use_large_aux_i:w} +% \begin{macro}[aux]{\fp_use_large_aux_1:w} +% \begin{macro}[aux]{\fp_use_large_aux_2:w} +% \begin{macro}[aux]{\fp_use_large_aux_3:w} +% \begin{macro}[aux]{\fp_use_large_aux_4:w} +% \begin{macro}[aux]{\fp_use_large_aux_5:w} +% \begin{macro}[aux]{\fp_use_large_aux_6:w} +% \begin{macro}[aux]{\fp_use_large_aux_7:w} +% \begin{macro}[aux]{\fp_use_large_aux_8:w} +% \begin{macro}[aux]{\fp_use_large_aux_i:w} +% \begin{macro}[aux]{\fp_use_large_aux_ii:w} +% The idea of the \cs{fp_use:N} function to convert the stored +% value into something suitable for \TeX{} to use as a number in an +% expandable manner. The first step is to deal with the sign, then +% work out how big the input is. +% \begin{macrocode} +\cs_new_nopar:Npn \fp_use:N #1 + { \exp_after:wN \fp_use_aux:w #1 \q_stop } +\cs_generate_variant:Nn \fp_use:N { c } +\cs_new_nopar:Npn \fp_use_aux:w #1#2 e #3 \q_stop + { + \if:w #1 - + - + \fi: + \if_int_compare:w #3 > \c_zero + \exp_after:wN \fp_use_large:w + \else: + \if_int_compare:w #3 < \c_zero + \exp_after:wN \exp_after:wN \exp_after:wN + \fp_use_small:w + \else: + \exp_after:wN \exp_after:wN \exp_after:wN \fp_use_none:w + \fi: + \fi: + #2 e #3 \q_stop + } +% \end{macrocode} +% When the exponent is zero, the input is simply returned as output. +% \begin{macrocode} +\cs_new_nopar:Npn \fp_use_none:w #1 e #2 \q_stop {#1} +% \end{macrocode} +% For small numbers (less than $1$) the correct number of zeros +% have to be inserted, but the decimal point is easy. +% \begin{macrocode} +\cs_new_nopar:Npn \fp_use_small:w #1 . #2 e #3 \q_stop + { + 0 . + \prg_replicate:nn { -#3 - 1 } { 0 } + #1#2 + } +% \end{macrocode} +% Life is more complex for large numbers. The decimal point needs to +% be shuffled, with potentially some zero-filling for very large values. +% \begin{macrocode} +\cs_new_nopar:Npn \fp_use_large:w #1 . #2 e #3 \q_stop + { + \if_int_compare:w #3 < \c_ten + \exp_after:wN \fp_use_large_aux_i:w + \else: + \exp_after:wN \fp_use_large_aux_ii:w + \fi: + #1#2 e #3 \q_stop + } +\cs_new_nopar:Npn \fp_use_large_aux_i:w #1#2 e #3 \q_stop + { + #1 + \use:c { fp_use_large_aux_ #3 :w } #2 \q_stop + } +\cs_new_nopar:cpn { fp_use_large_aux_1:w } #1#2 \q_stop { #1 . #2 } +\cs_new_nopar:cpn { fp_use_large_aux_2:w } #1#2#3 \q_stop + { #1#2 . #3 } +\cs_new_nopar:cpn { fp_use_large_aux_3:w } #1#2#3#4 \q_stop + { #1#2#3 . #4 } +\cs_new_nopar:cpn { fp_use_large_aux_4:w } #1#2#3#4#5 \q_stop + { #1#2#3#4 . #5 } +\cs_new_nopar:cpn { fp_use_large_aux_5:w } #1#2#3#4#5#6 \q_stop + { #1#2#3#4#5 . #6 } +\cs_new_nopar:cpn { fp_use_large_aux_6:w } #1#2#3#4#5#6#7 \q_stop + { #1#2#3#4#5#6 . #7 } +\cs_new_nopar:cpn { fp_use_large_aux_7:w } #1#2#3#4#5#6#7#8 \q_stop + { #1#2#3#4#6#7 . #8 } +\cs_new_nopar:cpn { fp_use_large_aux_8:w } #1#2#3#4#5#6#7#8#9 \q_stop + { #1#2#3#4#5#6#7#8 . #9 } +\cs_new_nopar:cpn { fp_use_large_aux_9:w } #1 \q_stop { #1 . } +\cs_new_nopar:Npn \fp_use_large_aux_ii:w #1 e #2 \q_stop + { + #1 + \prg_replicate:nn { #2 - 9 } { 0 } + . + } +% \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} +% +% \subsection{Transferring to other types} +% +% The \cs{fp_use:N} function converts a floating point variable to +% a form that can be used by \TeX{}. Here, the functions are slightly +% different, as some information may be discarded. +% +% \begin{macro}{\fp_to_dim:N, \fp_to_dim:c} +% A very simple wrapper. +% \begin{macrocode} +\cs_new_nopar:Npn \fp_to_dim:N #1 { \fp_use:N #1 pt } +\cs_generate_variant:Nn \fp_to_dim:N { c } +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\fp_to_int:N, \fp_to_int:c} +% \UnitTested +% \begin{macro}[aux]{\fp_to_int_aux:w} +% \begin{macro}[aux]{\fp_to_int_none:w} +% \begin{macro}[aux]{\fp_to_int_small:w} +% \begin{macro}[aux]{\fp_to_int_large:w} +% \begin{macro}[aux]{\fp_to_int_large_aux_i:w} +% \begin{macro}[aux]{\fp_to_int_large_aux_1:w} +% \begin{macro}[aux]{\fp_to_int_large_aux_2:w} +% \begin{macro}[aux]{\fp_to_int_large_aux_3:w} +% \begin{macro}[aux]{\fp_to_int_large_aux_4:w} +% \begin{macro}[aux]{\fp_to_int_large_aux_5:w} +% \begin{macro}[aux]{\fp_to_int_large_aux_6:w} +% \begin{macro}[aux]{\fp_to_int_large_aux_7:w} +% \begin{macro}[aux]{\fp_to_int_large_aux_8:w} +% \begin{macro}[aux]{\fp_to_int_large_aux_i:w} +% \begin{macro}[aux]{\fp_to_int_large_aux:nnn} +% \begin{macro}[aux]{\fp_to_int_large_aux_ii:w} +% Converting to integers in an expandable manner is very similar to +% simply using floating point variables, particularly in the lead-off. +% \begin{macrocode} +\cs_new_nopar:Npn \fp_to_int:N #1 + { \exp_after:wN \fp_to_int_aux:w #1 \q_stop } +\cs_generate_variant:Nn \fp_to_int:N { c } +\cs_new_nopar:Npn \fp_to_int_aux:w #1#2 e #3 \q_stop + { + \if:w #1 - + - + \fi: + \if_int_compare:w #3 < \c_zero + \exp_after:wN \fp_to_int_small:w + \else: + \exp_after:wN \fp_to_int_large:w + \fi: + #2 e #3 \q_stop + } +% \end{macrocode} +% For small numbers, if the decimal part is greater than a half then +% there is rounding up to do. +% \begin{macrocode} +\cs_new_nopar:Npn \fp_to_int_small:w #1 . #2 e #3 \q_stop + { + \if_int_compare:w #3 > \c_one + \else: + \if_int_compare:w #1 < \c_five + 0 + \else: + 1 + \fi: + \fi: + } +% \end{macrocode} +% For large numbers, the idea is to split off the part for rounding, +% do the rounding and fill if needed. +% \begin{macrocode} +\cs_new_nopar:Npn \fp_to_int_large:w #1 . #2 e #3 \q_stop + { + \if_int_compare:w #3 < \c_ten + \exp_after:wN \fp_to_int_large_aux_i:w + \else: + \exp_after:wN \fp_to_int_large_aux_ii:w + \fi: + #1#2 e #3 \q_stop + } +\cs_new_nopar:Npn \fp_to_int_large_aux_i:w #1#2 e #3 \q_stop + { \use:c { fp_to_int_large_aux_ #3 :w } #2 \q_stop {#1} } +\cs_new_nopar:cpn { fp_to_int_large_aux_1:w } #1#2 \q_stop + { \fp_to_int_large_aux:nnn { #2 0 } {#1} } +\cs_new_nopar:cpn { fp_to_int_large_aux_2:w } #1#2#3 \q_stop + { \fp_to_int_large_aux:nnn { #3 00 } {#1#2} } +\cs_new_nopar:cpn { fp_to_int_large_aux_3:w } #1#2#3#4 \q_stop + { \fp_to_int_large_aux:nnn { #4 000 } {#1#2#3} } +\cs_new_nopar:cpn { fp_to_int_large_aux_4:w } #1#2#3#4#5 \q_stop + { \fp_to_int_large_aux:nnn { #5 0000 } {#1#2#3#4} } +\cs_new_nopar:cpn { fp_to_int_large_aux_5:w } #1#2#3#4#5#6 \q_stop + { \fp_to_int_large_aux:nnn { #6 00000 } {#1#2#3#4#5} } +\cs_new_nopar:cpn { fp_to_int_large_aux_6:w } #1#2#3#4#5#6#7 \q_stop + { \fp_to_int_large_aux:nnn { #7 000000 } {#1#2#3#4#5#6} } +\cs_new_nopar:cpn { fp_to_int_large_aux_7:w } #1#2#3#4#5#6#7#8 \q_stop + { \fp_to_int_large_aux:nnn { #8 0000000 } {#1#2#3#4#5#6#7} } +\cs_new_nopar:cpn { fp_to_int_large_aux_8:w } #1#2#3#4#5#6#7#8#9 \q_stop + { \fp_to_int_large_aux:nnn { #9 00000000 } {#1#2#3#4#5#6#7#8} } +\cs_new_nopar:cpn { fp_to_int_large_aux_9:w } #1 \q_stop {#1} +\cs_new_nopar:Npn \fp_to_int_large_aux:nnn #1#2#3 + { + \if_int_compare:w #1 < \c_five_hundred_million + #3#2 + \else: + \int_value:w \int_eval:w #3#2 + 1 \int_eval_end: + \fi: + } +\cs_new_nopar:Npn \fp_to_int_large_aux_ii:w #1 e #2 \q_stop + { + #1 + \prg_replicate:nn { #2 - 9 } { 0 } + } +% \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} +% +% \begin{macro}{\fp_to_tl:N, \fp_to_tl:c} +% \UnitTested +% \begin{macro}[aux]{\fp_to_tl_aux:w} +% \begin{macro}[aux]{\fp_to_tl_large:w} +% \begin{macro}[aux]{\fp_to_tl_large_aux_i:w} +% \begin{macro}[aux]{\fp_to_tl_large_aux_ii:w} +% \begin{macro}[aux]{\fp_to_tl_large_0:w} +% \begin{macro}[aux]{\fp_to_tl_large_1:w} +% \begin{macro}[aux]{\fp_to_tl_large_2:w} +% \begin{macro}[aux]{\fp_to_tl_large_3:w} +% \begin{macro}[aux]{\fp_to_tl_large_4:w} +% \begin{macro}[aux]{\fp_to_tl_large_5:w} +% \begin{macro}[aux]{\fp_to_tl_large_6:w} +% \begin{macro}[aux]{\fp_to_tl_large_7:w} +% \begin{macro}[aux]{\fp_to_tl_large_8:w} +% \begin{macro}[aux]{\fp_to_tl_large_8_aux:w} +% \begin{macro}[aux]{\fp_to_tl_large_9:w} +% \begin{macro}[aux]{\fp_to_tl_small:w} +% \begin{macro}[aux]{\fp_to_tl_small_one:w} +% \begin{macro}[aux]{\fp_to_tl_small_two:w} +% \begin{macro}[aux]{\fp_to_tl_small_aux:w} +% \begin{macro}[aux]{\fp_to_tl_large_zeros:NNNNNNNNN} +% \begin{macro}[aux]{\fp_to_tl_small_zeros:NNNNNNNNN} +% \begin{macro}[aux]{\fp_use_iix_ix:NNNNNNNNN} +% \begin{macro}[aux]{\fp_use_ix:NNNNNNNNN} +% \begin{macro}[aux]{\fp_use_i_to_vii:NNNNNNNNN} +% \begin{macro}[aux]{\fp_use_i_to_iix:NNNNNNNNN} +% Converting to integers in an expandable manner is very similar to +% simply using floating point variables, particularly in the lead-off. +% \begin{macrocode} +\cs_new_nopar:Npn \fp_to_tl:N #1 + { \exp_after:wN \fp_to_tl_aux:w #1 \q_stop } +\cs_generate_variant:Nn \fp_to_tl:N { c } +\cs_new_nopar:Npn \fp_to_tl_aux:w #1#2 e #3 \q_stop + { + \if:w #1 - + - + \fi: + \if_int_compare:w #3 < \c_zero + \exp_after:wN \fp_to_tl_small:w + \else: + \exp_after:wN \fp_to_tl_large:w + \fi: + #2 e #3 \q_stop + } +% \end{macrocode} +% For \enquote{large} numbers (exponent $\ge 0$) there are two +% cases. For very large exponents ($ \ge 10 $) life is easy: apart +% from dropping extra zeros there is no work to do. On the other hand, +% for intermediate exponent values the decimal needs to be moved, then +% zeros can be dropped. +% \begin{macrocode} +\cs_new_nopar:Npn \fp_to_tl_large:w #1 e #2 \q_stop + { + \if_int_compare:w #2 < \c_ten + \exp_after:wN \fp_to_tl_large_aux_i:w + \else: + \exp_after:wN \fp_to_tl_large_aux_ii:w + \fi: + #1 e #2 \q_stop + } +\cs_new_nopar:Npn \fp_to_tl_large_aux_i:w #1 e #2 \q_stop + { \use:c { fp_to_tl_large_ #2 :w } #1 \q_stop } +\cs_new_nopar:Npn \fp_to_tl_large_aux_ii:w #1 . #2 e #3 \q_stop + { + #1 + \fp_to_tl_large_zeros:NNNNNNNNN #2 + e #3 + } +\cs_new_nopar:cpn { fp_to_tl_large_0:w } #1 . #2 \q_stop + { + #1 + \fp_to_tl_large_zeros:NNNNNNNNN #2 + } +\cs_new_nopar:cpn { fp_to_tl_large_1:w } #1 . #2#3 \q_stop + { + #1#2 + \fp_to_tl_large_zeros:NNNNNNNNN #3 0 + } +\cs_new_nopar:cpn { fp_to_tl_large_2:w } #1 . #2#3#4 \q_stop + { + #1#2#3 + \fp_to_tl_large_zeros:NNNNNNNNN #4 00 + } +\cs_new_nopar:cpn { fp_to_tl_large_3:w } #1 . #2#3#4#5 \q_stop + { + #1#2#3#4 + \fp_to_tl_large_zeros:NNNNNNNNN #5 000 + } +\cs_new_nopar:cpn { fp_to_tl_large_4:w } #1 . #2#3#4#5#6 \q_stop + { + #1#2#3#4#5 + \fp_to_tl_large_zeros:NNNNNNNNN #6 0000 + } +\cs_new_nopar:cpn { fp_to_tl_large_5:w } #1 . #2#3#4#5#6#7 \q_stop + { + #1#2#3#4#5#6 + \fp_to_tl_large_zeros:NNNNNNNNN #7 00000 + } +\cs_new_nopar:cpn { fp_to_tl_large_6:w } #1 . #2#3#4#5#6#7#8 \q_stop + { + #1#2#3#4#5#6#7 + \fp_to_tl_large_zeros:NNNNNNNNN #8 000000 + } +\cs_new_nopar:cpn { fp_to_tl_large_7:w } #1 . #2#3#4#5#6#7#8#9 \q_stop + { + #1#2#3#4#5#6#7#8 + \fp_to_tl_large_zeros:NNNNNNNNN #9 0000000 + } +\cs_new_nopar:cpn { fp_to_tl_large_8:w } #1 . + { + #1 + \use:c { fp_to_tl_large_8_aux:w } + } +\cs_new_nopar:cpn { fp_to_tl_large_8_aux:w } #1#2#3#4#5#6#7#8#9 \q_stop + { + #1#2#3#4#5#6#7#8 + \fp_to_tl_large_zeros:NNNNNNNNN #9 00000000 + } +\cs_new_nopar:cpn { fp_to_tl_large_9:w } #1 . #2 \q_stop {#1#2} +% \end{macrocode} +% Dealing with small numbers is a bit more complex as there has to be +% rounding. This makes life rather awkward, as there need to be a series +% of tests and calculations, as things cannot be stored in an +% expandable system. +% \begin{macrocode} +\cs_new_nopar:Npn \fp_to_tl_small:w #1 e #2 \q_stop + { + \if_int_compare:w #2 = \c_minus_one + \exp_after:wN \fp_to_tl_small_one:w + \else: + \if_int_compare:w #2 = -\c_two + \exp_after:wN \exp_after:wN \exp_after:wN \fp_to_tl_small_two:w + \else: + \exp_after:wN \exp_after:wN \exp_after:wN \fp_to_tl_small_aux:w + \fi: + \fi: + #1 e #2 \q_stop + } +\cs_new_nopar:Npn \fp_to_tl_small_one:w #1 . #2 e #3 \q_stop + { + \if_int_compare:w \fp_use_ix:NNNNNNNNN #2 > \c_four + \if_int_compare:w + \int_eval:w #1 \fp_use_i_to_iix:NNNNNNNNN #2 + 1 + < \c_one_thousand_million + 0. + \exp_after:wN \fp_to_tl_small_zeros:NNNNNNNNN + \int_value:w \int_eval:w + #1 \fp_use_i_to_iix:NNNNNNNNN #2 + 1 + \int_eval_end: + \else: + 1 + \fi: + \else: + 0. #1 + \fp_to_tl_small_zeros:NNNNNNNNN #2 + \fi: + } +\cs_new_nopar:Npn \fp_to_tl_small_two:w #1 . #2 e #3 \q_stop + { + \if_int_compare:w \fp_use_iix_ix:NNNNNNNNN #2 > \c_forty_four + \if_int_compare:w + \int_eval:w #1 \fp_use_i_to_vii:NNNNNNNNN #2 0 + \c_ten + < \c_one_thousand_million + 0.0 + \exp_after:wN \fp_to_tl_small_zeros:NNNNNNNNN + \int_value:w \int_eval:w + #1 \fp_use_i_to_vii:NNNNNNNNN #2 0 + \c_ten + \int_eval_end: + \else: + 0.1 + \fi: + \else: + 0.0 + #1 + \fp_to_tl_small_zeros:NNNNNNNNN #2 + \fi: + } +\cs_new_nopar:Npn \fp_to_tl_small_aux:w #1 . #2 e #3 \q_stop + { + #1 + \fp_to_tl_large_zeros:NNNNNNNNN #2 + e #3 + } +% \end{macrocode} +% Rather than a complex recursion, the tests for finding trailing zeros +% are written out long-hand. The difference between the two is only the +% need for a decimal marker. +% \begin{macrocode} +\cs_new_nopar:Npn \fp_to_tl_large_zeros:NNNNNNNNN #1#2#3#4#5#6#7#8#9 + { + \if_int_compare:w #9 = \c_zero + \if_int_compare:w #8 = \c_zero + \if_int_compare:w #7 = \c_zero + \if_int_compare:w #6 = \c_zero + \if_int_compare:w #5 = \c_zero + \if_int_compare:w #4 = \c_zero + \if_int_compare:w #3 = \c_zero + \if_int_compare:w #2 = \c_zero + \if_int_compare:w #1 = \c_zero + \else: + . #1 + \fi: + \else: + . #1#2 + \fi: + \else: + . #1#2#3 + \fi: + \else: + . #1#2#3#4 + \fi: + \else: + . #1#2#3#4#5 + \fi: + \else: + . #1#2#3#4#5#6 + \fi: + \else: + . #1#2#3#4#5#6#7 + \fi: + \else: + . #1#2#3#4#5#6#7#8 + \fi: + \else: + . #1#2#3#4#5#6#7#8#9 + \fi: + } +\cs_new_nopar:Npn \fp_to_tl_small_zeros:NNNNNNNNN #1#2#3#4#5#6#7#8#9 + { + \if_int_compare:w #9 = \c_zero + \if_int_compare:w #8 = \c_zero + \if_int_compare:w #7 = \c_zero + \if_int_compare:w #6 = \c_zero + \if_int_compare:w #5 = \c_zero + \if_int_compare:w #4 = \c_zero + \if_int_compare:w #3 = \c_zero + \if_int_compare:w #2 = \c_zero + \if_int_compare:w #1 = \c_zero + \else: + #1 + \fi: + \else: + #1#2 + \fi: + \else: + #1#2#3 + \fi: + \else: + #1#2#3#4 + \fi: + \else: + #1#2#3#4#5 + \fi: + \else: + #1#2#3#4#5#6 + \fi: + \else: + #1#2#3#4#5#6#7 + \fi: + \else: + #1#2#3#4#5#6#7#8 + \fi: + \else: + #1#2#3#4#5#6#7#8#9 + \fi: + } +% \end{macrocode} +% Some quick \enquote{return a few} functions. +% \begin{macrocode} +\cs_new_nopar:Npn \fp_use_iix_ix:NNNNNNNNN #1#2#3#4#5#6#7#8#9 {#8#9} +\cs_new_nopar:Npn \fp_use_ix:NNNNNNNNN #1#2#3#4#5#6#7#8#9 {#9} +\cs_new_nopar:Npn \fp_use_i_to_vii:NNNNNNNNN #1#2#3#4#5#6#7#8#9 + {#1#2#3#4#5#6#7} +\cs_new_nopar:Npn \fp_use_i_to_iix:NNNNNNNNN #1#2#3#4#5#6#7#8#9 + {#1#2#3#4#5#6#7#8} +% \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} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Rounding numbers} +% +% The results may well need to be rounded. A couple of related functions +% to do this for a stored value. +% +% \begin{macro}{\fp_round_figures:Nn, \fp_round_figures:cn} +% \UnitTested +% \begin{macro}{\fp_ground_figures:Nn, \fp_ground_figures:cn} +% \UnitTested +% \begin{macro}[aux]{\fp_round_figures_aux:NNn} +% Rounding to figures needs only an adjustment to the target by one +% (as the target is in decimal places). +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_round_figures:Nn + { \fp_round_figures_aux:NNn \tl_set:Nn } +\cs_generate_variant:Nn \fp_round_figures:Nn { c } +\cs_new_protected_nopar:Npn \fp_ground_figures:Nn + { \fp_round_figures_aux:NNn \tl_gset:Nn } +\cs_generate_variant:Nn \fp_ground_figures:Nn { c } +\cs_new_protected_nopar:Npn \fp_round_figures_aux:NNn #1#2#3 + { + \group_begin: + \fp_read:N #2 + \int_set:Nn \l_fp_round_target_int { #3 - 1 } + \if_int_compare:w \l_fp_round_target_int < \c_ten + \exp_after:wN \fp_round: + \fi: + \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million + \cs_set_protected_nopar:Npx \fp_tmp:w + { + \group_end: + #1 \exp_not:N #2 + { + \if_int_compare:w \l_fp_input_a_sign_int < \c_zero + - + \else: + + + \fi: + \int_use:N \l_fp_input_a_integer_int + . + \exp_after:wN \use_none:n + \int_use:N \l_fp_input_a_decimal_int + e + \int_use:N \l_fp_input_a_exponent_int + } + } + \fp_tmp:w + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\fp_round_places:Nn, \fp_round_places:cn} +% \UnitTested +% \begin{macro}{\fp_ground_places:Nn, \fp_ground_places:cn} +% \UnitTested +% \begin{macro}[aux]{\fp_round_places_aux:NNn} +% Rounding to places needs an adjustment for the exponent value, which +% will mean that everything should be correct. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_round_places:Nn + { \fp_round_places_aux:NNn \tl_set:Nn } +\cs_generate_variant:Nn \fp_round_places:Nn { c } +\cs_new_protected_nopar:Npn \fp_ground_places:Nn + { \fp_round_places_aux:NNn \tl_gset:Nn } +\cs_generate_variant:Nn \fp_ground_places:Nn { c } +\cs_new_protected_nopar:Npn \fp_round_places_aux:NNn #1#2#3 + { + \group_begin: + \fp_read:N #2 + \int_set:Nn \l_fp_round_target_int + { #3 + \l_fp_input_a_exponent_int } + \if_int_compare:w \l_fp_round_target_int < \c_ten + \exp_after:wN \fp_round: + \fi: + \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million + \cs_set_protected_nopar:Npx \fp_tmp:w + { + \group_end: + #1 \exp_not:N #2 + { + \if_int_compare:w \l_fp_input_a_sign_int < \c_zero + - + \else: + + + \fi: + \int_use:N \l_fp_input_a_integer_int + . + \exp_after:wN \use_none:n + \int_use:N \l_fp_input_a_decimal_int + e + \int_use:N \l_fp_input_a_exponent_int + } + } + \fp_tmp:w + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\fp_round:} +% \begin{macro}[aux]{\fp_round_aux:NNNNNNNNN} +% \begin{macro}{\fp_round_loop:N} +% The rounding approach is the same for decimal places and significant +% figures. There are always nine decimal digits to round, so the code +% can be written to account for this. The basic logic is simply to +% find the rounding, track any carry digit and move along. At the end +% of the loop there is a possible shuffle if the integer part has +% become $10$. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_round: + { + \bool_set_false:N \l_fp_round_carry_bool + \l_fp_round_position_int \c_eight + \tl_clear:N \l_fp_round_decimal_tl + \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million + \exp_after:wN \use_i:nn \exp_after:wN + \fp_round_aux:NNNNNNNNN \int_use:N \l_fp_input_a_decimal_int + } +\cs_new_protected_nopar:Npn \fp_round_aux:NNNNNNNNN #1#2#3#4#5#6#7#8#9 + { + \fp_round_loop:N #9#8#7#6#5#4#3#2#1 + \bool_if:NT \l_fp_round_carry_bool + { \tex_advance:D \l_fp_input_a_integer_int \c_one } + \l_fp_input_a_decimal_int \l_fp_round_decimal_tl \scan_stop: + \if_int_compare:w \l_fp_input_a_integer_int < \c_ten + \else: + \l_fp_input_a_integer_int \c_one + \tex_divide:D \l_fp_input_a_decimal_int \c_ten + \tex_advance:D \l_fp_input_a_exponent_int \c_one + \fi: + } +\cs_new_protected_nopar:Npn \fp_round_loop:N #1 + { + \if_int_compare:w \l_fp_round_position_int < \l_fp_round_target_int + \bool_if:NTF \l_fp_round_carry_bool + { \l_fp_tmp_int \int_eval:w #1 + \c_one \scan_stop: } + { \l_fp_tmp_int \int_eval:w #1 \scan_stop: } + \if_int_compare:w \l_fp_tmp_int = \c_ten + \l_fp_tmp_int \c_zero + \else: + \bool_set_false:N \l_fp_round_carry_bool + \fi: + \tl_set:Nx \l_fp_round_decimal_tl + { \int_use:N \l_fp_tmp_int \l_fp_round_decimal_tl } + \else: + \tl_set:Nx \l_fp_round_decimal_tl { 0 \l_fp_round_decimal_tl } + \if_int_compare:w \l_fp_round_position_int = \l_fp_round_target_int + \if_int_compare:w #1 > \c_four + \bool_set_true:N \l_fp_round_carry_bool + \fi: + \fi: + \fi: + \tex_advance:D \l_fp_round_position_int \c_minus_one + \if_int_compare:w \l_fp_round_position_int > \c_minus_one + \exp_after:wN \fp_round_loop:N + \fi: + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Unary functions} +% +% \begin{macro}{\fp_abs:N, \fp_abs:c} +% \UnitTested +% \begin{macro}{\fp_gabs:N, \fp_gabs:c} +% \UnitTested +% \begin{macro}[aux]{\fp_abs_aux:NN} +% Setting the absolute value is easy: read the value, ignore the sign, +% return the result. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_abs:N { \fp_abs_aux:NN \tl_set:Nn } +\cs_new_protected_nopar:Npn \fp_gabs:N { \fp_abs_aux:NN \tl_gset:Nn } +\cs_generate_variant:Nn \fp_abs:N { c } +\cs_generate_variant:Nn \fp_gabs:N { c } +\cs_new_protected_nopar:Npn \fp_abs_aux:NN #1#2 + { + \group_begin: + \fp_read:N #2 + \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million + \cs_set_protected_nopar:Npx \fp_tmp:w + { + \group_end: + #1 \exp_not:N #2 + { + + + \int_use:N \l_fp_input_a_integer_int + . + \exp_after:wN \use_none:n + \int_use:N \l_fp_input_a_decimal_int + e + \int_use:N \l_fp_input_a_exponent_int + } + } + \fp_tmp:w + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\fp_neg:N, \fp_neg:c} +% \UnitTested +% \begin{macro}{\fp_gneg:N, \fp_gneg:c} +% \UnitTested +% \begin{macro}[aux]{\fp_neg:NN} +% Just a bit more complex: read the input, reverse the sign and +% output the result. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_neg:N { \fp_neg_aux:NN \tl_set:Nn } +\cs_new_protected_nopar:Npn \fp_gneg:N { \fp_neg_aux:NN \tl_gset:Nn } +\cs_generate_variant:Nn \fp_neg:N { c } +\cs_generate_variant:Nn \fp_gneg:N { c } +\cs_new_protected_nopar:Npn \fp_neg_aux:NN #1#2 + { + \group_begin: + \fp_read:N #2 + \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million + \tl_set:Nx \l_fp_tmp_tl + { + \if_int_compare:w \l_fp_input_a_sign_int < \c_zero + + + \else: + - + \fi: + \int_use:N \l_fp_input_a_integer_int + . + \exp_after:wN \use_none:n + \int_use:N \l_fp_input_a_decimal_int + e + \int_use:N \l_fp_input_a_exponent_int + } + \exp_after:wN \group_end: \exp_after:wN + #1 \exp_after:wN #2 \exp_after:wN { \l_fp_tmp_tl } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Basic arithmetic} +% +% \begin{macro}{\fp_add:Nn, \fp_add:cn} +% \UnitTested +% \begin{macro}{\fp_gadd:Nn,\fp_gadd:cn} +% \UnitTested +% \begin{macro}[aux]{\fp_add_aux:NNn} +% \begin{macro}[aux]{\fp_add_core:} +% \begin{macro}[aux]{\fp_add_sum:} +% \begin{macro}[aux]{\fp_add_difference:} +% The various addition functions are simply different ways to call the +% single master function below. This pattern is repeated for the +% other arithmetic functions. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_add:Nn { \fp_add_aux:NNn \tl_set:Nn } +\cs_new_protected_nopar:Npn \fp_gadd:Nn { \fp_add_aux:NNn \tl_gset:Nn } +\cs_generate_variant:Nn \fp_add:Nn { c } +\cs_generate_variant:Nn \fp_gadd:Nn { c } +% \end{macrocode} +% Addition takes place using one of two paths. If the signs of the +% two parts are the same, they are simply combined. On the other +% hand, if the signs are different the calculation finds this +% difference. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_add_aux:NNn #1#2#3 + { + \group_begin: + \fp_read:N #2 + \fp_split:Nn b {#3} + \fp_standardise:NNNN + \l_fp_input_b_sign_int + \l_fp_input_b_integer_int + \l_fp_input_b_decimal_int + \l_fp_input_b_exponent_int + \fp_add_core: + \fp_tmp:w #1#2 + } +\cs_new_protected_nopar:Npn \fp_add_core: + { + \fp_level_input_exponents: + \if_int_compare:w + \int_eval:w + \l_fp_input_a_sign_int * \l_fp_input_b_sign_int + > \c_zero + \exp_after:wN \fp_add_sum: + \else: + \exp_after:wN \fp_add_difference: + \fi: + \l_fp_output_exponent_int \l_fp_input_a_exponent_int + \fp_standardise:NNNN + \l_fp_output_sign_int + \l_fp_output_integer_int + \l_fp_output_decimal_int + \l_fp_output_exponent_int + \cs_set_protected_nopar:Npx \fp_tmp:w ##1##2 + { + \group_end: + ##1 ##2 + { + \if_int_compare:w \l_fp_output_sign_int < \c_zero + - + \else: + + + \fi: + \int_use:N \l_fp_output_integer_int + . + \exp_after:wN \use_none:n + \int_value:w \int_eval:w + \l_fp_output_decimal_int + \c_one_thousand_million + e + \int_use:N \l_fp_output_exponent_int + } + } + } +% \end{macrocode} +% Finding the sum of two numbers is trivially easy. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_add_sum: + { + \l_fp_output_sign_int \l_fp_input_a_sign_int + \l_fp_output_integer_int + \int_eval:w + \l_fp_input_a_integer_int + \l_fp_input_b_integer_int + \scan_stop: + \l_fp_output_decimal_int + \int_eval:w + \l_fp_input_a_decimal_int + \l_fp_input_b_decimal_int + \scan_stop: + \if_int_compare:w \l_fp_output_decimal_int < \c_one_thousand_million + \else: + \tex_advance:D \l_fp_output_integer_int \c_one + \tex_advance:D \l_fp_output_decimal_int -\c_one_thousand_million + \fi: + } +% \end{macrocode} +% When the signs of the two parts of the input are different, the +% absolute difference is worked out first. There is then a calculation +% to see which way around everything has worked out, so that the final +% sign is correct. The difference might also give a zero result with +% a negative sign, which is reversed as zero is regarded as positive. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_add_difference: + { + \l_fp_output_integer_int + \int_eval:w + \l_fp_input_a_integer_int - \l_fp_input_b_integer_int + \scan_stop: + \l_fp_output_decimal_int + \int_eval:w + \l_fp_input_a_decimal_int - \l_fp_input_b_decimal_int + \scan_stop: + \if_int_compare:w \l_fp_output_decimal_int < \c_zero + \tex_advance:D \l_fp_output_integer_int \c_minus_one + \tex_advance:D \l_fp_output_decimal_int \c_one_thousand_million + \fi: + \if_int_compare:w \l_fp_output_integer_int < \c_zero + \l_fp_output_sign_int \l_fp_input_b_sign_int + \if_int_compare:w \l_fp_output_decimal_int = \c_zero + \l_fp_output_integer_int -\l_fp_output_integer_int + \else: + \l_fp_output_decimal_int + \int_eval:w + \c_one_thousand_million - \l_fp_output_decimal_int + \scan_stop: + \l_fp_output_integer_int + \int_eval:w + - \l_fp_output_integer_int - \c_one + \scan_stop: + \fi: + \else: + \l_fp_output_sign_int \l_fp_input_a_sign_int + \fi: + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\fp_sub:Nn, \fp_sub:cn} +% \UnitTested +% \begin{macro}{\fp_gsub:Nn,\fp_gsub:cn} +% \UnitTested +% \begin{macro}[aux]{\fp_sub_aux:NNn} +% Subtraction is essentially the same as addition, but with the sign +% of the second component reversed. Thus the core of the two function +% groups is the same, with just a little set up here. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_sub:Nn { \fp_sub_aux:NNn \tl_set:Nn } +\cs_new_protected_nopar:Npn \fp_gsub:Nn { \fp_sub_aux:NNn \tl_gset:Nn } +\cs_generate_variant:Nn \fp_sub:Nn { c } +\cs_generate_variant:Nn \fp_gsub:Nn { c } +\cs_new_protected_nopar:Npn \fp_sub_aux:NNn #1#2#3 + { + \group_begin: + \fp_read:N #2 + \fp_split:Nn b {#3} + \fp_standardise:NNNN + \l_fp_input_b_sign_int + \l_fp_input_b_integer_int + \l_fp_input_b_decimal_int + \l_fp_input_b_exponent_int + \tex_multiply:D \l_fp_input_b_sign_int \c_minus_one + \fp_add_core: + \fp_tmp:w #1#2 + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\fp_mul:Nn, \fp_mul:cn} +% \UnitTested +% \begin{macro}{\fp_gmul:Nn,\fp_gmul:cn} +% \UnitTested +% \begin{macro}[aux]{\fp_mul_aux:NNn} +% \begin{macro}[aux]{\fp_mul_internal:} +% \begin{macro}[aux]{\fp_mul_split:NNNN} +% \begin{macro}[aux]{\fp_mul_split:w} +% \begin{macro}[aux]{\fp_mul_end_level:} +% \begin{macro}[aux]{\fp_mul_end_level:NNNNNNNNN} +% The pattern is much the same for multiplication. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_mul:Nn { \fp_mul_aux:NNn \tl_set:Nn } +\cs_new_protected_nopar:Npn \fp_gmul:Nn { \fp_mul_aux:NNn \tl_gset:Nn } +\cs_generate_variant:Nn \fp_mul:Nn { c } +\cs_generate_variant:Nn \fp_gmul:Nn { c } +% \end{macrocode} +% The approach to multiplication is as follows. First, the two numbers +% are split into blocks of three digits. These are then multiplied +% together to find products for each group of three output digits. This +% is al written out in full for speed reasons. Between each block of +% three digits in the output, there is a carry step. The very lowest +% digits are not calculated, while +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_mul_aux:NNn #1#2#3 + { + \group_begin: + \fp_read:N #2 + \fp_split:Nn b {#3} + \fp_standardise:NNNN + \l_fp_input_b_sign_int + \l_fp_input_b_integer_int + \l_fp_input_b_decimal_int + \l_fp_input_b_exponent_int + \fp_mul_internal: + \l_fp_output_exponent_int + \int_eval:w + \l_fp_input_a_exponent_int + \l_fp_input_b_exponent_int + \scan_stop: + \fp_standardise:NNNN + \l_fp_output_sign_int + \l_fp_output_integer_int + \l_fp_output_decimal_int + \l_fp_output_exponent_int + \cs_set_protected_nopar:Npx \fp_tmp:w + { + \group_end: + #1 \exp_not:N #2 + { + \if_int_compare:w + \int_eval:w + \l_fp_input_a_sign_int * \l_fp_input_b_sign_int + < \c_zero + \if_int_compare:w + \int_eval:w + \l_fp_output_integer_int + \l_fp_output_decimal_int + = \c_zero + + + \else: + - + \fi: + \else: + + + \fi: + \int_use:N \l_fp_output_integer_int + . + \exp_after:wN \use_none:n + \int_value:w \int_eval:w + \l_fp_output_decimal_int + \c_one_thousand_million + e + \int_use:N \l_fp_output_exponent_int + } + } + \fp_tmp:w + } +% \end{macrocode} +% Done separately so that the internal use is a bit easier. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_mul_internal: + { + \fp_mul_split:NNNN \l_fp_input_a_decimal_int + \l_fp_mul_a_i_int \l_fp_mul_a_ii_int \l_fp_mul_a_iii_int + \fp_mul_split:NNNN \l_fp_input_b_decimal_int + \l_fp_mul_b_i_int \l_fp_mul_b_ii_int \l_fp_mul_b_iii_int + \l_fp_mul_output_int \c_zero + \tl_clear:N \l_fp_mul_output_tl + \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_iii_int + \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_ii_int + \fp_mul_product:NN \l_fp_mul_a_iii_int \l_fp_mul_b_i_int + \tex_divide:D \l_fp_mul_output_int \c_one_thousand + \fp_mul_product:NN \l_fp_input_a_integer_int \l_fp_mul_b_iii_int + \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_ii_int + \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_i_int + \fp_mul_product:NN \l_fp_mul_a_iii_int \l_fp_input_b_integer_int + \fp_mul_end_level: + \fp_mul_product:NN \l_fp_input_a_integer_int \l_fp_mul_b_ii_int + \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_i_int + \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_input_b_integer_int + \fp_mul_end_level: + \fp_mul_product:NN \l_fp_input_a_integer_int \l_fp_mul_b_i_int + \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_input_b_integer_int + \fp_mul_end_level: + \l_fp_output_decimal_int 0 \l_fp_mul_output_tl \scan_stop: + \tl_clear:N \l_fp_mul_output_tl + \fp_mul_product:NN \l_fp_input_a_integer_int \l_fp_input_b_integer_int + \fp_mul_end_level: + \l_fp_output_integer_int 0 \l_fp_mul_output_tl \scan_stop: + } +% \end{macrocode} +% The split works by making a $10$ digit number, from which +% the first digit can then be dropped using a delimited argument. The +% groups of three digits are then assigned to the various parts of +% the input: notice that |##9| contains the last two digits of the +% smallest part of the input. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_mul_split:NNNN #1#2#3#4 + { + \tex_advance:D #1 \c_one_thousand_million + \cs_set_protected_nopar:Npn \fp_mul_split_aux:w + ##1##2##3##4##5##6##7##8##9 \q_stop { + #2 ##2##3##4 \scan_stop: + #3 ##5##6##7 \scan_stop: + #4 ##8##9 \scan_stop: + } + \exp_after:wN \fp_mul_split_aux:w \int_use:N #1 \q_stop + \tex_advance:D #1 -\c_one_thousand_million + } +\cs_new_protected_nopar:Npn \fp_mul_product:NN #1#2 + { + \l_fp_mul_output_int + \int_eval:w \l_fp_mul_output_int + #1 * #2 \scan_stop: + } +% \end{macrocode} +% At the end of each output group of three, there is a transfer of +% information so that there is no danger of an overflow. This is done by +% expansion to keep the number of calculations down. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_mul_end_level: + { + \tex_advance:D \l_fp_mul_output_int \c_one_thousand_million + \exp_after:wN \use_i:nn \exp_after:wN + \fp_mul_end_level:NNNNNNNNN \int_use:N \l_fp_mul_output_int + } +\cs_new_protected_nopar:Npn \fp_mul_end_level:NNNNNNNNN #1#2#3#4#5#6#7#8#9 + { + \tl_set:Nx \l_fp_mul_output_tl { #7#8#9 \l_fp_mul_output_tl } + \l_fp_mul_output_int #1#2#3#4#5#6 \scan_stop: + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\fp_div:Nn, \fp_div:cn} +% \UnitTested +% \begin{macro}{\fp_gdiv:Nn,\fp_gdiv:cn} +% \UnitTested +% \begin{macro}[aux]{\fp_div_aux:NNn} +% \begin{macro}{\fp_div_internal:} +% \begin{macro}[aux]{\fp_div_loop:} +% \begin{macro}[aux]{\fp_div_divide:} +% \begin{macro}[aux]{\fp_div_divide_aux:} +% \begin{macro}[aux]{\fp_div_store:} +% \begin{macro}[aux]{\fp_div_store_integer:} +% \begin{macro}[aux]{\fp_div_store_decimal:} +% The pattern is much the same for multiplication. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_div:Nn { \fp_div_aux:NNn \tl_set:Nn } +\cs_new_protected_nopar:Npn \fp_gdiv:Nn { \fp_div_aux:NNn \tl_gset:Nn } +\cs_generate_variant:Nn \fp_div:Nn { c } +\cs_generate_variant:Nn \fp_gdiv:Nn { c } +% \end{macrocode} +% Division proper starts with a couple of tests. If the denominator is +% zero then a error is issued. On the other hand, if the numerator is +% zero then the result must be $0.0$ and can be given with no +% further work. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_div_aux:NNn #1#2#3 + { + \group_begin: + \fp_read:N #2 + \fp_split:Nn b {#3} + \fp_standardise:NNNN + \l_fp_input_b_sign_int + \l_fp_input_b_integer_int + \l_fp_input_b_decimal_int + \l_fp_input_b_exponent_int + \if_int_compare:w + \int_eval:w + \l_fp_input_b_integer_int + \l_fp_input_b_decimal_int + = \c_zero + \cs_set_protected_nopar:Npx \fp_tmp:w ##1##2 + { + \group_end: + #1 \exp_not:N #2 { \c_undefined_fp } + } + \else: + \if_int_compare:w + \int_eval:w + \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int + = \c_zero + \cs_set_protected_nopar:Npx \fp_tmp:w ##1##2 + { + \group_end: + #1 \exp_not:N #2 { \c_zero_fp } + } + \else: + \exp_after:wN \exp_after:wN \exp_after:wN \fp_div_internal: + \fi: + \fi: + \fp_tmp:w #1#2 + } +% \end{macrocode} +% The main division algorithm works by finding how many times |b| can +% be removed from |a|, storing the result and doing the subtraction. +% Input |a| is then multiplied by $10$, and the process is repeated. +% The looping ends either when there is nothing left of |a| +% (\emph{i.e.}~an exact result) or when the code reaches the ninth +% decimal place. Most of the process takes place in the loop function +% below. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_div_internal: { + \l_fp_output_integer_int \c_zero + \l_fp_output_decimal_int \c_zero + \cs_set_eq:NN \fp_div_store: \fp_div_store_integer: + \l_fp_div_offset_int \c_one_hundred_million + \fp_div_loop: + \l_fp_output_exponent_int + \int_eval:w + \l_fp_input_a_exponent_int - \l_fp_input_b_exponent_int + \scan_stop: + \fp_standardise:NNNN + \l_fp_output_sign_int + \l_fp_output_integer_int + \l_fp_output_decimal_int + \l_fp_output_exponent_int + \cs_set_protected_nopar:Npx \fp_tmp:w ##1##2 + { + \group_end: + ##1 ##2 + { + \if_int_compare:w + \int_eval:w + \l_fp_input_a_sign_int * \l_fp_input_b_sign_int + < \c_zero + \if_int_compare:w + \int_eval:w + \l_fp_output_integer_int + \l_fp_output_decimal_int + = \c_zero + + + \else: + - + \fi: + \else: + + + \fi: + \int_use:N \l_fp_output_integer_int + . + \exp_after:wN \use_none:n + \int_value:w \int_eval:w + \l_fp_output_decimal_int + \c_one_thousand_million + \int_eval_end: + e + \int_use:N \l_fp_output_exponent_int + } + } +} +% \end{macrocode} +% The main loop implements the approach described above. The storing +% function is done as a function so that the integer and decimal parts +% can be done separately but rapidly. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_div_loop: + { + \l_fp_count_int \c_zero + \fp_div_divide: + \fp_div_store: + \tex_multiply:D \l_fp_input_a_integer_int \c_ten + \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million + \exp_after:wN \fp_div_loop_step:w + \int_use:N \l_fp_input_a_decimal_int \q_stop + \if_int_compare:w + \int_eval:w \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int + > \c_zero + \if_int_compare:w \l_fp_div_offset_int > \c_zero + \exp_after:wN \exp_after:wN \exp_after:wN + \fp_div_loop: + \fi: + \fi: + } +% \end{macrocode} +% Checking to see if the numerator can be divides needs quite an +% involved check. Either the integer part has to be bigger for the +% numerator or, if it is not smaller then the decimal part of the +% numerator must not be smaller than that of the denominator. Once +% the test is right the rest is much as elsewhere. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_div_divide: + { + \if_int_compare:w \l_fp_input_a_integer_int > \l_fp_input_b_integer_int + \exp_after:wN \fp_div_divide_aux: + \else: + \if_int_compare:w \l_fp_input_a_integer_int < \l_fp_input_b_integer_int + \else: + \if_int_compare:w + \l_fp_input_a_decimal_int < \l_fp_input_b_decimal_int + \else: + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \fp_div_divide_aux: + \fi: + \fi: + \fi: + } +\cs_new_protected_nopar:Npn \fp_div_divide_aux: + { + \tex_advance:D \l_fp_count_int \c_one + \tex_advance:D \l_fp_input_a_integer_int -\l_fp_input_b_integer_int + \tex_advance:D \l_fp_input_a_decimal_int -\l_fp_input_b_decimal_int + \if_int_compare:w \l_fp_input_a_decimal_int < \c_zero + \tex_advance:D \l_fp_input_a_integer_int \c_minus_one + \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million + \fi: + \fp_div_divide: + } +% \end{macrocode} +% Storing the number of each division is done differently for the +% integer and decimal. The integer is easy and a one-off, while the +% decimal also needs to account for the position of the digit to store. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_div_store: { } +\cs_new_protected_nopar:Npn \fp_div_store_integer: + { + \l_fp_output_integer_int \l_fp_count_int + \cs_set_eq:NN \fp_div_store: \fp_div_store_decimal: + } +\cs_new_protected_nopar:Npn \fp_div_store_decimal: + { + \l_fp_output_decimal_int + \int_eval:w + \l_fp_output_decimal_int + + \l_fp_count_int * \l_fp_div_offset_int + \int_eval_end: + \tex_divide:D \l_fp_div_offset_int \c_ten + } +\cs_new_protected_nopar:Npn \fp_div_loop_step:w #1#2#3#4#5#6#7#8#9 \q_stop + { + \l_fp_input_a_integer_int + \int_eval:w #2 + \l_fp_input_a_integer_int \int_eval_end: + \l_fp_input_a_decimal_int #3#4#5#6#7#8#9 0 \scan_stop: + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Arithmetic for internal use} +% +% For the more complex functions, it is only possible to deliver +% reliable $10$ digit accuracy if the internal calculations are +% carried out to a higher degree of precision. This is done using a +% second set of functions so that the `user' versions are not +% slowed down. These versions are also focussed on the needs of internal +% calculations. No error checking, sign checking or exponent levelling +% is done. For addition and subtraction, the arguments are: +% \begin{itemize} +% \item Integer part of input |a|. +% \item Decimal part of input |a|. +% \item Additional decimal part of input |a|. +% \item Integer part of input |b|. +% \item Decimal part of input |b|. +% \item Additional decimal part of input |b|. +% \item Integer part of output. +% \item Decimal part of output. +% \item Additional decimal part of output. +% \end{itemize} +% The situation for multiplication and division is a little different as +% they only deal with the decimal part. +% +% \begin{macro}{\fp_add:NNNNNNNNN} +% The internal sum is always exactly that: it is always a sum and there +% is no sign check. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_add:NNNNNNNNN #1#2#3#4#5#6#7#8#9 + { + #7 \int_eval:w #1 + #4 \int_eval_end: + #8 \int_eval:w #2 + #5 \int_eval_end: + #9 \int_eval:w #3 + #6 \int_eval_end: + \if_int_compare:w #9 < \c_one_thousand_million + \else: + \tex_advance:D #8 \c_one + \tex_advance:D #9 -\c_one_thousand_million + \fi: + \if_int_compare:w #8 < \c_one_thousand_million + \else: + \tex_advance:D #7 \c_one + \tex_advance:D #8 -\c_one_thousand_million + \fi: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\fp_sub:NNNNNNNNN} +% Internal subtraction is needed only when the first number is bigger +% than the second, so there is no need to worry about the sign. This is +% a good job as there are no arguments left. The flipping flag is +% used in the rare case where a sign change is possible. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_sub:NNNNNNNNN #1#2#3#4#5#6#7#8#9 + { + #7 \int_eval:w #1 - #4 \int_eval_end: + #8 \int_eval:w #2 - #5 \int_eval_end: + #9 \int_eval:w #3 - #6 \int_eval_end: + \if_int_compare:w #9 < \c_zero + \tex_advance:D #8 \c_minus_one + \tex_advance:D #9 \c_one_thousand_million + \fi: + \if_int_compare:w #8 < \c_zero + \tex_advance:D #7 \c_minus_one + \tex_advance:D #8 \c_one_thousand_million + \fi: + \if_int_compare:w #7 < \c_zero + \if_int_compare:w \int_eval:w #8 + #9 = \c_zero + #7 -#7 + \else: + \tex_advance:D #7 \c_one + #8 \int_eval:w \c_one_thousand_million - #8 \int_eval_end: + #9 \int_eval:w \c_one_thousand_million - #9 \int_eval_end: + \fi: + \fi: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\fp_mul:NNNNNN} +% Decimal-part only multiplication but with higher accuracy than the +% user version. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_mul:NNNNNN #1#2#3#4#5#6 + { + \fp_mul_split:NNNN #1 + \l_fp_mul_a_i_int \l_fp_mul_a_ii_int \l_fp_mul_a_iii_int + \fp_mul_split:NNNN #2 + \l_fp_mul_a_iv_int \l_fp_mul_a_v_int \l_fp_mul_a_vi_int + \fp_mul_split:NNNN #3 + \l_fp_mul_b_i_int \l_fp_mul_b_ii_int \l_fp_mul_b_iii_int + \fp_mul_split:NNNN #4 + \l_fp_mul_b_iv_int \l_fp_mul_b_v_int \l_fp_mul_b_vi_int + \l_fp_mul_output_int \c_zero + \tl_clear:N \l_fp_mul_output_tl + \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_vi_int + \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_v_int + \fp_mul_product:NN \l_fp_mul_a_iii_int \l_fp_mul_b_iv_int + \fp_mul_product:NN \l_fp_mul_a_iv_int \l_fp_mul_b_iii_int + \fp_mul_product:NN \l_fp_mul_a_v_int \l_fp_mul_b_ii_int + \fp_mul_product:NN \l_fp_mul_a_vi_int \l_fp_mul_b_i_int + \tex_divide:D \l_fp_mul_output_int \c_one_thousand + \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_v_int + \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_iv_int + \fp_mul_product:NN \l_fp_mul_a_iii_int \l_fp_mul_b_iii_int + \fp_mul_product:NN \l_fp_mul_a_iv_int \l_fp_mul_b_ii_int + \fp_mul_product:NN \l_fp_mul_a_v_int \l_fp_mul_b_i_int + \fp_mul_end_level: + \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_iv_int + \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_iii_int + \fp_mul_product:NN \l_fp_mul_a_iii_int \l_fp_mul_b_ii_int + \fp_mul_product:NN \l_fp_mul_a_iv_int \l_fp_mul_b_i_int + \fp_mul_end_level: + \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_iii_int + \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_ii_int + \fp_mul_product:NN \l_fp_mul_a_iii_int \l_fp_mul_b_i_int + \fp_mul_end_level: + #6 0 \l_fp_mul_output_tl \scan_stop: + \tl_clear:N \l_fp_mul_output_tl + \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_ii_int + \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_i_int + \fp_mul_end_level: + \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_i_int + \fp_mul_end_level: + \fp_mul_end_level: + #5 0 \l_fp_mul_output_tl \scan_stop: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\fp_mul:NNNNNNNNN} +% For internal multiplication where the integer does need to be +% retained. This means of course that this code is quite slow, and so +% is only used when necessary. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_mul:NNNNNNNNN #1#2#3#4#5#6#7#8#9 + { + \fp_mul_split:NNNN #2 + \l_fp_mul_a_i_int \l_fp_mul_a_ii_int \l_fp_mul_a_iii_int + \fp_mul_split:NNNN #3 + \l_fp_mul_a_iv_int \l_fp_mul_a_v_int \l_fp_mul_a_vi_int + \fp_mul_split:NNNN #5 + \l_fp_mul_b_i_int \l_fp_mul_b_ii_int \l_fp_mul_b_iii_int + \fp_mul_split:NNNN #6 + \l_fp_mul_b_iv_int \l_fp_mul_b_v_int \l_fp_mul_b_vi_int + \l_fp_mul_output_int \c_zero + \tl_clear:N \l_fp_mul_output_tl + \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_vi_int + \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_v_int + \fp_mul_product:NN \l_fp_mul_a_iii_int \l_fp_mul_b_iv_int + \fp_mul_product:NN \l_fp_mul_a_iv_int \l_fp_mul_b_iii_int + \fp_mul_product:NN \l_fp_mul_a_v_int \l_fp_mul_b_ii_int + \fp_mul_product:NN \l_fp_mul_a_vi_int \l_fp_mul_b_i_int + \tex_divide:D \l_fp_mul_output_int \c_one_thousand + \fp_mul_product:NN #1 \l_fp_mul_b_vi_int + \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_v_int + \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_iv_int + \fp_mul_product:NN \l_fp_mul_a_iii_int \l_fp_mul_b_iii_int + \fp_mul_product:NN \l_fp_mul_a_iv_int \l_fp_mul_b_ii_int + \fp_mul_product:NN \l_fp_mul_a_v_int \l_fp_mul_b_i_int + \fp_mul_product:NN \l_fp_mul_a_vi_int #4 + \fp_mul_end_level: + \fp_mul_product:NN #1 \l_fp_mul_b_v_int + \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_iv_int + \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_iii_int + \fp_mul_product:NN \l_fp_mul_a_iii_int \l_fp_mul_b_ii_int + \fp_mul_product:NN \l_fp_mul_a_iv_int \l_fp_mul_b_i_int + \fp_mul_product:NN \l_fp_mul_a_v_int #4 + \fp_mul_end_level: + \fp_mul_product:NN #1 \l_fp_mul_b_iv_int + \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_iii_int + \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_ii_int + \fp_mul_product:NN \l_fp_mul_a_iii_int \l_fp_mul_b_i_int + \fp_mul_product:NN \l_fp_mul_a_iv_int #4 + \fp_mul_end_level: + #9 0 \l_fp_mul_output_tl \scan_stop: + \tl_clear:N \l_fp_mul_output_tl + \fp_mul_product:NN #1 \l_fp_mul_b_iii_int + \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_ii_int + \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_i_int + \fp_mul_product:NN \l_fp_mul_a_iii_int #4 + \fp_mul_end_level: + \fp_mul_product:NN #1 \l_fp_mul_b_ii_int + \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_i_int + \fp_mul_product:NN \l_fp_mul_a_ii_int #4 + \fp_mul_end_level: + \fp_mul_product:NN #1 \l_fp_mul_b_i_int + \fp_mul_product:NN \l_fp_mul_a_i_int #4 + \fp_mul_end_level: + #8 0 \l_fp_mul_output_tl \scan_stop: + \tl_clear:N \l_fp_mul_output_tl + \fp_mul_product:NN #1 #4 + \fp_mul_end_level: + #7 0 \l_fp_mul_output_tl \scan_stop: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\fp_div_integer:NNNNN} +% Here, division is always by an integer, and so it is possible to +% use \TeX{}'s native calculations rather than doing it in macros. +% The idea here is to divide the decimal part, find any remainder, +% then do the real division of the two parts before adding in what +% is needed for the remainder. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_div_integer:NNNNN #1#2#3#4#5 + { + \l_fp_tmp_int #1 + \tex_divide:D \l_fp_tmp_int #3 + \l_fp_tmp_int \int_eval:w #1 - \l_fp_tmp_int * #3 \int_eval_end: + #4 #1 + \tex_divide:D #4 #3 + #5 #2 + \tex_divide:D #5 #3 + \tex_multiply:D \l_fp_tmp_int \c_one_thousand + \tex_divide:D \l_fp_tmp_int #3 + #5 \int_eval:w #5 + \l_fp_tmp_int * \c_one_million \int_eval_end: + \if_int_compare:w #5 > \c_one_thousand_million + \tex_advance:D #4 \c_one + \tex_advance:D #5 -\c_one_thousand_million + \fi: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\fp_extended_normalise:} +% \begin{macro}[aux]{\fp_extended_normalise_aux_i:} +% \begin{macro}[aux]{\fp_extended_normalise_aux_i:w} +% \begin{macro}[aux]{\fp_extended_normalise_aux_ii:w} +% \begin{macro}[aux]{\fp_extended_normalise_aux_ii:} +% \begin{macro}[aux]{\fp_extended_normalise_aux:NNNNNNNNN} +% The \enquote{extended} integers for internal use are mainly used in +% fixed-point mode. This comes up in a few places, so a generalised +% utility is made available to carry out the change. This function +% simply calls the two loops to shift the input to the point of +% having a zero exponent. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_extended_normalise: + { + \fp_extended_normalise_aux_i: + \fp_extended_normalise_aux_ii: + } +\cs_new_protected_nopar:Npn \fp_extended_normalise_aux_i: + { + \if_int_compare:w \l_fp_input_a_exponent_int > \c_zero + \tex_multiply:D \l_fp_input_a_integer_int \c_ten + \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million + \exp_after:wN \fp_extended_normalise_aux_i:w + \int_use:N \l_fp_input_a_decimal_int \q_stop + \exp_after:wN \fp_extended_normalise_aux_i: + \fi: + } +\cs_new_protected_nopar:Npn \fp_extended_normalise_aux_i:w + #1#2#3#4#5#6#7#8#9 \q_stop + { + \l_fp_input_a_integer_int + \int_eval:w \l_fp_input_a_integer_int + #2 \scan_stop: + \l_fp_input_a_decimal_int #3#4#5#6#7#8#9 0 \scan_stop: + \tex_advance:D \l_fp_input_a_extended_int \c_one_thousand_million + \exp_after:wN \fp_extended_normalise_aux_ii:w + \int_use:N \l_fp_input_a_extended_int \q_stop + } +\cs_new_protected_nopar:Npn \fp_extended_normalise_aux_ii:w + #1#2#3#4#5#6#7#8#9 \q_stop + { + \l_fp_input_a_decimal_int + \int_eval:w \l_fp_input_a_decimal_int + #2 \scan_stop: + \l_fp_input_a_extended_int #3#4#5#6#7#8#9 0 \scan_stop: + \tex_advance:D \l_fp_input_a_exponent_int \c_minus_one + } +\cs_new_protected_nopar:Npn \fp_extended_normalise_aux_ii: + { + \if_int_compare:w \l_fp_input_a_exponent_int < \c_zero + \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million + \exp_after:wN \use_i:nn \exp_after:wN + \fp_extended_normalise_ii_aux:NNNNNNNNN + \int_use:N \l_fp_input_a_decimal_int + \exp_after:wN \fp_extended_normalise_aux_ii: + \fi: + } +\cs_new_protected_nopar:Npn \fp_extended_normalise_ii_aux:NNNNNNNNN + #1#2#3#4#5#6#7#8#9 + { + \if_int_compare:w \l_fp_input_a_integer_int = \c_zero + \l_fp_input_a_decimal_int #1#2#3#4#5#6#7#8 \scan_stop: + \else: + \tl_set:Nx \l_fp_tmp_tl + { + \int_use:N \l_fp_input_a_integer_int + #1#2#3#4#5#6#7#8 + } + \l_fp_input_a_integer_int \c_zero + \l_fp_input_a_decimal_int \l_fp_tmp_tl \scan_stop: + \fi: + \tex_divide:D \l_fp_input_a_extended_int \c_ten + \tl_set:Nx \l_fp_tmp_tl + { + #9 + \int_use:N \l_fp_input_a_extended_int + } + \l_fp_input_a_extended_int \l_fp_tmp_tl \scan_stop: + \tex_advance:D \l_fp_input_a_exponent_int \c_one + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\fp_extended_normalise_output:} +% \begin{macro}[aux]{\fp_extended_normalise_output_aux_i:NNNNNNNNN} +% \begin{macro}[aux]{\fp_extended_normalise_output_aux_ii:NNNNNNNNN} +% \begin{macro}[aux]{\fp_extended_normalise_output_aux:N} +% At some stages in working out extended output, it is possible for the +% value to need shifting to keep the integer part in range. This only +% ever happens such that the integer needs to be made smaller. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_extended_normalise_output: + { + \if_int_compare:w \l_fp_output_integer_int > \c_nine + \tex_advance:D \l_fp_output_integer_int \c_one_thousand_million + \exp_after:wN \use_i:nn \exp_after:wN + \fp_extended_normalise_output_aux_i:NNNNNNNNN + \int_use:N \l_fp_output_integer_int + \exp_after:wN \fp_extended_normalise_output: + \fi: + } +\cs_new_protected_nopar:Npn \fp_extended_normalise_output_aux_i:NNNNNNNNN + #1#2#3#4#5#6#7#8#9 + { + \l_fp_output_integer_int #1#2#3#4#5#6#7#8 \scan_stop: + \tex_advance:D \l_fp_output_decimal_int \c_one_thousand_million + \tl_set:Nx \l_fp_tmp_tl + { + #9 + \exp_after:wN \use_none:n + \int_use:N \l_fp_output_decimal_int + } + \exp_after:wN \fp_extended_normalise_output_aux_ii:NNNNNNNNN + \l_fp_tmp_tl + } +\cs_new_protected_nopar:Npn \fp_extended_normalise_output_aux_ii:NNNNNNNNN + #1#2#3#4#5#6#7#8#9 + { + \l_fp_output_decimal_int #1#2#3#4#5#6#7#8#9 \scan_stop: + \fp_extended_normalise_output_aux:N + } +\cs_new_protected_nopar:Npn \fp_extended_normalise_output_aux:N #1 + { + \tex_advance:D \l_fp_output_extended_int \c_one_thousand_million + \tex_divide:D \l_fp_output_extended_int \c_ten + \tl_set:Nx \l_fp_tmp_tl + { + #1 + \exp_after:wN \use_none:n + \int_use:N \l_fp_output_extended_int + } + \l_fp_output_extended_int \l_fp_tmp_tl \scan_stop: + \tex_advance:D \l_fp_output_exponent_int \c_one + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Trigonometric functions} +% +% \begin{macro}{\fp_trig_normalise:} +% \begin{macro}[aux]{\fp_trig_normalise_aux:} +% \begin{macro}[aux]{\fp_trig_sub:NNN} +% For normalisation, the code essentially switches to fixed-point +% arithmetic. There is a shift of the exponent, then repeated +% subtractions. The end result is a number in the range +% $ -\pi < x \le \pi $. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_trig_normalise: + { + \if_int_compare:w \l_fp_input_a_exponent_int < \c_ten + \l_fp_input_a_extended_int \c_zero + \fp_extended_normalise: + \fp_trig_normalise_aux: + \if_int_compare:w \l_fp_input_a_integer_int < \c_zero + \l_fp_input_a_sign_int -\l_fp_input_a_sign_int + \l_fp_input_a_integer_int -\l_fp_input_a_integer_int + \fi: + \exp_after:wN \fp_trig_octant: + \else: + \l_fp_input_a_sign_int \c_one + \l_fp_output_integer_int \c_zero + \l_fp_output_decimal_int \c_zero + \l_fp_output_exponent_int \c_zero + \exp_after:wN \fp_trig_overflow_msg: + \fi: + } +\cs_new_protected_nopar:Npn \fp_trig_normalise_aux: + { + \if_int_compare:w \l_fp_input_a_integer_int > \c_three + \fp_trig_sub:NNN + \c_six \c_fp_two_pi_decimal_int \c_fp_two_pi_extended_int + \exp_after:wN \fp_trig_normalise_aux: + \else: + \if_int_compare:w \l_fp_input_a_integer_int > \c_two + \if_int_compare:w \l_fp_input_a_decimal_int > \c_fp_pi_decimal_int + \fp_trig_sub:NNN + \c_six \c_fp_two_pi_decimal_int \c_fp_two_pi_extended_int + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \fp_trig_normalise_aux: + \fi: + \fi: + \fi: + } +% \end{macrocode} +% Here, there may be a sign change but there will never be any +% variation in the input. So a dedicated function can be used. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_trig_sub:NNN #1#2#3 + { + \l_fp_input_a_integer_int + \int_eval:w \l_fp_input_a_integer_int - #1 \int_eval_end: + \l_fp_input_a_decimal_int + \int_eval:w \l_fp_input_a_decimal_int - #2 \int_eval_end: + \l_fp_input_a_extended_int + \int_eval:w \l_fp_input_a_extended_int - #3 \int_eval_end: + \if_int_compare:w \l_fp_input_a_extended_int < \c_zero + \tex_advance:D \l_fp_input_a_decimal_int \c_minus_one + \tex_advance:D \l_fp_input_a_extended_int \c_one_thousand_million + \fi: + \if_int_compare:w \l_fp_input_a_decimal_int < \c_zero + \tex_advance:D \l_fp_input_a_integer_int \c_minus_one + \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million + \fi: + \if_int_compare:w \l_fp_input_a_integer_int < \c_zero + \l_fp_input_a_sign_int -\l_fp_input_a_sign_int + \if_int_compare:w + \int_eval:w + \l_fp_input_a_decimal_int + \l_fp_input_a_extended_int + = \c_zero + \l_fp_input_a_integer_int -\l_fp_input_a_integer_int + \else: + \l_fp_input_a_integer_int + \int_eval:w + - \l_fp_input_a_integer_int - \c_one + \int_eval_end: + \l_fp_input_a_decimal_int + \int_eval:w + \c_one_thousand_million - \l_fp_input_a_decimal_int + \int_eval_end: + \l_fp_input_a_extended_int + \int_eval:w + \c_one_thousand_million - \l_fp_input_a_extended_int + \int_eval_end: + \fi: + \fi: + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\fp_trig_octant:} +% \begin{macro}[aux]{\fp_trig_octant_aux:} +% Here, the input is further reduced into the range +% $ 0 \le x < \pi / 4 $. This is pretty simple: check if +% $ \pi / 4 $ can be taken off and if it can do it and loop. The +% check at the end is to \enquote{mop up} values which are so close to +% $ \pi / 4 $ that they should be treated as such. The test for +% an even octant is needed as the `remainder' needed is from +% the nearest $ \pi / 2 $. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_trig_octant: + { + \l_fp_trig_octant_int \c_one + \fp_trig_octant_aux: + \if_int_compare:w \l_fp_input_a_decimal_int < \c_ten + \l_fp_input_a_decimal_int \c_zero + \l_fp_input_a_extended_int \c_zero + \fi: + \if_int_odd:w \l_fp_trig_octant_int + \else: + \fp_sub:NNNNNNNNN + \c_zero \c_fp_pi_by_four_decimal_int \c_fp_pi_by_four_extended_int + \l_fp_input_a_integer_int \l_fp_input_a_decimal_int + \l_fp_input_a_extended_int + \l_fp_input_a_integer_int \l_fp_input_a_decimal_int + \l_fp_input_a_extended_int + \fi: + } +\cs_new_protected_nopar:Npn \fp_trig_octant_aux: + { + \if_int_compare:w \l_fp_input_a_integer_int > \c_zero + \fp_sub:NNNNNNNNN + \l_fp_input_a_integer_int \l_fp_input_a_decimal_int + \l_fp_input_a_extended_int + \c_zero \c_fp_pi_by_four_decimal_int \c_fp_pi_by_four_extended_int + \l_fp_input_a_integer_int \l_fp_input_a_decimal_int + \l_fp_input_a_extended_int + \tex_advance:D \l_fp_trig_octant_int \c_one + \exp_after:wN \fp_trig_octant_aux: + \else: + \if_int_compare:w + \l_fp_input_a_decimal_int > \c_fp_pi_by_four_decimal_int + \fp_sub:NNNNNNNNN + \l_fp_input_a_integer_int \l_fp_input_a_decimal_int + \l_fp_input_a_extended_int + \c_zero \c_fp_pi_by_four_decimal_int + \c_fp_pi_by_four_extended_int + \l_fp_input_a_integer_int \l_fp_input_a_decimal_int + \l_fp_input_a_extended_int + \tex_advance:D \l_fp_trig_octant_int \c_one + \exp_after:wN \exp_after:wN \exp_after:wN + \fp_trig_octant_aux: + \fi: + \fi: + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\fp_sin:Nn, \fp_sin:cn} +% \UnitTested +% \begin{macro}{\fp_gsin:Nn,\fp_gsin:cn} +% \UnitTested +% \begin{macro}[aux]{\fp_sin_aux:NNn} +% \begin{macro}[aux]{\fp_sin_aux_i:} +% \begin{macro}[aux]{\fp_sin_aux_ii:} +% Calculating the sine starts off in the usual way. There is a check +% to see if the value has already been worked out before proceeding +% further. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_sin:Nn { \fp_sin_aux:NNn \tl_set:Nn } +\cs_new_protected_nopar:Npn \fp_gsin:Nn { \fp_sin_aux:NNn \tl_gset:Nn } +\cs_generate_variant:Nn \fp_sin:Nn { c } +\cs_generate_variant:Nn \fp_gsin:Nn { c } +% \end{macrocode} +% The internal routine for sines does a check to see if the value is +% already known. This saves a lot of repetition when doing rotations. +% For very small values it is best to simply return the input as the +% sine: the cut-off is $ 1 \times 10^{-5} $. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_sin_aux:NNn #1#2#3 + { + \group_begin: + \fp_split:Nn a {#3} + \fp_standardise:NNNN + \l_fp_input_a_sign_int + \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int + \l_fp_input_a_exponent_int + \tl_set:Nx \l_fp_arg_tl + { + \if_int_compare:w \l_fp_input_a_sign_int < \c_zero + - + \else: + + + \fi: + \int_use:N \l_fp_input_a_integer_int + . + \exp_after:wN \use_none:n + \int_value:w \int_eval:w + \l_fp_input_a_decimal_int + \c_one_thousand_million + e + \int_use:N \l_fp_input_a_exponent_int + } + \if_int_compare:w \l_fp_input_a_exponent_int < -\c_five + \cs_set_protected_nopar:Npx \fp_tmp:w + { + \group_end: + #1 \exp_not:N #2 { \l_fp_arg_tl } + } + \else: + \if_cs_exist:w + c_fp_sin ( \l_fp_arg_tl ) _fp + \cs_end: + \else: + \exp_after:wN \exp_after:wN \exp_after:wN + \fp_sin_aux_i: + \fi: + \cs_set_protected_nopar:Npx \fp_tmp:w + { + \group_end: + #1 \exp_not:N #2 + { \use:c { c_fp_sin ( \l_fp_arg_tl ) _fp } } + } + \fi: + \fp_tmp:w + } +% \end{macrocode} +% The internals for sine first normalise the input into an octant, then +% choose the correct set up for the Taylor series. The sign for the sine +% function is easy, so there is no worry about it. So the only thing to +% do is to get the output standardised. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_sin_aux_i: + { + \fp_trig_normalise: + \fp_sin_aux_ii: + \if_int_compare:w \l_fp_output_integer_int = \c_one + \l_fp_output_exponent_int \c_zero + \else: + \l_fp_output_integer_int \l_fp_output_decimal_int + \l_fp_output_decimal_int \l_fp_output_extended_int + \l_fp_output_exponent_int -\c_nine + \fi: + \fp_standardise:NNNN + \l_fp_input_a_sign_int + \l_fp_output_integer_int + \l_fp_output_decimal_int + \l_fp_output_exponent_int + \tl_new:c { c_fp_sin ( \l_fp_arg_tl ) _fp } + \tl_gset:cx { c_fp_sin ( \l_fp_arg_tl ) _fp } + { + \if_int_compare:w \l_fp_input_a_sign_int > \c_zero + + + \else: + - + \fi: + \int_use:N \l_fp_output_integer_int + . + \exp_after:wN \use_none:n + \int_value:w \int_eval:w + \l_fp_output_decimal_int + \c_one_thousand_million + e + \int_use:N \l_fp_output_exponent_int + } + } +\cs_new_protected_nopar:Npn \fp_sin_aux_ii: + { + \if_case:w \l_fp_trig_octant_int + \or: + \exp_after:wN \fp_trig_calc_sin: + \or: + \exp_after:wN \fp_trig_calc_cos: + \or: + \exp_after:wN \fp_trig_calc_cos: + \or: + \exp_after:wN \fp_trig_calc_sin: + \fi: + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\fp_cos:Nn, \fp_cos:cn} +% \UnitTested +% \begin{macro}{\fp_gcos:Nn,\fp_gcos:cn} +% \UnitTested +% \begin{macro}[aux]{\fp_cos_aux:NNn} +% \begin{macro}[aux]{\fp_cos_aux_i:} +% \begin{macro}[aux]{\fp_cos_aux_ii:} +% Cosine is almost identical, but there is no short cut code here. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_cos:Nn { \fp_cos_aux:NNn \tl_set:Nn } +\cs_new_protected_nopar:Npn \fp_gcos:Nn { \fp_cos_aux:NNn \tl_gset:Nn } +\cs_generate_variant:Nn \fp_cos:Nn { c } +\cs_generate_variant:Nn \fp_gcos:Nn { c } +\cs_new_protected_nopar:Npn \fp_cos_aux:NNn #1#2#3 + { + \group_begin: + \fp_split:Nn a {#3} + \fp_standardise:NNNN + \l_fp_input_a_sign_int + \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int + \l_fp_input_a_exponent_int + \tl_set:Nx \l_fp_arg_tl + { + \if_int_compare:w \l_fp_input_a_sign_int < \c_zero + - + \else: + + + \fi: + \int_use:N \l_fp_input_a_integer_int + . + \exp_after:wN \use_none:n + \int_value:w \int_eval:w + \l_fp_input_a_decimal_int + \c_one_thousand_million + e + \int_use:N \l_fp_input_a_exponent_int + } + \if_cs_exist:w c_fp_cos ( \l_fp_arg_tl ) _fp \cs_end: + \else: + \exp_after:wN \fp_cos_aux_i: + \fi: + \cs_set_protected_nopar:Npx \fp_tmp:w + { + \group_end: + #1 \exp_not:N #2 + { \use:c { c_fp_cos ( \l_fp_arg_tl ) _fp } } + } + \fp_tmp:w + } +% \end{macrocode} +% Almost the same as for sine: just a bit of correction for the sign +% of the output. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_cos_aux_i: + { + \fp_trig_normalise: + \fp_cos_aux_ii: + \if_int_compare:w \l_fp_output_integer_int = \c_one + \l_fp_output_exponent_int \c_zero + \else: + \l_fp_output_integer_int \l_fp_output_decimal_int + \l_fp_output_decimal_int \l_fp_output_extended_int + \l_fp_output_exponent_int -\c_nine + \fi: + \fp_standardise:NNNN + \l_fp_input_a_sign_int + \l_fp_output_integer_int + \l_fp_output_decimal_int + \l_fp_output_exponent_int + \tl_new:c { c_fp_cos ( \l_fp_arg_tl ) _fp } + \tl_gset:cx { c_fp_cos ( \l_fp_arg_tl ) _fp } + { + \if_int_compare:w \l_fp_input_a_sign_int > \c_zero + + + \else: + - + \fi: + \int_use:N \l_fp_output_integer_int + . + \exp_after:wN \use_none:n + \int_value:w \int_eval:w + \l_fp_output_decimal_int + \c_one_thousand_million + e + \int_use:N \l_fp_output_exponent_int + } + } +\cs_new_protected_nopar:Npn \fp_cos_aux_ii: + { + \if_case:w \l_fp_trig_octant_int + \or: + \exp_after:wN \fp_trig_calc_cos: + \or: + \exp_after:wN \fp_trig_calc_sin: + \or: + \exp_after:wN \fp_trig_calc_sin: + \or: + \exp_after:wN \fp_trig_calc_cos: + \fi: + \if_int_compare:w \l_fp_input_a_sign_int > \c_zero + \if_int_compare:w \l_fp_trig_octant_int > \c_two + \l_fp_input_a_sign_int \c_minus_one + \fi: + \else: + \if_int_compare:w \l_fp_trig_octant_int > \c_two + \else: + \l_fp_input_a_sign_int \c_one + \fi: + \fi: + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\fp_trig_calc_cos:} +% \begin{macro}{\fp_trig_calc_sin:} +% \begin{macro}[aux]{\fp_trig_calc_Taylor:} +% These functions actually do the calculation for sine and cosine. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_trig_calc_cos: + { + \if_int_compare:w \l_fp_input_a_decimal_int = \c_zero + \l_fp_output_integer_int \c_one + \l_fp_output_decimal_int \c_zero + \else: + \l_fp_trig_sign_int \c_minus_one + \fp_mul:NNNNNN + \l_fp_input_a_decimal_int \l_fp_input_a_extended_int + \l_fp_input_a_decimal_int \l_fp_input_a_extended_int + \l_fp_trig_decimal_int \l_fp_trig_extended_int + \fp_div_integer:NNNNN + \l_fp_trig_decimal_int \l_fp_trig_extended_int + \c_two + \l_fp_trig_decimal_int \l_fp_trig_extended_int + \l_fp_count_int \c_three + \if_int_compare:w \l_fp_trig_extended_int = \c_zero + \if_int_compare:w \l_fp_trig_decimal_int = \c_zero + \l_fp_output_integer_int \c_one + \l_fp_output_decimal_int \c_zero + \l_fp_output_extended_int \c_zero + \else: + \l_fp_output_integer_int \c_zero + \l_fp_output_decimal_int \c_one_thousand_million + \l_fp_output_extended_int \c_zero + \fi: + \else: + \l_fp_output_integer_int \c_zero + \l_fp_output_decimal_int 999999999 \scan_stop: + \l_fp_output_extended_int \c_one_thousand_million + \fi: + \tex_advance:D \l_fp_output_extended_int -\l_fp_trig_extended_int + \tex_advance:D \l_fp_output_decimal_int -\l_fp_trig_decimal_int + \exp_after:wN \fp_trig_calc_Taylor: + \fi: + } +\cs_new_protected_nopar:Npn \fp_trig_calc_sin: + { + \l_fp_output_integer_int \c_zero + \if_int_compare:w \l_fp_input_a_decimal_int = \c_zero + \l_fp_output_decimal_int \c_zero + \else: + \l_fp_output_decimal_int \l_fp_input_a_decimal_int + \l_fp_output_extended_int \l_fp_input_a_extended_int + \l_fp_trig_sign_int \c_one + \l_fp_trig_decimal_int \l_fp_input_a_decimal_int + \l_fp_trig_extended_int \l_fp_input_a_extended_int + \l_fp_count_int \c_two + \exp_after:wN \fp_trig_calc_Taylor: + \fi: + } +% \end{macrocode} +% This implements a Taylor series calculation for the trigonometric +% functions. Lots of shuffling about as \TeX\ is not exactly a natural +% choice for this sort of thing. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_trig_calc_Taylor: + { + \l_fp_trig_sign_int -\l_fp_trig_sign_int + \fp_mul:NNNNNN + \l_fp_trig_decimal_int \l_fp_trig_extended_int + \l_fp_input_a_decimal_int \l_fp_input_a_extended_int + \l_fp_trig_decimal_int \l_fp_trig_extended_int + \fp_mul:NNNNNN + \l_fp_trig_decimal_int \l_fp_trig_extended_int + \l_fp_input_a_decimal_int \l_fp_input_a_extended_int + \l_fp_trig_decimal_int \l_fp_trig_extended_int + \fp_div_integer:NNNNN + \l_fp_trig_decimal_int \l_fp_trig_extended_int + \l_fp_count_int + \l_fp_trig_decimal_int \l_fp_trig_extended_int + \tex_advance:D \l_fp_count_int \c_one + \fp_div_integer:NNNNN + \l_fp_trig_decimal_int \l_fp_trig_extended_int + \l_fp_count_int + \l_fp_trig_decimal_int \l_fp_trig_extended_int + \tex_advance:D \l_fp_count_int \c_one + \if_int_compare:w \l_fp_trig_decimal_int > \c_zero + \if_int_compare:w \l_fp_trig_sign_int > \c_zero + \tex_advance:D \l_fp_output_decimal_int \l_fp_trig_decimal_int + \tex_advance:D \l_fp_output_extended_int + \l_fp_trig_extended_int + \if_int_compare:w \l_fp_output_extended_int < \c_one_thousand_million + \else: + \tex_advance:D \l_fp_output_decimal_int \c_one + \tex_advance:D \l_fp_output_extended_int + -\c_one_thousand_million + \fi: + \if_int_compare:w \l_fp_output_decimal_int < \c_one_thousand_million + \else: + \tex_advance:D \l_fp_output_integer_int \c_one + \tex_advance:D \l_fp_output_decimal_int + -\c_one_thousand_million + \fi: + \else: + \tex_advance:D \l_fp_output_decimal_int -\l_fp_trig_decimal_int + \tex_advance:D \l_fp_output_extended_int + -\l_fp_input_a_extended_int + \if_int_compare:w \l_fp_output_extended_int < \c_zero + \tex_advance:D \l_fp_output_decimal_int \c_minus_one + \tex_advance:D \l_fp_output_extended_int \c_one_thousand_million + \fi: + \if_int_compare:w \l_fp_output_decimal_int < \c_zero + \tex_advance:D \l_fp_output_integer_int \c_minus_one + \tex_advance:D \l_fp_output_decimal_int \c_one_thousand_million + \fi: + \fi: + \exp_after:wN \fp_trig_calc_Taylor: + \fi: + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\fp_tan:Nn, \fp_tan:cn} +% \UnitTested +% \begin{macro}{\fp_gtan:Nn,\fp_gtan:cn} +% \UnitTested +% \begin{macro}[aux]{\fp_tan_aux:NNn} +% \begin{macro}[aux]{\fp_tan_aux_i:} +% \begin{macro}[aux]{\fp_tan_aux_ii:} +% \begin{macro}[aux]{\fp_tan_aux_iii:} +% \begin{macro}[aux]{\fp_tan_aux_iv:} +% As might be expected, tangents are calculated from the sine and cosine +% by division. So there is a bit of set up, the two subsidiary pieces +% of work are done and then a division takes place. For small numbers, +% the same approach is used as for sines, with the input value simply +% returned as is. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_tan:Nn { \fp_tan_aux:NNn \tl_set:Nn } +\cs_new_protected_nopar:Npn \fp_gtan:Nn { \fp_tan_aux:NNn \tl_gset:Nn } +\cs_generate_variant:Nn \fp_tan:Nn { c } +\cs_generate_variant:Nn \fp_gtan:Nn { c } +\cs_new_protected_nopar:Npn \fp_tan_aux:NNn #1#2#3 + { + \group_begin: + \fp_split:Nn a {#3} + \fp_standardise:NNNN + \l_fp_input_a_sign_int + \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int + \l_fp_input_a_exponent_int + \tl_set:Nx \l_fp_arg_tl + { + \if_int_compare:w \l_fp_input_a_sign_int < \c_zero + - + \else: + + + \fi: + \int_use:N \l_fp_input_a_integer_int + . + \exp_after:wN \use_none:n + \int_value:w \int_eval:w + \l_fp_input_a_decimal_int + \c_one_thousand_million + e + \int_use:N \l_fp_input_a_exponent_int + } + \if_int_compare:w \l_fp_input_a_exponent_int < -\c_five + \cs_set_protected_nopar:Npx \fp_tmp:w + { + \group_end: + #1 \exp_not:N #2 { \l_fp_arg_tl } + } + \else: + \if_cs_exist:w + c_fp_tan ( \l_fp_arg_tl ) _fp + \cs_end: + \else: + \exp_after:wN \exp_after:wN \exp_after:wN + \fp_tan_aux_i: + \fi: + \cs_set_protected_nopar:Npx \fp_tmp:w + { + \group_end: + #1 \exp_not:N #2 + { \use:c { c_fp_tan ( \l_fp_arg_tl ) _fp } } + } + \fi: + \fp_tmp:w + } +% \end{macrocode} +% The business of the calculation does not check for stored sines or +% cosines as there would then be an overhead to reading them back in. +% There is also no need to worry about \enquote{small} sine values as +% these will have been dealt with earlier. There is a two-step lead off +% so that undefined division is not even attempted. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_tan_aux_i: + { + \if_int_compare:w \l_fp_input_a_exponent_int < \c_ten + \exp_after:wN \fp_tan_aux_ii: + \else: + \cs_new_eq:cN { c_fp_tan ( \l_fp_arg_tl ) _fp } + \c_zero_fp + \exp_after:wN \fp_trig_overflow_msg: + \fi: + } +\cs_new_protected_nopar:Npn \fp_tan_aux_ii: + { + \fp_trig_normalise: + \if_int_compare:w \l_fp_input_a_sign_int > \c_zero + \if_int_compare:w \l_fp_trig_octant_int > \c_two + \l_fp_output_sign_int \c_minus_one + \else: + \l_fp_output_sign_int \c_one + \fi: + \else: + \if_int_compare:w \l_fp_trig_octant_int > \c_two + \l_fp_output_sign_int \c_one + \else: + \l_fp_output_sign_int \c_minus_one + \fi: + \fi: + \fp_cos_aux_ii: + \if_int_compare:w \l_fp_input_a_decimal_int = \c_zero + \if_int_compare:w \l_fp_input_a_integer_int = \c_zero + \cs_new_eq:cN { c_fp_tan ( \l_fp_arg_tl ) _fp } + \c_undefined_fp + \else: + \exp_after:wN \exp_after:wN \exp_after:wN + \fp_tan_aux_iii: + \fi: + \else: + \exp_after:wN \fp_tan_aux_iii: + \fi: + } +% \end{macrocode} +% The division is done here using the same code as the standard division +% unit, shifting the digits in the calculated sine and cosine to +% maintain accuracy. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_tan_aux_iii: + { + \l_fp_input_b_integer_int \l_fp_output_decimal_int + \l_fp_input_b_decimal_int \l_fp_output_extended_int + \l_fp_input_b_exponent_int -\c_nine + \fp_standardise:NNNN + \l_fp_input_b_sign_int + \l_fp_input_b_integer_int + \l_fp_input_b_decimal_int + \l_fp_input_b_exponent_int + \fp_sin_aux_ii: + \l_fp_input_a_integer_int \l_fp_output_decimal_int + \l_fp_input_a_decimal_int \l_fp_output_extended_int + \l_fp_input_a_exponent_int -\c_nine + \fp_standardise:NNNN + \l_fp_input_a_sign_int + \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int + \l_fp_input_a_exponent_int + \if_int_compare:w \l_fp_input_a_decimal_int = \c_zero + \if_int_compare:w \l_fp_input_a_integer_int = \c_zero + \cs_new_eq:cN { c_fp_tan ( \l_fp_arg_tl ) _fp } + \c_zero_fp + \else: + \exp_after:wN \exp_after:wN \exp_after:wN \fp_tan_aux_iv: + \fi: + \else: + \exp_after:wN \fp_tan_aux_iv: + \fi: + } +\cs_new_protected_nopar:Npn \fp_tan_aux_iv: + { + \l_fp_output_integer_int \c_zero + \l_fp_output_decimal_int \c_zero + \cs_set_eq:NN \fp_div_store: \fp_div_store_integer: + \l_fp_div_offset_int \c_one_hundred_million + \fp_div_loop: + \l_fp_output_exponent_int + \int_eval:w + \l_fp_input_a_exponent_int - \l_fp_input_b_exponent_int + \int_eval_end: + \fp_standardise:NNNN + \l_fp_output_sign_int + \l_fp_output_integer_int + \l_fp_output_decimal_int + \l_fp_output_exponent_int + \tl_new:c { c_fp_tan ( \l_fp_arg_tl ) _fp } + \tl_gset:cx { c_fp_tan ( \l_fp_arg_tl ) _fp } + { + \if_int_compare:w \l_fp_output_sign_int > \c_zero + + + \else: + - + \fi: + \int_use:N \l_fp_output_integer_int + . + \exp_after:wN \use_none:n + \int_value:w \int_eval:w + \l_fp_output_decimal_int + \c_one_thousand_million + e + \int_use:N \l_fp_output_exponent_int + } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Exponent and logarithm functions} +% +% \begin{variable}{\c_fp_exp_1_tl} +% \begin{variable}{\c_fp_exp_2_tl} +% \begin{variable}{\c_fp_exp_3_tl} +% \begin{variable}{\c_fp_exp_4_tl} +% \begin{variable}{\c_fp_exp_5_tl} +% \begin{variable}{\c_fp_exp_6_tl} +% \begin{variable}{\c_fp_exp_7_tl} +% \begin{variable}{\c_fp_exp_8_tl} +% \begin{variable}{\c_fp_exp_9_tl} +% \begin{variable}{\c_fp_exp_10_tl} +% \begin{variable}{\c_fp_exp_20_tl} +% \begin{variable}{\c_fp_exp_30_tl} +% \begin{variable}{\c_fp_exp_40_tl} +% \begin{variable}{\c_fp_exp_50_tl} +% \begin{variable}{\c_fp_exp_60_tl} +% \begin{variable}{\c_fp_exp_70_tl} +% \begin{variable}{\c_fp_exp_80_tl} +% \begin{variable}{\c_fp_exp_90_tl} +% \begin{variable}{\c_fp_exp_100_tl} +% \begin{variable}{\c_fp_exp_200_tl} +% Calculation of exponentials requires a number of precomputed values: +% first the positive integers. +% \begin{macrocode} +\tl_const:cn { c_fp_exp_1_tl } { { 2 } { 718281828 } { 459045235 } { 0 } } +\tl_const:cn { c_fp_exp_2_tl } { { 7 } { 389056098 } { 930650227 } { 0 } } +\tl_const:cn { c_fp_exp_3_tl } { { 2 } { 008553692 } { 318766774 } { 1 } } +\tl_const:cn { c_fp_exp_4_tl } { { 5 } { 459815003 } { 314423908 } { 1 } } +\tl_const:cn { c_fp_exp_5_tl } { { 1 } { 484131591 } { 025766034 } { 2 } } +\tl_const:cn { c_fp_exp_6_tl } { { 4 } { 034287934 } { 927351226 } { 2 } } +\tl_const:cn { c_fp_exp_7_tl } { { 1 } { 096633158 } { 428458599 } { 3 } } +\tl_const:cn { c_fp_exp_8_tl } { { 2 } { 980957987 } { 041728275 } { 3 } } +\tl_const:cn { c_fp_exp_9_tl } { { 8 } { 103083927 } { 575384008 } { 3 } } +\tl_const:cn { c_fp_exp_10_tl } { { 2 } { 202646579 } { 480671652 } { 4 } } +\tl_const:cn { c_fp_exp_20_tl } { { 4 } { 851651954 } { 097902280 } { 8 } } +\tl_const:cn { c_fp_exp_30_tl } { { 1 } { 068647458 } { 152446215 } { 13 } } +\tl_const:cn { c_fp_exp_40_tl } { { 2 } { 353852668 } { 370199854 } { 17 } } +\tl_const:cn { c_fp_exp_50_tl } { { 5 } { 184705528 } { 587072464 } { 21 } } +\tl_const:cn { c_fp_exp_60_tl } { { 1 } { 142007389 } { 815684284 } { 26 } } +\tl_const:cn { c_fp_exp_70_tl } { { 2 } { 515438670 } { 919167006 } { 30 } } +\tl_const:cn { c_fp_exp_80_tl } { { 5 } { 540622384 } { 393510053 } { 34 } } +\tl_const:cn { c_fp_exp_90_tl } { { 1 } { 220403294 } { 317840802 } { 39 } } +\tl_const:cn { c_fp_exp_100_tl } { { 2 } { 688117141 } { 816135448 } { 43 } } +\tl_const:cn { c_fp_exp_200_tl } { { 7 } { 225973768 } { 125749258 } { 86 } } +% \end{macrocode} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% +% \begin{variable}{\c_fp_exp_-1_tl} +% \begin{variable}{\c_fp_exp_-2_tl} +% \begin{variable}{\c_fp_exp_-3_tl} +% \begin{variable}{\c_fp_exp_-4_tl} +% \begin{variable}{\c_fp_exp_-5_tl} +% \begin{variable}{\c_fp_exp_-6_tl} +% \begin{variable}{\c_fp_exp_-7_tl} +% \begin{variable}{\c_fp_exp_-8_tl} +% \begin{variable}{\c_fp_exp_-9_tl} +% \begin{variable}{\c_fp_exp_-10_tl} +% \begin{variable}{\c_fp_exp_-20_tl} +% \begin{variable}{\c_fp_exp_-30_tl} +% \begin{variable}{\c_fp_exp_-40_tl} +% \begin{variable}{\c_fp_exp_-50_tl} +% \begin{variable}{\c_fp_exp_-60_tl} +% \begin{variable}{\c_fp_exp_-70_tl} +% \begin{variable}{\c_fp_exp_-80_tl} +% \begin{variable}{\c_fp_exp_-90_tl} +% \begin{variable}{\c_fp_exp_-100_tl} +% \begin{variable}{\c_fp_exp_-200_tl} +% Now the negative integers. +% \begin{macrocode} +\tl_const:cn { c_fp_exp_-1_tl } { { 3 } { 678794411 } { 71442322 } { -1 } } +\tl_const:cn { c_fp_exp_-2_tl } { { 1 } { 353352832 } { 366132692 } { -1 } } +\tl_const:cn { c_fp_exp_-3_tl } { { 4 } { 978706836 } { 786394298 } { -2 } } +\tl_const:cn { c_fp_exp_-4_tl } { { 1 } { 831563888 } { 873418029 } { -2 } } +\tl_const:cn { c_fp_exp_-5_tl } { { 6 } { 737946999 } { 085467097 } { -3 } } +\tl_const:cn { c_fp_exp_-6_tl } { { 2 } { 478752176 } { 666358423 } { -3 } } +\tl_const:cn { c_fp_exp_-7_tl } { { 9 } { 118819655 } { 545162080 } { -4 } } +\tl_const:cn { c_fp_exp_-8_tl } { { 3 } { 354626279 } { 025118388 } { -4 } } +\tl_const:cn { c_fp_exp_-9_tl } { { 1 } { 234098040 } { 866795495 } { -4 } } +\tl_const:cn { c_fp_exp_-10_tl } { { 4 } { 539992976 } { 248451536 } { -5 } } +\tl_const:cn { c_fp_exp_-20_tl } { { 2 } { 061153622 } { 438557828 } { -9 } } +\tl_const:cn { c_fp_exp_-30_tl } { { 9 } { 357622968 } { 840174605 } { -14 } } +\tl_const:cn { c_fp_exp_-40_tl } { { 4 } { 248354255 } { 291588995 } { -18 } } +\tl_const:cn { c_fp_exp_-50_tl } { { 1 } { 928749847 } { 963917783 } { -22 } } +\tl_const:cn { c_fp_exp_-60_tl } { { 8 } { 756510762 } { 696520338 } { -27 } } +\tl_const:cn { c_fp_exp_-70_tl } { { 3 } { 975449735 } { 908646808 } { -31 } } +\tl_const:cn { c_fp_exp_-80_tl } { { 1 } { 804851387 } { 845415172 } { -35 } } +\tl_const:cn { c_fp_exp_-90_tl } { { 8 } { 194012623 } { 990515430 } { -40 } } +\tl_const:cn { c_fp_exp_-100_tl } { { 3 } { 720075976 } { 020835963 } { -44 } } +\tl_const:cn { c_fp_exp_-200_tl } { { 1 } { 383896526 } { 736737530 } { -87 } } +% \end{macrocode} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% +% \begin{macro}{\fp_exp:Nn, \fp_exp:cn} +% \UnitTested +% \begin{macro}{\fp_gexp:Nn,\fp_gexp:cn} +% \UnitTested +% \begin{macro}[aux]{\fp_exp_aux:NNn} +% \begin{macro}[aux]{\fp_exp_internal:} +% \begin{macro}[aux]{\fp_exp_aux:} +% \begin{macro}[aux]{\fp_exp_integer:} +% \begin{macro}[aux]{\fp_exp_integer_tens:} +% \begin{macro}[aux]{\fp_exp_integer_units:} +% \begin{macro}[aux]{\fp_exp_integer_const:n} +% \begin{macro}[aux]{\fp_exp_integer_const:nnnn} +% \begin{macro}[aux]{\fp_exp_decimal:} +% \begin{macro}[aux]{\fp_exp_Taylor:} +% \begin{macro}[aux]{\fp_exp_const:Nx} +% \begin{macro}[aux]{\fp_exp_const:cx} +% The calculation of an exponent starts off starts in much the same +% way as the trigonometric functions: normalise the input, look for +% a pre-defined value and if one is not found hand off to the real +% workhorse function. The test for a definition of the result is used +% so that overflows do not result in any outcome being defined. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_exp:Nn { \fp_exp_aux:NNn \tl_set:Nn } +\cs_new_protected_nopar:Npn \fp_gexp:Nn { \fp_exp_aux:NNn \tl_gset:Nn } +\cs_generate_variant:Nn \fp_exp:Nn { c } +\cs_generate_variant:Nn \fp_gexp:Nn { c } +\cs_new_protected_nopar:Npn \fp_exp_aux:NNn #1#2#3 + { + \group_begin: + \fp_split:Nn a {#3} + \fp_standardise:NNNN + \l_fp_input_a_sign_int + \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int + \l_fp_input_a_exponent_int + \l_fp_input_a_extended_int \c_zero + \tl_set:Nx \l_fp_arg_tl + { + \if_int_compare:w \l_fp_input_a_sign_int < \c_zero + - + \else: + + + \fi: + \int_use:N \l_fp_input_a_integer_int + . + \exp_after:wN \use_none:n + \int_value:w \int_eval:w + \l_fp_input_a_decimal_int + \c_one_thousand_million + e + \int_use:N \l_fp_input_a_exponent_int + } + \if_cs_exist:w c_fp_exp ( \l_fp_arg_tl ) _fp \cs_end: + \else: + \exp_after:wN \fp_exp_internal: + \fi: + \cs_set_protected_nopar:Npx \fp_tmp:w + { + \group_end: + #1 \exp_not:N #2 + { + \if_cs_exist:w c_fp_exp ( \l_fp_arg_tl ) _fp + \cs_end: + \use:c { c_fp_exp ( \l_fp_arg_tl ) _fp } + \else: + \c_zero_fp + \fi: + } + } + \fp_tmp:w + } +% \end{macrocode} +% The first real step is to convert the input into a fixed-point +% representation for further calculation: anything which is dropped +% here as too small would not influence the output in any case. There +% are a couple of overflow tests: the maximum +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_exp_internal: + { + \if_int_compare:w \l_fp_input_a_exponent_int < \c_three + \fp_extended_normalise: + \if_int_compare:w \l_fp_input_a_sign_int > \c_zero + \if_int_compare:w \l_fp_input_a_integer_int < 230 \scan_stop: + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \fp_exp_aux: + \else: + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \fp_exp_overflow_msg: + \fi: + \else: + \if_int_compare:w \l_fp_input_a_integer_int < 230 \scan_stop: + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \fp_exp_aux: + \else: + \fp_exp_const:cx { c_fp_exp ( \l_fp_arg_tl ) _fp } + { \c_zero_fp } + \fi: + \fi: + \else: + \exp_after:wN \fp_exp_overflow_msg: + \fi: + } +% \end{macrocode} +% The main algorithm makes use of the fact that +% \[ +% \mathrm{e}^{nmp.q} = +% \mathrm{e}^{n} +% \mathrm{e}^{m} +% \mathrm{e}^{p} +% \mathrm{e}^{0.q} +% \] +% and that there is a Taylor series that can be used to calculate +% $ \mathrm{e}^{0.q} $. Thus the approach needed is in three parts. +% First, the exponent of the integer part of the input is found +% using the pre-calculated constants. Second, the Taylor series is +% used to find the exponent for the decimal part of the input. Finally, +% the two parts are multiplied together to give the result. As the +% normalisation code will already have dealt with any overflowing +% values, there are no further checks needed. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_exp_aux: + { + \if_int_compare:w \l_fp_input_a_integer_int > \c_zero + \exp_after:wN \fp_exp_integer: + \else: + \l_fp_output_integer_int \c_one + \l_fp_output_decimal_int \c_zero + \l_fp_output_extended_int \c_zero + \l_fp_output_exponent_int \c_zero + \exp_after:wN \fp_exp_decimal: + \fi: + } +% \end{macrocode} +% The integer part calculation starts with the hundreds. This is +% set up such that very large negative numbers can short-cut the entire +% procedure and simply return zero. In other cases, the code either +% recovers the exponent of the hundreds value or sets the appropriate +% storage to one (so that multiplication works correctly). +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_exp_integer: + { + \if_int_compare:w \l_fp_input_a_integer_int < \c_one_hundred + \l_fp_exp_integer_int \c_one + \l_fp_exp_decimal_int \c_zero + \l_fp_exp_extended_int \c_zero + \l_fp_exp_exponent_int \c_zero + \exp_after:wN \fp_exp_integer_tens: + \else: + \tl_set:Nx \l_fp_tmp_tl + { + \exp_after:wN \use_i:nnn + \int_use:N \l_fp_input_a_integer_int + } + \l_fp_input_a_integer_int + \int_eval:w + \l_fp_input_a_integer_int - \l_fp_tmp_tl 00 + \int_eval_end: + \if_int_compare:w \l_fp_input_a_sign_int < \c_zero + \if_int_compare:w \l_fp_output_integer_int > 200 \scan_stop: + \fp_exp_const:cx { c_fp_exp ( \l_fp_arg_tl ) _fp } + { \c_zero_fp } + \else: + \fp_exp_integer_const:n { - \l_fp_tmp_tl 00 } + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \fp_exp_integer_tens: + \fi: + \else: + \fp_exp_integer_const:n { \l_fp_tmp_tl 00 } + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \fp_exp_integer_tens: + \fi: + \fi: + } +% \end{macrocode} +% The tens and units parts are handled in a similar way, with a +% multiplication step to build up the final value. That also includes a +% correction step to avoid an overflow of the integer part. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_exp_integer_tens: + { + \l_fp_output_integer_int \l_fp_exp_integer_int + \l_fp_output_decimal_int \l_fp_exp_decimal_int + \l_fp_output_extended_int \l_fp_exp_extended_int + \l_fp_output_exponent_int \l_fp_exp_exponent_int + \if_int_compare:w \l_fp_input_a_integer_int > \c_nine + \tl_set:Nx \l_fp_tmp_tl + { + \exp_after:wN \use_i:nn + \int_use:N \l_fp_input_a_integer_int + } + \l_fp_input_a_integer_int + \int_eval:w + \l_fp_input_a_integer_int - \l_fp_tmp_tl 0 + \int_eval_end: + \if_int_compare:w \l_fp_input_a_sign_int > \c_zero + \fp_exp_integer_const:n { \l_fp_tmp_tl 0 } + \else: + \fp_exp_integer_const:n { - \l_fp_tmp_tl 0 } + \fi: + \fp_mul:NNNNNNNNN + \l_fp_exp_integer_int \l_fp_exp_decimal_int \l_fp_exp_extended_int + \l_fp_output_integer_int \l_fp_output_decimal_int + \l_fp_output_extended_int + \l_fp_output_integer_int \l_fp_output_decimal_int + \l_fp_output_extended_int + \tex_advance:D \l_fp_output_exponent_int \l_fp_exp_exponent_int + \fp_extended_normalise_output: + \fi: + \fp_exp_integer_units: + } +\cs_new_protected_nopar:Npn \fp_exp_integer_units: + { + \if_int_compare:w \l_fp_input_a_integer_int > \c_zero + \if_int_compare:w \l_fp_input_a_sign_int > \c_zero + \fp_exp_integer_const:n { \int_use:N \l_fp_input_a_integer_int } + \else: + \fp_exp_integer_const:n + { - \int_use:N \l_fp_input_a_integer_int } + \fi: + \fp_mul:NNNNNNNNN + \l_fp_exp_integer_int \l_fp_exp_decimal_int \l_fp_exp_extended_int + \l_fp_output_integer_int \l_fp_output_decimal_int + \l_fp_output_extended_int + \l_fp_output_integer_int \l_fp_output_decimal_int + \l_fp_output_extended_int + \tex_advance:D \l_fp_output_exponent_int \l_fp_exp_exponent_int + \fp_extended_normalise_output: + \fi: + \fp_exp_decimal: + } +% \end{macrocode} +% Recovery of the stored constant values into the separate registers +% is done with a simple expansion then assignment. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_exp_integer_const:n #1 + { + \exp_after:wN \exp_after:wN \exp_after:wN + \fp_exp_integer_const:nnnn + \cs:w c_fp_exp_ #1 _tl \cs_end: + } +\cs_new_protected_nopar:Npn \fp_exp_integer_const:nnnn #1#2#3#4 + { + \l_fp_exp_integer_int #1 \scan_stop: + \l_fp_exp_decimal_int #2 \scan_stop: + \l_fp_exp_extended_int #3 \scan_stop: + \l_fp_exp_exponent_int #4 \scan_stop: + } +% \end{macrocode} +% Finding the exponential for the decimal part of the number requires +% a Taylor series calculation. The set up is done here with the loop +% itself a separate function. Once the decimal part is available this +% is multiplied by the integer part already worked out to give +% the final result. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_exp_decimal: + { + \if_int_compare:w \l_fp_input_a_decimal_int > \c_zero + \if_int_compare:w \l_fp_input_a_sign_int > \c_zero + \l_fp_exp_integer_int \c_one + \l_fp_exp_decimal_int \l_fp_input_a_decimal_int + \l_fp_exp_extended_int \l_fp_input_a_extended_int + \else: + \l_fp_exp_integer_int \c_zero + \if_int_compare:w \l_fp_exp_extended_int = \c_zero + \l_fp_exp_decimal_int + \int_eval:w + \c_one_thousand_million - \l_fp_input_a_decimal_int + \int_eval_end: + \l_fp_exp_extended_int \c_zero + \else: + \l_fp_exp_decimal_int + \int_eval:w + 999999999 - \l_fp_input_a_decimal_int + \scan_stop: + \l_fp_exp_extended_int + \int_eval:w + \c_one_thousand_million - \l_fp_input_a_extended_int + \int_eval_end: + \fi: + \fi: + \l_fp_input_b_sign_int \l_fp_input_a_sign_int + \l_fp_input_b_decimal_int \l_fp_input_a_decimal_int + \l_fp_input_b_extended_int \l_fp_input_a_extended_int + \l_fp_count_int \c_one + \fp_exp_Taylor: + \fp_mul:NNNNNNNNN + \l_fp_exp_integer_int \l_fp_exp_decimal_int \l_fp_exp_extended_int + \l_fp_output_integer_int \l_fp_output_decimal_int + \l_fp_output_extended_int + \l_fp_output_integer_int \l_fp_output_decimal_int + \l_fp_output_extended_int + \fi: + \if_int_compare:w \l_fp_output_extended_int < \c_five_hundred_million + \else: + \tex_advance:D \l_fp_output_decimal_int \c_one + \if_int_compare:w \l_fp_output_decimal_int < \c_one_thousand_million + \else: + \l_fp_output_decimal_int \c_zero + \tex_advance:D \l_fp_output_integer_int \c_one + \fi: + \fi: + \fp_standardise:NNNN + \l_fp_output_sign_int + \l_fp_output_integer_int + \l_fp_output_decimal_int + \l_fp_output_exponent_int + \fp_exp_const:cx { c_fp_exp ( \l_fp_arg_tl ) _fp } + { + + + \int_use:N \l_fp_output_integer_int + . + \exp_after:wN \use_none:n + \int_value:w \int_eval:w + \l_fp_output_decimal_int + \c_one_thousand_million + e + \int_use:N \l_fp_output_exponent_int + } + } +% \end{macrocode} +% The Taylor series for $ \exp(x) $ is +% \[ +% 1 + x + \frac{x^2}{2!} + \frac{x^3}{3!} + \frac{x^4}{4!} + \cdots +% \] +% which converges for $ -1 < x < 1 $. The code above sets up +% the $ x $ part, leaving the loop to multiply the running +% value by $ x / n $ and add it onto the sum. The way that this is +% done is that the running total is stored in the \texttt{exp} set of +% registers, while the current item is stored as \texttt{input_b}. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_exp_Taylor: + { + \tex_advance:D \l_fp_count_int \c_one + \tex_multiply:D \l_fp_input_b_sign_int \l_fp_input_a_sign_int + \fp_mul:NNNNNN + \l_fp_input_a_decimal_int \l_fp_input_a_extended_int + \l_fp_input_b_decimal_int \l_fp_input_b_extended_int + \l_fp_input_b_decimal_int \l_fp_input_b_extended_int + \fp_div_integer:NNNNN + \l_fp_input_b_decimal_int \l_fp_input_b_extended_int + \l_fp_count_int + \l_fp_input_b_decimal_int \l_fp_input_b_extended_int + \if_int_compare:w + \int_eval:w + \l_fp_input_b_decimal_int + \l_fp_input_b_extended_int + > \c_zero + \if_int_compare:w \l_fp_input_b_sign_int > \c_zero + \tex_advance:D \l_fp_exp_decimal_int \l_fp_input_b_decimal_int + \tex_advance:D \l_fp_exp_extended_int + \l_fp_input_b_extended_int + \if_int_compare:w \l_fp_exp_extended_int < \c_one_thousand_million + \else: + \tex_advance:D \l_fp_exp_decimal_int \c_one + \tex_advance:D \l_fp_exp_extended_int + -\c_one_thousand_million + \fi: + \if_int_compare:w \l_fp_exp_decimal_int < \c_one_thousand_million + \else: + \tex_advance:D \l_fp_exp_integer_int \c_one + \tex_advance:D \l_fp_exp_decimal_int + -\c_one_thousand_million + \fi: + \else: + \tex_advance:D \l_fp_exp_decimal_int -\l_fp_input_b_decimal_int + \tex_advance:D \l_fp_exp_extended_int + -\l_fp_input_a_extended_int + \if_int_compare:w \l_fp_exp_extended_int < \c_zero + \tex_advance:D \l_fp_exp_decimal_int \c_minus_one + \tex_advance:D \l_fp_exp_extended_int \c_one_thousand_million + \fi: + \if_int_compare:w \l_fp_exp_decimal_int < \c_zero + \tex_advance:D \l_fp_exp_integer_int \c_minus_one + \tex_advance:D \l_fp_exp_decimal_int \c_one_thousand_million + \fi: + \fi: + \exp_after:wN \fp_exp_Taylor: + \fi: + } +% \end{macrocode} +% This is set up as a function so that the power code can redirect +% the effect. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_exp_const:Nx #1#2 + { + \tl_new:N #1 + \tl_gset:Nx #1 {#2} + } +\cs_generate_variant:Nn \fp_exp_const:Nx { c } +% \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} +% +% \begin{variable}{\c_fp_ln_10_1_tl} +% \begin{variable}{\c_fp_ln_10_2_tl} +% \begin{variable}{\c_fp_ln_10_3_tl} +% \begin{variable}{\c_fp_ln_10_4_tl} +% \begin{variable}{\c_fp_ln_10_5_tl} +% \begin{variable}{\c_fp_ln_10_6_tl} +% \begin{variable}{\c_fp_ln_10_7_tl} +% \begin{variable}{\c_fp_ln_10_8_tl} +% \begin{variable}{\c_fp_ln_10_9_tl} +% Constants for working out logarithms: first those for the powers of +% ten. +% \begin{macrocode} +\tl_const:cn { c_fp_ln_10_1_tl } { { 2 } { 302585092 } { 994045684 } { 0 } } +\tl_const:cn { c_fp_ln_10_2_tl } { { 4 } { 605170185 } { 988091368 } { 0 } } +\tl_const:cn { c_fp_ln_10_3_tl } { { 6 } { 907755278 } { 982137052 } { 0 } } +\tl_const:cn { c_fp_ln_10_4_tl } { { 9 } { 210340371 } { 976182736 } { 0 } } +\tl_const:cn { c_fp_ln_10_5_tl } { { 1 } { 151292546 } { 497022842 } { 1 } } +\tl_const:cn { c_fp_ln_10_6_tl } { { 1 } { 381551055 } { 796427410 } { 1 } } +\tl_const:cn { c_fp_ln_10_7_tl } { { 1 } { 611809565 } { 095831979 } { 1 } } +\tl_const:cn { c_fp_ln_10_8_tl } { { 1 } { 842068074 } { 395226547 } { 1 } } +\tl_const:cn { c_fp_ln_10_9_tl } { { 2 } { 072326583 } { 694641116 } { 1 } } +% \end{macrocode} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +%^^A 0.69...309 4. +% \begin{variable}{\c_fp_ln_2_1_tl } +% \begin{variable}{\c_fp_ln_2_2_tl } +% \begin{variable}{\c_fp_ln_2_3_tl } +% The smaller set for powers of two. +% \begin{macrocode} +\tl_const:cn { c_fp_ln_2_1_tl } { { 0 } { 693147180 } { 559945309 } { 0 } } +\tl_const:cn { c_fp_ln_2_2_tl } { { 1 } { 386294361 } { 119890618 } { 0 } } +\tl_const:cn { c_fp_ln_2_3_tl } { { 2 } { 079441541 } { 679835928 } { 0 } } +% \end{macrocode} +% \end{variable} +% \end{variable} +% \end{variable} +% +% \begin{macro}{\fp_ln:Nn, \fp_ln:cn} +% \UnitTested +% \begin{macro}{\fp_gln:Nn,\fp_gln:cn} +% \UnitTested +% \begin{macro}[aux]{\fp_ln_aux:NNn} +% \begin{macro}[aux]{\fp_ln_aux:} +% \begin{macro}[aux]{\fp_ln_exponent:} +% \begin{macro}[aux]{\fp_ln_internal:} +% \begin{macro}[aux]{\fp_ln_exponent_tens:} +% \begin{macro}[aux]{\fp_ln_exponent_units:} +% \begin{macro}[aux]{\fp_ln_normalise:} +% \begin{macro}[aux]{\fp_ln_nornalise_aux:NNNNNNNNN} +% \begin{macro}[aux]{\fp_ln_mantissa:} +% \begin{macro}[aux]{\fp_ln_mantissa_aux:} +% \begin{macro}[aux]{\fp_ln_mantissa_divide_two:} +% \begin{macro}[aux]{\fp_ln_integer_const:nn} +% \begin{macro}[aux]{\fp_ln_Taylor:} +% \begin{macro}[aux]{\fp_ln_fixed:} +% \begin{macro}[aux]{\fp_ln_fixed_aux:NNNNNNNNN} +% \begin{macro}[aux]{\fp_ln_Taylor_aux:} +% The approach for logarithms is again based on a mix of tables and +% Taylor series. Here, the initial validation is a bit easier and so it +% is set up earlier, meaning less need to escape later on. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_ln:Nn { \fp_ln_aux:NNn \tl_set:Nn } +\cs_new_protected_nopar:Npn \fp_gln:Nn { \fp_ln_aux:NNn \tl_gset:Nn } +\cs_generate_variant:Nn \fp_ln:Nn { c } +\cs_generate_variant:Nn \fp_gln:Nn { c } +\cs_new_protected_nopar:Npn \fp_ln_aux:NNn #1#2#3 + { + \group_begin: + \fp_split:Nn a {#3} + \fp_standardise:NNNN + \l_fp_input_a_sign_int + \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int + \l_fp_input_a_exponent_int + \if_int_compare:w \l_fp_input_a_sign_int > \c_zero + \if_int_compare:w + \int_eval:w + \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int + > \c_zero + \exp_after:wN \exp_after:wN \exp_after:wN \fp_ln_aux: + \else: + \cs_set_protected_nopar:Npx \fp_tmp:w ##1##2 + { + \group_end: + ##1 \exp_not:N ##2 { \c_zero_fp } + } + \exp_after:wN \exp_after:wN \exp_after:wN \fp_ln_error_msg: + \fi: + \else: + \cs_set_protected_nopar:Npx \fp_tmp:w ##1##2 + { + \group_end: + ##1 \exp_not:N ##2 { \c_zero_fp } + } + \exp_after:wN \fp_ln_error_msg: + \fi: + \fp_tmp:w #1 #2 + } +% \end{macrocode} +% As the input at this stage meets the validity criteria above, the +% argument can now be saved for further processing. There is no need +% to look at the sign of the input as it must be positive. The function +% here simply sets up to either do the full calculation or recover +% the stored value, as appropriate. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_ln_aux: + { + \tl_set:Nx \l_fp_arg_tl + { + + + \int_use:N \l_fp_input_a_integer_int + . + \exp_after:wN \use_none:n + \int_value:w \int_eval:w + \l_fp_input_a_decimal_int + \c_one_thousand_million + e + \int_use:N \l_fp_input_a_exponent_int + } + \if_cs_exist:w c_fp_ln ( \l_fp_arg_tl ) _fp \cs_end: + \else: + \exp_after:wN \fp_ln_exponent: + \fi: + \cs_set_protected_nopar:Npx \fp_tmp:w ##1##2 + { + \group_end: + ##1 \exp_not:N ##2 + { \use:c { c_fp_ln ( \l_fp_arg_tl ) _fp } } + } + } +% \end{macrocode} +% The main algorithm here uses the fact the logarithm can be divided +% up, first taking out the powers of ten, then powers of two and finally +% using a Taylor series for the remainder. +% \[ +% \ln ( 10^{n} \times 2^{m} \times x ) +% = \ln ( 10^{n} ) + \ln ( 2^{m} ) + \ln ( x ) +% \] +% The second point to remember is that +% \[ +% \ln ( x^{-1} ) = - \ln ( x ) +% \] +% which means that for the powers of $ 10 $ and $ 2 $ constants +% are only needed for positive powers. +% +% The first step is to set up the sign for the output functions and +% work out the powers of ten in the exponent. First the larger powers +% are sorted out. The values for the constants are the same as those +% for the smaller ones, just with a shift in the exponent. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_ln_exponent: + { + \fp_ln_internal: + \if_int_compare:w \l_fp_output_extended_int < \c_five_hundred_million + \else: + \tex_advance:D \l_fp_output_decimal_int \c_one + \if_int_compare:w \l_fp_output_decimal_int < \c_one_thousand_million + \else: + \l_fp_output_decimal_int \c_zero + \tex_advance:D \l_fp_output_integer_int \c_one + \fi: + \fi: + \fp_standardise:NNNN + \l_fp_output_sign_int + \l_fp_output_integer_int + \l_fp_output_decimal_int + \l_fp_output_exponent_int + \tl_const:cx { c_fp_ln ( \l_fp_arg_tl ) _fp } + { + \if_int_compare:w \l_fp_output_sign_int > \c_zero + + + \else: + - + \fi: + \int_use:N \l_fp_output_integer_int + . + \exp_after:wN \use_none:n + \int_value:w \int_eval:w + \l_fp_output_decimal_int + \c_one_thousand_million + \scan_stop: + e + \int_use:N \l_fp_output_exponent_int + } + } +\cs_new_protected_nopar:Npn \fp_ln_internal: + { + \if_int_compare:w \l_fp_input_a_exponent_int < \c_zero + \l_fp_input_a_exponent_int -\l_fp_input_a_exponent_int + \l_fp_output_sign_int \c_minus_one + \else: + \l_fp_output_sign_int \c_one + \fi: + \if_int_compare:w \l_fp_input_a_exponent_int > \c_nine + \exp_after:wN \fp_ln_exponent_tens:NN + \int_use:N \l_fp_input_a_exponent_int + \else: + \l_fp_output_integer_int \c_zero + \l_fp_output_decimal_int \c_zero + \l_fp_output_extended_int \c_zero + \l_fp_output_exponent_int \c_zero + \fi: + \fp_ln_exponent_units: + } +\cs_new_protected_nopar:Npn \fp_ln_exponent_tens:NN #1 #2 + { + \l_fp_input_a_exponent_int #2 \scan_stop: + \fp_ln_const:nn { 10 } { #1 } + \tex_advance:D \l_fp_exp_exponent_int \c_one + \l_fp_output_integer_int \l_fp_exp_integer_int + \l_fp_output_decimal_int \l_fp_exp_decimal_int + \l_fp_output_extended_int \l_fp_exp_extended_int + \l_fp_output_exponent_int \l_fp_exp_exponent_int + } +% \end{macrocode} +% Next the smaller powers of ten, which will need to be combined +% with the above: always an additive process. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_ln_exponent_units: + { + \if_int_compare:w \l_fp_input_a_exponent_int > \c_zero + \fp_ln_const:nn { 10 } { \int_use:N \l_fp_input_a_exponent_int } + \fp_ln_normalise: + \fp_add:NNNNNNNNN + \l_fp_exp_integer_int \l_fp_exp_decimal_int \l_fp_exp_extended_int + \l_fp_output_integer_int \l_fp_output_decimal_int + \l_fp_output_extended_int + \l_fp_output_integer_int \l_fp_output_decimal_int + \l_fp_output_extended_int + \fi: + \fp_ln_mantissa: + } +% \end{macrocode} +% The smaller table-based parts may need to be exponent shifted so that +% they stay in line with the larger parts. This is similar to the +% approach in other places, but here there is a need to watch the +% extended part of the number. The only case where the new exponent is +% larger than the old is if there was no previous part. Then simply set +% the exponent. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_ln_normalise: + { + \if_int_compare:w \l_fp_exp_exponent_int < \l_fp_output_exponent_int + \tex_advance:D \l_fp_exp_decimal_int \c_one_thousand_million + \exp_after:wN \use_i:nn \exp_after:wN + \fp_ln_normalise_aux:NNNNNNNNN + \int_use:N \l_fp_exp_decimal_int + \exp_after:wN \fp_ln_normalise: + \else: + \l_fp_output_exponent_int \l_fp_exp_exponent_int + \fi: + } +\cs_new_protected_nopar:Npn \fp_ln_normalise_aux:NNNNNNNNN #1#2#3#4#5#6#7#8#9 + { + \if_int_compare:w \l_fp_exp_integer_int = \c_zero + \l_fp_exp_decimal_int #1#2#3#4#5#6#7#8 \scan_stop: + \else: + \tl_set:Nx \l_fp_tmp_tl + { + \int_use:N \l_fp_exp_integer_int + #1#2#3#4#5#6#7#8 + } + \l_fp_exp_integer_int \c_zero + \l_fp_exp_decimal_int \l_fp_tmp_tl \scan_stop: + \fi: + \tex_divide:D \l_fp_exp_extended_int \c_ten + \tl_set:Nx \l_fp_tmp_tl + { + #9 + \int_use:N \l_fp_exp_extended_int + } + \l_fp_exp_extended_int \l_fp_tmp_tl \scan_stop: + \tex_advance:D \l_fp_exp_exponent_int \c_one + } +% \end{macrocode} +% The next phase is to decompose the mantissa by division by two to +% leave a value which is in the range $ 1 \le x < 2 $. The sum of the +% two powers needs to take account of the sign of the output: if it +% is negative then the result gets \emph{smaller} as the mantissa gets +% \emph{bigger}. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_ln_mantissa: + { + \l_fp_count_int \c_zero + \l_fp_input_a_extended_int \c_zero + \fp_ln_mantissa_aux: + \if_int_compare:w \l_fp_count_int > \c_zero + \fp_ln_const:nn { 2 } { \int_use:N \l_fp_count_int } + \fp_ln_normalise: + \if_int_compare:w \l_fp_output_sign_int > \c_zero + \exp_after:wN \fp_add:NNNNNNNNN + \else: + \exp_after:wN \fp_sub:NNNNNNNNN + \fi: + \l_fp_output_integer_int \l_fp_output_decimal_int + \l_fp_output_extended_int + \l_fp_exp_integer_int \l_fp_exp_decimal_int \l_fp_exp_extended_int + \l_fp_output_integer_int \l_fp_output_decimal_int + \l_fp_output_extended_int + \fi: + \if_int_compare:w + \int_eval:w + \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int > \c_one + \exp_after:wN \fp_ln_Taylor: + \fi: + } +\cs_new_protected_nopar:Npn \fp_ln_mantissa_aux: + { + \if_int_compare:w \l_fp_input_a_integer_int > \c_one + \tex_advance:D \l_fp_count_int \c_one + \fp_ln_mantissa_divide_two: + \exp_after:wN \fp_ln_mantissa_aux: + \fi: + } +% \end{macrocode} +% A fast one-shot division by two. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_ln_mantissa_divide_two: + { + \if_int_odd:w \l_fp_input_a_decimal_int + \tex_advance:D \l_fp_input_a_extended_int \c_one_thousand_million + \fi: + \if_int_odd:w \l_fp_input_a_integer_int + \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million + \fi: + \tex_divide:D \l_fp_input_a_integer_int \c_two + \tex_divide:D \l_fp_input_a_decimal_int \c_two + \tex_divide:D \l_fp_input_a_extended_int \c_two + } +% \end{macrocode} +% Recovering constants makes use of the same auxiliary code as for +% exponents. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_ln_const:nn #1#2 + { + \exp_after:wN \exp_after:wN \exp_after:wN + \fp_exp_integer_const:nnnn + \cs:w c_fp_ln_ #1 _ #2 _tl \cs_end: + } +% \end{macrocode} +% The Taylor series for the logarithm function is best implemented using +% the identity +% \[ +% \ln(x) = \ln\left( \frac{y + 1}{y - 1} \right) +% \] +% with +% \[ +% y = \frac{x - 1}{x + 1} +% \] +% This leads to the series +% \[ +% \ln(x) +% = 2y +% \left( +% 1 + y^{2} +% \left( +% \frac{1}{3} + y^{2} +% \left( +% \frac{1}{5} + y^{2} +% \left( +% \frac{1}{7} + y^{2} +% \left( +% \frac{1}{9} + \cdots +% \right) +% \right) +% \right) +% \right) +% \right) +% \] +% This expansion has the advantage that a lot of the work can be +% loaded up early by finding $ y^{2} $ before the loop itself starts. +% (In practice, the implementation does the multiplication by two at the +% end of the loop, and expands out the brackets as this is an overall +% more efficient approach.) +% +% At the implementation level, the code starts by calculating $ y $ +% and storing that in input \texttt{a} (which is no longer needed +% for other purposes). That is done using the full division system +% avoiding the parsing step. The value is then switched to a fixed-point +% representation. There is then some shuffling to get all of the working +% space set up. At this stage, a lot of registers are in use and so +% the Taylor series is calculated within a group so that the +% \texttt{output} variables can be used to hold the result. The value +% of $ y^{2} $ is held in input \texttt{b} (there are a few +% assignments saved by choosing this over \texttt{a}), while input +% \texttt{a} is used for the \enquote{loop value}. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_ln_Taylor: + { + \group_begin: + \l_fp_input_a_integer_int \c_zero + \l_fp_input_a_exponent_int \c_zero + \l_fp_input_b_integer_int \c_two + \l_fp_input_b_decimal_int \l_fp_input_a_decimal_int + \l_fp_input_b_exponent_int \c_zero + \fp_div_internal: + \fp_ln_fixed: + \l_fp_input_a_integer_int \l_fp_output_integer_int + \l_fp_input_a_decimal_int \l_fp_output_decimal_int + \l_fp_input_a_extended_int \c_zero + \l_fp_input_a_exponent_int \l_fp_output_exponent_int + \l_fp_output_decimal_int \c_zero %^^A Bug? + \l_fp_output_decimal_int \l_fp_input_a_decimal_int + \l_fp_output_extended_int \l_fp_input_a_extended_int + \fp_mul:NNNNNN + \l_fp_input_a_decimal_int \l_fp_input_a_extended_int + \l_fp_input_a_decimal_int \l_fp_input_a_extended_int + \l_fp_input_b_decimal_int \l_fp_input_b_extended_int + \l_fp_count_int \c_one + \fp_ln_Taylor_aux: + \cs_set_protected_nopar:Npx \fp_tmp:w + { + \group_end: + \l_fp_exp_integer_int \c_zero + \exp_not:N \l_fp_exp_decimal_int + \int_use:N \l_fp_output_decimal_int \scan_stop: + \exp_not:N \l_fp_exp_extended_int + \int_use:N \l_fp_output_extended_int \scan_stop: + \exp_not:N \l_fp_exp_exponent_int + \int_use:N \l_fp_output_exponent_int \scan_stop: + } + \fp_tmp:w +% \end{macrocode} +% After the loop part of the Taylor series, the factor of $ 2 $ needs +% to be included. The total for the result can then be constructed. +% \begin{macrocode} + \tex_advance:D \l_fp_exp_decimal_int \l_fp_exp_decimal_int + \if_int_compare:w \l_fp_exp_extended_int < \c_five_hundred_million + \else: + \tex_advance:D \l_fp_exp_extended_int -\c_five_hundred_million + \tex_advance:D \l_fp_exp_decimal_int \c_one + \fi: + \tex_advance:D \l_fp_exp_extended_int \l_fp_exp_extended_int + \fp_ln_normalise: + \if_int_compare:w \l_fp_output_sign_int > \c_zero + \exp_after:wN \fp_add:NNNNNNNNN + \else: + \exp_after:wN \fp_sub:NNNNNNNNN + \fi: + \l_fp_output_integer_int \l_fp_output_decimal_int + \l_fp_output_extended_int + \c_zero \l_fp_exp_decimal_int \l_fp_exp_extended_int + \l_fp_output_integer_int \l_fp_output_decimal_int + \l_fp_output_extended_int + } +% \end{macrocode} +% The usual shifts to move to fixed-point working. This is done using +% the \texttt{output} registers as this saves a reassignment here. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_ln_fixed: + { + \if_int_compare:w \l_fp_output_exponent_int < \c_zero + \tex_advance:D \l_fp_output_decimal_int \c_one_thousand_million + \exp_after:wN \use_i:nn \exp_after:wN + \fp_ln_fixed_aux:NNNNNNNNN + \int_use:N \l_fp_output_decimal_int + \exp_after:wN \fp_ln_fixed: + \fi: + } +\cs_new_protected_nopar:Npn \fp_ln_fixed_aux:NNNNNNNNN #1#2#3#4#5#6#7#8#9 + { + \if_int_compare:w \l_fp_output_integer_int = \c_zero + \l_fp_output_decimal_int #1#2#3#4#5#6#7#8 \scan_stop: + \else: + \tl_set:Nx \l_fp_tmp_tl + { + \int_use:N \l_fp_output_integer_int + #1#2#3#4#5#6#7#8 + } + \l_fp_output_integer_int \c_zero + \l_fp_output_decimal_int \l_fp_tmp_tl \scan_stop: + \fi: + \tex_advance:D \l_fp_output_exponent_int \c_one + } +% \end{macrocode} +% The main loop for the Taylor series: unlike some of the other similar +% functions, the result here is not the final value and is therefore +% subject to further manipulation outside of the loop. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_ln_Taylor_aux: + { + \tex_advance:D \l_fp_count_int \c_two + \fp_mul:NNNNNN + \l_fp_input_a_decimal_int \l_fp_input_a_extended_int + \l_fp_input_b_decimal_int \l_fp_input_b_extended_int + \l_fp_input_a_decimal_int \l_fp_input_a_extended_int + \if_int_compare:w + \int_eval:w + \l_fp_input_a_decimal_int + \l_fp_input_a_extended_int + > \c_zero + \fp_div_integer:NNNNN + \l_fp_input_a_decimal_int \l_fp_input_a_extended_int + \l_fp_count_int + \l_fp_exp_decimal_int \l_fp_exp_extended_int + \tex_advance:D \l_fp_output_decimal_int \l_fp_exp_decimal_int + \tex_advance:D \l_fp_output_extended_int \l_fp_exp_extended_int + \if_int_compare:w \l_fp_output_extended_int < \c_one_thousand_million + \else: + \tex_advance:D \l_fp_output_decimal_int \c_one + \tex_advance:D \l_fp_output_extended_int + -\c_one_thousand_million + \fi: + \if_int_compare:w \l_fp_output_decimal_int < \c_one_thousand_million + \else: + \tex_advance:D \l_fp_output_integer_int \c_one + \tex_advance:D \l_fp_output_decimal_int + -\c_one_thousand_million + \fi: + \exp_after:wN \fp_ln_Taylor_aux: + \fi: + } +% \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}{\fp_pow:Nn, \fp_pow:cn} +% \UnitTested +% \begin{macro}{\fp_gpow:Nn,\fp_gpow:cn} +% \UnitTested +% \begin{macro}[aux]{\fp_pow_aux:NNn} +% \begin{macro}[aux]{\fp_pow_aux_i:} +% \begin{macro}[aux]{\fp_pow_positive:} +% \begin{macro}[aux]{\fp_pow_negative:} +% \begin{macro}[aux]{\fp_pow_aux_ii:} +% \begin{macro}[aux]{\fp_pow_aux_iii:} +% \begin{macro}[aux]{\fp_pow_aux_iv:} +% The approach used for working out powers is to first filter out the +% various special cases and then do most of the work using the +% logarithm and exponent functions. The two storage areas are used +% in the reverse of the `natural' logic as this avoids some +% re-assignment in the sanity checking code. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_pow:Nn { \fp_pow_aux:NNn \tl_set:Nn } +\cs_new_protected_nopar:Npn \fp_gpow:Nn { \fp_pow_aux:NNn \tl_gset:Nn } +\cs_generate_variant:Nn \fp_pow:Nn { c } +\cs_generate_variant:Nn \fp_gpow:Nn { c } +\cs_new_protected_nopar:Npn \fp_pow_aux:NNn #1#2#3 + { + \group_begin: + \fp_read:N #2 + \l_fp_input_b_sign_int \l_fp_input_a_sign_int + \l_fp_input_b_integer_int \l_fp_input_a_integer_int + \l_fp_input_b_decimal_int \l_fp_input_a_decimal_int + \l_fp_input_b_exponent_int \l_fp_input_a_exponent_int + \fp_split:Nn a {#3} + \fp_standardise:NNNN + \l_fp_input_a_sign_int + \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int + \l_fp_input_a_exponent_int + \if_int_compare:w + \int_eval:w + \l_fp_input_b_integer_int + \l_fp_input_b_decimal_int + = \c_zero + \if_int_compare:w + \int_eval:w + \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int + = \c_zero + \cs_set_protected_nopar:Npx \fp_tmp:w ##1##2 + { + \group_end: + ##1 ##2 { \c_undefined_fp } + } + \else: + \cs_set_protected_nopar:Npx \fp_tmp:w ##1##2 + { + \group_end: + ##1 ##2 { \c_zero_fp } + } + \fi: + \else: + \if_int_compare:w + \int_eval:w + \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int + = \c_zero + \cs_set_protected_nopar:Npx \fp_tmp:w ##1##2 + { + \group_end: + ##1 ##2 { \c_one_fp } + } + \else: + \exp_after:wN \exp_after:wN \exp_after:wN + \fp_pow_aux_i: + \fi: + \fi: + \fp_tmp:w #1 #2 +} +% \end{macrocode} +% Simply using the logarithm function directly will fail when negative +% numbers are raised to integer powers, which is a mathematically valid +% operation. So there are some more tests to make, after forcing the +% power into an integer and decimal parts, if necessary. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_pow_aux_i: + { + \if_int_compare:w \l_fp_input_b_sign_int > \c_zero + \tl_set:Nn \l_fp_sign_tl { + } + \exp_after:wN \fp_pow_aux_ii: + \else: + \l_fp_input_a_extended_int \c_zero + \if_int_compare:w \l_fp_input_a_exponent_int < \c_ten + \group_begin: + \fp_extended_normalise: + \if_int_compare:w + \int_eval:w + \l_fp_input_a_decimal_int + \l_fp_input_a_extended_int + = \c_zero + \group_end: + \tl_set:Nn \l_fp_sign_tl { - } + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \fp_pow_aux_ii: + \else: + \group_end: + \cs_set_protected_nopar:Npx \fp_tmp:w ##1##2 + { + \group_end: + ##1 ##2 { \c_undefined_fp } + } + \fi: + \else: + \cs_set_protected_nopar:Npx \fp_tmp:w ##1##2 + { + \group_end: + ##1 ##2 { \c_undefined_fp } + } + \fi: + \fi: + } +% \end{macrocode} +% The approach used here for powers works well in most cases but gives +% poorer results for negative integer powers, which often have exact +% values. So there is some filtering to do. For negative powers where +% the power is small, an alternative approach is used in which the +% positive value is worked out and the reciprocal is then taken. The +% filtering is unfortunately rather long. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_pow_aux_ii: + { + \if_int_compare:w \l_fp_input_a_sign_int > \c_zero + \exp_after:wN \fp_pow_aux_iv: + \else: + \if_int_compare:w \l_fp_input_a_exponent_int < \c_ten + \group_begin: + \l_fp_input_a_extended_int \c_zero + \fp_extended_normalise: + \if_int_compare:w \l_fp_input_a_decimal_int = \c_zero + \if_int_compare:w \l_fp_input_a_integer_int > \c_ten + \group_end: + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \exp_after:wN \exp_after:wN + \fp_pow_aux_iv: + \else: + \group_end: + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \fp_pow_aux_iii: + \fi: + \else: + \group_end: + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \fp_pow_aux_iv: + \fi: + \else: + \exp_after:wN \exp_after:wN \exp_after:wN + \fp_pow_aux_iv: + \fi: + \fi: + \cs_set_protected_nopar:Npx \fp_tmp:w ##1##2 + { + \group_end: + ##1 ##2 + { + \l_fp_sign_tl + \int_use:N \l_fp_output_integer_int + . + \exp_after:wN \use_none:n + \int_value:w \int_eval:w + \l_fp_output_decimal_int + \c_one_thousand_million + e + \int_use:N \l_fp_output_exponent_int + } + } + } +% \end{macrocode} +% For the small negative integer powers, the calculation is done for +% the positive power and the reciprocal is then taken. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_pow_aux_iii: + { + \l_fp_input_a_sign_int \c_one + \fp_pow_aux_iv: + \l_fp_input_a_integer_int \c_one + \l_fp_input_a_decimal_int \c_zero + \l_fp_input_a_exponent_int \c_zero + \l_fp_input_b_integer_int \l_fp_output_integer_int + \l_fp_input_b_decimal_int \l_fp_output_decimal_int + \l_fp_input_b_exponent_int \l_fp_output_exponent_int + \fp_div_internal: + } +% \end{macrocode} +% The business end of the code starts by finding the logarithm of the +% given base. There is a bit of a shuffle so that this does not have +% to be re-parsed and so that the output ends up in the correct place. +% There is also a need to enable using the short-cut for a +% pre-calculated result. The internal part of the multiplication +% function can then be used to do the second part of the calculation +% directly. There is some more set up before doing the exponential: +% the idea here is to deactivate some internals so that everything works +% smoothly. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_pow_aux_iv: + { + \group_begin: + \l_fp_input_a_integer_int \l_fp_input_b_integer_int + \l_fp_input_a_decimal_int \l_fp_input_b_decimal_int + \l_fp_input_a_exponent_int \l_fp_input_b_exponent_int + \fp_ln_internal: + \cs_set_protected_nopar:Npx \fp_tmp:w + { + \group_end: + \exp_not:N \l_fp_input_b_sign_int + \int_use:N \l_fp_output_sign_int \scan_stop: + \exp_not:N \l_fp_input_b_integer_int + \int_use:N \l_fp_output_integer_int \scan_stop: + \exp_not:N \l_fp_input_b_decimal_int + \int_use:N \l_fp_output_decimal_int \scan_stop: + \exp_not:N \l_fp_input_b_extended_int + \int_use:N \l_fp_output_extended_int \scan_stop: + \exp_not:N \l_fp_input_b_exponent_int + \int_use:N \l_fp_output_exponent_int \scan_stop: + } + \fp_tmp:w + \l_fp_input_a_extended_int \c_zero + \fp_mul:NNNNNNNNN + \l_fp_input_a_integer_int \l_fp_input_a_decimal_int + \l_fp_input_a_extended_int + \l_fp_input_b_integer_int \l_fp_input_b_decimal_int + \l_fp_input_b_extended_int + \l_fp_output_integer_int \l_fp_output_decimal_int + \l_fp_output_extended_int + \l_fp_output_exponent_int + \int_eval:w + \l_fp_input_a_exponent_int + \l_fp_input_b_exponent_int + \scan_stop: + \fp_extended_normalise_output: + \tex_multiply:D \l_fp_input_a_sign_int \l_fp_input_b_sign_int + \l_fp_input_a_integer_int \l_fp_output_integer_int + \l_fp_input_a_decimal_int \l_fp_output_decimal_int + \l_fp_input_a_extended_int \l_fp_output_extended_int + \l_fp_input_a_exponent_int \l_fp_output_exponent_int + \l_fp_output_integer_int \c_zero + \l_fp_output_decimal_int \c_zero + \l_fp_output_extended_int \c_zero + \l_fp_output_exponent_int \c_zero + \cs_set_eq:NN \fp_exp_const:Nx \use_none:nn + \fp_exp_internal: + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Tests for special values} +% +% \begin{macro}[pTF]{\fp_if_undefined:N} +% \UnitTested +% Testing for an undefined value is easy. +% \begin{macrocode} +\prg_new_conditional:Npnn \fp_if_undefined:N #1 { p , T , F , TF } + { + \if_meaning:w #1 \c_undefined_fp + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[pTF]{\fp_if_zero:N} +% \UnitTested +% Testing for a zero fixed-point is also easy. +% \begin{macrocode} +\prg_new_conditional:Npnn \fp_if_zero:N #1 { p , T , F , TF } + { + \if_meaning:w #1 \c_zero_fp + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +% \end{macrocode} +% \end{macro} +% +% \subsection{Floating-point conditionals} +% +% \begin{macro}[TF]{\fp_compare:nNn} +% \begin{macro}[TF]{\fp_compare:NNN} +% \UnitTested +% \begin{macro}[aux]{\fp_compare_aux:N} +% \begin{macro}[aux]{\fp_compare_=:} +% \begin{macro}[aux]{\fp_compare_<:} +% \begin{macro}[aux]{\fp_compare_<_aux:} +% \begin{macro}[aux]{\fp_compare_absolute_a>b:} +% \begin{macro}[aux]{\fp_compare_absolute_a<b:} +% \begin{macro}[aux]{\fp_compare_>:} +% The idea for the comparisons is to provide two versions: slower and +% faster. The lead off for both is the same: get the two numbers +% read and then look for a function to handle the comparison. +% \begin{macrocode} +\prg_new_protected_conditional:Npnn \fp_compare:nNn #1#2#3 { T , F , TF } + { + \group_begin: + \fp_split:Nn a {#1} + \fp_standardise:NNNN + \l_fp_input_a_sign_int + \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int + \l_fp_input_a_exponent_int + \fp_split:Nn b {#3} + \fp_standardise:NNNN + \l_fp_input_b_sign_int + \l_fp_input_b_integer_int + \l_fp_input_b_decimal_int + \l_fp_input_b_exponent_int + \fp_compare_aux:N #2 + } +\prg_new_protected_conditional:Npnn \fp_compare:NNN #1#2#3 { T , F , TF } + { + \group_begin: + \fp_read:N #3 + \l_fp_input_b_sign_int \l_fp_input_a_sign_int + \l_fp_input_b_integer_int \l_fp_input_a_integer_int + \l_fp_input_b_decimal_int \l_fp_input_a_decimal_int + \l_fp_input_b_exponent_int \l_fp_input_a_exponent_int + \fp_read:N #1 + \fp_compare_aux:N #2 + } +\cs_new_protected_nopar:Npn \fp_compare_aux:N #1 + { + \cs_if_exist:cTF { fp_compare_#1: } + { \use:c { fp_compare_#1: } } + { + \group_end: + \prg_return_false: + } + } +% \end{macrocode} +% For equality, the test is pretty easy as things are either equal or +% they are not. +% \begin{macrocode} +\cs_new_protected_nopar:cpn { fp_compare_=: } + { + \if_int_compare:w \l_fp_input_a_sign_int = \l_fp_input_b_sign_int + \if_int_compare:w \l_fp_input_a_integer_int = \l_fp_input_b_integer_int + \if_int_compare:w \l_fp_input_a_decimal_int = \l_fp_input_b_decimal_int + \if_int_compare:w + \l_fp_input_a_exponent_int = \l_fp_input_b_exponent_int + \group_end: + \prg_return_true: + \else: + \group_end: + \prg_return_false: + \fi: + \else: + \group_end: + \prg_return_false: + \fi: + \else: + \group_end: + \prg_return_false: + \fi: + \else: + \group_end: + \prg_return_false: + \fi: + } +% \end{macrocode} +% Comparing two values is quite complex. First, there is a filter step +% to check if one or other of the given values is zero. If it is then +% the result is relatively easy to determine. +% \begin{macrocode} +\cs_new_protected_nopar:cpn { fp_compare_>: } + { + \if_int_compare:w \int_eval:w + \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int + = \c_zero + \if_int_compare:w \int_eval:w + \l_fp_input_b_integer_int + \l_fp_input_b_decimal_int + = \c_zero + \group_end: + \prg_return_false: + \else: + \if_int_compare:w \l_fp_input_b_sign_int > \c_zero + \group_end: + \prg_return_false: + \else: + \group_end: + \prg_return_true: + \fi: + \fi: + \else: + \if_int_compare:w \int_eval:w + \l_fp_input_b_integer_int + \l_fp_input_b_decimal_int + = \c_zero + \if_int_compare:w \l_fp_input_a_sign_int > \c_zero + \group_end: + \prg_return_true: + \else: + \group_end: + \prg_return_false: + \fi: + \else: + \use:c { fp_compare_>_aux: } + \fi: + \fi: + } +% \end{macrocode} +% Next, check the sign of the input: this again may give an obvious +% result. If both signs are the same, then hand off to comparing the +% absolute values. +% \begin{macrocode} +\cs_new_protected_nopar:cpn { fp_compare_>_aux: } + { + \if_int_compare:w \l_fp_input_a_sign_int > \l_fp_input_b_sign_int + \group_end: + \prg_return_true: + \else: + \if_int_compare:w \l_fp_input_a_sign_int < \l_fp_input_b_sign_int + \group_end: + \prg_return_false: + \else: + \if_int_compare:w \l_fp_input_a_sign_int > \c_zero + \use:c { fp_compare_absolute_a>b: } + \else: + \use:c { fp_compare_absolute_a<b: } + \fi: + \fi: + \fi: + } +% \end{macrocode} +% Rather long runs of checks, as there is the need to go through each +% layer of the input and do the comparison. There is also the need to +% avoid messing up with equal inputs at each stage. +% \begin{macrocode} +\cs_new_protected_nopar:cpn { fp_compare_absolute_a>b: } + { + \if_int_compare:w \l_fp_input_a_exponent_int > \l_fp_input_b_exponent_int + \group_end: + \prg_return_true: + \else: + \if_int_compare:w \l_fp_input_a_exponent_int < \l_fp_input_b_exponent_int + \group_end: + \prg_return_false: + \else: + \if_int_compare:w \l_fp_input_a_integer_int > \l_fp_input_b_integer_int + \group_end: + \prg_return_true: + \else: + \if_int_compare:w + \l_fp_input_a_integer_int < \l_fp_input_b_integer_int + \group_end: + \prg_return_false: + \else: + \if_int_compare:w + \l_fp_input_a_decimal_int > \l_fp_input_b_decimal_int + \group_end: + \prg_return_true: + \else: + \group_end: + \prg_return_false: + \fi: + \fi: + \fi: + \fi: + \fi: + } +\cs_new_protected_nopar:cpn { fp_compare_absolute_a<b: } + { + \if_int_compare:w \l_fp_input_b_exponent_int > \l_fp_input_a_exponent_int + \group_end: + \prg_return_true: + \else: + \if_int_compare:w \l_fp_input_b_exponent_int < \l_fp_input_a_exponent_int + \group_end: + \prg_return_false: + \else: + \if_int_compare:w \l_fp_input_b_integer_int > \l_fp_input_a_integer_int + \group_end: + \prg_return_true: + \else: + \if_int_compare:w + \l_fp_input_b_integer_int < \l_fp_input_a_integer_int + \group_end: + \prg_return_false: + \else: + \if_int_compare:w + \l_fp_input_b_decimal_int > \l_fp_input_a_decimal_int + \group_end: + \prg_return_true: + \else: + \group_end: + \prg_return_false: + \fi: + \fi: + \fi: + \fi: + \fi: + } +% \end{macrocode} +% This is just a case of reversing the two input values and then +% running the tests already defined. +% \begin{macrocode} +\cs_new_protected_nopar:cpn { fp_compare_<: } + { + \tl_set:Nx \l_fp_tmp_tl + { + \int_set:Nn \exp_not:N \l_fp_input_a_sign_int + { \int_use:N \l_fp_input_b_sign_int } + \int_set:Nn \exp_not:N \l_fp_input_a_integer_int + { \int_use:N \l_fp_input_b_integer_int } + \int_set:Nn \exp_not:N \l_fp_input_a_decimal_int + { \int_use:N \l_fp_input_b_decimal_int } + \int_set:Nn \exp_not:N \l_fp_input_a_exponent_int + { \int_use:N \l_fp_input_b_exponent_int } + \int_set:Nn \exp_not:N \l_fp_input_b_sign_int + { \int_use:N \l_fp_input_a_sign_int } + \int_set:Nn \exp_not:N \l_fp_input_b_integer_int + { \int_use:N \l_fp_input_a_integer_int } + \int_set:Nn \exp_not:N \l_fp_input_b_decimal_int + { \int_use:N \l_fp_input_a_decimal_int } + \int_set:Nn \exp_not:N \l_fp_input_b_exponent_int + { \int_use:N \l_fp_input_a_exponent_int } + } + \l_fp_tmp_tl + \use:c { fp_compare_>: } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}[TF]{\fp_compare:n} +% \begin{macro}[aux] +% { +% \fp_compare_aux_i:w, \fp_compare_aux_ii:w, \fp_compare_aux_iii:w, +% \fp_compare_aux_iv:w, \fp_compare_aux_v:w, \fp_compare_aux_vi:w, +% \fp_compare_aux_vii:w +% } +% As \TeX{} cannot help out here, a daisy-chain of delimited functions +% are used. This is very much a first-generation approach: revision will +% be needed if these functions are really useful. +% \begin{macrocode} +\prg_new_protected_conditional:Npnn \fp_compare:n #1 { T , F , TF } + { + \group_begin: + \tl_set:Nx \l_fp_tmp_tl + { + \group_end: + \fp_compare_aux_i:w #1 \exp_not:n { == \q_nil == \q_stop } + } + \l_fp_tmp_tl + } +\cs_new_protected_nopar:Npn \fp_compare_aux_i:w #1 == #2 == #3 \q_stop + { + \quark_if_nil:nTF {#2} + { \fp_compare_aux_ii:w #1 != \q_nil != \q_stop } + { \fp_compare:nNnTF {#1} = {#2} \prg_return_true: \prg_return_false: } + } +\cs_new_protected_nopar:Npn \fp_compare_aux_ii:w #1 != #2 != #3 \q_stop + { + \quark_if_nil:nTF {#2} + { \fp_compare_aux_iii:w #1 <= \q_nil <= \q_stop } + { \fp_compare:nNnTF {#1} = {#2} \prg_return_false: \prg_return_true: } + } +\cs_new_protected_nopar:Npn \fp_compare_aux_iii:w #1 <= #2 <= #3 \q_stop + { + \quark_if_nil:nTF {#2} + { \fp_compare_aux_iv:w #1 >= \q_nil >= \q_stop } + { \fp_compare:nNnTF {#1} > {#2} \prg_return_false: \prg_return_true: } + } +\cs_new_protected_nopar:Npn \fp_compare_aux_iv:w #1 >= #2 >= #3 \q_stop + { + \quark_if_nil:nTF {#2} + { \fp_compare_aux_v:w #1 = \q_nil \q_stop } + { \fp_compare:nNnTF {#1} < {#2} \prg_return_false: \prg_return_true: } + } +\cs_new_protected_nopar:Npn \fp_compare_aux_v:w #1 = #2 = #3 \q_stop + { + \quark_if_nil:nTF {#2} + { \fp_compare_aux_vi:w #1 < \q_nil < \q_stop } + { \fp_compare:nNnTF {#1} = {#2} \prg_return_true: \prg_return_false: } + } +\cs_new_protected_nopar:Npn \fp_compare_aux_vi:w #1 < #2 < #3 \q_stop + { + \quark_if_nil:nTF {#2} + { \fp_compare_aux_vii:w #1 > \q_nil > \q_stop } + { \fp_compare:nNnTF {#1} < {#2} \prg_return_true: \prg_return_false: } + } +\cs_new_protected_nopar:Npn \fp_compare_aux_vii:w #1 > #2 > #3 \q_stop + { + \quark_if_nil:nTF {#2} + { \prg_return_false: } + { \fp_compare:nNnTF {#1} > {#2} \prg_return_true: \prg_return_false: } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Messages} +% +% \begin{macro}{\fp_overflow_msg:} +% A generic overflow message, used whenever there is a possible +% overflow. +% \begin{macrocode} +\msg_kernel_new:nnnn { fpu } { overflow } + { Number~too~big. } + { + The~input~given~is~too~big~for~the~LaTeX~floating~point~unit. \\ + Further~errors~may~well~occur! + } +\cs_new_protected_nopar:Npn \fp_overflow_msg: + { \msg_kernel_error:nn { fpu } { overflow } } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\fp_exp_overflow_msg:} +% A slightly more helpful message for exponent overflows. +% \begin{macrocode} +\msg_kernel_new:nnnn { fpu } { exponent-overflow } + { Number~too~big~for~exponent~unit. } + { + The~exponent~of~the~input~given~is~too~big~for~the~floating~point~ + unit:~the~maximum~input~value~for~an~exponent~is~230. + } +\cs_new_protected_nopar:Npn \fp_exp_overflow_msg: + { \msg_kernel_error:nn { fpu } { exponent-overflow } } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\fp_ln_error_msg:} +% Logarithms are only valid for positive number +% \begin{macrocode} +\msg_kernel_new:nnnn { fpu } { logarithm-input-error } + { Invalid~input~to~ln~function. } + { Logarithms~can~only~be~calculated~for~positive~numbers. } +\cs_new_protected_nopar:Npn \fp_ln_error_msg: { + \msg_kernel_error:nn { fpu } { logarithm-input-error } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\fp_trig_overflow_msg:} +% A slightly more helpful message for trigonometric overflows. +% \begin{macrocode} +\msg_kernel_new:nnnn { fpu } { trigonometric-overflow } + { Number~too~big~for~trigonometry~unit. } + { + The~trigonometry~code~can~only~work~with~numbers~smaller~ + than~1000000000. + } +\cs_new_protected_nopar:Npn \fp_trig_overflow_msg: + { \msg_kernel_error:nn { fpu } { trigonometric-overflow } } +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +%</initex|package> +% \end{macrocode} +% +% \end{implementation} +% +%\PrintIndex diff --git a/Master/texmf-dist/source/latex/l3kernel/l3int.dtx b/Master/texmf-dist/source/latex/l3kernel/l3int.dtx new file mode 100644 index 00000000000..70264286d27 --- /dev/null +++ b/Master/texmf-dist/source/latex/l3kernel/l3int.dtx @@ -0,0 +1,2197 @@ +% \iffalse meta-comment +% +%% File: l3int.dtx Copyright (C) 1990-2011 The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +% +%<*driver|package> +\RequirePackage{l3names} +\GetIdInfo$Id: l3int.dtx 2478 2011-06-19 21:34:23Z joseph $ + {L3 Experimental integers} +%</driver|package> +%<*driver> +\documentclass[full]{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{^^A +% The \pkg{l3int} package\\ Integers^^A +% \thanks{This file describes v\ExplFileVersion, +% last revised \ExplFileDate.}^^A +% } +% +% \author{^^A +% The \LaTeX3 Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% +% \date{Released \ExplFileDate} +% +% \maketitle +% +% \begin{documentation} +% +% Calculation and comparison of integer values can be carried out +% using literal numbers, \texttt{int} registers, constants and +% integers stored in token list variables. The standard operators +% \texttt{+}, \texttt{-}, \texttt{/} and \texttt{*} and +% parentheses can be used within such expressions to carry +% arithmetic operations. This module carries out these functions +% on \emph{integer expressions} (\enquote{\texttt{int expr}}). +% +% \section{Integer expressions} +% +% \begin{function}[EXP]{\int_eval:n} +% \begin{syntax} +% \cs{int_eval:n} \Arg{integer expression} +% \end{syntax} +% Evaluates the \meta{integer expression}, expanding any +% integer and token list variables within the \meta{expression} +% to their content (without requiring \cs{int_use:N}/\cs{tl_use:N}) +% and applying the standard mathematical rules. For example both +% \begin{verbatim} +% \int_eval:n { 5 + 4 * 3 - ( 3 + 4 * 5 ) } +% \end{verbatim} +% and +% \begin{verbatim} +% \tl_new:N \l_my_tl +% \tl_set:Nn \l_my_tl { 5 } +% \int_new:N \l_my_int +% \int\set:Nn \l_my_int { 4 } +% \int_eval:n { \l_my_tl + \l_my_int * 3 - ( 3 + 4 * 5 ) } +% \end{verbatim} +% both evaluate to \( -6 \). The \Arg{integer expression} may +% contain the operators \texttt{+}, \texttt{-}, \texttt{*} and +% \texttt{/}, along with parenthesis \texttt{(} and \texttt{)}. +% After two expansions, \cs{int_eval:n} yields a +% \meta{integer denotation} which is left in the input stream. This is +% \emph{not} an \meta{internal integer}, and therefore requires +% suitable termination if used in a \TeX{}-style integer assignment. +% \end{function} +% +% \begin{function}[EXP]{\int_abs:n} +% \begin{syntax} +% \cs{int_abs:n} \Arg{integer expression} +% \end{syntax} +% Evaluates the \meta{integer expression} as described for +% \cs{int_eval:n} and leaves the absolute value of the result in +% the input stream as an \meta{integer denotation} after two +% expansions. +% \end{function} +% +% \begin{function}[EXP]{\int_div_round:nn} +% \begin{syntax} +% \cs{int_div_round:nn} \Arg{intexpr1} \Arg{intexpr2} +% \end{syntax} +% Evaluates the two \meta{integer expressions} as described earlier, +% then calculates the result of dividing the first value by the +% second, round any remainder. Note that this is identical to using +% |/| directly in an \meta{integer expression}. The result is left in +% the input stream as a \meta{integer denotation} after two expansions. +% \end{function} +% +% \begin{function}[EXP]{\int_div_truncate:nn} +% \begin{syntax} +% \cs{int_div_truncate:nn} \Arg{intexpr1} \Arg{intexpr2} +% \end{syntax} +% Evaluates the two \meta{integer expressions} as described earlier, +% then calculates the result of dividing the first value by the +% second, truncating any remainder. Note that division using |/| +% rounds the result. The result is left in the input stream as a +% \meta{integer denotation} after two expansions. +% \end{function} +% +% \begin{function}[EXP]{\int_max:nn, \int_min:nn} +% \begin{syntax} +% \cs{int_max:nn} \Arg{intexpr1} \Arg{intexpr2} +% \cs{int_min:nn} \Arg{intexpr1} \Arg{intexpr2} +% \end{syntax} +% Evaluates the \meta{integer expressions} as described for +% \cs{int_eval:n} and leaves either the larger or smaller value +% in the input stream as an \meta{integer denotation} after two +% expansions. +% \end{function} +% +% \begin{function}[EXP]{\int_mod:nn} +% \begin{syntax} +% \cs{int_mod:nn} \Arg{intexpr1} \Arg{intexpr2} +% \end{syntax} +% Evaluates the two \meta{integer expressions} as described earlier, +% then calculates the integer remainder of dividing the first +% expression by the second. This is left in the input stream as an +% \meta{integer denotation} after two expansions. +% \end{function} +% +% \section{Creating and initialising integers} +% +% \begin{function}{\int_new:N, \int_new:c} +% \begin{syntax} +% \cs{int_new:N} \meta{integer} +% \end{syntax} +% Creates a new \meta{integer} or raises an error if the name is +% already taken. The declaration is global. The \meta{integer} will +% initially be equal to $0$. +% \end{function} +% +% \begin{function}{\int_const:Nn, \int_const:cn} +% \begin{syntax} +% \cs{int_const:Nn} \meta{integer} \Arg{integer expression} +% \end{syntax} +% Creates a new constant \meta{integer} or raises an error if the name +% is already taken. The value of the \meta{integer} will be set +% globally to the \meta{integer expression}. +% \end{function} +% +% \begin{function}{\int_zero:N, \int_zero:c} +% \begin{syntax} +% \cs{int_zero:N} \meta{integer} +% \end{syntax} +% Sets \meta{integer} to $0$ within the scope of the current \TeX{} group. +% \end{function} +% +% \begin{function}{\int_gzero:N, \int_gzero:c} +% \begin{syntax} +% \cs{int_gzero:N} \meta{integer} +% \end{syntax} +% Sets \meta{integer} to $0$ globally, \emph{i.e.}~not +% restricted by the current \TeX{} group level. +% \end{function} +% +% \begin{function} +% {\int_set_eq:NN, \int_set_eq:cN, \int_set_eq:Nc, \int_set_eq:cc} +% \begin{syntax} +% \cs{int_set_eq:NN} \meta{integer1} \meta{integer2} +% \end{syntax} +% Sets the content of \meta{integer1} equal to that of +% \meta{integer2}. This assignment is restricted to the current +% \TeX{} group level. +% \end{function} +% +% \begin{function} +% {\int_gset_eq:NN, \int_gset_eq:cN, \int_gset_eq:Nc, \int_gset_eq:cc} +% \begin{syntax} +% \cs{int_gset_eq:NN} \meta{integer1} \meta{integer2} +% \end{syntax} +% Sets the content of \meta{integer1} equal to that of \meta{integer2}. +% This assignment is global and so is not limited by the current +% \TeX{} group level. +% \end{function} +% +% \section{Setting and incrementing integers} +% +% \begin{function}{\int_add:Nn, \int_add:cn} +% \begin{syntax} +% \cs{int_add:Nn} \meta{integer} \Arg{integer expression} +% \end{syntax} +% Adds the result of the \meta{integer expression} to the current +% content of the \meta{integer}. This assignment is local. +% \end{function} +% +% \begin{function}{\int_gadd:Nn, \int_gadd:cn} +% \begin{syntax} +% \cs{int_gadd:Nn} \meta{integer} \Arg{integer expression} +% \end{syntax} +% Adds the result of the \meta{integer expression} to the current +% content of the \meta{integer}. This assignment is global. +% \end{function} +% +% \begin{function}{\int_decr:N, \int_decr:c} +% \begin{syntax} +% \cs{int_decr:N} \meta{integer} +% \end{syntax} +% Decreases the value stored in \meta{integer} by $1$ within +% the scope of the current \TeX{} group. +% \end{function} +% +% \begin{function}{\int_gdecr:N, \int_gdecr:c} +% \begin{syntax} +% \cs{int_incr:N} \meta{integer} +% \end{syntax} +% Decreases the value stored in \meta{integer} by $1$ globally +% (\emph{i.e.}~not limited by the current group level). +% \end{function} +% +% \begin{function}{\int_incr:N, \int_incr:c} +% \begin{syntax} +% \cs{int_incr:N} \meta{integer} +% \end{syntax} +% Increases the value stored in \meta{integer} by $1$ within +% the scope of the current \TeX{} group. +% \end{function} +% +% \begin{function}{\int_gincr:N, \int_gincr:c} +% \begin{syntax} +% \cs{int_incr:N} \meta{integer} +% \end{syntax} +% Increases the value stored in \meta{integer} by $1$ globally +% (\emph{i.e.}~not limited by the current group level). +% \end{function} +% +% \begin{function}{\int_set:Nn, \int_set:cn} +% \begin{syntax} +% \cs{int_set:Nn} \meta{integer} \Arg{integer expression} +% \end{syntax} +% Sets \meta{integer} to the value of \meta{integer expression}, +% which must evaluate to an integer (as described for +% \cs{int_eval:n}). This assignment is restricted to the +% current \TeX{} group. +% \end{function} +% +% \begin{function}{\int_gset:Nn, \int_gset:cn} +% \begin{syntax} +% \cs{int_gset:Nn} \meta{integer} \Arg{integer expression} +% \end{syntax} +% Sets \meta{integer} to the value of \meta{integer expression}, +% which must evaluate to an integer (as described for +% \cs{int_eval:n}). This assignment is global and is not limited +% to the current \TeX{} group level. +% \end{function} +% +% \begin{function}{\int_sub:Nn, \int_sub:cn} +% \begin{syntax} +% \cs{int_sub:Nn} \meta{integer} \Arg{integer expression} +% \end{syntax} +% Subtracts the result of the \meta{integer expression} to the +% current content of the \meta{integer}. This assignment is local. +% \end{function} +% +% \begin{function}{\int_gsub:Nn, \int_gsub:cn} +% \begin{syntax} +% \cs{int_gsub:Nn} \meta{integer} \Arg{integer expression} +% \end{syntax} +% Subtracts the result of the \meta{integer expression} to the +% current content of the \meta{integer}. This assignment is global. +% \end{function} +% +% \section{Using integers} +% +% \begin{function}[EXP]{\int_use:N, \int_use:c} +% \begin{syntax} +% \cs{int_use:N} \meta{integer} +% \end{syntax} +% Recovers the content of a \meta{integer} and places it directly +% in the input stream. An error will be raised if the variable does +% not exist or if it is invalid. Can be omitted in places where a +% \meta{integer} is required (such as in the first and third arguments +% of \cs{int_compare:nNnTF}). +% \begin{texnote} +% \cs{int_use:N} is the \TeX{} primitive \cs{the}: this is one of +% several \LaTeX3 names for this primitive. +% \end{texnote} +% \end{function} +% +% \section{Integer expression conditionals} +% +% \begin{function}[EXP,pTF]{\int_compare:nNn} +% \begin{syntax} +% \cs{int_compare_p:nNn} +% ~~\Arg{intexpr1} \meta{relation} \Arg{intexpr2} +% \cs{int_compare:nNnTF} +% ~~\Arg{intexpr1} \meta{relation} \Arg{intexpr2} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% This function first evaluates each of the \meta{integer expressions} +% as described for \cs{int_eval:n}. The two results are then +% compared using the \meta{relation}: +% \begin{center} +% \begin{tabular}{ll} +% Equal & |=| \\ +% Greater than & |>| \\ +% Less than & |<| \\ +% \end{tabular} +% \end{center} +% The branching versions then leave either \meta{true code} or +% \meta{false code} in the input stream, as appropriate to the truth +% of the test and the variant of the function chosen. The logical +% truth of the test is left in the input stream by the predicate +% version. +% \end{function} +% +% \begin{function}[EXP,pTF]{\int_compare:n} +% \begin{syntax} +% \cs{int_compare_p:n} +% ~~\{ \meta{intexpr1} \meta{relation} \meta{intexpr2} \} +% \cs{int_compare:nTF} +% ~~\{ \meta{intexpr1} \meta{relation} \meta{intexpr2} \} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% This function first evaluates each of the \meta{integer expressions} +% as described for \cs{int_eval:n}. The two results are then +% compared using the \meta{relation}: +% \begin{center} +% \begin{tabular}{ll} +% Equal & |=| or |==| \\ +% Greater than or equal to & |=>| \\ +% Greater than & |>| \\ +% Less than or equal to & |=<| \\ +% Less than & |<| \\ +% Not equal & |!=| \\ +% \end{tabular} +% \end{center} +% The branching versions then leave either \meta{true code} or +% \meta{false code} in the input stream, as appropriate to the truth +% of the test and the variant of the function chosen. The logical +% truth of the test is left in the input stream by the predicate +% version. +% \end{function} +% +% \begin{function}[EXP,pTF]{\int_if_even:n, \int_if_odd:n} +% \begin{syntax} +% \cs{int_if_odd_p:n} \Arg{integer expression} +% \cs{int_if_odd:nTF} \Arg{integer expression} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% This function first evaluates the \meta{integer expression} +% as described for \cs{int_eval:n}. It then evaluates if this +% is odd or even, as appropriate. The branching versions then leave +% either \meta{true code} or \meta{false code} in the input stream, +% as appropriate to the truth of the test and the variant of the +% function chosen. The logical truth of the test is left in the input +% stream by the predicate version. +% \end{function} +% +% \section{Integer expression loops} +% +% \begin{function}[EXP]{\int_do_while:nNnn} +% \begin{syntax} +% \cs{int_do_while:nNnn} +% ~~\Arg{intexpr1} \meta{relation} \Arg{intexpr2} \Arg{code} +% \end{syntax} +% Evaluates the relationship between the two \meta{integer expressions} +% as described for \cs{int_compare:nNnTF}, and then places the +% \meta{code} in the input stream if the \meta{relation} is +% \texttt{true}. After the \meta{code} has been processed by \TeX{} the +% test will be repeated, and a loop will occur until the test is +% \texttt{false}. +% \end{function} +% +% \begin{function}[EXP]{\int_do_until:nNnn} +% \begin{syntax} +% \cs{int_do_until:nNnn} +% ~~\Arg{intexpr1} \meta{relation} \Arg{intexpr2} \Arg{code} +% \end{syntax} +% Evaluates the relationship between the two \meta{integer expressions} +% as described for \cs{int_compare:nNnTF}, and then places the +% \meta{code} in the input stream if the \meta{relation} is +% \texttt{false}. After the \meta{code} has been processed by \TeX{} the +% test will be repeated, and a loop will occur until the test is +% \texttt{true}. +% \end{function} +% +% \begin{function}[EXP]{\int_until_do:nNnn} +% \begin{syntax} +% \cs{int_until_do:nNnn} +% ~~\Arg{intexpr1} \meta{relation} \Arg{intexpr2} \Arg{code} +% \end{syntax} +% Places the \meta{code} in the input stream for \TeX{} to process, and +% then evaluates the relationship between the two +% \meta{integer expressions} as described for \cs{int_compare:nNnTF}. +% If the test is \texttt{false} then the \meta{code} will be inserted +% into the input stream again and a loop will occur until the +% \meta{relation} is \texttt{true}. +% \end{function} +% +% \begin{function}[EXP]{\int_while_do:nNnn} +% \begin{syntax} +% \cs{int_while_do:nNnn} \ +% ~~\Arg{intexpr1} \meta{relation} \Arg{intexpr2} \Arg{code} +% \end{syntax} +% Places the \meta{code} in the input stream for \TeX{} to process, and +% then evaluates the relationship between the two +% \meta{integer expressions} as described for \cs{int_compare:nNnTF}. +% If the test is \texttt{true} then the \meta{code} will be inserted +% into the input stream again and a loop will occur until the +% \meta{relation} is \texttt{false}. +% \end{function} +% +% \begin{function}[EXP]{\int_do_while:nn} +% \begin{syntax} +% \cs{int_do_while:nNnn} +% ~~\{ \meta{intexpr1} \meta{relation} \meta{intexpr2} \} \Arg{code} +% \end{syntax} +% Evaluates the relationship between the two \meta{integer expressions} +% as described for \cs{int_compare:nTF}, and then places the +% \meta{code} in the input stream if the \meta{relation} is +% \texttt{true}. After the \meta{code} has been processed by \TeX{} the +% test will be repeated, and a loop will occur until the test is +% \texttt{false}. +% \end{function} +% +% \begin{function}[EXP]{\int_do_until:nn} +% \begin{syntax} +% \cs{int_do_until:nn} +% ~~\{ \meta{intexpr1} \meta{relation} \meta{intexpr2} \} \Arg{code} +% \end{syntax} +% Evaluates the relationship between the two \meta{integer expressions} +% as described for \cs{int_compare:nTF}, and then places the +% \meta{code} in the input stream if the \meta{relation} is +% \texttt{false}. After the \meta{code} has been processed by \TeX{} the +% test will be repeated, and a loop will occur until the test is +% \texttt{true}. +% \end{function} +% +% \begin{function}[EXP]{\int_until_do:nn} +% \begin{syntax} +% \cs{int_until_do:nn} +% ~~\{ \meta{intexpr1} \meta{relation} \meta{intexpr2} \} \Arg{code} +% \end{syntax} +% Places the \meta{code} in the input stream for \TeX\ to process, and +% then evaluates the relationship between the two +% \meta{integer expressions} as described for \cs{int_compare:nTF}. +% If the test is \texttt{false} then the \meta{code} will be inserted +% into the input stream again and a loop will occur until the +% \meta{relation} is \texttt{true}. +% \end{function} +% +% \begin{function}[EXP]{\int_while_do:nn} +% \begin{syntax} +% \cs{int_while_do:nn} \ +% ~~\{ \meta{intexpr1} \meta{relation} \meta{intexpr2} \} \Arg{code} +% \end{syntax} +% Places the \meta{code} in the input stream for \TeX{} to process, and +% then evaluates the relationship between the two +% \meta{integer expressions} as described for \cs{int_compare:nTF}. +% If the test is \texttt{true} then the \meta{code} will be inserted +% into the input stream again and a loop will occur until the +% \meta{relation} is \texttt{false}. +% \end{function} +% +% \section{Formatting integers} +% +% Integers can be placed into the output stream with formatting. These +% conversions apply to any integer expressions. +% +% \begin{function}[EXP]{\int_to_arabic:n} +% \begin{syntax} +% \cs{int_to_arabic:n} \Arg{integer expression} +% \end{syntax} +% Places the value of the \meta{integer expression} in the input +% stream as digits, with category code $12$ (other). +% \end{function} +% +% \begin{function}[EXP]{\int_to_alph:n, \int_to_Alph:n} +% \begin{syntax} +% \cs{int_to_alph:n} \Arg{integer expression} +% \end{syntax} +% Evaluates the \meta{integer expression} and converts the result +% into a series of letters, which are then left in the input stream. +% The conversion rule uses the $26$ letters of the English +% alphabet, in order. Thus +% \begin{verbatim} +% \int_to_alph:n { 1 } +% \end{verbatim} +% places |a| in the input stream, +% \begin{verbatim} +% \int_to_alph:n { 26 } +% \end{verbatim} +% is represented as |z| and +% \begin{verbatim} +% \int_to_alph:n { 27 } +% \end{verbatim} +% is converted to |aa|. For conversions using other alphabets, use +% \cs{int_convert_to_symbols:nnn} to define an alphabet-specific +% function. The basic \cs{int_to_alph:n} and \cs{int_to_Alph:n} +% functions should not be modified. +% \end{function} +% +% \begin{function}[EXP]{\int_to_symbols:nnn} +% \begin{syntax} +% \cs{int_to_symbols:nnn} +% ~~\Arg{integer expression} \Arg{total symbols} +% ~~\meta{value to symbol mapping} +% \end{syntax} +% This is the low-level function for conversion of an +% \meta{integer expression} into a symbolic form (which will often +% be letters). The \meta{total symbols} available should be given +% as an integer expression. Values are actually converted to symbols +% according to the \meta{value to symbol mapping}. This should be given +% as \meta{total symbols} pairs of entries, a number and the +% appropriate symbol. Thus the \cs{int_to_alph:n} function is defined +% as +% \begin{verbatim} +% \cs_new:Npn \int_to_alph:n #1 +% { +% \int_convert_to_sybols:nnn {#1} { 26 } +% { +% { 1 } { a } +% { 2 } { b } +% { 3 } { c } +% { 4 } { d } +% { 5 } { e } +% { 6 } { f } +% { 7 } { g } +% { 8 } { h } +% { 9 } { i } +% { 10 } { j } +% { 11 } { k } +% { 12 } { l } +% { 13 } { m } +% { 14 } { n } +% { 15 } { o } +% { 16 } { p } +% { 17 } { q } +% { 18 } { r } +% { 19 } { s } +% { 20 } { t } +% { 21 } { u } +% { 22 } { v } +% { 23 } { w } +% { 24 } { x } +% { 25 } { y } +% { 26 } { z } +% } +% } +% \end{verbatim} +% \end{function} +% +% \begin{function}[EXP]{\int_to_binary:n} +% \begin{syntax} +% \cs{int_to_binary:n} \Arg{integer expression} +% \end{syntax} +% Calculates the value of the \meta{integer expression} and places +% the binary representation of the result in the input stream. +% \end{function} +% +% \begin{function}[EXP]{\int_to_hexadecimal:n} +% \begin{syntax} +% \cs{int_to_binary:n} \Arg{integer expression} +% \end{syntax} +% Calculates the value of the \meta{integer expression} and places +% the hexadecimal (base~$16$) representation of the result in the +% input stream. Upper case letters are used for digits beyond $9$. +% \end{function} +% +% \begin{function}[EXP]{\int_to_octal:n} +% \begin{syntax} +% \cs{int_to_octal:n} \Arg{integer expression} +% \end{syntax} +% Calculates the value of the \meta{integer expression} and places +% the octal (base~$8$) representation of the result in the input +% stream. +% \end{function} +% +% \begin{function}[EXP]{\int_to_base:nn} +% \begin{syntax} +% \cs{int_to_base:nn} \Arg{integer expression} \Arg{base} +% \end{syntax} +% Calculates the value of the \meta{integer expression} and +% converts it into the appropriate representation in the \meta{base}; +% the later may be given as an integer expression. For bases greater +% than $10$ the higher \enquote{digits} are represented by the upper case +% letters from the English alphabet. +% The maximum \meta{base} value is $36$. +% \begin{texnote} +% This is a generic version of \cs{int_to_binary:n}, \emph{etc.} +% \end{texnote} +% \end{function} +% +% \begin{function}[EXP]{\int_to_roman:n, \int_to_Roman:n} +% \begin{syntax} +% \cs{int_to_roman:n} \Arg{integer expression} +% \end{syntax} +% Places the value of the \meta{integer expression} in the input +% stream as Roman numerals, either lower case (\cs{int_to_roman:n}) +% or upper case (\cs{int_to_Roman:n}). The Roman numerals are letters +% with category code $11$ (letter). +% \end{function} +% +% \begin{function}[EXP]{\int_to_symbol:n} +% \begin{syntax} +% \cs{int_to_symbol:n} \Arg{integer expression} +% \end{syntax} +% Calculates the value of the \meta{integer expression} and places +% the symbol representation of the result in the input stream. The +% list of symbols used is equivalent to \LaTeXe{}'s \cs{@fnsymbol} +% set. +% \end{function} +% +% \section{Converting from other formats to integers} +% +% \begin{function}[EXP]{\int_from_alph:n} +% \begin{syntax} +% \cs{int_from_alpa:n} \Arg{letters} +% \end{syntax} +% Converts the \meta{letters} into the integer (base~$10$) +% representation and leaves this in the input stream. The +% \meta{letters} are treated using the English alphabet only, with +% \enquote{a} equal to $1$ through to \enquote{z} equal to $26$. Either lower +% or upper case letters may be used. This is the inverse function of +% \cs{int_to_alph:n}. +% \end{function} +% +% \begin{function}[EXP]{\int_from_binary:n} +% \begin{syntax} +% \cs{int_from_binary:n} \Arg{binary number} +% \end{syntax} +% Converts the \meta{binary number} into the integer (base~$10$) +% representation and leaves this in the input stream. +% \end{function} +% +% \begin{function}[EXP]{\int_from_hexadecimal:n} +% \begin{syntax} +% \cs{int_from_binary:n} \Arg{hexadecimal number} +% \end{syntax} +% Converts the \meta{hexadecimal number} into the integer +% (base~$10$) representation and leaves this in the input stream. +% Digits greater than $9$ may be represented in the +% \meta{hexadecimal number} by upper or lower case letters. +% \end{function} +% +% \begin{function}[EXP]{\int_from_octal:n} +% \begin{syntax} +% \cs{int_from_octal:n} \Arg{octal number} +% \end{syntax} +% Converts the \meta{octal number} into the integer (base~$10$) +% representation and leaves this in the input stream. +% \end{function} +% +% \begin{function}[EXP]{\int_from_roman:n} +% \begin{syntax} +% \cs{int_from_roman:n} \Arg{roman numeral} +% \end{syntax} +% Converts the \meta{roman numeral} into the integer (base~$10$) +% representation and leaves this in the input stream. The +% \meta{roman numeral} may be in upper or lower case; if the numeral +% is not valid then the resulting value will be $-1$. +% \end{function} +% +% \begin{function}[EXP]{\int_from_base:nn} +% \begin{syntax} +% \cs{int_from_base:nn} \Arg{number} +% ~~\Arg{base} +% \end{syntax} +% Converts the \meta{number} in \meta{base} into the appropriate +% value in base $10$. The \meta{number} should consist of +% digits and letters (either lower or upper case), plus optionally +% a leading sign. The maximum \meta{base} value is $36$. +% \end{function} +% +% \section{Viewing integers} +% +% \begin{function}{\int_show:N, \int_show:c} +% \begin{syntax} +% \cs{int_show:N} \meta{integer} +% \end{syntax} +% Displays the value of the \meta{integer} on the terminal. +% \end{function} +% +% \section{Constant integers} +% +% \begin{variable} +% { +% \c_minus_one , +% \c_zero , +% \c_one , +% \c_two , +% \c_three , +% \c_four , +% \c_five , +% \c_six , +% \c_seven , +% \c_eight , +% \c_nine , +% \c_ten , +% \c_eleven , +% \c_twelve , +% \c_thirteen , +% \c_fourteen , +% \c_fifteen , +% \c_sixteen , +% \c_thirty_two , +% \c_one_hundred , +% \c_two_hundred_fifty_five , +% \c_two_hundred_fifty_six , +% \c_one_thousand , +% \c_ten_thousand +% } +% Integer values used with primitive tests and assignments: +% self-terminating nature makes these more convenient and faster than +% literal numbers. +% \end{variable} +% +% \begin{variable}{\c_max_int} +% The maximum value that can be stored as an integer. +% \end{variable} +% +% \begin{variable}{\c_max_register_int} +% Maximum number of registers. +% \end{variable} +% +% \section{Scratch integers} +% +% \begin{variable}{\l_tmpa_int, \l_tmpb_int, \l_tmpc_int} +% Scratch integer for local assignment. These are never used by +% the kernel code, and so are safe for use with any \LaTeX3-defined +% function. However, they may be overwritten by other non-kernel +% code and so should only be used for short-term storage. +% \end{variable} +% +% \begin{variable}{\g_tmpa_int, \g_tmpb_int} +% Scratch integer for global assignment. These are never used by +% the kernel code, and so are safe for use with any \LaTeX3-defined +% function. However, they may be overwritten by other non-kernel +% code and so should only be used for short-term storage. +% \end{variable} +% +% \section{Internal functions} +% +% \begin{function}[EXP]{int_get_digits:n} +% \begin{syntax} +% \cs{int_get_digits:n} \meta{value} +% \end{syntax} +% Parses the \meta{value} to leave the absolute \meta{value} +% in the input stream. This may therefore be used +% to remove multiple sign tokens from the \meta{value} +% (which may be symbolic). +% \end{function} +% +% \begin{function}[EXP]{int_get_sign:n} +% \begin{syntax} +% \cs{int_get_sign:n} \meta{value} +% \end{syntax} +% Parses the \meta{value} to leave a single sign token +% (either |+| or |-|) in the input stream. This may therefore be used +% to sanitise sign tokens from the \meta{value} (which may be symbolic). +% \end{function} +% +% \begin{function}[EXP]{int_to_letter:n} +% \begin{syntax} +% \cs{int_to_letter:n} \meta{integer value} +% \end{syntax} +% For \meta{integer values} from $0$ to $9$, leaves the \meta{value} +% in the input stream unchanged. For \meta{integer values} from +% $10$ to $35$, leaves the appropriate upper case letter (from the +% standard English alphabet) in the input stream: for example, +% $10$ is converted to |A|, $11$ to |B|, \emph{etc.} +% \end{function} +% +% \begin{function}[EXP]{\int_to_roman:w} +% \begin{syntax} +% \cs{int_to_roman:w} \meta{integer} +% ~~\meta{space} \textit{or} \meta{non-expandable token} +% \end{syntax} +% Converts \meta{integer} to it lower case Roman representation. Expansion +% ends when a space or non-expandable token is found. +% Note that this function produces a string of letters with category code +% $12$ and that protected functions \emph{are} expanded by this +% process. Negative \meta{integer} values result in no output, although +% the function does not terminate expansion until a suitable endpoint +% is found in the same way as for positive numbers. +% \begin{texnote} +% This is the \TeX{} primitive \tn{romannumeral} renamed. +% \end{texnote} +% \end{function} +% +% \begin{function}[EXP]{\if_num:w, \if_int_compare:w} +% \begin{syntax} +% \cs{if_num:w} \meta{integer1} \meta{relation} \meta{integer2} +% ~~\meta{true code} +% \cs{else:} +% ~~\meta{false code} +% \cs{fi:} +% \end{syntax} +% Compare two integers using \meta{relation}, which must be one of +% |=|, |<| or |>| with category code $12$. +% The \cs{else:} branch is optional. +% \begin{texnote} +% These are both names for the \TeX{} primitive \cs{ifnum}. +% \end{texnote} +% \end{function} +% +% \begin{function}[EXP]{\if_case:w, \or:} +% \begin{syntax} +% \cs{if_case:w} \meta{integer} \meta{case0} +% ~~\cs{or:} \meta{case1} +% ~~\cs{or:} |...| +% ~~\cs{else:} \meta{default} +% \cs{fi:} +% \end{syntax} +% Selects a case to execute based on the value of the \meta{integer}. The +% first case (\meta{case0}) is executed if \meta{integer} is $0$, the second +% (\meta{case1}) if the \meta{integer} is $1$, \emph{etc.} The +% \meta{integer} may be a literal, a constant or an integer +% expression (\emph{e.g.}~using \cs{int_eval:n}). +% \begin{texnote} +% These are the \TeX{} primitives \cs{ifcase} and \cs{or}. +% \end{texnote} +% \end{function} +% +% \begin{function}[EXP]{\int_value:w} +% \begin{syntax} +% \cs{int_value:w} \meta{integer} +% \cs{int_value:w} \meta{tokens} \meta{optional space} +% \end{syntax} +% Expands \meta{tokens} until an \meta{integer} is formed. One space may be +% gobbled in the process. +% \begin{texnote} +% This is the \TeX{} primitive \cs{number}. +% \end{texnote} +% \end{function} +% +% \begin{function}[EXP]{\int_eval:w, \int_eval_end:} +% \begin{syntax} +% \cs{int_eval:w} \meta{intexpr} \cs{int_eval_end:} +% \end{syntax} +% Evaluates \meta{integer expression} as described for \cs{int_eval:n}. +% The evaluation stops when an unexpandable token which is not a valid +% part of an integer is read or when \cs{int_eval_end:} is +% reached. The latter is gobbled by the scanner mechanism: +% \cs{int_eval_end:} itself is unexpandable but used correctly +% the entire construct is expandable. +% \begin{texnote} +% This is the \eTeX{} primitive \cs{numexpr}. +% \end{texnote} +% \end{function} +% +% \begin{function}[EXP]{\if_int_odd:w} +% \begin{syntax} +% \cs{if_int_odd:w} \meta{tokens} \meta{optional space} +% ~~\meta{true code} +% \cs{else:} +% ~~\meta{true code} +% \cs{fi:} +% \end{syntax} +% Expands \meta{tokens} until a non-numeric token or a space is found, and +% tests whether the resulting \meta{integer} is odd. If so, \meta{true code} +% is executed. The \cs{else:} branch is optional. +% \begin{texnote} +% This is the \TeX{} primitive \cs{ifodd}. +% \end{texnote} +% \end{function} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{l3int} implementation} +% +% \begin{macrocode} +%<*initex|package> +% \end{macrocode} +% +% \TestFiles{m3int001,m3int002,m3int03} +% +% \begin{macrocode} +%<*package> +\ProvidesExplPackage + {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +\package_check_loaded_expl: +%</package> +% \end{macrocode} +% +% \begin{macro}{\int_to_roman:w} +% \begin{macro}{\if_int_compare:w} +% Done in \pkg{l3basics}. +% \end{macro} +% \end{macro} +% +% \begin{macro}{\int_value:w} +% \begin{macro}{\int_eval:w} +% \begin{macro}{\int_eval_end:} +% \begin{macro}{\if_num:w} +% \begin{macro}{\if_int_odd:w} +% \begin{macro}{\if_case:w} +% Here are the remaining primitives for number comparisons and +% expressions. +% \begin{macrocode} +\cs_set_eq:NN \int_value:w \tex_number:D +\cs_set_eq:NN \int_eval:w \etex_numexpr:D +\cs_new_eq:NN \int_eval_end: \tex_relax:D +\cs_new_eq:NN \if_num:w \tex_ifnum:D +\cs_set_eq:NN \if_int_odd:w \tex_ifodd:D +\cs_new_eq:NN \if_case:w \tex_ifcase:D +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Integer expressions} +% +% \begin{macro}{\int_eval:n} +% Wrapper for \cs{int_eval:w}. Can be used in an integer expression +% or directly in the input stream. +% \begin{macrocode} +\cs_new:Npn \int_eval:n #1 + { \int_value:w \int_eval:w #1 \int_eval_end: } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\int_max:nn} +% \UnitTested +% \begin{macro}{\int_min:nn} +% \UnitTested +% \begin{macro}{\int_abs:n} +% \UnitTested +% Functions for $\min$, $\max$, and absolute value. +% \begin{macrocode} +\cs_new:Npn \int_abs:n #1 + { + \int_value:w + \if_int_compare:w \int_eval:w #1 < \c_zero + - + \fi: + \int_eval:w #1 \int_eval_end: + } +\cs_new:Npn \int_max:nn #1#2 + { + \int_value:w \int_eval:w + \if_int_compare:w + \int_eval:w #1 > \int_eval:w #2 \int_eval_end: + #1 + \else: + #2 + \fi: + \int_eval_end: + } +\cs_new:Npn \int_min:nn #1#2 + { + \int_value:w \int_eval:w + \if_int_compare:w + \int_eval:w #1 < \int_eval:w #2 \int_eval_end: + #1 + \else: + #2 + \fi: + \int_eval_end: + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\int_div_truncate:nn} +% \UnitTested +% \begin{macro}{\int_div_round:nn} +% \UnitTested +% \begin{macro}{\int_mod:nn} +% \UnitTested +% As \cs{int_eval:w} rounds the result of a division we also +% provide a version that truncates the result. This version is thanks +% to Heiko Oberdiek: getting things right in all cases is not so easy. +% \begin{macrocode} +\cs_new:Npn \int_div_truncate:nn #1#2 + { + \int_value:w \int_eval:w + \if_int_compare:w \int_eval:w #1 = \c_zero + 0 + \else: + ( #1 % ) + \if_int_compare:w \int_eval:w #1 < \c_zero + \if_int_compare:w \int_eval:w #2 < \c_zero + - ( #2 + % ) + \else: + + ( #2 - % ) + \fi: + \else: + \if_int_compare:w \int_eval:w #2 < \c_zero + + ( #2 + % ) + \else: + - ( #2 - % ) + \fi: + \fi: % ( ( + 1 ) / 2 ) + \fi: + / ( #2 ) + \int_eval_end: + } +% \end{macrocode} +% For the sake of completeness: +% \begin{macrocode} +\cs_new:Npn \int_div_round:nn #1#2 { \int_eval:n { ( #1 ) / ( #2 ) } } +% \end{macrocode} +% Finally there's the modulus operation. +% \begin{macrocode} +\cs_new:Npn \int_mod:nn #1#2 + { + \int_value:w \int_eval:w + #1 - \int_div_truncate:nn {#1} {#2} * ( #2 ) + \int_eval_end: + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Creating and initialising integers} +% +% \begin{macro}{\int_new:N, \int_new:c} +% \UnitTested +% Two ways to do this: one for the format and one for the \LaTeXe{} +% package. +% \begin{macrocode} +%<*initex> +\alloc_new:nnnN { int } { 11 } { \c_max_register_int } \tex_countdef:D +%</initex> +%<*package> +\cs_new_protected_nopar:Npn \int_new:N #1 + { + \chk_if_free_cs:N #1 + \newcount #1 + } +%</package> +\cs_generate_variant:Nn \int_new:N { c } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\int_const:Nn, \int_const:cn} +% \UnitTested +% As stated, most constants can be defined as \cs{tex_chardef:D} or +% \cs{tex_mathchardef:D} but that's engine dependent. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \int_const:Nn #1#2 + { + \int_compare:nNnTF {#2} > \c_minus_one + { + \int_compare:nNnTF {#2} > \c_max_register_int + { + \int_new:N #1 + \int_gset:Nn #1 {#2} + } + { + \chk_if_free_cs:N #1 + \pref_global:D \tex_mathchardef:D #1 = + \int_eval:w #2 \int_eval_end: + } + } + { + \int_new:N #1 + \int_gset:Nn #1 {#2} + } + } +\cs_generate_variant:Nn \int_const:Nn { c } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\int_zero:N, \int_zero:c} +% \UnitTested +% \begin{macro}{\int_gzero:N, \int_gzero:c} +% \UnitTested +% Functions that reset an \meta{integer} register to zero. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \int_zero:N #1 { #1 = \c_zero } +\cs_new_protected_nopar:Npn \int_gzero:N #1 { \pref_global:D #1 = \c_zero } +\cs_generate_variant:Nn \int_zero:N { c } +\cs_generate_variant:Nn \int_gzero:N { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\int_set_eq:NN,\int_set_eq:cN, \int_set_eq:Nc,\int_set_eq:cc} +% \UnitTested +% \begin{macro} +% {\int_gset_eq:NN,\int_gset_eq:cN, \int_gset_eq:Nc,\int_gset_eq:cc} +% \UnitTested +% Setting equal means using one integer inside the set function of +% another. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \int_set_eq:NN #1#2 { #1 = #2 } +\cs_generate_variant:Nn \int_set_eq:NN { c } +\cs_generate_variant:Nn \int_set_eq:NN { Nc , cc } +\cs_new_protected_nopar:Npn \int_gset_eq:NN #1#2 { \pref_global:D #1 = #2 } +\cs_generate_variant:Nn \int_gset_eq:NN { c } +\cs_generate_variant:Nn \int_gset_eq:NN { Nc , cc } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Setting and incrementing integers} +% +% \begin{macro}{\int_add:Nn, \int_add:cn} +% \UnitTested +% \begin{macro}{\int_gadd:Nn, \int_gadd:cn} +% \UnitTested +% \begin{macro}{\int_sub:Nn, \int_sub:cn} +% \UnitTested +% \begin{macro}{\int_gsub:Nn, \int_gsub:cn} +% \UnitTested +% Adding and subtracting to and from a counter \ldots +% \begin{macrocode} +\cs_new_protected_nopar:Npn \int_add:Nn #1#2 + { \tex_advance:D #1 by \int_eval:w #2 \int_eval_end: } +\cs_new_nopar:Npn \int_sub:Nn #1#2 + { \tex_advance:D #1 by - \int_eval:w #2 \int_eval_end: } +\cs_new_protected_nopar:Npn \int_gadd:Nn + { \pref_global:D \int_add:Nn } +\cs_new_protected_nopar:Npn \int_gsub:Nn + { \pref_global:D \int_sub:Nn } +\cs_generate_variant:Nn \int_add:Nn { c } +\cs_generate_variant:Nn \int_gadd:Nn { c } +\cs_generate_variant:Nn \int_sub:Nn { c } +\cs_generate_variant:Nn \int_gsub:Nn { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\int_incr:N, \int_incr:c} +% \UnitTested +% \begin{macro}{\int_gincr:N, \int_gincr:c} +% \UnitTested +% \begin{macro}{\int_decr:N, \int_decr:c} +% \UnitTested +% \begin{macro}{\int_gdecr:N, \int_gdecr:c} +% \UnitTested +% Incrementing and decrementing of integer registers is done with +% the following functions. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \int_incr:N #1 + { \tex_advance:D #1 \c_one } +\cs_new_protected_nopar:Npn \int_decr:N #1 + { \tex_advance:D #1 \c_minus_one } +\cs_new_protected_nopar:Npn \int_gincr:N + { \pref_global:D \int_incr:N } +\cs_new_protected_nopar:Npn \int_gdecr:N + { \pref_global:D \int_decr:N } +\cs_generate_variant:Nn \int_incr:N { c } +\cs_generate_variant:Nn \int_decr:N { c } +\cs_generate_variant:Nn \int_gincr:N { c } +\cs_generate_variant:Nn \int_gdecr:N { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\int_set:Nn, \int_set:cn} +% \UnitTested +% \begin{macro}{\int_gset:Nn, \int_gset:cn} +% \UnitTested +% As integers are register-based \TeX{} will issue an error +% if they are not defined. Thus there is no need for the checking +% code seen with token list variables. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \int_set:Nn #1#2 + { #1 ~ \int_eval:w #2\int_eval_end: } +\cs_new_protected_nopar:Npn \int_gset:Nn { \pref_global:D \int_set:Nn } +\cs_generate_variant:Nn \int_set:Nn { c } +\cs_generate_variant:Nn \int_gset:Nn { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Using integers} +% +% \begin{macro}{\int_use:N, \int_use:c} +% \UnitTested +% Here is how counters are accessed: +% \begin{macrocode} +\cs_new_eq:NN \int_use:N \tex_the:D +\cs_new_nopar:Npn \int_use:c #1 { \int_use:N \cs:w #1 \cs_end: } +% \end{macrocode} +% \end{macro} +% +% \subsection{Integer expression conditionals} +% +% \begin{macro}[pTF]{\int_compare:n} +% \begin{macro}[aux]{\int_compare_aux:nw} +% \begin{macro}[aux]{\int_compare_aux:Nw} +% \begin{macro}[aux]{int_compare_=:w} +% \begin{macro}[aux]{int_compare_==:w} +% \begin{macro}[aux]{int_compare_!=:w} +% \begin{macro}[aux]{int_compare_<:w} +% \begin{macro}[aux]{int_compare_>:w} +% \begin{macro}[aux]{int_compare_<=:w} +% \begin{macro}[aux]{int_compare_>=:w} +% Comparison tests using a simple syntax where only one set of braces +% is required and additional operators such as |!=| and |>=| are +% supported. First some notes on the idea behind this. We wish to +% support writing code like +% \begin{verbatim} +% \int_compare_p:n { 5 + \l_tmpa_int != 4 - \l_tmpb_int } +% \end{verbatim} +% In other words, we want to somehow add the missing \cs{int_eval:w} +% where required. We can start evaluating from the left using +% \cs{int_eval:w}, and we know that since the relation symbols |<|, |>|, +% |=| and |!| are not allowed in such expressions, they will terminate +% the expression. Therefore, we first let \TeX{} evaluate this left +% hand side of the (in)equality. +% \begin{macrocode} +\prg_new_conditional:Npnn \int_compare:n #1 { p , T , F , TF } + { \exp_after:wN \int_compare_aux:nw \int_value:w \int_eval:w #1 \q_stop } +% \end{macrocode} +% Then the next step is to figure out which relation we should use, so +% we have to somehow get rid of the first evaluation so that we can +% see what stopped it. \cs{int_to_roman:w} is handy here since its +% expansion given a non-positive number is \meta{null}. We therefore +% simply check if the first token of the left hand side evaluation is +% a minus. If not, we insert it and issue \cs{int_to_roman:w}, +% thereby ridding us of the left hand side evaluation. We do however +% save it for later. +% \begin{macrocode} +\cs_new:Npn \int_compare_aux:nw #1#2 \q_stop + { + \exp_after:wN \int_compare_aux:Nw + \int_to_roman:w + \if:w #1 - + \else: + - + \fi: + #1#2 \q_mark #1#2 \q_stop + } +% \end{macrocode} +% This leaves the first relation symbol in front and assuming the +% right hand side has been input, at least one other token as well. We +% support the following forms: |=|, |<|, |>| and the extended |!=|, +% |==|, |<=| and |>=|. All the extended forms have an extra |=| so we +% check if that is present as well. Then use specific function to +% perform the test. +% \begin{macrocode} +\cs_new:Npn \int_compare_aux:Nw #1#2#3 \q_mark + { \use:c { int_compare_ #1 \if_meaning:w = #2 = \fi: :w } } +% \end{macrocode} +% The actual comparisons are then simple function calls, using the +% relation as delimiter for a delimited argument. +% Equality is easy: +% \begin{macrocode} +\cs_new:cpn { int_compare_=:w } #1 = #2 \q_stop + { + \if_int_compare:w #1 = \int_eval:w #2 \int_eval_end: + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +% \end{macrocode} +% So is the one using |==| we just have to use |==| in the +% parameter text. +% \begin{macrocode} +\cs_new:cpn { int_compare_==:w } #1 == #2 \q_stop + { + \if_int_compare:w #1 = \int_eval:w #2 \int_eval_end: + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +% \end{macrocode} +% Not equal is just about reversing the truth value. +% \begin{macrocode} +\cs_new:cpn { int_compare_!=:w } #1 != #2 \q_stop + { + \if_int_compare:w #1 = \int_eval:w #2 \int_eval_end: + \prg_return_false: + \else: + \prg_return_true: + \fi: + } +% \end{macrocode} +% Less than and greater than are also straight forward. +% \begin{macrocode} +\cs_new:cpn { int_compare_<:w } #1 < #2 \q_stop + { + \if_int_compare:w #1 < \int_eval:w #2 \int_eval_end: + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +\cs_new:cpn { int_compare_>:w } #1 > #2 \q_stop + { + \if_int_compare:w #1 > \int_eval:w #2 \int_eval_end: + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +% \end{macrocode} +% The less than or equal operation is just the opposite of the greater +% than operation. \emph{Vice versa} for less than or equal. +% \begin{macrocode} +\cs_new:cpn { int_compare_<=:w } #1 <= #2 \q_stop + { + \if_int_compare:w #1 > \int_eval:w #2 \int_eval_end: + \prg_return_false: + \else: + \prg_return_true: + \fi: + } +\cs_new:cpn { int_compare_>=:w } #1 >= #2 \q_stop + { + \if_int_compare:w #1 < \int_eval:w #2 \int_eval_end: + \prg_return_false: + \else: + \prg_return_true: + \fi: + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}[pTF]{\int_compare:nNn} +% \UnitTested +% More efficient but less natural in typing. +% \begin{macrocode} +\prg_new_conditional:Npnn \int_compare:nNn #1#2#3 { p , T , F , TF} + { + \if_int_compare:w \int_eval:w #1 #2 \int_eval:w #3 \int_eval_end: + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[pTF]{\int_if_odd:n} +% \UnitTested +% \begin{macro}[pTF]{\int_if_even:n} +% \UnitTested +% A predicate function. +% \begin{macrocode} +\prg_new_conditional:Npnn \int_if_odd:n #1 { p , T , F , TF} + { + \if_int_odd:w \int_eval:w #1 \int_eval_end: + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +\prg_new_conditional:Npnn \int_if_even:n #1 { p , T , F , TF} + { + \if_int_odd:w \int_eval:w #1 \int_eval_end: + \prg_return_false: + \else: + \prg_return_true: + \fi: + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Integer expression loops} +% +% \begin{macro}{\int_while_do:nn} +% \UnitTested +% \TestMissing{Boundary cases} +% \begin{macro}{\int_until_do:nn} +% \UnitTested +% \TestMissing{Boundary cases} +% \begin{macro}{\int_do_while:nn} +% \UnitTested +% \TestMissing{Boundary cases} +% \begin{macro}{\int_do_until:nn} +% \UnitTested +% \TestMissing{Boundary cases} +% These are quite easy given the above functions. The |while| versions +% test first and then execute the body. The |do_while| does it the +% other way round. +% \begin{macrocode} +\cs_new:Npn \int_while_do:nn #1#2 + { + \int_compare:nT {#1} + { + #2 + \int_while_do:nn {#1} {#2} + } + } +\cs_new:Npn \int_until_do:nn #1#2 + { + \int_compare:nF {#1} + { + #2 + \int_until_do:nn {#1} {#2} + } + } +\cs_new:Npn \int_do_while:nn #1#2 + { + #2 + \int_compare:nT {#1} + { \int_do_while:nNnn {#1} {#2} } + } +\cs_new:Npn \int_do_until:nn #1#2 + { + #2 + \int_compare:nF {#1} + { \int_do_until:nn {#1} {#2} } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\int_while_do:nNnn} +% \begin{macro}{\int_until_do:nNnn} +% \begin{macro}{\int_do_while:nNnn} +% \begin{macro}{\int_do_until:nNnn} +% As above but not using the more natural syntax. +% \begin{macrocode} +\cs_new:Npn \int_while_do:nNnn #1#2#3#4 + { + \int_compare:nNnT {#1} #2 {#3} + { + #4 + \int_while_do:nNnn {#1} #2 {#3} {#4} + } + } +\cs_new:Npn \int_until_do:nNnn #1#2#3#4 + { + \int_compare:nNnF {#1} #2 {#3} + { + #4 + \int_until_do:nNnn {#1} #2 {#3} {#4} + } + } +\cs_new:Npn \int_do_while:nNnn #1#2#3#4 + { + #4 + \int_compare:nNnT {#1} #2 {#3} + { \int_do_while:nNnn {#1} #2 {#3} {#4} } + } +\cs_new:Npn \int_do_until:nNnn #1#2#3#4 + { + #4 + \int_compare:nNnF {#1} #2 {#3} + { \int_do_until:nNnn {#1} #2 {#3} {#4} } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Formatting integers} +% +% \begin{macro}{\int_to_arabic:n} +% \UnitTested +% Nothing exciting here. +% \begin{macrocode} +\cs_new_nopar:Npn \int_to_arabic:n #1 { \int_eval:n {#1} } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\int_to_symbols:nnn} +% \UnitTested +% For conversion of integers to arbitrary symbols the method is in +% general as follows. The input number (|#1|) is compared to the total +% number of symbols available at each place (|#2|). If the input is larger +% than the total number of symbols available then the modulus is needed, +% with one added so that the positions don't have to number from +% zero. Using an \texttt{f}-type expansion, this is done so that the system +% is recursive. The actual conversion function therefore gets a `nice' +% number at each stage. Of course, if the initial input was small enough +% then there is no problem and everything is easy. This is more or less the +% same as \cs{int_convert_number_with_rule:nnN} but \enquote{pre-packaged}. +% \begin{macrocode} +\cs_new_nopar:Npn \int_to_symbols:nnn #1#2#3 + { + \int_compare:nNnTF {#1} > {#2} + { + \exp_args:Nf \int_to_symbols:nnn + { \int_div_truncate:nn { #1 - 1 } {#2} } {#2} {#3} + \exp_args:Nf \prg_case_int:nnn + { \int_eval:n { 1 + \int_mod:nn { #1 - 1 } {#2} } } + {#3} { } + } + { \exp_args:Nf \prg_case_int:nnn { \int_eval:n {#1} } {#3} { } } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\int_to_alph:n,\int_to_Alph:n} +% \UnitTested +% These both use the above function with input functions that make sense +% for the alphabet in English. +% \begin{macrocode} +\cs_new:Npn \int_to_alph:n #1 + { + \int_to_symbols:nnn {#1} { 26 } + { + { 1 } { a } + { 2 } { b } + { 3 } { c } + { 4 } { d } + { 5 } { e } + { 6 } { f } + { 7 } { g } + { 8 } { h } + { 9 } { i } + { 10 } { j } + { 11 } { k } + { 12 } { l } + { 13 } { m } + { 14 } { n } + { 15 } { o } + { 16 } { p } + { 17 } { q } + { 18 } { r } + { 19 } { s } + { 20 } { t } + { 21 } { u } + { 22 } { v } + { 23 } { w } + { 24 } { x } + { 25 } { y } + { 26 } { z } + } + } +\cs_new:Npn \int_to_Alph:n #1 + { + \int_to_symbols:nnn {#1} { 26 } + { + { 1 } { A } + { 2 } { B } + { 3 } { C } + { 4 } { D } + { 5 } { E } + { 6 } { F } + { 7 } { G } + { 8 } { H } + { 9 } { I } + { 10 } { J } + { 11 } { K } + { 12 } { L } + { 13 } { M } + { 14 } { N } + { 15 } { O } + { 16 } { P } + { 17 } { Q } + { 18 } { R } + { 19 } { S } + { 20 } { T } + { 21 } { U } + { 22 } { V } + { 23 } { W } + { 24 } { X } + { 25 } { Y } + { 26 } { Z } + } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\int_to_base:nn} +% \UnitTested +% \begin{macro}[aux]{\int_to_base_aux:nnn} +% \begin{macro}[int]{\int_to_letter:n} +% \UnitTested +% Converting from base ten (|#1|) to a second base (|#2|) starts with +% a simple sign check. As the input is base $10$ \TeX{} can then +% do the actual work with the sign itself. +% \begin{macrocode} +\cs_new:Npn \int_to_base:nn #1#2 + { + \int_compare:nNnTF {#1} < \c_zero + { + - + \exp_args:Nnf \int_to_base_aux:nnn + { } { \int_eval:n { 0 - ( #1 ) } } {#2} + } + { + \exp_args:Nnf \int_to_base_aux:nnn + { } { \int_eval:n {#1} } {#2} + } +} +% \end{macrocode} +% Here, the idea is to provide a recursive system to deal with the +% input. The output is build up as argument |#1|, which is why it +% starts off empty in the above. At each pass, the value in |#2| is +% checked to see if it is less than the new base (|#3|). If it is +% the it is converted directly and the rest of the output is added in. +% On the other hand, if the value to convert is greater than or equal +% to the new base then the modulus and remainder values are found. The +% modulus is converted to a symbol and the remainder is carried forward +% to the next round. +% \begin{macrocode} +\cs_new:Npn \int_to_base_aux:nnn #1#2#3 { + \int_compare:nNnTF {#2} < {#3} + { + \int_to_letter:n {#2} + #1 + } + { + \exp_args:Nff \int_to_base_aux:nnn + { + \int_to_letter:n { \int_mod:nn {#2} {#3} } + #1 + } + { \int_div_truncate:nn {#2} {#3} } + {#3} + } + } +% \end{macrocode} +% Convert to a letter only if necessary, otherwise simply return the +% value unchanged. +% \begin{macrocode} +\cs_new:Npn \int_to_letter:n #1 + { + \prg_case_int:nnn { #1 - 9 } + { + { 1 } { A } + { 2 } { B } + { 3 } { C } + { 4 } { D } + { 5 } { E } + { 6 } { F } + { 7 } { G } + { 8 } { H } + { 9 } { I } + { 10 } { J } + { 11 } { K } + { 12 } { L } + { 13 } { M } + { 14 } { N } + { 15 } { O } + { 16 } { P } + { 17 } { Q } + { 18 } { R } + { 19 } { S } + { 20 } { T } + { 21 } { U } + { 22 } { V } + { 23 } { W } + { 24 } { X } + { 25 } { Y } + { 26 } { Z } + } + {#1} + } +% \end{macrocode} +%\end{macro} +%\end{macro} +%\end{macro} +% +% \begin{macro}{\int_to_binary:n, \int_to_hexadecimal:n, \int_to_octal:n} +% \UnitTested +% Wrappers around the generic function. +% \begin{macrocode} +\cs_new:Npn \int_to_binary:n #1 + { \int_to_base:nn {#1} { 2 } } +\cs_new:Npn \int_to_hexadecimal:n #1 + { \int_to_base:nn {#1} { 16 } } +\cs_new:Npn \int_to_octal:n #1 + { \int_to_base:nn {#1} { 8 } } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\int_to_roman:n, \int_to_Roman:n} +% \UnitTested +% \begin{macro}[aux]{\int_to_roman_aux:N, \int_to_roman_aux:N} +% \begin{macro}[aux] +% { +% \int_to_roman_i:w, \int_to_roman_v:w, \int_to_roman_x:w, +% \int_to_roman_l:w, \int_to_roman_c:w, \int_to_roman_d:w, +% \int_to_roman_m:w, \int_to_roman_Q:w, +% \int_to_Roman_i:w, \int_to_Roman_v:w, \int_to_Roman_x:w, +% \int_to_Roman_l:w, \int_to_Roman_c:w, \int_to_Roman_d:w, +% \int_to_Roman_m:w, \int_to_Roman_Q:w, +% } +% The \cs{int_to_roman:w} primitive creates tokens of category +% code $12$ (other). Usually, what is actually wanted is letters. +% The approach here is to convert the output of the primitive into +% letters using appropriate control sequence names. That keeps +% everything expandable. The loop will be terminated by the conversion +% of the |Q|. +% \begin{macrocode} +\cs_new_nopar:Npn \int_to_roman:n #1 + { + \exp_after:wN \int_to_roman_aux:N + \int_to_roman:w \int_eval:n {#1} Q + } +\cs_new_nopar:Npn \int_to_roman_aux:N #1 + { + \use:c { int_to_roman_ #1 :w } + \int_to_roman_aux:N + } +\cs_new_nopar:Npn \int_to_Roman:n #1 + { + \exp_after:wN \int_to_Roman_aux:N + \int_to_roman:w \int_eval:n {#1} Q + } +\cs_new_nopar:Npn \int_to_Roman_aux:N #1 + { + \use:c { int_to_Roman_ #1 :w } + \int_to_Roman_aux:N + } +\cs_new_nopar:Npn \int_to_roman_i:w { i } +\cs_new_nopar:Npn \int_to_roman_v:w { v } +\cs_new_nopar:Npn \int_to_roman_x:w { x } +\cs_new_nopar:Npn \int_to_roman_l:w { l } +\cs_new_nopar:Npn \int_to_roman_c:w { c } +\cs_new_nopar:Npn \int_to_roman_d:w { d } +\cs_new_nopar:Npn \int_to_roman_m:w { m } +\cs_new_nopar:Npn \int_to_roman_Q:w #1 { } +\cs_new_nopar:Npn \int_to_Roman_i:w { I } +\cs_new_nopar:Npn \int_to_Roman_v:w { V } +\cs_new_nopar:Npn \int_to_Roman_x:w { X } +\cs_new_nopar:Npn \int_to_Roman_l:w { L } +\cs_new_nopar:Npn \int_to_Roman_c:w { C } +\cs_new_nopar:Npn \int_to_Roman_d:w { D } +\cs_new_nopar:Npn \int_to_Roman_m:w { M } +\cs_new_nopar:Npn \int_to_Roman_Q:w #1 { } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Converting from other formats to integers} +% +% \begin{macro}[int]{\int_get_sign:n} +% \begin{macro}[int]{\int_get_digits:n} +% \begin{macro}[aux] +% {\int_get_sign_and_digits_aux:nNNN, \int_get_sign_and_digits_aux:oNNN} +% Finding a number and its sign requires dealing with an arbitrary +% list of |+| and |-| symbols. This is done by working through token +% by token until there is something else at the start of the input. +% The sign of the input is tracked by the first Boolean used by the +% auxiliary function. +% \begin{macrocode} +\cs_new:Npn \int_get_sign:n #1 + { + \int_get_sign_and_digits_aux:nNNN {#1} + \c_true_bool \c_true_bool \c_false_bool + } +\cs_new:Npn \int_get_digits:n #1 + { + \int_get_sign_and_digits_aux:nNNN {#1} + \c_true_bool \c_false_bool \c_true_bool + } +% \end{macrocode} +% The auxiliary loops through, finding sign tokens and removing them. +% The sign itself is carried through as a flag. +% \begin{macrocode} +\cs_new:Npn \int_get_sign_and_digits_aux:nNNN #1#2#3#4 + { + \tl_if_head_eq_charcode:fNTF {#1} - + { + \bool_if:NTF #2 + { + \int_get_sign_and_digits_aux:oNNN + { \use_none:n #1 } \c_false_bool #3#4 + } + { + \int_get_sign_and_digits_aux:oNNN + { \use_none:n #1 } \c_true_bool #3#4 + } + } + { + \tl_if_head_eq_charcode:fNTF {#1} + + { \int_get_sign_and_digits_aux:oNNN { \use_none:n #1 } #2#3#4 } + { + \bool_if:NT #3 { \bool_if:NF #2 - } + \bool_if:NT #4 {#1} + } + } + } +\cs_generate_variant:Nn \int_get_sign_and_digits_aux:nNNN { o } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\int_from_alph:n} +% \UnitTested +% \begin{macro}[aux]{\int_from_alph_aux:n} +% \begin{macro}[aux]{\int_from_alph_aux:nN} +% \begin{macro}[aux]{\int_from_alph_aux:N} +% The aim here is to iterate through the input, converting one letter at +% a time to a number. The same approach is also used for base +% conversion, but this needs a different final auxiliary. +% \begin{macrocode} +\cs_new:Npn \int_from_alph:n #1 + { + \int_eval:n + { + \int_get_sign:n {#1} + \exp_args:Nf \int_from_alph_aux:n { \int_get_digits:n {#1} } + } + } +\cs_new:Npn \int_from_alph_aux:n #1 + { \int_from_alph_aux:nN { 0 } #1 \q_nil } +\cs_new:Npn \int_from_alph_aux:nN #1#2 + { + \quark_if_nil:NTF #2 + {#1} + { + \exp_args:Nf \int_from_alph_aux:nN + { \int_eval:n { #1 * 26 + \int_from_alph_aux:N #2 } } + } + } +\cs_new:Npn \int_from_alph_aux:N #1 + { \int_eval:n { `#1 - \int_compare:nNnTF { `#1 } < { 91 } { 64 } { 96 } } } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\int_from_base:nn} +% \UnitTested +% \begin{macro}[aux]{\int_from_base_aux:nn} +% \begin{macro}[aux]{\int_from_base_aux:nnN} +% \begin{macro}[aux]{\int_from_base_aux:N} +% Conversion to base ten means stripping off the sign then iterating +% through the input one token at a time. The total number is then added +% up as the code loops. +% \begin{macrocode} +\cs_new:Npn \int_from_base:nn #1#2 + { + \int_eval:n + { + \int_get_sign:n {#1} + \exp_args:Nf \int_from_base_aux:nn + { \int_get_digits:n {#1} } {#2} + } + } +\cs_new:Npn \int_from_base_aux:nn #1#2 + { \int_from_base_aux:nnN { 0 } { #2 } #1 \q_nil } +\cs_new:Npn \int_from_base_aux:nnN #1#2#3 + { + \quark_if_nil:NTF #3 + {#1} + { + \exp_args:Nf \int_from_base_aux:nnN + { \int_eval:n { #1 * #2 + \int_from_base_aux:N #3 } } + {#2} + } + } +% \end{macrocode} +% The conversion here will take lower or upper case letters and turn +% them into the appropriate number, hence the two-part nature of the +% function. +% \begin{macrocode} +\cs_new:Npn \int_from_base_aux:N #1 + { + \int_compare:nNnTF { `#1 } < { 58 } + {#1} + { + \int_eval:n + { `#1 - \int_compare:nNnTF { `#1 } < { 91 } { 55 } { 87 } } + } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\int_from_binary:n, \int_from_hexadecimal:n, \int_from_octal:n} +% \UnitTested +% Wrappers around the generic function. +% \begin{macrocode} +\cs_new:Npn \int_from_binary:n #1 + { \int_from_base:nn {#1} \c_two } +\cs_new:Npn \int_from_hexadecimal:n #1 + { \int_from_base:nn {#1} \c_sixteen } +\cs_new:Npn \int_from_octal:n #1 + { \int_from_base:nn {#1} \c_eight } +% \end{macrocode} +% \end{macro} +% +% \begin{variable}[aux] +% { +% \c_int_from_roman_i_int, \c_int_from_roman_v_int, +% \c_int_from_roman_x_int, \c_int_from_roman_l_int, +% \c_int_from_roman_c_int, \c_int_from_roman_d_int, +% \c_int_from_roman_m_int, +% \c_int_from_roman_I_int, \c_int_from_roman_V_int, +% \c_int_from_roman_X_int, \c_int_from_roman_L_int, +% \c_int_from_roman_C_int, \c_int_from_roman_D_int, +% \c_int_from_roman_M_int +% } +% Constants used to convert from Roman numerals to integers. +% \begin{macrocode} +\int_const:cn { c_int_from_roman_i_int } { 1 } +\int_const:cn { c_int_from_roman_v_int } { 5 } +\int_const:cn { c_int_from_roman_x_int } { 10 } +\int_const:cn { c_int_from_roman_l_int } { 50 } +\int_const:cn { c_int_from_roman_c_int } { 100 } +\int_const:cn { c_int_from_roman_d_int } { 500 } +\int_const:cn { c_int_from_roman_m_int } { 1000 } +\int_const:cn { c_int_from_roman_I_int } { 1 } +\int_const:cn { c_int_from_roman_V_int } { 5 } +\int_const:cn { c_int_from_roman_X_int } { 10 } +\int_const:cn { c_int_from_roman_L_int } { 50 } +\int_const:cn { c_int_from_roman_C_int } { 100 } +\int_const:cn { c_int_from_roman_D_int } { 500 } +\int_const:cn { c_int_from_roman_M_int } { 1000 } +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\int_from_roman:n} +% \UnitTested +% \TestMissing{boundary cases / wrong input?} +% \begin{macro}[aux]{\int_from_roman_aux:NN} +% \begin{macro}[aux]{\int_from_roman_end:w} +% \begin{macro}[aux]{\int_from_roman_clean_up:w} +% The method here is to iterate through the input, finding the +% appropriate value for each letter and building up a sum. This is +% then evaluated by \TeX{}. +% \begin{macrocode} +\cs_new_nopar:Npn \int_from_roman:n #1 + { + \tl_if_blank:nF {#1} + { + \exp_after:wN \int_from_roman_end:w + \int_value:w \int_eval:w + \int_from_roman_aux:NN #1 Q \q_stop + } + } +\cs_new_nopar:Npn \int_from_roman_aux:NN #1#2 + { + \str_if_eq:nnTF {#1} { Q } + {#1#2} + { + \str_if_eq:nnTF {#2} { Q } + { + \cs_if_exist:cF { c_int_from_roman_ #1 _int } + { \int_from_roman_clean_up:w } + + + \use:c { c_int_from_roman_ #1 _int } + #2 + } + { + \cs_if_exist:cF { c_int_from_roman_ #1 _int } + { \int_from_roman_clean_up:w } + \cs_if_exist:cF { c_int_from_roman_ #2 _int } + { \int_from_roman_clean_up:w } + \int_compare:nNnTF + { \use:c { c_int_from_roman_ #1 _int } } + < + { \use:c { c_int_from_roman_ #2 _int } } + { + + \use:c { c_int_from_roman_ #2 _int } + - \use:c { c_int_from_roman_ #1 _int } + \int_from_roman_aux:NN + } + { + + \use:c { c_int_from_roman_ #1 _int } + \int_from_roman_aux:NN #2 + } + } + } + } +\cs_new_nopar:Npn \int_from_roman_end:w #1 Q #2 \q_stop + { \tl_if_empty:nTF {#2} {#1} {#2} } +\cs_new_nopar:Npn \int_from_roman_clean_up:w #1 Q { + 0 Q -1 } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Viewing integer} +% +% \begin{macro}{\int_show:N,\int_show:c} +% \UnitTested +% \begin{macrocode} +\cs_new_eq:NN \int_show:N \kernel_register_show:N +\cs_new_eq:NN \int_show:c \kernel_register_show:c +% \end{macrocode} +% \end{macro} +% +% \subsection{Constant integers} +% +% \begin{variable}{\c_minus_one} +% This is needed early, and so is in \pkg{l3basics} +% \end{variable} +% +% \begin{variable}{\c_zero} +% Again, one in \pkg{l3basics} for obvious reasons. +% \end{variable} +% +% \begin{variable}{\c_six, \c_seven} +% \begin{variable}{\c_twelve} +% \begin{variable}{\c_sixteen} +% Once again, in \pkg{l3basics}. +% \end{variable} +% \end{variable} +% \end{variable} +% +% \begin{variable} +% { +% \c_one, \c_two, \c_three, \c_four, \c_five, \c_eight, \c_nine, \c_ten, +% \c_eleven, \c_thirteen, \c_fourteen, \c_fifteen, +% } +% Low-number values not previously defined. +% \begin{macrocode} +\int_const:Nn \c_one { 1 } +\int_const:Nn \c_two { 2 } +\int_const:Nn \c_three { 3 } +\int_const:Nn \c_four { 4 } +\int_const:Nn \c_five { 5 } +\int_const:Nn \c_eight { 8 } +\int_const:Nn \c_nine { 9 } +\int_const:Nn \c_ten { 10 } +\int_const:Nn \c_eleven { 11 } +\int_const:Nn \c_thirteen { 13 } +\int_const:Nn \c_fourteen { 14 } +\int_const:Nn \c_fifteen { 15 } +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\c_thirty_two} +% One middling value. +% \begin{macrocode} +\int_const:Nn \c_thirty_two { 32 } +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\c_two_hundred_fifty_five, \c_two_hundred_fifty_six} +% Two classic mid-range integer constants. +% \begin{macrocode} +\int_const:Nn \c_two_hundred_fifty_five { 255 } +\int_const:Nn \c_two_hundred_fifty_six { 256 } +% \end{macrocode} +%\end{variable} +% +% \begin{variable} +% {\c_one_hundred, \c_one_thousand, \c_ten_thousand} +% Simple runs of powers of ten. +% \begin{macrocode} +\int_const:Nn \c_one_hundred { 100 } +\int_const:Nn \c_one_thousand { 1000 } +\int_const:Nn \c_ten_thousand { 10000 } +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\c_max_int} +% The largest number allowed is $2^{31}-1$ +% \begin{macrocode} +\int_const:Nn \c_max_int { 2 147 483 647 } +% \end{macrocode} +% \end{variable} +% +% \subsection{Scratch integers} +% +% \begin{variable}{\l_tmpa_int, \l_tmpb_int, \l_tmpc_int} +% \begin{variable}{\g_tmpa_int, \g_tmpb_int} +% We provide four local and two global scratch counters, maybe we +% need more or less. +% \begin{macrocode} +\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 +% \end{macrocode} +% \end{variable} +% \end{variable} +% +% \subsection{Registers for earlier modules} +% +% Needed from other modules: +% \begin{macrocode} +\int_new:N \g_seq_nesting_depth_int +\int_new:N \g_tl_inline_level_int +% \end{macrocode} +% +% \subsection{Deprecated functions} +% +% Deprecated on 2011-05-27, for removal by 2011-08-31. +% +% \begin{macro}{\int_convert_from_base_ten:nn} +% \begin{macro}{\int_convert_to_symbols:nnn} +% \begin{macro}{\int_convert_to_base_ten:nn} +% Some simple renames. +% \begin{macrocode} +\cs_new_eq:NN \int_convert_from_base_ten:nn \int_to_base:nn +\cs_new_eq:NN \int_convert_to_symbols:nnn \int_to_symbols:nnn +\cs_new_eq:NN \int_convert_to_base_ten:nn \int_from_base:nn +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\int_to_symbol:n} +% \begin{macro}[aux]{\int_to_symbol_math:n} +% \begin{macro}[aux]{\int_to_symbol_text:n} +% \UnitTested +% This is rather too tied to \LaTeXe{}. +% \begin{macrocode} +\cs_new_nopar:Npn \int_to_symbol:n + { + \mode_if_math:TF + { \int_to_symbol_math:n } + { \int_to_symbol_text:n } + } +\cs_new:Npn \int_to_symbol_math:n #1 + { + \int_to_symbols:nnn {#1} { 9 } + { + { 1 } { * } + { 2 } { \dagger } + { 3 } { \ddagger } + { 4 } { \mathsection } + { 5 } { \mathparagraph } + { 6 } { \| } + { 7 } { ** } + { 8 } { \dagger \dagger } + { 9 } { \ddagger \ddagger } + } + } +\cs_new:Npn \int_to_symbol_text:n #1 + { + \int_to_symbols:nnn {#1} { 9 } + { + { 1 } { \textasteriskcentered } + { 2 } { \textdagger } + { 3 } { \textdaggerdbl } + { 4 } { \textsection } + { 5 } { \textparagraph } + { 6 } { \textbardbl } + { 7 } { \textasteriskcentered \textasteriskcentered } + { 8 } { \textdagger \textdagger } + { 9 } { \textdaggerdbl \textdaggerdbl } + } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macrocode} +%</initex|package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintIndex diff --git a/Master/texmf-dist/source/latex/l3kernel/l3io.dtx b/Master/texmf-dist/source/latex/l3kernel/l3io.dtx new file mode 100644 index 00000000000..bf71c3df878 --- /dev/null +++ b/Master/texmf-dist/source/latex/l3kernel/l3io.dtx @@ -0,0 +1,1185 @@ +% \iffalse meta-comment +% +%% File: l3io.dtx Copyright (C) 1990-2011 The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +% +%<*driver|package> +\RequirePackage{l3names} +\GetIdInfo$Id: l3io.dtx 2478 2011-06-19 21:34:23Z joseph $ + {L3 Experimental input-output operations} +%</driver|package> +%<*driver> +\documentclass[full]{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{^^A +% The \pkg{l3io} package\\ Input--output operations^^A +% \thanks{This file describes v\ExplFileVersion, +% last revised \ExplFileDate.}^^A +% } +% +% \author{^^A +% The \LaTeX3 Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% +% \date{Released \ExplFileDate} +% +% \maketitle +% +% \begin{documentation} +% +% Reading and writing from file streams is handled in \LaTeX3 using +% functions with prefixes \cs{iow_\ldots} (file reading) and +% \cs{ior_\ldots} (file writing). Many of the basic functions are +% very similar, with reading and writing using the same syntax and +% function concepts. As a result, the reading and writing functions +% are documented together where this makes sense. +% +% As \TeX{} is limited to $16$ input streams and $16$ output +% streams, direct use of the streams by the programmer is not +% supported in \LaTeX3. Instead, an internal pool of streams is +% maintained, and these are allocated and deallocated as needed +% by other modules. As a result, the programmer should close streams +% when they are no longer needed, to release them for other processes. +% +% Reading from or writing to a file requires a \meta{stream} to +% be used. This is a csname which refers to the file being processed, +% and is independent of the name of the file (except of course that +% the file name is needed when the file is opened). +% +% \section{Opening and closing streams} +% +% \begin{function}{\ior_open:Nn, \ior_open:cn} +% \begin{syntax} +% \cs{ior_open:Nn} \meta{stream} \Arg{file name} +% \end{syntax} +% Opens \meta{file name} for reading using \meta{stream} as the +% control sequence for file access. If the \meta{stream} was already +% open it is closed before the new operation begins. The +% \meta{stream} is available for access immediately and will remain +% allocated to \meta{file name} until a \cs{ior_close:N} instruction +% is given or the file ends. +% \end{function} +% +% \begin{function}{\iow_open:Nn, \iow_open:cn} +% \begin{syntax} +% \cs{iow_open:Nn} \meta{stream} \Arg{file name} +% \end{syntax} +% Opens \meta{file name} for writing using \meta{stream} as the +% control sequence for file access. If the \meta{stream} was already +% open it is closed before the new operation begins. The +% \meta{stream} is available for access immediately and will remain +% allocated to \meta{file name} until a \cs{iow_close:N} instruction +% is given or the file ends. Opening a file for writing will clear +% any existing content in the file (\emph{i.e.}~writing is \emph{not} +% additive). +% \end{function} +% +% \begin{function}{\ior_close:N, \ior_close:c} +% \begin{syntax} +% \cs{ior_close:N} \meta{stream} +% \end{syntax} +% Closes the \meta{stream}. Streams should always be closed when +% they are finished with as this ensures that they remain available +% to other programmer. The name of the \meta{stream} will be freed at +% this stage, to ensure that any further attempts to read from it results +% in an error. +% \end{function} +% +% \begin{function}{\iow_close:N, \iow_close:c} +% \begin{syntax} +% \cs{iow_close:N} \meta{stream} +% \end{syntax} +% Closes the \meta{stream}. Streams should always be closed when +% they are finished with as this ensures that they remain available +% to other programmer. The name of the \meta{stream} will be freed at +% this stage, to ensure that any further attempts to write to it results +% in an error. +% \end{function} +% +% \begin{function}{\ior_list_streams:, \iow_list_streams:} +% \begin{syntax} +% \cs{ior_list_streams:} \\ +% \cs{iow_list_streams:} +% \end{syntax} +% Displays a list of the file names associated with each open +% stream: intended for tracking down problems. +% \end{function} +% +% \section{Writing to files} +% +% \begin{function}{\iow_now:Nn, \iow_now:Nx} +% \begin{syntax} +% \cs{iow_now:Nn} \meta{stream} \Arg{tokens} +% \end{syntax} +% This functions writes \meta{tokens} to the specified +% \meta{stream} immediately (\emph{i.e.}~the write operation is called +% on expansion of \cs{iow_now:Nn}). +% \begin{texnote} +% \cs{iow_now:Nx} is a protected macro which expands to +% the two \TeX{} primitives \cs{immediate}\cs{write}. +% \end{texnote} +% \end{function} +% +% \begin{function}{\iow_log:n, \iow_log:x} +% \begin{syntax} +% \cs{iow_log:n} \Arg{tokens} +% \end{syntax} +% This function writes the given \meta{tokens} to the log (transcript) +% file immediately: it is a dedicated version of \cs{iow_now:Nn}. +% \end{function} +% +% \begin{function}{\iow_term:n, \iow_term:x} +% \begin{syntax} +% \cs{iow_term:n} \Arg{tokens} +% \end{syntax} +% This function writes the given \meta{tokens} to the terminal +% file immediately: it is a dedicated version of \cs{iow_now:Nn}. +% \end{function} +% +% \begin{function}{\iow_now_when_avail:Nn, \iow_now_when_avail:Nx} +% \begin{syntax} +% \cs{iow_now_when_avail:Nn} \meta{stream} \Arg{tokens} +% \end{syntax} +% If \meta{stream} is open, writes the \meta{tokens} to the \meta{stream} +% in the same manner as \cs{iow_now:Nn}. If the \meta{stream} is not open, +% the \meta{tokens}are simply thrown away. +% \end{function} +% +% \begin{function}{\iow_shipout:Nn, \iow_shipout:Nx} +% \begin{syntax} +% \cs{iow_shipout:Nn} \meta{stream} \Arg{tokens} +% \end{syntax} +% This functions writes \meta{tokens} to the specified +% \meta{stream} when the current page is finalised (\emph{i.e.}~at +% shipout). The \texttt{x}-type variants expand the \meta{tokens} +% at the point where the function is used but \emph{not} when the +% resulting tokens are written to the \meta{stream} +% (\emph{cf.}~\cs{iow_shipout_x:Nn}). +% \end{function} +% +% \begin{function}{\iow_shipout_x:Nn, \iow_shipout_x:Nx} +% \begin{syntax} +% \cs{iow_shipout_x:Nn} \meta{stream} \Arg{tokens} +% \end{syntax} +% This functions writes \meta{tokens} to the specified +% \meta{stream} when the current page is finalised (\emph{i.e}.~at +% shipout). The \meta{tokens} are expanded at the time of writing +% in addition to any expansion when the function is used. This makes +% these functions suitable for including material finalised during +% the page building process (such as the page number integer). +% \begin{texnote} +% \cs{iow_shipout_x:Nn} is the \TeX{} primitive \cs{write} renamed. +% \end{texnote} +% \end{function} +% +% \begin{function}[EXP]{\iow_char:N} +% \begin{syntax} +% \cs{iow_char:N} \meta{token} +% \end{syntax} +% Inserts \meta{token} into the output stream. Useful when trying to +% write difficult characters such as "%", "{", "}", +% \emph{etc}.~in messages, for example: +% \begin{verbatim} +% \iow_now:Nx \g_my_stream { \iow_char:N \{ text \iow_char:N \} } +% \end{verbatim} +% The function has no effect if writing is taking place without +% expansion (\emph{e.g.}~in the second argument of \cs{iow_now:Nn}). +% \end{function} +% +% \begin{function}[EXP]{\iow_newline:} +% \begin{syntax} +% \cs{iow_newline:} +% \end{syntax} +% Function to add a new line within the \meta{tokens} written to a +% file. The function has no effect if writing is taking place without +% expansion (\emph{e.g.}~in the second argument of \cs{iow_now:Nn}). +% \end{function} +% +% \section{Wrapping lines in output} +% +% \begin{function}{\iow_wrap:xnnnN} +% \begin{syntax} +% \cs{iow_wrap:xnnnN} \Arg{text} \Arg{run-on text} \Arg{run-on length} +% ~~\Arg{set up} \meta{function} +% \end{syntax} +% This function will wrap the \meta{text} to a fixed number of +% characters per line. At the start of each line which is wrapped, +% the \meta{run-on text} will be inserted. The line length targeted +% will be the value of \cs{l_iow_line_length_int} minus the +% \meta{run-on length}. The later value should be the number of +% characters in the \meta{run-on text}. Additional functions may be +% added to the wrapping by using the \meta{set up}, which is executed +% before the wrapping takes place. The result of the wrapping operation +% is passed as a braced argument to the \meta{function}, which will +% typically be a wrapper around a writing operation. Within the +% \meta{text}, |\\| may be used to force a new line and \verb|\ | may be +% used to represent a forced space (for example after a control +% sequence). Both the wrapping process and the subsequent write operation +% will perform \texttt{x}-type expansion. For this reason, material which +% is to be written \enquote{as is} should be given as the argument to +% \cs{token_to_str:N} or \cs{tl_to_str:n} (as appropriate) within +% the \meta{text}. The output of \cs{iow_wrap:xnnnN} (\emph{i.e.}~the +% argument passed to the \meta{function}) will consist of characters of +% category code $12$ (other) and $10$ (space) only. This means that the +% output will \emph{not} expand further when written to a file. +% \end{function} +% +% \begin{variable}{\l_iow_line_length_int} +% The maximum length of a line to be written by the \cs{iow_wrap:xxnnN} +% function. This value depends on the \TeX{} system in use: the standard +% value is $78$, which is typically correct for unmodified \TeX{}live +% and MiK\TeX{} systems. +% \end{variable} +% +% \section{Reading from files} +% +% \begin{function}{\ior_to:NN} +% \begin{syntax} +% \cs{ior_to:NN} \meta{stream} \meta{token list variable} +% \end{syntax} +% Functions that reads one or more lines (until an equal number of left +% and right braces are found) from the input \meta{stream} and stores +% the result locally in the \meta{token list} variable. If the +% \meta{stream} is not open, input is requested from the terminal. +% The material read from the \meta{stream} will be tokenized by +% \TeX{} according to the category codes in force when the function +% is used. +% \begin{texnote} +% The is protected macro which expands to the \TeX{} primitive \cs{read} +% along with the |to| keyword. +% \end{texnote} +% \end{function} +% +% \begin{function}{\ior_gto:NN} +% \begin{syntax} +% \cs{ior_gto:NN} \meta{stream} \meta{token list variable} +% \end{syntax} +% Functions that reads one or more lines (until an equal number of left +% and right braces are found) from the input \meta{stream} and stores +% the result globally in the \meta{token list} variable. If the +% \meta{stream} is not open, input is requested from the terminal. +% The material read from the \meta{stream} will be tokenized by +% \TeX{} according to the category codes in force when the function +% is used. +% \begin{texnote} +% The is protected macro which expands to the \TeX{} primitives +% \cs{global} \cs{read} along with the |to| keyword. +% \end{texnote} +% \end{function} +% +% \begin{function}{\ior_str_to:NN} +% \begin{syntax} +% \cs{ior_str_to:NN} \meta{stream} \meta{token list variable} +% \end{syntax} +% Functions that reads one or more lines (until an equal number of left +% and right braces are found) from the input \meta{stream} and stores +% the result locally in the \meta{token list} variable. If the +% \meta{stream} is not open, input is requested from the terminal. +% The material read from the \meta{stream} as a series of tokens with +% category code $12$ (other), with the exception of space +% characters which are given category code $10$ (space). +% \begin{texnote} +% The is protected macro which expands to the \eTeX{} primitive +% \cs{readline} along with the |to| keyword. +% \end{texnote} +% \end{function} +% +% \begin{function}{\ior_str_gto:NN} +% \begin{syntax} +% \cs{ior_str_gto:NN} \meta{stream} \meta{token list variable} +% \end{syntax} +% Functions that reads one or more lines (until an equal number of left +% and right braces are found) from the input \meta{stream} and stores +% the result globally in the \meta{token list} variable. If the +% \meta{stream} is not open, input is requested from the terminal. +% The material read from the \meta{stream} as a series of tokens with +% category code $12$ (other), with the exception of space +% characters which are given category code $10$ (space). +% \begin{texnote} +% The is protected macro which expands to the primitives +% \cs{global} \cs{readline} along with the |to| keyword. +% \end{texnote} +% \end{function} +% +%\begin{function}[EXP,pTF]{\ior_if_eof:N} +% \begin{syntax} +% \cs{ior_if_eof_p:N} \meta{stream} +% \cs{ior_if_eof:NTF} \meta{stream} \Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the end of a \meta{stream} has been reached during a reading +% operation. The test will also return a \texttt{true} value if +% the \meta{stream} is not open or the \meta{file name} associated with +% a \meta{stream} does not exist at all. The branching versions then +% leave either \meta{true code} or \meta{false code} in the input +% stream, as appropriate to the truth of the test and the variant of +% the function chosen. The logical truth of the test is left in the +% input stream by the predicate version. +%\end{function} +% +% \section{Internal input--output functions} +% +% \begin{function}[EXP]{\if_eof:w} +% \begin{syntax} +% \cs{if_eof:w} \meta{stream} +% ~~\meta{true code} +% \cs{else:} +% ~~\meta{false code} +% \cs{fi:} +% \end{syntax} +% Tests if the \meta{stream} returns \enquote{end of file}, which is true +% for non-existent files. The \cs{else:} branch is optional. +% \begin{texnote} +% This is the \TeX{} primitive \cs{ifeof}. +% \end{texnote} +% \end{function} +% +% \begin{function}{\ior_raw_new:N, \ior_raw_new:c} +% \begin{syntax} +% \cs{ior_raw_new:N} \meta{stream} +% \end{syntax} +% Directly allocates a new stream for reading, bypassing the stack +% system. This is to be used only when a new stream is required at a +% \TeX{} level, when a new stream is requested by the stack itself. +% \end{function} +% +% \begin{function}{\iow_raw_new:N, \iow_raw_new:c} +% \begin{syntax} +% \cs{iow_raw_new:N} \meta{stream} +% \end{syntax} +% Directly allocates a new stream for writing, bypassing the stack +% system. This is to be used only when a new stream is required at a +% \TeX{} level, when a new stream is requested by the stack itself. +% \end{function} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{l3io} implementation} +% +% \begin{macrocode} +%<*initex|package> +% \end{macrocode} +% +% \begin{macrocode} +%<*package> +\ProvidesExplPackage + {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +\package_check_loaded_expl: +%</package> +% \end{macrocode} +% +% \subsection{Primitives} +% +% \begin{macro}{\if_eof:w} +% The primitive conditional +% \begin{macrocode} +\cs_new_eq:NN \if_eof:w \tex_ifeof:D +% \end{macrocode} +% \end{macro} +% +% \subsection{Variables and constants} +% +% \begin{variable}{\c_iow_term_stream, \c_ior_term_stream} +% \begin{variable}{\c_iow_log_stream, \c_ior_log_stream} +% Here we allocate two output streams for writing to the transcript +% file only (\cs{c_iow_log_stream}) and to both the terminal and +% transcript file (\cs{c_iow_term_stream}). Both can be used to read +% from and have equivalent \cs{c_ior} versions. +% \begin{macrocode} +\cs_new_eq:NN \c_iow_term_stream \c_sixteen +\cs_new_eq:NN \c_ior_term_stream \c_sixteen +\cs_new_eq:NN \c_iow_log_stream \c_minus_one +\cs_new_eq:NN \c_ior_log_stream \c_minus_one +% \end{macrocode} +% \end{variable} +% \end{variable} +% +% \begin{variable}{\c_iow_streams_tl, \c_ior_streams_tl} +% The list of streams available, by number. +% \begin{macrocode} +\tl_const:Nn \c_iow_streams_tl + { + \c_zero + \c_one + \c_two + \c_three + \c_four + \c_five + \c_six + \c_seven + \c_eight + \c_nine + \c_ten + \c_eleven + \c_twelve + \c_thirteen + \c_fourteen + \c_fifteen + } +\cs_new_eq:NN \c_ior_streams_tl \c_iow_streams_tl +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\g_iow_streams_prop, \g_ior_streams_prop} +% The allocations for streams are stored in property lists, which +% are set up to have a \enquote{full} set of allocations from the start. +% In package mode, a few slots are always taken, so these are +% blocked off from use. +% \begin{macrocode} +\prop_new:N \g_iow_streams_prop +\prop_new:N \g_ior_streams_prop +%<*package> +\prop_put:Nnn \g_iow_streams_prop { 0 } { LaTeX2e~reserved } +\prop_put:Nnn \g_iow_streams_prop { 1 } { LaTeX2e~reserved } +\prop_put:Nnn \g_iow_streams_prop { 2 } { LaTeX2e~reserved } +\prop_put:Nnn \g_ior_streams_prop { 0 } { LaTeX2e~reserved } +%</package> +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_iow_stream_int, \l_ior_stream_int} +% Used to track the number allocated to the stream being created: +% this is taken from the property list but does alter. +% \begin{macrocode} +\int_new:N \l_iow_stream_int +\cs_new_eq:NN \l_ior_stream_int \l_iow_stream_int +% \end{macrocode} +% \end{variable} +% +% \subsection{Stream management} +% +% \begin{macro}[int]{\ior_raw_new:N, \ior_raw_new:c} +% \begin{macro}[int]{\iow_raw_new:N, \iow_raw_new:c} +% The lowest level for stream management is actually creating raw \TeX{} +% streams. As these are very limited (even with \eTeX{}), this should not +% be addressed directly. +% \begin{macrocode} +%<*initex> +\alloc_setup_type:nnn { ior } \c_zero \c_sixteen +\cs_new_protected_nopar:Npn \ior_raw_new:N #1 + { \alloc_reg:NnNN g { ior } \tex_chardef:D #1 } +\alloc_setup_type:nnn { iow } \c_zero \c_sixteen +\cs_new_protected_nopar:Npn \iow_raw_new:N #1 + { \alloc_reg:NnNN g { iow } \tex_chardef:D #1 } +%</initex> +%<*package> +\cs_set_eq:NN \iow_raw_new:N \newwrite +\cs_set_eq:NN \ior_raw_new:N \newread +%</package> +\cs_generate_variant:Nn \ior_raw_new:N { c } +\cs_generate_variant:Nn \iow_raw_new:N { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\ior_open:Nn, \ior_open:cn} +% \begin{macro}{\iow_open:Nn, \iow_open:cn} +% In both cases, opening a stream starts with a call to the closing +% function: this is safest. There is then a loop through the +% allocation number list to find the first free stream number. +% When one is found the allocation can take place, the information +% can be stored and finally the file can actually be opened. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \ior_open:Nn #1#2 + { + \ior_close:N #1 + \int_set:Nn \l_ior_stream_int \c_sixteen + \tl_map_function:NN \c_ior_streams_tl \ior_alloc_read:n + \int_compare:nNnTF \l_ior_stream_int = \c_sixteen + { \msg_kernel_error:nn { ior } { streams-exhausted } } + { + \ior_stream_alloc:N #1 + \prop_gput:NVn \g_ior_streams_prop \l_ior_stream_int {#2} + \tex_openin:D #1#2 \scan_stop: + } + } +\cs_new_protected_nopar:Npn \iow_open:Nn #1#2 + { + \iow_close:N #1 + \int_set:Nn \l_iow_stream_int \c_sixteen + \tl_map_function:NN \c_iow_streams_tl \iow_alloc_write:n + \int_compare:nNnTF \l_iow_stream_int = \c_sixteen + { \msg_kernel_error:nn { iow } { streams-exhausted } } + { + \iow_stream_alloc:N #1 + \prop_gput:NVn \g_iow_streams_prop \l_iow_stream_int {#2} + \tex_immediate:D \tex_openout:D #1#2 \scan_stop: + } + } +\cs_generate_variant:Nn \ior_open:Nn { c } +\cs_generate_variant:Nn \iow_open:Nn { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[aux]{\ior_alloc_read:n} +% \begin{macro}[aux]{\iow_alloc_write:n} +% These functions are used to see if a particular stream is available. +% The property list contains file names for streams in use, so +% any unused ones are for the taking. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \iow_alloc_write:n #1 + { + \prop_if_in:NnF \g_iow_streams_prop {#1} + { + \int_set:Nn \l_iow_stream_int {#1} + \tl_map_break: + } + } +\cs_new_protected_nopar:Npn \ior_alloc_read:n #1 + { + \prop_if_in:NnF \g_iow_streams_prop {#1} + { + \int_set:Nn \l_ior_stream_int {#1} + \tl_map_break: + } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[aux]{\iow_stream_alloc:N} +% \begin{macro}[aux]{\ior_stream_alloc:N} +% \begin{macro}[aux]{\iow_stream_alloc_aux:} +% \begin{macro}[aux]{\ior_stream_alloc_aux:} +% \begin{variable}{\g_iow_tmp_stream} +% \begin{variable}{\g_ior_tmp_stream} +% Allocating a raw stream is much easier in \IniTeX{} mode than for +% the package. For the format, all streams will be allocated by +% \pkg{l3io} and so there is a simple check to see if a raw +% stream is actually available. On the other hand, for the +% package there will be non-managed streams. So if the managed +% one is not open, a check is made to see if some other managed +% stream is available before deciding to open a new one. If a new +% one is needed, we get the number allocated by \LaTeXe{} to get +% \enquote{back on track} with allocation. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \iow_stream_alloc:N #1 + { + \cs_if_exist:cTF { g_iow_ \int_use:N \l_iow_stream_int _stream } + { \cs_gset_eq:Nc #1 { g_iow_ \int_use:N \l_iow_stream_int _stream } } + { +%<*package> + \iow_stream_alloc_aux: + \int_compare:nNnT \l_iow_stream_int = \c_sixteen + { + \iow_raw_new:N \g_iow_tmp_stream + \int_set:Nn \l_iow_stream_int { \g_iow_tmp_stream } + \cs_gset_eq:cN + { g_iow_ \int_use:N \l_iow_stream_int _stream } + \g_iow_tmp_stream + } +%</package> +%<*initex> + \iow_raw_new:c { g_iow_ \int_use:N \l_iow_stream_int _stream } +%</initex> + \cs_gset_eq:Nc #1 { g_iow_ \int_use:N \l_iow_stream_int _stream } + } + } +%<*package> +\cs_new_protected_nopar:Npn \iow_stream_alloc_aux: + { + \int_incr:N \l_iow_stream_int + \int_compare:nNnT \l_iow_stream_int < \c_sixteen + { + \cs_if_exist:cTF { g_iow_ \int_use:N \l_iow_stream_int _stream } + { + \prop_if_in:NVT \g_iow_streams_prop \l_iow_stream_int + { \iow_stream_alloc_aux: } + } + { \iow_stream_alloc_aux: } + } + } +%</package> +\cs_new_protected_nopar:Npn \ior_stream_alloc:N #1 + { + \cs_if_exist:cTF { g_ior_ \int_use:N \l_ior_stream_int _stream } + { \cs_gset_eq:Nc #1 { g_ior_ \int_use:N \l_ior_stream_int _stream } } + { +%<*package> + \ior_stream_alloc_aux: + \int_compare:nNnT \l_ior_stream_int = \c_sixteen + { + \ior_raw_new:N \g_ior_tmp_stream + \int_set:Nn \l_ior_stream_int { \g_ior_tmp_stream } + \cs_gset_eq:cN + { g_ior_ \int_use:N \l_iow_stream_int _stream } + \g_ior_tmp_stream + } +%</package> +%<*initex> + \ior_raw_new:c { g_ior_ \int_use:N \l_ior_stream_int _stream } +%</initex> + \cs_gset_eq:Nc #1 { g_ior_ \int_use:N \l_ior_stream_int _stream } + } + } +%<*package> +\cs_new_protected_nopar:Npn \ior_stream_alloc_aux: + { + \int_incr:N \l_ior_stream_int + \int_compare:nNnT \l_ior_stream_int < \c_sixteen + { + \cs_if_exist:cTF { g_ior_ \int_use:N \l_ior_stream_int _stream } + { + \prop_if_in:NVT \g_ior_streams_prop \l_ior_stream_int + { \ior_stream_alloc_aux: } + } + { \ior_stream_alloc_aux: } + } + } +%</package> +% \end{macrocode} +% \end{variable} +% \end{variable} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\iow_close:N, \iow_close:c} +% \begin{macro}{\iow_close:N, \iow_close:c} +% Closing a stream is not quite the reverse of opening one. First, +% the close operation is easier than the open one, and second as the +% stream is actually a number we can use it directly to show that the +% slot has been freed up. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \ior_close:N #1 + { + \cs_if_exist:NT #1 + { + \int_compare:nNnF #1 = \c_minus_one + { + \tex_closein:D #1 + \prop_gdel:NV \g_ior_streams_prop #1 + \cs_undefine:N #1 + } + } + } +\cs_new_protected_nopar:Npn \iow_close:N #1 + { + \cs_if_exist:NT #1 + { + \int_compare:nNnF #1 = \c_minus_one + { + \tex_immediate:D \tex_closeout:D #1 + \prop_gdel:NV \g_iow_streams_prop #1 + \cs_undefine:N #1 + } + } + } +\cs_generate_variant:Nn \ior_close:N { c } +\cs_generate_variant:Nn \iow_close:N { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\ior_list_streams:} +% \begin{macro}{\iow_list_streams:} +% \begin{macro}[aux]{\iow_show_aux:nn} +% \begin{macro}[aux]{\ior_show_aux:nn} +% Show the property lists, but with some \enquote{pretty printing}. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \ior_list_streams: + { + \prop_if_empty:NTF \g_ior_streams_prop + { + \iow_term:x { No~input~streams~are~open } + \tl_show:n { } + } + { + \iow_term:x { The~following~input~streams~are~in~use: } + \tl_set:Nx \l_prop_show_tl + { \prop_map_function:NN \g_ior_streams_prop \ior_show_aux:nn } + \etex_showtokens:D \exp_after:wN \exp_after:wN \exp_after:wN + { \exp_after:wN \prop_show_aux:w \l_prop_show_tl } + } + } +\cs_new:Npn \ior_show_aux:nn #1#2 + { + \iow_newline: > \c_space_tl \c_space_tl + #1 \iow_char:N + \c_space_tl \c_space_tl => \c_space_tl \c_space_tl + \exp_not:n {#2} + } +\cs_new_protected_nopar:Npn \iow_list_streams: + { + \prop_if_empty:NTF \g_iow_streams_prop + { + \iow_term:x { No~output~streams~are~open } + \tl_show:n { } + } + { + \iow_term:x { The~following~output~streams~are~in~use: } + \tl_set:Nx \l_prop_show_tl + { \prop_map_function:NN \g_iow_streams_prop \iow_show_aux:nn } + \etex_showtokens:D \exp_after:wN \exp_after:wN \exp_after:wN + { \exp_after:wN \prop_show_aux:w \l_prop_show_tl } + } + } +\cs_new_eq:NN \iow_show_aux:nn \ior_show_aux:nn +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% Text for the error messages. +% \begin{macrocode} +\msg_kernel_new:nnnn { iow } { streams-exhausted } + { Output~streams~exhausted } + { + TeX~can~only~open~up~to~16~output~streams~at~one~time.\\ + All~16 are currently~in~use,~and~something~wanted~to~open + another~one. + } +\msg_kernel_new:nnnn { ior } { streams-exhausted } + { Input~streams~exhausted } + { + TeX~can~only~open~up~to~16~input~streams~at~one~time.\\ + All~16 are currently~in~use,~and~something~wanted~to~open + another~one. + } +% \end{macrocode} +% +% \subsection{Deferred writing} +% +% \begin{macro}{\iow_shipout_x:Nn, \iow_shipout_x:Nx} +% First the easy part, this is the primitive. +% \begin{macrocode} +\cs_new_eq:NN \iow_shipout_x:Nn \tex_write:D +\cs_generate_variant:Nn \iow_shipout_x:Nn { Nx } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\iow_shipout:Nn, \iow_shipout:Nx} +% With \eTeX{} available deferred writing is easy. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \iow_shipout:Nn #1#2 + { \iow_shipout_x:Nn #1 { \exp_not:n {#2} } } +\cs_generate_variant:Nn \iow_shipout:Nn { Nx } +% \end{macrocode} +% \end{macro} +% +% \subsection{Immediate writing} +% +% \begin{macro}{\iow_now:Nx} +% An abbreviation for an often used operation, which immediately +% writes its second argument expanded to the output stream. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \iow_now:Nx { \tex_immediate:D \iow_shipout_x:Nn } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\iow_now:Nn} +% This routine writes the second argument onto the output stream without +% expansion. If this stream isn't open, the output goes to the terminal +% instead. If the first argument is no output stream at all, we get an +% internal error. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \iow_now:Nn #1#2 + { \iow_now:Nx #1 { \exp_not:n {#2} } } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\iow_log:n, \iow_log:x} +% \begin{macro}{\iow_term:n, \iow_term:x} +% Writing to the log and the terminal directly are relatively easy. +% \begin{macrocode} +\cs_set_protected_nopar:Npn \iow_log:x { \iow_now:Nx \c_iow_log_stream } +\cs_new_protected_nopar:Npn \iow_log:n { \iow_now:Nn \c_iow_log_stream } +\cs_set_protected_nopar:Npn \iow_term:x { \iow_now:Nx \c_iow_term_stream } +\cs_new_protected_nopar:Npn \iow_term:n { \iow_now:Nn \c_iow_term_stream } +% \end{macrocode} +%\end{macro} +%\end{macro} +% +% \begin{macro}{\iow_now_when_avail:Nn, \iow_now_when_avail:Nx} +% For writing only if the stream requested is open at all. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \iow_now_when_avail:Nn #1 + { \cs_if_free:NTF #1 { \use_none:n } { \iow_now:Nn #1 } } +\cs_new_protected_nopar:Npn \iow_now_when_avail:Nx #1 + { \cs_if_free:NTF #1 { \use_none:n } { \iow_now:Nx #1 } } +% \end{macrocode} +% \end{macro} +% +% \subsection{Hard-wrapping lines based on length} +% +% The code here implements a generic hard-wrapping function. This is +% used by the messaging system, but is designed such that it is +% available for other uses. +% +% \begin{macro}{\l_iow_line_length_int} +% The is the \enquote{raw} length of a line which can be written to +% file. The standard value is the line length typically used by +% \TeX{}Live and Mik\TeX{}. +% \begin{macrocode} +\int_new:N \l_iow_line_length_int +\int_set:Nn \l_iow_line_length_int { 78 } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[aux]{\l_iow_target_length_int} +% This stores the target line length: the full length minus any +% part for a leader at the start of each line. +% \begin{macrocode} +\int_new:N \l_iow_target_length_int +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[aux]{\l_iow_current_line_int, \l_iow_current_word_int} +% These store the number of characters in the line and word currently +% being constructed, respectively. +% \begin{macrocode} +\int_new:N \l_iow_current_line_int +\int_new:N \l_iow_current_word_int +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[aux]{\l_iow_current_line_tl, \l_iow_current_word_tl} +% These hold the current line of text and current word, respectively. +% \begin{macrocode} +\tl_new:N \l_iow_current_line_tl +\tl_new:N \l_iow_current_word_tl +% \end{macrocode} +%\end{macro} +% +% \begin{macro}[aux]{\l_iow_wrap_tl} +% Used for the expansion step before detokenizing. +% \begin{macrocode} +\tl_new:N \l_iow_wrap_tl +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[aux]{\l_iow_wrapped_tl} +% The output from wrapping text: fully expanded and with lines +% which are not overly long. +% \begin{macrocode} +\tl_new:N \l_iow_wrapped_tl +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\q_iow_stop} +% A quark which will not appear elsewhere. +% \begin{macrocode} +\quark_new:N \q_iow_stop +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\l_iow_line_start_bool} +% Boolean to avoid adding a space at the beginning of lines. +% \begin{macrocode} +\bool_new:N \l_iow_line_start_bool +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\iow_wrap:xnnnN} +% \begin{macro}[aux]{\iow_wrap_loop:w} +% \begin{macro}[aux]{\iow_wrap_word:} +% \begin{macro}[aux]{\iow_wrap_word_fits:} +% \begin{macro}[aux]{\iow_wrap_word_newline:} +% \begin{macro}[aux]{\iow_wrap_newline:} +% \begin{macro}[aux]{\iow_wrap_end:} +% The main wrapping function works as follows. The target number of +% characters in a line is calculated, before fully-expanding the input +% such that |\\| and \verb*|\ | are converted into the appropriate +% values. There is then a loop over each word in the input, which +% will do the actual wrapping. After the loop, the resulting text is +% passed on to the function which has been given as a post-processor. +% The argument |#4| is available for additional set up steps for +% the output. +% \begin{macrocode} +\cs_new_protected:Npn \iow_wrap:xnnnN #1#2#3#4#5 + { + \group_begin: + \int_set:Nn \l_iow_target_length_int { \l_iow_line_length_int - ( #3 ) } + \int_zero:N \l_iow_current_line_int + \tl_clear:N \l_iow_current_line_tl + \tl_clear:N \l_iow_wrap_tl + \bool_set_true:N \l_iow_line_start_bool + \cs_set:Npx \\ { \c_space_tl \iow_newline: \c_space_tl } + \cs_set_eq:NN \ \c_space_tl + #4 +%<*initex> + \tl_set:Nx \l_iow_wrap_tl {#1} +%</initex> +%<*package> + \protected@edef \l_iow_wrap_tl {#1} +%</package> + \cs_set:Npn \\ { \iow_newline: #2 } + \use:x + { + \exp_not:N \iow_wrap_loop:w + \tl_to_str:N \l_iow_wrap_tl \c_space_tl + \exp_not:N \q_iow_stop \c_space_tl + } + \exp_args:NNo \group_end: + #5 \l_iow_wrapped_tl + } +% \end{macrocode} +% The loop grabs one word in the input, and checks whether it is +% the end, or a forced new line, or a normal word. +% \begin{macrocode} +\cs_new_protected:Npn \iow_wrap_loop:w #1 ~ % + { + \tl_set:Nn \l_iow_current_word_tl {#1} + \tl_if_eq:NNTF \l_iow_current_word_tl \iow_newline: + { \iow_wrap_newline: } + { + \tl_if_eq:NNTF \l_iow_current_word_tl \q_iow_stop + { \iow_wrap_end: } + { \iow_wrap_word: } + } + } +% \end{macrocode} +% For a normal word, update the line length, then test if the current +% word would fit in the current line, and call the appropriate function. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \iow_wrap_word: + { + \int_set:Nn \l_iow_current_word_int + { \str_length_skip_spaces:N \l_iow_current_word_tl } + \int_add:Nn \l_iow_current_line_int { \l_iow_current_word_int } + \int_compare:nNnTF \l_iow_current_line_int + < \l_iow_target_length_int + { \iow_wrap_word_fits: } + { \iow_wrap_word_newline: } + \iow_wrap_loop:w + } +% \end{macrocode} +% If the word fits in the current line, add it to the line, preceded by +% a space unless it is the first word of the line. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \iow_wrap_word_fits: + { + \bool_if:NTF \l_iow_line_start_bool + { + \bool_set_false:N \l_iow_line_start_bool + \tl_set_eq:NN \l_iow_current_line_tl \l_iow_current_word_tl + } + { + \tl_put_right:Nx \l_iow_current_line_tl + { ~ \l_iow_current_word_tl } + \int_incr:N \l_iow_current_line_int + } + } +% \end{macrocode} +% Otherwise, the current line is added to the result, with the run-on text. +% The current word (and its length) are then put in the new line. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \iow_wrap_word_newline: + { + \tl_put_right:Nx \l_iow_wrapped_tl + { \l_iow_current_line_tl \\ } + \int_set_eq:NN \l_iow_current_line_int \l_iow_current_word_int + \tl_set_eq:NN \l_iow_current_line_tl \l_iow_current_word_tl + } +% \end{macrocode} +% Forced newlines are almost identical to those caused by overflow, +% except that here the word is empty. And remember to continue the loop! +% \begin{macrocode} +\cs_new_protected_nopar:Npn \iow_wrap_newline: + { + \tl_put_right:Nx \l_iow_wrapped_tl + { \l_iow_current_line_tl \\ } + \int_zero:N \l_iow_current_line_int + \tl_clear:N \l_iow_current_line_tl + \bool_set_true:N \l_iow_line_start_bool + \iow_wrap_loop:w + } +% \end{macrocode} +% At the end, we simply save the last line (without the run-on text). +% \begin{macrocode} +\cs_new_protected_nopar:Npn \iow_wrap_end: + { + \tl_put_right:Nx \l_iow_wrapped_tl + { \l_iow_current_line_tl } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\str_length_skip_spaces:N} +% \begin{macro}{\str_length_skip_spaces:n} +% \begin{macro}{\str_length_loop:NNNNNNNNN} +% The wrapping code requires to measure the number of character +% in each word. This could be done with \cs{tl_length:n}, but +% it is ten times faster (literally) to use the code below. +% \begin{macrocode} +\cs_new_nopar:Npn \str_length_skip_spaces:N + { \exp_args:No \str_length_skip_spaces:n } +\cs_new:Npn \str_length_skip_spaces:n #1 + { + \int_value:w \int_eval:w + \exp_after:wN \str_length_loop:NNNNNNNNN \tl_to_str:n {#1} + {X8}{X7}{X6}{X5}{X4}{X3}{X2}{X1}{X0} \q_stop + \int_eval_end: + } +\cs_new:Npn \str_length_loop:NNNNNNNNN #1#2#3#4#5#6#7#8#9 + { + \if_catcode:w X #9 + \exp_after:wN \use_none_delimit_by_q_stop:w + \else: + 9 + + \exp_after:wN \str_length_loop:NNNNNNNNN + \fi: + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{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} +\cs_new_nopar:Npn \iow_newline: { ^^J } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\iow_char:N} +% Function to write any escaped char to an output stream. +% \begin{macrocode} +\cs_new_eq:NN \iow_char:N \cs_to_str:N +% \end{macrocode} +% \end{macro} +% +% \subsection{Reading input} +% +% \begin{macro}[pTF]{\ior_if_eof_p:N} +% To test if some particular input stream is exhausted the following +% conditional is provided. As the pool model means that closed +% streams are undefined control sequences, the test has two parts. +% \begin{macrocode} +\prg_new_conditional:Nnn \ior_if_eof:N { p , T , F , TF } + { + \cs_if_exist:NTF #1 + { + \if_eof:w #1 + \prg_return_true: + \else: + \prg_return_false: + \fi: + } + { \prg_return_true: } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\ior_to:NN} +% \begin{macro}{\ior_gto:NN} +% And here we read from files. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \ior_to:NN #1#2 + { \tex_read:D #1 to #2 } +\cs_new_protected_nopar:Npn \ior_gto:NN #1#2 + { \pref_global:D \tex_read:D #1 to #2 } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\ior_str_to:NN} +% \begin{macro}{\ior_str_gto:NN} +% Reading as strings is also a primitive wrapper. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \ior_str_to:NN #1#2 + { \etex_readline:D #1 to #2 } +\cs_new_protected_nopar:Npn \ior_str_gto:NN #1#2 + { \pref_global:D \etex_readline:D #1 to #2 } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Deprecated functions} +% +% Deprecated on 2011-05-27, for removal by 2011-08-31. +% +% \begin{macro}{\iow_now_buffer_safe:Nn, \iow_now_buffer_safe:Nx} +% This is much more easily done using the wrapping system: there is +% an expansion there, so a bit of a hack is needed. +% \begin{macrocode} +\cs_new_protected:Npn \iow_now_buffer_safe:Nn #1#2 + { \iow_wrap:xnnnN { \exp_not:n {#2} } { } \c_zero { } \iow_now:Nn #1 } +\cs_new_protected:Npn \iow_now_buffer_safe:Nx #1#2 + { \iow_wrap:xnnnN {#2} { } \c_zero { } \iow_now:Nn #1 } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\ior_new:N, \ior_new:c} +% \begin{macro}{\iow_new:N, \iow_new:c} +% As input--output operations are done using a stack, |new| operations seem +% out-of-place. They are therefore set up just to gobble the input. +% \begin{macrocode} +\cs_new_eq:NN \ior_new:N \use_none:n +\cs_new_eq:NN \ior_new:c \use_none:n +\cs_new_eq:NN \iow_new:N \use_none:n +\cs_new_eq:NN \iow_new:c \use_none:n +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\ior_open_streams:} +% \begin{macro}{\iow_open_streams:} +% Slightly misleading names. +% \begin{macrocode} +\cs_new_eq:NN \ior_open_streams: \ior_list_streams: +\cs_new_eq:NN \iow_open_streams: \iow_list_streams: +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macrocode} +%</initex|package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintIndex diff --git a/Master/texmf-dist/source/latex/l3kernel/l3keys.dtx b/Master/texmf-dist/source/latex/l3kernel/l3keys.dtx new file mode 100644 index 00000000000..cbc1fb62a7d --- /dev/null +++ b/Master/texmf-dist/source/latex/l3kernel/l3keys.dtx @@ -0,0 +1,1365 @@ +% \iffalse meta-comment +% +%% File: l3keys.dtx Copyright (C) 2009-2011 The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +% +%<*driver|package> +\RequirePackage{l3names} +\GetIdInfo$Id: l3keys.dtx 2478 2011-06-19 21:34:23Z joseph $ + {L3 Experimental key-value interfaces} +%</driver|package> +%<*driver> +\documentclass[full]{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{^^A +% The \pkg{l3keys} package\\ Key--value interfaces^^A +% \thanks{This file describes v\ExplFileVersion, +% last revised \ExplFileDate.}^^A +% } +% +% \author{^^A +% The \LaTeX3 Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% +% \date{Released \ExplFileDate} +% +% \maketitle +% +% \begin{documentation} +% +% The key--value method is a popular system for creating large numbers +% of settings for controlling function or package behaviour. For the +% user, the system normally results in input of the form +% \begin{verbatim} +% \PackageControlMacro{ +% key-one = value one, +% key-two = value two +% } +% \end{verbatim} +% or +% \begin{verbatim} +% \PackageMacro[ +% key-one = value one, +% key-two = value two +% ]{argument}. +% \end{verbatim} +% +% The high level functions here are intended as a method to create +% key--value controls. Keys are themselves created using a key--value +% interface, minimising the number of functions and arguments +% required. Each key is created by setting one or more \emph{properties} +% of the key: +% \begin{verbatim} +% \keys_define:nn { module } +% { +% key-one .code:n = code including parameter #1, +% key-two .tl_set:N = \l_module_store_tl +% } +% \end{verbatim} +% These values can then be set as with other key--value approaches: +% \begin{verbatim} +% \keys_set:nn { module } +% { +% key-one = value one, +% key-two = value two +% } +% \end{verbatim} +% +% At a document level, \cs{keys_set:nn} will be used within a +% document function, for example +% \begin{verbatim} +% \DeclareDocumentCommand \SomePackageSetup { m } +% { \keys_set:nn { module } { #1 } } +% \DeclareDocumentCommand \SomePackageMacro { o m } +% { +% \group_begin: +% \keys_set:nn { module } { #1 } +% % Main code for \SomePackageMacro +% \group_end: +% } +% \end{verbatim} +% +% Key names may contain any tokens, as they are handled internally +% using \cs{tl_to_str:n}. As will be discussed in +% section~\ref{sec:subdivision}, it is suggested that the character +% |/| is reserved for sub-division of keys into logical +% groups. Functions and variables are \emph{not} expanded when creating +% key names, and so +% \begin{verbatim} +% \tl_set:Nn \l_module_tmp_tl { key } +% \keys_define:nn { module } +% { +% \l_module_tmp_tl .code:n = code +% } +% \end{verbatim} +% will create a key called \cs{l_module_tmp_tl}, and not one called +% \texttt{key}. +% +% \section{Creating keys} +% +% \begin{function}{\keys_define:nn} +% \begin{syntax} +% \cs{keys_define:nn} \Arg{module} \Arg{keyval list} +% \end{syntax} +% Parses the \meta{keyval list} and defines the keys listed there for +% \meta{module}. The \meta{module} name should be a text value, but +% there are no restrictions on the nature of the text. In practice the +% \meta{module} should be chosen to be unique to the module in question +% (unless deliberately adding keys to an existing module). +% +% The \meta{keyval list} should consist of one or more key names along +% with an associated key \emph{property}. The properties of a key +% determine how it acts. The individual properties are described +% in the following text; a typical use of \cs{keys_define:nn} might +% read +% \begin{verbatim} +% \keys_define:nn { mymodule } +% { +% keyname .code:n = Some~code~using~#1, +% keyname .value_required: +% } +% \end{verbatim} +% where the properties of the key begin from the |.| after the key +% name. +% \end{function} +% +% The various properties available take either no arguments at +% all, or require exactly one argument. This is indicated in the +% name of the property using an argument specification. In the following +% discussion, each property is illustrated attached to an +% arbitrary \meta{key}, which when used may be supplied with a +% \meta{value}. All key \emph{definitions} are local. +% +% \begin{function}{.bool_set:N} +% \begin{syntax} +% \meta{key} .bool_set:N = \meta{boolean} +% \end{syntax} +% Defines \meta{key} to set \meta{boolean} to \meta{value} (which +% must be either \texttt{true} or \texttt{false}). If the variable +% does not exist, it will be created at the point that the key is +% set up. The \meta{boolean} will be assigned locally. +% \end{function} +% +% \begin{function}{.bool_gset:N} +% \begin{syntax} +% \meta{key} .bool_gset:N = \meta{boolean} +% \end{syntax} +% Defines \meta{key} to set \meta{boolean} to \meta{value} (which +% must be either \texttt{true} or \texttt{false}). If the variable +% does not exist, it will be created at the point that the key is +% set up. The \meta{boolean} will be assigned globally. +% \end{function} +% +% \begin{function}{.choice:} +% \begin{syntax} +% \meta{key} .choice: +% \end{syntax} +% Sets \meta{key} to act as a multiple choice key. Each valid choice +% for \meta{key} must then be created, as discussed in +% section~\ref{sec:choice}. +% \end{function} +% +% \begin{function}{.choice_code:n, .choice_code:x} +% \begin{syntax} +% \meta{key} .choice_code:n = \meta{code} +% \end{syntax} +% Stores \meta{code} for use when \texttt{.generate_choices:n} creates +% one or more choice sub-keys of the current key. Inside \meta{code}, +% \cs{l_keys_choice_tl} will expand to the name of the choice made, and +% \cs{l_keys_choice_int} will be the position of the choice in the list +% given to \texttt{.generate_choices:n}. Choices are discussed in +% detail in section~\ref{sec:choice}. +% \end{function} +% +% \begin{function}{.code:n, .code:x} +% \begin{syntax} +% \meta{key} .code:n = \meta{code} +% \end{syntax} +% Stores the \meta{code} for execution when \meta{key} is used. The +% The \meta{code} can include one parameter ("#1"), which will be the +% \meta{value} given for the \meta{key}. The \texttt{x}-type variant +% will expand \meta{code} at the point where the \meta{key} is +% created. +% \end{function} +% +% \begin{function}{.default:n, .default:V} +% \begin{syntax} +% \meta{key} .default:n = \meta{default} +% \end{syntax} +% Creates a \meta{default} value for \meta{key}, which is used if no +% value is given. This will be used if only the key name is given, +% but not if a blank \meta{value} is given: +% \begin{verbatim} +% \keys_define:nn { module } +% { +% key .code:n = Hello~#1, +% key .default:n = World +% } +% \keys_set:nn { module } +% { +% key = Fred, % Prints 'Hello Fred' +% key, % Prints 'Hello World' +% key = , % Prints 'Hello ' +% } +% \end{verbatim} +% \end{function} +% +% \begin{function}{.dim_set:N, .dim_set:c} +% \begin{syntax} +% \meta{key} .dim_set:N = \meta{dimension} +% \end{syntax} +% Defines \meta{key} to set \meta{dimension} to \meta{value} (which +% must a dimension expression). If the variable does not exist, it +% will be created at the point that the key is set up. The +% \meta{dimension} will be assigned locally. +% \end{function} +% +% \begin{function}{.dim_gset:N, .dim_gset:c} +% \begin{syntax} +% \meta{key} .dim_gset:N = \meta{dimension} +% \end{syntax} +% Defines \meta{key} to set \meta{dimension} to \meta{value} (which +% must a dimension expression). If the variable does not exist, it +% will be created at the point that the key is set up. The +% \meta{dimension} will be assigned globally. +% \end{function} +% +% \begin{function}{.fp_set:N, .fp_set:c} +% \begin{syntax} +% \meta{key} .fp_set:N = \meta{floating point} +% \end{syntax} +% Defines \meta{key} to set \meta{floating point} to \meta{value} +% (which must a integer expression). If the variable does not exist, +% it will be created at the point that the key is set up. The +% \meta{integer} will be assigned locally. +% \end{function} +% +% \begin{function}{.fp_gset:N, .fp_gset:c} +% \begin{syntax} +% \meta{key} .fp_gset:N = \meta{floating point} +% \end{syntax} +% Defines \meta{key} to set \meta{floating-point} to \meta{value} +% (which must a integer expression). If the variable does not exist, +% it will be created at the point that the key is set up. The +% \meta{integer} will be assigned globally. +% \end{function} +% +% \begin{function}{.generate_choices:n} +% \begin{syntax} +% \meta{key} .generate_choices:n = \Arg{list} +% \end{syntax} +% This property will mark \meta{key} as a multiple choice key, +% and will use the \meta{list} to define the choices. The \meta{list} +% should consist of a comma-separated list of choice names. Each +% choice will be set up to execute \meta{code} as set using +% \texttt{.choice_code:n} (or \texttt{.choice_code:x}). Choices are +% discussed in detail in section~\ref{sec:choice}. +% \end{function} +% +% \begin{function}{.int_set:N, .int_set:c} +% \begin{syntax} +% \meta{key} .int_set:N = \meta{integer} +% \end{syntax} +% Defines \meta{key} to set \meta{integer} to \meta{value} (which +% must a integer expression). If the variable does not exist, it +% will be created at the point that the key is set up. The +% \meta{integer} will be assigned locally. +% \end{function} +% +% \begin{function}{.int_gset:N, .int_gset:c} +% \begin{syntax} +% \meta{key} .int_gset:N = \meta{integer} +% \end{syntax} +% Defines \meta{key} to set \meta{integer} to \meta{value} (which +% must a integer expression). If the variable does not exist, it +% will be created at the point that the key is set up. The +% \meta{integer} will be assigned globally. +% \end{function} +% +% \begin{function}{.meta:n, .meta:x} +% \begin{syntax} +% \meta{key} .meta:n = \Arg{keyval list} +% \end{syntax} +% Makes \meta{key} a meta-key, which will set \meta{keyval list} in +% one go. If \meta{key} is given with a value at the time the key +% is used, then the value will be passed through to the subsidiary +% \meta{keys} for processing (as |#1|). +% \end{function} +% +% \begin{function}{.skip_set:N, .skip_set:c} +% \begin{syntax} +% \meta{key} .skip_set:N = \meta{skip} +% \end{syntax} +% Defines \meta{key} to set \meta{skip} to \meta{value} (which +% must a skip expression). If the variable does not exist, it +% will be created at the point that the key is set up. The +% \meta{skip} will be assigned locally. +% \end{function} +% +% \begin{function}{.skip_gset:N, .skip_gset:c} +% \begin{syntax} +% \meta{key} .skip_gset:N = \meta{skip} +% \end{syntax} +% Defines \meta{key} to set \meta{skip} to \meta{value} (which +% must a skip expression). If the variable does not exist, it +% will be created at the point that the key is set up. The +% \meta{skip} will be assigned globally. +% \end{function} +% +% \begin{function}{.tl_set:N, .tl_set:c} +% \begin{syntax} +% \meta{key} .tl_set:N = \meta{token list variable} +% \end{syntax} +% Defines \meta{key} to set \meta{token list variable} to \meta{value}. +% If the variable does not exist, it will be created at the point that +% the key is set up. The \meta{token list variable} will be assigned +% locally. +% \end{function} +% +% \begin{function}{.tl_gset:N, .tl_gset:c} +% \begin{syntax} +% \meta{key} .tl_gset:N = \meta{token list variable} +% \end{syntax} +% Defines \meta{key} to set \meta{token list variable} to \meta{value}. +% If the variable does not exist, it will be created at the point that +% the key is set up. The \meta{token list variable} will be assigned +% globally. +% \end{function} +% +% \begin{function}{.tl_set_x:N, .tl_set_x:c} +% \begin{syntax} +% \meta{key} .tl_set_x:N = \meta{token list variable} +% \end{syntax} +% Defines \meta{key} to set \meta{token list variable} to \meta{value}, +% which will be subjected to an \texttt{x}-type expansion +% (\emph{i.e.}~using \cs{tl_set:Nx}). If the variable does not exist, +% it will be created at the point that the key is set up. The +% \meta{token list variable} will be assigned locally. +% \end{function} +% +% \begin{function}{.tl_gset_x:N, .tl_gset_x:c} +% \begin{syntax} +% \meta{key} .tl_gset_x:N = \meta{token list variable} +% \end{syntax} +% Defines \meta{key} to set \meta{token list variable} to \meta{value}, +% which will be subjected to an \texttt{x}-type expansion +% (\emph{i.e.}~using \cs{tl_set:Nx}). If the variable does not exist, +% it will be created at the point that the key is set up. The +% \meta{token list variable} will be assigned globally. +% \end{function} +% +% \begin{function}{.value_forbidden:} +% \begin{syntax} +% \meta{key} .value_forbidden: +% \end{syntax} +% Specifies that \meta{key} cannot receive a \meta{value} when used. +% If a \meta{value} is given then an error will be issued. +% \end{function} +% +% \begin{function}{.value_required:} +% \begin{syntax} +% \meta{key} .value_required: +% \end{syntax} +% Specifies that \meta{key} must receive a \meta{value} when used. +% If a \meta{value} is not given then an error will be issued. +% \end{function} +% +% \section{Sub-dividing keys} +% \label{sec:subdivision} +% +% When creating large numbers of keys, it may be desirable to divide +% them into several sub-groups for a given module. This can be achieved +% either by adding a sub-division to the module name: +% \begin{verbatim} +% \keys_define:nn { module / subgroup } +% { key .code:n = code } +% \end{verbatim} +% or to the key name: +% \begin{verbatim} +% \keys_define:nn { module } +% { subgroup / key .code:n = code } +% \end{verbatim} +% As illustrated, the best choice of token for sub-dividing keys in +% this way is |/|. This is because of the method that is +% used to represent keys internally. Both of the above code fragments +% set the same key, which has full name \texttt{module/subgroup/key}. +% +% As will be illustrated in the next section, this subdivision is +% particularly relevant to making multiple choices. +% +% \section{Multiple choice keys} +% \label{sec:choice} +% +% Multiple choices are created by setting the \texttt{.choice:} +% property: +% \begin{verbatim} +% \keys_define:nn { module } +% { key .choice: } +% \end{verbatim} +% For keys which are set up as choices, the valid choices are generated +% by creating sub-keys of the choice key. This can be carried out in +% two ways. +% +% In many cases, choices execute similar code which is dependant only +% on the name of the choice or the position of the choice in the +% list of choices. Here, the keys can share the same code, and can +% be rapidly created using the \texttt{.choice_code:n} and +% \texttt{.generate_choices:n} properties: +% \begin{verbatim} +% \keys_define:nn { module } +% { +% key .choice_code:n = +% { +% You~gave~choice~'\int_use:N \l_keys_choice_tl',~ +% which~is~in~position~ +% \int_use:N \l_keys_choice_int \c_space_tl +% in~the~list. +% }, +% key .generate_choices:n = +% { choice-a, choice-b, choice-c } +% } +% \end{verbatim} +% Following common computing practice, \cs{l_keys_choice_int} is +% indexed from $0$ (as an offset), so that the value of +% \cs{l_keys_choice_int} for the first choice in a list will be +% zero. +% +% \begin{variable}{\l_keys_choice_int, \l_keys_choice_tl} +% Inside the code block for a choice generated using +% \texttt{.generate_choice:}, the variables \cs{l_keys_choice_tl} and +% \cs{l_keys_choice_int} are available to indicate the name of the +% current choice, and its position in the comma list. The position +% is indexed from $0$. +% \end{variable} +% +% On the other hand, it is sometimes useful to create choices which +% use entirely different code from one another. This can be achieved +% by setting the \texttt{.choice:} property of a key, then manually +% defining sub-keys. +% \begin{verbatim} +% \keys_define:nn { module } +% { +% key .choice:n, +% key / choice-a .code:n = code-a, +% key / choice-b .code:n = code-b, +% key / choice-c .code:n = code-c, +% } +%\end{verbatim} +% +% It is possible to mix the two methods, but manually-created choices +% should \emph{not} use \cs{l_keys_choice_tl} or \cs{l_keys_choice_int}. +% These variables do not have defined behaviour when used outside of +% code created using \texttt{.generate_choices:n} +% (\emph{i.e.}~anything might happen). +% +% \section{Setting keys} +% +% \begin{function}{\keys_set:nn, \keys_set:nV, \keys_set:nv, \keys_set:no} +% \begin{syntax} +% \cs{keys_set:nn} \Arg{module} \Arg{keyval list} +% \end{syntax} +% Parses the \meta{keyval list}, and sets those keys which are defined +% for \meta{module}. The behaviour on finding an unknown key can be set +% by defining a special \texttt{unknown} key: this will be illustrated +% later. In contrast to \cs{keys_define:nn}, this function does check +% category codes and ignore spaces, and is therefore suitable for user +% input. +% \end{function} +% +% If a key is not known, \cs{keys_set:nn} will look for a special +% \texttt{unknown} key for the same module. This mechanism can be +% used to create new keys from user input. +% \begin{verbatim} +% \keys_define:nn { module } +% { +% unknown .code:n = +% You~tried~to~set~key~'\l_keys_key_tl'~to~'#1'. +% } +%\end{verbatim} +% +% \begin{variable}{\l_keys_key_tl} +% When processing an unknown key, the name of the key is available +% as \cs{l_keys_key_tl}. Note that this will have been processed +% using \cs{tl_to_str:n}. The value passed to the key (if any) is +% available as the macro parameter |#1|. +% \end{variable} +% +% \begin{variable}{\l_keys_path_tl} +% When processing an unknown key, the path of the key used is available +% as \cs{l_keys_path_tl}. Note that this will have been processed +% using \cs{tl_to_str:n}. +% \end{variable} +% +% \section{Utility functions for keys} +% +% \begin{function}[EXP,pTF]{\keys_if_exist:nn} +% \begin{syntax} +% \cs{keys_if_exist:nn} \meta{module} \meta{key} +% \cs{keys_if_exist:nn} \meta{module} \meta{key} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the \meta{key} exists for \meta{module}, \emph{i.e.}~if any code +% has been defined for \meta{key}. +% The branching versions then leave either \meta{true code} or +% \meta{false code} in the input stream, as appropriate to the truth +% of the test and the variant of the function chosen. The logical +% truth of the test is left in the input stream by the predicate +% version. +% \end{function} +% +% \begin{function}{\keys_show:nn} +% \begin{syntax} +% \cs{keys_show:nn} \Arg{module} \Arg{key} +% \end{syntax} +% Shows the function which is used to actually implement a +% \meta{key} for a \meta{module}. +% \end{function} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{l3keys} Implementation} +% +% \begin{macrocode} +%<*initex|package> +% \end{macrocode} +% +% \begin{macrocode} +%<*package> +\ProvidesExplPackage + {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +\package_check_loaded_expl: +%</package> +% \end{macrocode} +% +% \subsection{Constants and variables} +% +% \begin{variable}{\c_keys_code_root_tl, \c_keys_vars_root_tl} +% The prefixes for the code and variables of the keys themselves. +% \begin{macrocode} +\tl_const:Nn \c_keys_code_root_tl { key~code~>~ } +\tl_const:Nn \c_keys_vars_root_tl { key~var~>~ } +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\c_keys_props_root_tl} +% The prefix for storing properties. +% \begin{macrocode} +\tl_const:Nn \c_keys_props_root_tl { key~prop~>~ } +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\c_keys_value_forbidden_tl, \c_keys_value_required_tl} +% Two marker token lists. +% \begin{macrocode} +\tl_const:Nn \c_keys_value_forbidden_tl { forbidden } +\tl_const:Nn \c_keys_value_required_tl { required } +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_keys_choice_int, \l_keys_choices_tl} +% Publicly accessible data on which choice is being used when several +% are generated as a set. +% \begin{macrocode} +\int_new:N \l_keys_choice_int +\tl_new:N \l_keys_choices_tl +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_keys_key_tl} +% The name of a key itself: needed when setting keys. +% \begin{macrocode} +\tl_new:N \l_keys_key_tl +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_keys_module_tl} +% The module for an entire set of keys. +% \begin{macrocode} +\tl_new:N \l_keys_module_tl +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_keys_no_value_bool} +% A marker is needed internally to show if only a key or a key plus a +% value was seen: this is recorded here. +% \begin{macrocode} +\bool_new:N \l_keys_no_value_bool +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_keys_path_tl} +% The \enquote{path} of the current key is stored here: this is +% available to the programmer and so is public. +% \begin{macrocode} +\tl_new:N \l_keys_path_tl +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_keys_property_tl} +% The \enquote{property} begin set for a key at definition time is +% stored here. +% \begin{macrocode} +\tl_new:N \l_keys_property_tl +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_keys_value_tl} +% The value given for a key: may be empty if no value was given. +% \begin{macrocode} +\tl_new:N \l_keys_value_tl +% \end{macrocode} +% \end{variable} +% +% \subsection{The key defining mechanism} +% +% \begin{macro}{\keys_define:nn} +% \begin{macro}[aux]{\keys_define_aux:nnn, \keys_define_aux:onn} +% The public function for definitions is just a wrapper for the lower +% level mechanism, more or less. The outer function is designed to +% keep a track of the current module, to allow safe nesting. +% \begin{macrocode} +\cs_new_protected:Npn \keys_define:nn + { \keys_define_aux:onn \l_keys_module_tl } +\cs_new_protected:Npn \keys_define_aux:nnn #1#2#3 + { + \tl_set:Nx \l_keys_module_tl { \tl_to_str:n {#2} } + \keyval_parse:NNn \keys_define_elt:n \keys_define_elt:nn {#3} + \tl_set:Nn \l_keys_module_tl {#1} + } +\cs_generate_variant:Nn \keys_define_aux:nnn { o } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[int]{\keys_define_elt:n} +% \begin{macro}[int]{\keys_define_elt:nn} +% \begin{macro}[aux]{\keys_define_elt_aux:nn} +% The outer functions here record whether a value was given and then +% converge on a common internal mechanism. There is first a search for +% a property in the current key name, then a check to make sure it is +% known before the code hands off to the next step. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \keys_define_elt:n #1 + { + \bool_set_true:N \l_keys_no_value_bool + \keys_define_elt_aux:nn {#1} { } + } +\cs_new_protected:Npn \keys_define_elt:nn #1#2 + { + \bool_set_false:N \l_keys_no_value_bool + \keys_define_elt_aux:nn {#1} {#2} + } +\cs_new_protected:Npn \keys_define_elt_aux:nn #1#2 { + \keys_property_find:n {#1} + \cs_if_exist:cTF { \c_keys_props_root_tl \l_keys_property_tl } + { \keys_define_key:n {#2} } + { + \msg_kernel_error:nnxx { keys } { property-unknown } + { \l_keys_property_tl } { \l_keys_path_tl } + } +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}[int]{\keys_property_find:n} +% \begin{macro}[aux]{\keys_property_find_aux:w} +% Searching for a property means finding the last |.| in the input, +% and storing the text before and after it. Everything is turned into +% strings, so there is no problem using an \texttt{x}-type expansion. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \keys_property_find:n #1 + { + \tl_set:Nx \l_keys_path_tl { \l_keys_module_tl / } + \tl_if_in:nnTF {#1} { . } + { \keys_property_find_aux:w #1 \q_stop } + { \msg_kernel_error:nnx { keys } { key-no-property } {#1} } + } +\cs_new_protected_nopar:Npn \keys_property_find_aux:w #1 . #2 \q_stop + { + \tl_set:Nx \l_keys_path_tl { \l_keys_path_tl \tl_to_str:n {#1} } + \tl_if_in:nnTF {#2} { . } + { + \tl_set:Nx \l_keys_path_tl { \l_keys_path_tl . } + \keys_property_find_aux:w #2 \q_stop + } + { \tl_set:Nn \l_keys_property_tl { . #2 } } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[int]{\keys_define_key:n} +% \begin{macro}[aux]{\keys_define_key_aux:w} +% Two possible cases. If there is a value for the key, then just use +% the function. If not, then a check to make sure there is no need for +% a value with the property. If there should be one then complain, +% otherwise execute it. There is no need to check for a |:| as if it +% is missing the earlier tests will have failed. +% \begin{macrocode} +\cs_new_protected:Npn \keys_define_key:n #1 + { + \bool_if:NTF \l_keys_no_value_bool + { + \exp_after:wN \keys_define_key_aux:w + \l_keys_property_tl \q_stop + { \use:c { \c_keys_props_root_tl \l_keys_property_tl } } + { + \msg_kernel_error:nnxx { keys } + { property-requires-value } { \l_keys_property_tl } + { \l_keys_path_tl } + } + } + { \use:c { \c_keys_props_root_tl \l_keys_property_tl } {#1} } + } +\cs_new_protected:Npn \keys_define_key_aux:w #1 : #2 \q_stop + { \tl_if_empty:nTF {#2} } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Turning properties into actions} +% +% \begin{macro}[int]{\keys_bool_set:NN} +% Boolean keys are really just choices, but all done by hand. The +% second argument here is the scope: either empty or \texttt{g} for +% global. +% \begin{macrocode} +\cs_new_nopar:Npn \keys_bool_set:NN #1#2 + { + \cs_if_exist:NF #1 { \bool_new:N #1 } + \keys_choice_make: + \keys_cmd_set:nx { \l_keys_path_tl / true } + { \exp_not:c { bool_ #2 set_true:N } \exp_not:N #1 } + \keys_cmd_set:nx { \l_keys_path_tl / false } + { \exp_not:c { bool_ #2 set_false:N } \exp_not:N #1 } + \keys_cmd_set:nn { \l_keys_path_tl / unknown } + { + \msg_kernel_error:nnx { keys } { boolean-values-only } + { \l_keys_key_tl } + } + \keys_default_set:n { true } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int]{\keys_choice_make:} +% To make a choice from a key, two steps: set the code, and set the +% unknown key. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \keys_choice_make: + { + \keys_cmd_set:nn { \l_keys_path_tl } + { \keys_choice_find:n {##1} } + \keys_cmd_set:nn { \l_keys_path_tl / unknown } + { + \msg_kernel_error:nnxx { keys } { choice-unknown } + { \l_keys_path_tl } {##1} + } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int]{\keys_choices_generate:n} +% \begin{macro}[aux]{\keys_choices_generate_aux:n} +% Creating multiple-choices means setting up the \enquote{indicator} +% code, then applying whatever the user wanted. +% \begin{macrocode} +\cs_new_protected:Npn \keys_choices_generate:n #1 + { + \cs_if_exist:cTF + { \c_keys_vars_root_tl \l_keys_path_tl .choice~code } + { + \keys_choice_make: + \int_zero:N \l_keys_choice_int + \clist_map_function:nN {#1} \keys_choices_generate_aux:n + } + { + \msg_kernel_error:nnx { keys } + { generate-choices-before-code } { \l_keys_path_tl } + } + } +\cs_new_protected_nopar:Npn \keys_choices_generate_aux:n #1 + { + \keys_cmd_set:nx { \l_keys_path_tl / #1 } + { + \exp_not:n { \tl_set:Nn \l_keys_choice_tl } {#1} + \exp_not:n { \int_set:Nn \l_keys_choice_int } + { \int_use:N \l_keys_choice_int } + \exp_not:v + { \c_keys_vars_root_tl \l_keys_path_tl .choice~code } + } + \int_incr:N \l_keys_choice_int + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[int]{\keys_choice_code_store:x} +% The code for making multiple choices is stored in a token list. +% \begin{macrocode} +\cs_new_protected:Npn \keys_choice_code_store:x #1 + { + \cs_if_exist:cF + { \c_keys_vars_root_tl \l_keys_path_tl .choice~code } + { + \tl_new:c + { \c_keys_vars_root_tl \l_keys_path_tl .choice~code } + } + \tl_set:cx { \c_keys_vars_root_tl \l_keys_path_tl .choice~code } + {#1} + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int]{\keys_cmd_set:nn, \keys_cmd_set:nx} +% \begin{macro}[aux]{\keys_cmd_set_aux:n} +% Creating a new command means tidying up the properties and then making +% the internal function which actually does the work. +% \begin{macrocode} +\cs_new_protected:Npn \keys_cmd_set:nn #1#2 + { + \keys_cmd_set_aux:n {#1} + \cs_set:cpn { \c_keys_code_root_tl #1 } ##1 {#2} + } +\cs_new_protected:Npn \keys_cmd_set:nx #1#2 + { + \keys_cmd_set_aux:n {#1} + \cs_set:cpx { \c_keys_code_root_tl #1 } ##1 {#2} + } +\cs_new_protected_nopar:Npn \keys_cmd_set_aux:n #1 + { + \tl_clear_new:c { \c_keys_vars_root_tl #1 .default } + \tl_set:cn { \c_keys_vars_root_tl #1 .default } { \q_no_value } + \tl_clear_new:c { \c_keys_vars_root_tl #1 .req } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[int]{\keys_default_set:n, \keys_default_set:V} +% Setting a default value is easy. +% \begin{macrocode} +\cs_new_protected:Npn \keys_default_set:n #1 + { \tl_set:cn { \c_keys_vars_root_tl \l_keys_path_tl .default } {#1} } +\cs_generate_variant:Nn \keys_default_set:n { V } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\keys_meta_make:n, \keys_meta_make:x} +% To create a meta-key, simply set up to pass data through. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \keys_meta_make:n #1 + { + \exp_args:NNo \keys_cmd_set:nn \l_keys_path_tl + { \exp_after:wN \keys_set:nn \exp_after:wN { \l_keys_module_tl } {#1} } + } +\cs_new_protected_nopar:Npn \keys_meta_make:x #1 + { + \keys_cmd_set:nx { \l_keys_path_tl } + { \exp_not:N \keys_set:nn { \l_keys_module_tl } {#1} } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int]{\keys_value_requirement:n} +% Values can be required or forbidden by having the appropriate marker +% set. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \keys_value_requirement:n #1 + { + \tl_set_eq:cc + { \c_keys_vars_root_tl \l_keys_path_tl .req } + { c_keys_value_ #1 _tl } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int]{\keys_variable_set:NnNN, \keys_variable_set:cnNN} +% \begin{macro}[int]{\keys_variable_set:NnN, \keys_variable_set:cnN} +% Setting a variable takes the type and scope separately so that +% it is easy to make a new variable if needed. The three-argument +% version is set up so that the use of |{ }| as an \texttt{N}-type +% variable is only done once! +% \begin{macrocode} +\cs_new_protected_nopar:Npn \keys_variable_set:NnNN #1#2#3#4 + { + \cs_if_exist:NF #1 { \use:c { #2 _new:N } #1 } + \keys_cmd_set:nx { \l_keys_path_tl } + { \exp_not:c { #2 _ #3 set:N #4 } \exp_not:N #1 {##1} } + } +\cs_new_protected_nopar:Npn \keys_variable_set:NnN #1#2#3 + { \keys_variable_set:NnNN #1 {#2} { } #3 } +\cs_generate_variant:Nn \keys_variable_set:NnNN { c } +\cs_generate_variant:Nn \keys_variable_set:NnN { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Creating key properties} +% +% The key property functions are all wrappers for internal functions, +% meaning that things stay readable and can also be altered later on. +% +% \begin{macro}{.bool_set:N} +% \begin{macro}{.bool_gset:N} +% One function for this. +% \begin{macrocode} +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .bool_set:N } #1 + { \keys_bool_set:NN #1 { } } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .bool_gset:N } #1 + { \keys_bool_set:NN #1 g } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{.choice:} +% Making a choice is handled internally, as it is also needed by +% \texttt{.generate_choices:n}. +% \begin{macrocode} +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .choice: } + { \keys_choice_make: } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{.code:n, .code:x} +% Creating code is simply a case of passing through to the underlying +% \texttt{set} function. +% \begin{macrocode} +\cs_new_protected:cpn { \c_keys_props_root_tl .code:n } #1 + { \keys_cmd_set:nn { \l_keys_path_tl } {#1} } +\cs_new_protected:cpn { \c_keys_props_root_tl .code:x } #1 + { \keys_cmd_set:nx { \l_keys_path_tl } {#1} } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{.choice_code:n, .choice_code:x} +% Storing the code for choices, using \cs{exp_not:n} to avoid needing +% two internal functions. +% \begin{macrocode} +\cs_new_protected:cpn { \c_keys_props_root_tl .choice_code:n } #1 + { \keys_choice_code_store:x { \exp_not:n {#1} } } +\cs_new_protected:cpn { \c_keys_props_root_tl .choice_code:x } #1 + { \keys_choice_code_store:x {#1} } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{.default:n, .default:V} +% Expansion is left to the internal functions. +% \begin{macrocode} +\cs_new_protected:cpn { \c_keys_props_root_tl .default:n } #1 + { \keys_default_set:n {#1} } +\cs_new_protected:cpn { \c_keys_props_root_tl .default:V } #1 + { \keys_default_set:V #1 } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{.dim_set:N, .dim_set:c} +% \begin{macro}{.dim_gset:N, .dim_gset:c} +% Setting a variable is very easy: just pass the data along. +% \begin{macrocode} +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .dim_set:N } #1 + { \keys_variable_set:NnN #1 { dim } n } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .dim_set:c } #1 + { \keys_variable_set:cnN {#1} { dim } n } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .dim_gset:N } #1 + { \keys_variable_set:NnNN #1 { dim } g n } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .dim_gset:c } #1 + { \keys_variable_set:cnNN {#1} { dim } g n } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{.fp_set:N, .fp_set:c} +% \begin{macro}{.fp_gset:N, .fp_gset:c} +% Setting a variable is very easy: just pass the data along. +% \begin{macrocode} +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .fp_set:N } #1 + { \keys_variable_set:NnN #1 { fp } n } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .fp_set:c } #1 + { \keys_variable_set:cnN {#1} { fp } n } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .fp_gset:N } #1 + { \keys_variable_set:NnNN #1 { fp } g n } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .fp_gset:c } #1 + { \keys_variable_set:cnNN {#1} { fp } g n } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{.generate_choices:n} +% Making choices is easy. +% \begin{macrocode} +\cs_new_protected:cpn { \c_keys_props_root_tl .generate_choices:n } #1 + { \keys_choices_generate:n {#1} } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{.int_set:N, .int_set:c} +% \begin{macro}{.int_gset:N, .int_gset:c} +% Setting a variable is very easy: just pass the data along. +% \begin{macrocode} +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .int_set:N } #1 + { \keys_variable_set:NnN #1 { int } n } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .int_set:c } #1 + { \keys_variable_set:cnN {#1} { int } n } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .int_gset:N } #1 + { \keys_variable_set:NnNN #1 { int } g n } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .int_gset:c } #1 + { \keys_variable_set:cnNN {#1} { int } g n } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +%\begin{macro}{.meta:n, .meta:x} +% Making a meta is handled internally. +% \begin{macrocode} +\cs_new_protected:cpn { \c_keys_props_root_tl .meta:n } #1 + { \keys_meta_make:n {#1} } +\cs_new_protected:cpn { \c_keys_props_root_tl .meta:x } #1 + { \keys_meta_make:x {#1} } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{.skip_set:N, .skip_set:c} +% \begin{macro}{.skip_gset:N, .skip_gset:c} +% Setting a variable is very easy: just pass the data along. +% \begin{macrocode} +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .skip_set:N } #1 + { \keys_variable_set:NnN #1 { skip } n } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .skip_set:c } #1 + { \keys_variable_set:cnN {#1} { skip } n } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .skip_gset:N } #1 + { \keys_variable_set:NnNN #1 { skip } g n } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .skip_gset:c } #1 + { \keys_variable_set:cnNN {#1} { skip } g n } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{.tl_set:N, .tl_set:c} +% \begin{macro}{.tl_gset:N, .tl_gset:c} +% \begin{macro}{.tl_set_x:N, .tl_set_x:c} +% \begin{macro}{.tl_gset_x:N, .tl_gset_x:c} +% Setting a variable is very easy: just pass the data along. +% \begin{macrocode} +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .tl_set:N } #1 + { \keys_variable_set:NnN #1 { tl } n } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .tl_set:c } #1 + { \keys_variable_set:cnN {#1} { tl } n } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .tl_set_x:N } #1 + { \keys_variable_set:NnN #1 { tl } x } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .tl_set_x:c } #1 + { \keys_variable_set:cnN {#1} { tl } x } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .tl_gset:N } #1 + { \keys_variable_set:NnNN #1 { tl } g n } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .tl_gset:c } #1 + { \keys_variable_set:cnNN {#1} { tl } g n } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .tl_gset_x:N } #1 + { \keys_variable_set:NnNN #1 { tl } g x } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .tl_gset_x:c } #1 + { \keys_variable_set:cnNN {#1} { tl } g x } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{.value_forbidden:} +% \begin{macro}{.value_required:} +% These are very similar, so both call the same function. +% \begin{macrocode} +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .value_forbidden: } + { \keys_value_requirement:n { forbidden } } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .value_required: } + { \keys_value_requirement:n { required } } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Setting keys} +% +% \begin{macro}{\keys_set:nn, \keys_set:nV, \keys_set:nv, \keys_set:no} +% \begin{macro}[aux]{\keys_set_aux:nnn, \keys_set_aux:onn} +% A simple wrapper again. +% \begin{macrocode} +\cs_new_protected:Npn \keys_set:nn + { \keys_set_aux:onn { \l_keys_module_tl } } +\cs_new_protected:Npn \keys_set_aux:nnn #1#2#3 + { + \tl_set:Nn \l_keys_module_tl {#2} + \keyval_parse:NNn \keys_set_elt:n \keys_set_elt:nn {#3} + \tl_set:Nn \l_keys_module_tl {#1} + } +\cs_generate_variant:Nn \keys_set:nn { nV , nv , no } +\cs_generate_variant:Nn \keys_set_aux:nnn { o } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[int]{\keys_set_elt:n, \keys_set_elt:nn} +% \begin{macro}[aux]{\keys_set_elt_aux:nn} +% A shared system once again. First, set the current path and add a +% default if needed. There are then checks to see if the a value is +% required or forbidden. If everything passes, move on to execute the +% code. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \keys_set_elt:n #1 + { + \bool_set_true:N \l_keys_no_value_bool + \keys_set_elt_aux:nn {#1} { } + } +\cs_new_protected:Npn \keys_set_elt:nn #1#2 + { + \bool_set_false:N \l_keys_no_value_bool + \keys_set_elt_aux:nn {#1} {#2} + } +\cs_new_protected:Npn \keys_set_elt_aux:nn #1#2 + { + \tl_set:Nx \l_keys_key_tl { \tl_to_str:n {#1} } + \tl_set:Nx \l_keys_path_tl { \l_keys_module_tl / \l_keys_key_tl } + \keys_value_or_default:n {#2} + \bool_if:nTF + { + \keys_if_value_p:n { required } && + \l_keys_no_value_bool + } + { + \msg_kernel_error:nnx { keys } { value-required } + { \l_keys_path_tl } + } + { + \bool_if:nTF + { + \keys_if_value_p:n { forbidden } && + ! \l_keys_no_value_bool + } + { + \msg_kernel_error:nnxx { keys } { value-forbidden } + { \l_keys_path_tl } { \l_keys_value_tl } + } + { \keys_execute: } + } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[int]{\keys_value_or_default:n} +% If a value is given, return it as |#1|, otherwise send a default if +% available. +% \begin{macrocode} +\cs_new_protected:Npn \keys_value_or_default:n #1 + { + \tl_set:Nn \l_keys_value_tl {#1} + \bool_if:NT \l_keys_no_value_bool + { + \quark_if_no_value:cF { \c_keys_vars_root_tl \l_keys_path_tl .default } + { + \tl_set_eq:Nc \l_keys_value_tl + { \c_keys_vars_root_tl \l_keys_path_tl .default } + } + } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int]{\keys_if_value_p:n} +% To test if a value is required or forbidden. A simple check for +% the existence of the appropriate marker. +% \begin{macrocode} +\prg_new_conditional:Npnn \keys_if_value:n #1 { p } + { + \tl_if_eq:ccTF { c_keys_value_ #1 _tl } + { \c_keys_vars_root_tl \l_keys_path_tl .req } + { \prg_return_true: } + { \prg_return_false: } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int]{\keys_execute:} +% \begin{macro}[aux]{\keys_execute_unknown:} +% \begin{macro}[aux]{\keys_execute:nn} +% Actually executing a key is done in two parts. First, look for the +% key itself, then look for the \texttt{unknown} key with the same +% path. If both of these fail, complain. +% \begin{macrocode} +\cs_new_nopar:Npn \keys_execute: + { \keys_execute:nn { \l_keys_path_tl } { \keys_execute_unknown: } } +\cs_new_nopar:Npn \keys_execute_unknown: + { + \keys_execute:nn { \l_keys_module_tl / unknown } + { + \msg_kernel_error:nnxx { keys } { key-unknown } + { \l_keys_path_tl } { \l_keys_module_tl } + } + } +\cs_new_nopar:Npn \keys_execute:nn #1#2 + { + \cs_if_exist:cTF { \c_keys_code_root_tl #1 } + { + \exp_args:Nno \use:c { \c_keys_code_root_tl #1 } + \l_keys_value_tl + } + {#2} + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\keys_choice_find:n} +% Executing a choice has two parts. First, try the choice given, then +% if that fails call the unknown key. That will exist, as it is created +% when a choice is first made. So there is no need for any escape code. +% \begin{macrocode} +\cs_new_nopar:Npn \keys_choice_find:n #1 + { + \keys_execute:nn { \l_keys_path_tl / \tl_to_str:n {#1} } + { \keys_execute:nn { \l_keys_path_tl / unknown } { } } + } +% \end{macrocode} +% \end{macro} +% +% \subsection{Utilities} +% +% \begin{macro}[pTF]{\keys_if_exist:nn} +% A utility for others to see if a key exists. +% \begin{macrocode} +\prg_new_conditional:Npnn \keys_if_exist:nn #1#2 { p , T , F , TF } + { + \cs_if_exist:cTF { \c_keys_code_root_tl #1 / #2 } + { \prg_return_true:} + { \prg_return_false:} + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\keys_show:nn} +% Showing a key is just a question of using the correct name. +% \begin{macrocode} +\cs_new_nopar:Npn \keys_show:nn #1#2 + { \cs_show:c { \c_keys_code_root_tl #1 / \tl_to_str:n {#2} } } +% \end{macrocode} +% \end{macro} +% +% \subsection{Messages} +% +% For when there is a need to complain. +% \begin{macrocode} +\msg_kernel_new:nnnn { keys } { boolean-values-only } + { Key~'#1'~accepts~boolean~values~only. } + { The~key~'#1'~only~accepts~the~values~'true'~and~'false'. } +\msg_kernel_new:nnnn { keys } { choice-unknown } + { Choice~'#2'~unknown~for~key~'#1'. } + { + The~key~'#1'~takes~a~limited~number~of~values.\\ + The~input~given,~'#2',~is~not~on~the~list~accepted. + } +\msg_kernel_new:nnnn { keys } { generate-choices-before-code } + { No~code~available~to~generate~choices~for~key~'#1'. } + { + \c_msg_coding_error_text_tl + Before~using~.generate_choices:n~the~code~should~be~defined~ + with~'.choice_code:n'~or~'.choice_code:x'. + } +\msg_kernel_new:nnnn { keys } { key-no-property } + { No~property~given~in~definition~of~key~'#1'. } + { + \c_msg_coding_error_text_tl + Inside~\keys_define:nn each~key~name + needs~a~property: \\ + ~ ~ #1 .<property> \\ + LaTeX~did~not~find~a~'.'~to~indicate~the~start~of~a~property. + } +\msg_kernel_new:nnnn { keys } { key-unknown } + { The~key~'#1'~is~unknown~and~is~being~ignored. } + { + The~module~'#2'~does~not~have~a~key~called~#1'.\\ + Check~that~you~have~spelled~the~key~name~correctly. + } +\msg_kernel_new:nnnn { keys } { option-unknown } + { Unknown~option~'#1'~for~package~#2. } + { + LaTeX~has~been~asked~to~set~an~option~called~'#1'~ + but~the~#2~package~has~not~created~an~option~with~this~name. + } +\msg_kernel_new:nnnn { keys } { property-requires-value } + { The~property~'#1'~requires~a~value. } + { + \c_msg_coding_error_text_tl + LaTeX~was~asked~to~set~property~'#2'~for~key~'#1'.\\ + No~value~was~given~for~the~property,~and~one~is~required. + } +\msg_kernel_new:nnnn { keys } { property-unknown } + { The~key~property~'#1'~is~unknown. } + { + \c_msg_coding_error_text_tl + LaTeX~has~been~asked~to~set~the~property~'#1'~for~key~'#2':~ + this~property~is~not~defined. + } +\msg_kernel_new:nnnn { keys } { value-forbidden } + { The~key~'#1'~does~not~taken~a~value. } + { + The~key~'#1'~should~be~given~without~a~value.\\ + LaTeX~will~ignore~the~given~value~'#2'. + } +\msg_kernel_new:nnnn { keys } { value-required } + { The~key~'#1'~requires~a~value. } + { + The~key~'#1'~must~have~a~value.\\ + No~value~was~present:~the~key~will~be~ignored. + } +% \end{macrocode} +% +% \begin{macrocode} +%</initex|package> +% \end{macrocode} +% +%\end{implementation} +% +%\PrintIndex
\ No newline at end of file diff --git a/Master/texmf-dist/source/latex/l3kernel/l3keyval.dtx b/Master/texmf-dist/source/latex/l3kernel/l3keyval.dtx new file mode 100644 index 00000000000..999ae7e5b08 --- /dev/null +++ b/Master/texmf-dist/source/latex/l3kernel/l3keyval.dtx @@ -0,0 +1,405 @@ +% \iffalse meta-comment +% +%% File: l3keyval.dtx Copyright (C) 2006-2011 The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +% +%<*driver|package> +\RequirePackage{l3names} +\GetIdInfo$Id: l3keyval.dtx 2478 2011-06-19 21:34:23Z joseph $ + {L3 Experimental key-value parsing} +%</driver|package> +%<*driver> +\documentclass[full]{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{^^A +% The \pkg{l3keyval} package\\ Key--value parsing^^A +% \thanks{This file describes v\ExplFileVersion, +% last revised \ExplFileDate.}^^A +% } +% +% \author{^^A +% The \LaTeX3 Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% +% \date{Released \ExplFileDate} +% +% \maketitle +% +% \begin{documentation} +% +% A key--value list is input of the form +% \begin{verbatim} +% KeyOne = ValueOne , +% KeyTwo = ValueTwo , +% KeyThree +% \end{verbatim} +% where each key--value pair is separated by a comma from the rest of +% the list, and each key--value pair does not necessarily contain an +% equals sign or a value! Processing this type of input correctly +% requires a number of careful steps, to correctly account for +% braces, spaces and the category codes of separators. +% +% This module provides the low-level machinery for processing arbitrary +% key--value lists. The \pkg{l3keys} module provides a higher-level +% interface for managing run-time settings using key--value input, +% while other parts of \LaTeX3 also use key--value input based on +% \pkg{l3keyval} (for example the \pkg{xtemplate} module). +% + %\section{Parsing key--value lists} +% +% The low-level parsing system converts a \meta{key--value list} +% into \meta{keys} and associated \meta{values}. After the parsing phase +% is completed, the resulting keys and values (or keys alone) are +% available for further processing. This is not carried out by the +% low-level parser, and so the parser requires the names of +% two functions along with the key--value list. One function is +% needed to process key--value pairs (\emph{i.e}~two arguments), +% and a second function if required for keys given without arguments +% (\emph{i.e.}~a single argument). +% +% The parser does not double |#| tokens or expand any input. The tokens +% |=| and |,| are corrected so that the parser does not \enquote{miss} +% any due to category code changes. Spaces are removed from the ends +% of the keys and values. Values which are given in braces will have +% exactly one set removed, thus +% \begin{verbatim} +% key = {value here}, +% \end{verbatim} +% and +% \begin{verbatim} +% key = value here, +% \end{verbatim} +% are treated identically. +% + %\begin{function}{\keyval_parse:NNn} +% \begin{syntax} +% \cs{keyval_parse:NNn} \meta{function1} \meta{function2} +% ~~\Arg{key--value list} +% \end{syntax} +% Parses the \meta{key--value list} into a series of \meta{keys} and +% associated \meta{values}, or keys alone (if no \meta{value} was +% given). \meta{function1} should take one argument, while +% \meta{function2} should absorb two arguments. After +% \cs{keyval_parse:NNn} has parsed the \meta{key--value list}, +% \meta{function1} will be used to process keys given with no value +% and \meta{function2} will be used to process keys given with a +% value. The order of the \meta{keys} in the \meta{key--value list} +% will be preserved. Thus +% \begin{verbatim} +% \keyval_parse:NNn \function:n \function:nn +% { key1 = value1 , key2 = value2, key3 = , key4 } +% \end{verbatim} +% will be converted into an input stream +% \begin{verbatim} +% \function:nn { key1 } { value1 } +% \function:nn { key2 } { value2 } +% \function:nn { key3 } { } +% \function:n { key4 } +% \end{verbatim} +% Note that there is a difference between an empty value (an equals +% sign followed by nothing) and a missing value (no equals sign at +% all). +% \end{function} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{l3keyval} implementation} +% +% \begin{macrocode} +%<*initex|package> +% \end{macrocode} +% +% \begin{macrocode} +%<*package> +\ProvidesExplPackage + {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +\package_check_loaded_expl: +%</package> +% \end{macrocode} +% +% \begin{variable}{\g_keyval_level_int} +% For nesting purposes an integer is needed for the current level. +% \begin{macrocode} +\int_new:N \g_keyval_level_int +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_keyval_key_tl, \l_keyval_value_tl} +% The current key name and value. +% \begin{macrocode} +\tl_new:N \l_keyval_key_tl +\tl_new:N \l_keyval_value_tl +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_keyval_sanitise_tl} +% \begin{variable}{\l_keyval_parse_tl} +% Token list variables for dealing with awkward category codes in the +% input. +% \begin{macrocode} +\tl_new:N \l_keyval_sanitise_tl +\tl_new:N \l_keyval_parse_tl +% \end{macrocode} +%\end{variable} +%\end{variable} +% +% \begin{macro}{\keyval_parse:n} +% The parsing function first deals with the category codes for +% |=| and |,|, so that there are no odd events. The input is then +% handed off to the element by element system. +% \begin{macrocode} +\group_begin: + \char_set_catcode_active:n { `\= } + \char_set_catcode_active:n { `\, } + \char_set_lccode:nn { `\8 } { `\= } + \char_set_lccode:nn { `\9 } { `\, } +\tl_to_lowercase:n + { + \group_end: + \cs_new_protected:Npn \keyval_parse:n #1 + { + \group_begin: + \tl_clear:N \l_keyval_sanitise_tl + \tl_set:Nn \l_keyval_sanitise_tl {#1} + \tl_replace_all_in:Nnn \l_keyval_sanitise_tl { = } { 8 } + \tl_replace_all_in:Nnn \l_keyval_sanitise_tl { , } { 9 } + \tl_clear:N \l_keyval_parse_tl + \exp_after:wN \keyval_parse_elt:w \exp_after:wN + \q_no_value \l_keyval_sanitise_tl 9 \q_nil 9 + \exp_after:wN \group_end: + \l_keyval_parse_tl + } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\keyval_parse_elt:w} +% Each item to be parsed will have \cs{q_no_value} added to the front. +% Hence the blank test here can always be used to find a totally +% empty argument. If this is the case, the system loops round. If there +% is something to parse, there is a check for the \cs{q_nil} marker +% and if not a hand-off. +% \begin{macrocode} +\cs_new_protected:Npn \keyval_parse_elt:w #1 , + { + \tl_if_blank:oTF { \use_none:n #1 } + { \keyval_parse_elt:w \q_no_value } + { + \quark_if_nil:oF { \use_ii:nn #1 } + { + \keyval_split_key_value:w #1 = = \q_stop + \keyval_parse_elt:w \q_no_value + } + } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\keyval_split_key_value:w} +% \begin{macro}[aux]{\keyval_split_key_value_aux:wTF} +% The key and value are handled separately. First the key is grabbed and +% saved as \cs{l_keyval_key_tl}. Then a check is need to see if there is +% a value at all: if not then the key name is simply added to the output. +% If there is a value then there is a check to ensure that there was +% only one |=| in the input (remembering some extra ones are around at +% the moment to prevent errors). All being well, there is an +% hand-off to find the value: the \cs{q_nil} is there to prevent loss +% of braces. +% \begin{macrocode} +\cs_new_protected:Npn \keyval_split_key_value:w #1 = #2 \q_stop + { + \keyval_split_key:w #1 \q_stop + \str_if_eq:nnTF {#2} { = } + { + \tl_put_right:Nx \l_keyval_parse_tl + { + \exp_not:c { keyval_key_no_value_elt_ \int_use:N \g_keyval_level_int :n } + { \exp_not:o \l_keyval_key_tl } + } + } + { + \keyval_split_key_value_aux:wTF #2 \q_no_value \q_stop + { \keyval_split_value:w \q_nil #2 } + { \msg_kernel_error:nn { keyval } { misplaced-equals-sign } } + } + } +\cs_new:Npn \keyval_split_key_value_aux:wTF #1 = #2#3 \q_stop + { \tl_if_head_eq_meaning:nNTF {#3} \q_no_value } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\keyval_split_key:w} +% \begin{macro}{\keyval_remove_spaces:w} +% \begin{macro}[aux]{\keyval_split_key_aux:w} +% \begin{macro}[aux]{\keyval_remove_spaces_aux:w} +% The aim here is to remove spaces and also exactly one set of braces. +% The spaces are trimmed off from each end using a \enquote{funny} +% |Q|, which will never turn up in normal use. The idea is that +% the \texttt{f}-type expansion will stop if it finds an unexpandable +% token or a space, and will gobble the space. To avoid expanding +% anything else, the \cs{exp_not:N} works by ensuring that the first +% non-space token in the setting will stop the \texttt{f}-type +% expansion. The \cs{use_none:n} is needed to remove the leading +% quark, while the second setting of \cs{l_keyval_key_tl} +% removes exactly one set of braces. +% \begin{macrocode} +\group_begin: + \char_set_catcode_math_toggle:n { `\Q } + \cs_new_protected:Npn \keyval_split_key:w #1 \q_stop + { + \exp_args:NNf \tl_set:Nn \l_keyval_key_tl + { + \exp_after:wN \keyval_remove_spaces:w \exp_after:wN + \exp_not:N \use_none:n #1 Q ~ Q + } + \tl_set:Nx \l_keyval_key_tl + { \exp_after:wN \keyval_split_key_aux:w \l_keyval_key_tl \q_stop } + } + \cs_gset:Npn \keyval_split_key_aux:w #1 \q_stop { \exp_not:n {#1} } + \cs_gset:Npn \keyval_remove_spaces:w #1 ~ Q { \keyval_remove_spaces_aux:w #1 Q } + \cs_gset:Npn \keyval_remove_spaces_aux:w #1 Q #2 {#1} +\group_end: +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\keyval_split_value:w} +% Here the value has to be separated from the equals signs and the +% leading \cs{q_nil} added in to keep the brace levels. Fist the +% processing function can be added to the output list. If there is no +% value, setting \cs{l_keyval_value_tl} with three groups removed will +% leave nothing at all, and so an empty group can be added to the +% parsed list. On the other hand, if the value is entirely contained +% within a set of braces then \cs{l_keyval_value_tl} will contain +% \cs{q_nil} only. In that case, strip off the leading quark using +% \cs{use_ii:nnn}, which also deals with any spaces. +% \begin{macrocode} +\cs_new_protected:Npn \keyval_split_value:w #1 = = + { + \tl_put_right:Nx \l_keyval_parse_tl + { + \exp_not:c { keyval_key_value_elt_ \int_use:N \g_keyval_level_int :nn } + { \exp_not:o \l_keyval_key_tl } + } + \tl_set:Nx \l_keyval_value_tl { \exp_not:o { \use_none:nnn #1 \q_nil \q_nil } } + \tl_if_empty:NTF \l_keyval_value_tl + { \tl_put_right:Nn \l_keyval_parse_tl { { } } } + { + \quark_if_nil:NTF \l_keyval_value_tl + { + \tl_put_right:Nx \l_keyval_parse_tl + { { \exp_not:o { \use_ii:nnn #1 \q_nil } } } + } + { \keyval_split_value_aux:w #1 \q_stop } + } + } +% \end{macrocode} +% A similar idea to the key code: remove the spaces from each end and +% deal with one set of braces. +% \begin{macrocode} +\group_begin: + \char_set_catcode_math_toggle:n { `\Q } + \cs_new_protected:Npn \keyval_split_value_aux:w \q_nil #1 \q_stop + { + \exp_args:NNf \tl_set:Nn \l_keyval_value_tl + { \keyval_remove_spaces:w \exp_not:N #1 Q ~ Q } + \tl_put_right:Nx \l_keyval_parse_tl { { \exp_not:o \l_keyval_value_tl } } + } +\group_end: +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\keyval_parse:NNn} +% The outer parsing routine just sets up the processing functions and +% hands off. +% \begin{macrocode} +\cs_new_protected:Npn \keyval_parse:NNn #1#2#3 + { + \int_gincr:N \g_keyval_level_int + \cs_gset_eq:cN { keyval_key_no_value_elt_ \int_use:N \g_keyval_level_int :n } #1 + \cs_gset_eq:cN { keyval_key_value_elt_ \int_use:N \g_keyval_level_int :nn } #2 + \keyval_parse:n {#3} + \int_gdecr:N \g_keyval_level_int + } +% \end{macrocode} +% \end{macro} +% +% One message for the low level parsing system. +% \begin{macrocode} +\msg_kernel_new:nnnn { keyval } { misplaced-equals-sign } + { Misplaced~equals~sign~in~key-value~input~\msg_line_number: } + { + LaTeX~is~attempting~to~parse~some~key-value~input~but~found~ + two~equals~signs~not~separated~by~a~comma. + } +% \end{macrocode} +% +% \subsection{Deprecated functions} +% +% Deprecated on 2011-05-27, for removal by 2011-08-31. +% +% \begin{macro}{\KV_process_space_removal_sanitize:NNn} +% \begin{macro}{\KV_process_space_removal_no_sanitize:NNn} +% \begin{macro}{\KV_process_no_space_removal_no_sanitize:NNn} +% There is just one function for this now. +% \begin{macrocode} +\cs_new_eq:NN \KV_process_space_removal_sanitize:NNn \keyval_parse:NNn +\cs_new_eq:NN \KV_process_space_removal_no_sanitize:NNn \keyval_parse:NNn +\cs_new_eq:NN \KV_process_no_space_removal_no_sanitize:NNn \keyval_parse:NNn +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macrocode} +%</initex|package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintIndex diff --git a/Master/texmf-dist/source/latex/l3kernel/l3luatex.dtx b/Master/texmf-dist/source/latex/l3kernel/l3luatex.dtx new file mode 100644 index 00000000000..70259184340 --- /dev/null +++ b/Master/texmf-dist/source/latex/l3kernel/l3luatex.dtx @@ -0,0 +1,459 @@ +% \iffalse meta-comment +% +%% File: l3luatex.dtx Copyright (C) 2010,2011 The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +% +%<*driver|package> +\RequirePackage{l3names} +\GetIdInfo$Id: l3luatex.dtx 2478 2011-06-19 21:34:23Z joseph $ + {L3 Experimental LuaTeX-specific functions} +%</driver|package> +%<*driver> +\documentclass[full]{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{^^A +% The \pkg{l3luatex} package\\ LuaTeX-specific functions^^A +% \thanks{This file describes v\ExplFileVersion, +% last revised \ExplFileDate.}^^A +% } +% +% \author{^^A +% The \LaTeX3 Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% +% \date{Released \ExplFileDate} +% +% \maketitle +% +% \begin{documentation} +% +% \section{Breaking out to \Lua{}} +% +% The \LuaTeX{} engine provides access to the \Lua{} programming language, +% and with it access to the \enquote{internals} of \TeX{}. In order to use +% this within the framework provided here, a family of functions is +% available. When used with \pdfTeX{} or \XeTeX{} these will raise an +% error: use \cs{luatex_if_engine:T} to avoid this. Details of coding +% the \LuaTeX{} engine are detailed in the \LuaTeX{} manual. +% +% \begin{function}[EXP]{\lua_now:n, \lua_now:x} +% \begin{syntax} +% \cs{lua_now:n} \Arg{token list} +% \end{syntax} +% The \meta{token list} is first tokenized by \TeX{}, which will include +% converting line ends to spaces in the usual \TeX{} manner and which +% respects currently-applicable \TeX\ category codes. The resulting +% \meta{\Lua{} input} is passed to the \Lua{} interpreter for processing. +% Each \cs{lua_now:n} block is treated by \Lua{} as a separate chunk. +% The \Lua{} interpreter will execute the \meta{\Lua{} input} immediately, +% and in an expandable manner. +% \begin{texnote} +% \cs{lua_now:x} is the \LuaTeX{} primitive \cs{directlua} renamed. +% \end{texnote} +% \end{function} +% +% \begin{function}{\lua_shipout:n, \lua_shipout:x} +% \begin{syntax} +% \cs{lua_shipout:x} \Arg{token list} +% \end{syntax} +% The \meta{token list} is first tokenized by \TeX{}, which will include +% converting line ends to spaces in the usual \TeX{} manner and which +% respects currently-applicable \TeX{} category codes. The resulting +% \meta{\Lua{} input} is passed to the \Lua\ interpreter when the +% current page is finalised (\emph{i.e.}~at shipout). Each +% \cs{lua_shipout:n} block is treated by \Lua{} as a separate chunk. +% The \Lua{} interpreter will execute the \meta{\Lua{} input} during the +% page-building routine: no \TeX{} expansion of the \meta{\Lua{} input} +% will occur at this stage. +% \begin{texnote} +% At a \TeX{} level, the \meta{\Lua{} input} is stored as a +% \enquote{whatsit}. +% \end{texnote} +% \end{function} +% +% \begin{function}{\lua_shipout_x:n, \lua_shipout_x:x} +% \begin{syntax} +% \cs{lua_shipout:n} \Arg{token list} +% \end{syntax} +% The \meta{token list} is first tokenized by \TeX{}, which will include +% converting line ends to spaces in the usual \TeX{} manner and which +% respects currently-applicable \TeX{} category codes. The resulting +% \meta{\Lua{} input} is passed to the \Lua{} interpreter when the +% current page is finalised (\emph{i.e.}~at shipout). Each +% \cs{lua_shipout:n} block is treated by \Lua{} as a separate chunk. +% The \Lua{} interpreter will execute the \meta{\Lua{} input} during the +% page-building routine: the \meta{\Lua{} input} is expanded during this +% process in addition to any expansion when the argument was read. This +% makes these functions suitable for including material finalised +% during the page building process (such as the page number). +% \begin{texnote} +% \cs{lua_shipout_x:n} is the \LuaTeX{} primitive \cs{latelua} +% named using the \LaTeX3 scheme. +% +% At a \TeX{} level, the \meta{\Lua{} input} is stored as a +% \enquote{whatsit}. +% \end{texnote} +% \end{function} +% +% \section{Category code tables} +% +% As well as providing methods to break out into \Lua{}, there are +% places where additional \LaTeX3 functions are provided by the +% \LuaTeX{} engine. In particular, \LuaTeX{} provides category code +% tables. These can be used to ensure that a set of category codes +% are in force in a more robust way than is possible with other +% engines. These are therefore used by \cs{ExplSyntaxOn} and +% \pkg{ExplSyntaxOff} when using the \LuaTeX{} engine. +% +% \begin{function}{\cctab_new:N} +% \begin{syntax} +% \cs{cctab_new:N} \meta{category code table} +% \end{syntax} +% Creates a new category code table, initially with the codes as +% used by \IniTeX{}. +% \end{function} +% +% \begin{function}{\cctab_gset:Nn} +% \begin{syntax} +% \cs{cctab_gset:Nn} \meta{category code table} +% \Arg{category code set up} +% \end{syntax} +% Sets the \meta{category code table} to apply the category codes +% which apply when the prevailing regime is modified by the +% \meta{category code set up}. Thus within a standard code block +% the starting point will be the code applied by \cs{c_code_cctab}. +% The assignment of the table is global: the underlying primitive does +% not respect grouping. +% \end{function} +% +% \begin{function}{\cctab_begin:N} +% \begin{syntax} +% \cs{cctab_begin:N} \meta{category code table} +% \end{syntax} +% Switches the category codes in force to those stored in the +% \meta{category code table}. The prevailing codes before the +% function is called are added to a stack, for use with +% \cs{cctab_end:}. +% \end{function} +% +% \begin{function}{\cctab_end:} +% \begin{syntax} +% \cs{cctab_end:} +% \end{syntax} +% Ends the scope of a \meta{category code table} started using +% \cs{cctab_begin:N}, retuning the codes to those in force before the +% matching \cs{cctab_begin:N} was used. +% \end{function} +% +% \begin{variable}{\c_code_cctab} +% Category code table for the code environment. This does not include +% setting the behaviour of the line-end character, which is only +% altered by \cs{ExplSyntaxOn}. +% \end{variable} +% +% \begin{variable}{\c_document_cctab} +% Category code table for a standard \LaTeX{} document. This does not +% include setting the behaviour of the line-end character, which is +% only altered by \cs{ExplSyntaxOff}. +% \end{variable} +% +% \begin{variable}{\c_initex_cctab} +% Category code table as set up by \IniTeX{}. +% \end{variable} +% +% \begin{variable}{\c_other_cctab} +% Category code table where all characters have category code $12$ +% (other). +% \end{variable} +% +% \begin{variable}{\c_string_cctab} +% Category code table where all characters have category code $12$ +% (other) with the exception of spaces, which have category code +% $10$ (space). +% \end{variable} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{l3luatex} implementation} +% +% \begin{macrocode} +%<*initex|package> +% \end{macrocode} +% +% Announce and ensure that the required packages are loaded. +% \begin{macrocode} +%<*package> +\ProvidesExplPackage + {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +\package_check_loaded_expl: +%</package> +%<*initex|package> +% \end{macrocode} +% +% \begin{macro}{\lua_now:n, \lua_now:x} +% \begin{macro}{\lua_shipout_x:n, \lua_shipout_x:x} +% \begin{macro}{\lua_shipout:n, \lua_shipout:x} +% \begin{macro}[aux]{\lua_wrong_engine:} +% When \LuaTeX{} is in use, this is all a question of primitives with new +% names. On the other hand, for \pdfTeX{} and \XeTeX{} the argument should +% be removed from the input stream before issuing an error. This needs +% to be expandable, so the same idea is used as for \texttt{V}-type +% expansion, with an appropriately-named but undefined function. +% \begin{macrocode} +\luatex_if_engine:TF + { + \cs_new_eq:NN \lua_now:x \luatex_directlua:D + \cs_new_eq:NN \lua_shipout_x:n \luatex_latelua:D + } + { + \cs_new:Npn \lua_now:x #1 { \lua_wrong_engine: } + \cs_new_protected:Npn \lua_shipout_x:n #1 { \lua_wrong_engine: } + } +\cs_new:Npn \lua_now:n #1 + { \lua_now:x { \exp_not:n {#1} } } +\cs_generate_variant:Nn \lua_shipout_x:n { x } +\cs_new_protected:Npn \lua_shipout:n #1 + { \lua_shipout_x:n { \exp_not:n {#1} } } +\cs_generate_variant:Nn \lua_shipout:n { x } +\group_begin: +\char_set_catcode_letter:N\! +\char_set_catcode_letter:N\ % +\cs_gset:Npn\lua_wrong_engine:{% +\LuaTeX engine not in use!% +}% +\group_end:% +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Category code tables} +% +% \begin{variable}{\g_cctab_allocate_int} +% \begin{variable}{\g_cctab_stack_int} +% \begin{variable}{\g_cctab_stack_seq} +% To allocate category code tables, both the read-only and stack +% tables need to be followed. There is also a sequence stack for the +% dynamic tables themselves. +% \begin{macrocode} +\int_new:N \g_cctab_allocate_int +\int_set:Nn \g_cctab_allocate_int { -1 } +\int_new:N \g_cctab_stack_int +\seq_new:N \g_cctab_stack_seq +% \end{macrocode} +% \end{variable} +% \end{variable} +% \end{variable} +% +% \begin{macro}{\cctab_new:N} +% Creating a new category code table is done slightly differently +% from other registers. Low-numbered tables are more efficiently-stored +% than high-numbered ones. There is also a need to have a stack of +% flexible tables as well as the set of read-only ones. To satisfy both +% of these requirements, odd numbered tables are used for read-only +% tables, and even ones for the stack. Here, therefore, the odd numbers +% are allocated. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \cctab_new:N #1 + { + \cs_if_free:NTF #1 + { + \int_gadd:Nn \g_cctab_allocate_int { 2 } + \int_compare:nNnTF + { \g_cctab_allocate_int } < { \c_max_register_int + 1 } + { + \pref_global:D \tex_mathchardef:D #1 \g_cctab_allocate_int + \luatex_initcatcodetable:D #1 + } + { \msg_kernel_fatal:nnx { alloc } { out-of-registers } { cctab } } + } + { + \msg_kernel_error:nnx { code } { variable-already-defined } + { \token_to_str:N #1 } + } + } +\luatex_if_engine:F + { \cs_set_protected_nopar:Npn \cctab_new:N #1 { \lua_wrong_engine: } } +%<*package> +\luatex_if_engine:T + { + \cs_set_protected_nopar:Npn \cctab_new:N #1 + { + \newcatcodetable #1 + \luatex_initcatcodetable:D #1 + } + } +%</package> +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\cctab_begin:N} +% \begin{macro}{\cctab_end:} +% \begin{variable}{\l_cctab_tmp_tl} +% The aim here is to ensure that the saved tables are read-only. This is +% done by using a stack of tables which are not read only, and actually +% having them as \enquote{in use} copies. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \cctab_begin:N #1 + { + \seq_gpush:Nx \g_cctab_stack_seq { \tex_the:D \luatex_catcodetable:D } + \luatex_catcodetable:D #1 + \int_gadd:Nn \g_cctab_stack_int { 2 } + \int_compare:nNnT { \g_cctab_stack_int } > { 268 435 453 } + { \msg_kernel_error:nn { code } { cctab-stack-full } } + \luatex_savecatcodetable:D \g_cctab_stack_int + \luatex_catcodetable:D \g_cctab_stack_int + } +\cs_new_protected_nopar:Npn \cctab_end: + { + \int_gsub:Nn \g_cctab_stack_int { 2 } + \seq_gpop:NN \g_cctab_stack_seq \l_cctab_tmp_tl + \quark_if_no_value:NT \l_cctab_tmp_tl + { \tl_set:Nn \l_cctab_tmp_tl { 0 } } + \luatex_catcodetable:D \l_cctab_tmp_tl \scan_stop: + } +\luatex_if_engine:F + { + \cs_set_protected_nopar:Npn \cctab_begin:N #1 { \lua_wrong_engine: } + \cs_set_protected_nopar:Npn \cctab_end: { \lua_wrong_engine: } + } +%<*package> +\luatex_if_engine:T + { + \cs_set_protected_nopar:Npn \cctab_begin:N #1 { \BeginCatcodeRegime #1 } + \cs_set_protected_nopar:Npn \cctab_end: { \EndCatcodeRegime } + } +%</package> +\tl_new:N \l_cctab_tmp_tl +% \end{macrocode} +% \end{variable} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\cctab_gset:Nn} +% Category code tables are always global, so only one version is needed. +% The set up here is simple, and means that at the point of use there is +% no need to worry about escaping category codes. +% \begin{macrocode} +\cs_new_protected:Npn \cctab_gset:Nn #1#2 + { + \group_begin: + #2 + \luatex_savecatcodetable:D #1 + \group_end: + } +\luatex_if_engine:F + { \cs_set_protected_nopar:Npn \cctab_gset:Nn #1#2 { \lua_wrong_engine: } } +% \end{macrocode} +% \end{macro} +% +% \begin{variable}{\c_code_cctab} +% \begin{variable}{\c_document_cctab} +% \begin{variable}{\c_initex_cctab} +% \begin{variable}{\c_other_cctab} +% \begin{variable}{\c_string_cctab} +% Creating category code tables is easy using the function above. +% The \texttt{other} and \texttt{string} ones are done by completely +% ignoring the existing codes as this makes life a lot less complex. The +% table for \pkg{expl3} category codes is always needed, whereas when in +% package mode the rest can be copied from the existing \LaTeXe{} package +% \pkg{luatex}. +% \begin{macrocode} +\luatex_if_engine:T + { + \cctab_new:N \c_code_cctab + \cctab_gset:Nn \c_code_cctab { } + } +%<*package> +\luatex_if_engine:T + { + \cs_new_eq:NN \c_document_cctab \CatcodeTableLaTeX + \cs_new_eq:NN \c_initex_cctab \CatcodeTableIniTeX + \cs_new_eq:NN \c_other_cctab \CatcodeTableOther + \cs_new_eq:NN \c_string_cctab \CatcodeTableString + } +%</package> +%<*initex> +\luatex_if_engine:T + { + \cctab_new:N \c_document_cctab + \cctab_new:N \c_other_cctab + \cctab_new:N \c_string_cctab + \cctab_gset:Nn \c_document_cctab + { + \char_set_catcode_space:n { 9 } + \char_set_catcode_space:n { 32 } + \char_set_catcode_other:n { 58 } + \char_set_catcode_math_subscript:n { 95 } + \char_set_catcode_active:n { 126 } + } + \cctab_gset:Nn \c_other_cctab + { + \prg_stepwise_inline:nnnn { 0 } { 1 } { 127 } + { \char_set_catcode_other:n {#1} } + } + \cctab_gset:Nn \c_string_cctab + { + \prg_stepwise_inline:nnnn { 0 } { 1 } { 127 } + { \char_set_catcode_other:n {#1} } + \char_set_catcode_space:n { 32 } + } + } +%</initex> +% \end{macrocode} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% \end{variable} +% +% \begin{macrocode} +%</initex|package> +% \end{macrocode} +% +%\end{implementation} +% +%\PrintIndex
\ No newline at end of file diff --git a/Master/texmf-dist/source/latex/l3kernel/l3msg.dtx b/Master/texmf-dist/source/latex/l3kernel/l3msg.dtx new file mode 100644 index 00000000000..eceadf3c1a8 --- /dev/null +++ b/Master/texmf-dist/source/latex/l3kernel/l3msg.dtx @@ -0,0 +1,1609 @@ +% \iffalse meta-comment +% +%% File: l3msg.dtx Copyright (C) 2009-2011 The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +% +%<*driver|package> +\RequirePackage{l3names} +\GetIdInfo$Id: l3msg.dtx 2478 2011-06-19 21:34:23Z joseph $ + {L3 Experimental messages} +%</driver|package> +%<*driver> +\documentclass[full]{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{^^A +% The \pkg{l3msg} package\\ Messages^^A +% \thanks{This file describes v\ExplFileVersion, +% last revised \ExplFileDate.}^^A +% } +% +% \author{^^A +% The \LaTeX3 Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% +% \date{Released \ExplFileDate} +% +% \maketitle +% +% \begin{documentation} +% +% Messages need to be passed to the user by modules, either when errors +% occur or to indicate how the code is proceeding. The \pkg{l3msg} +% module provides a consistent method for doing this (as opposed to +% writing directly to the terminal or log). +% +% The system used by \pkg{l3msg} to create messages divides the process +% into two distinct parts. Named messages are created in the first part +% of the process; at this stage, no decision is made about the type +% output that the message will produce. The second part of the process +% is actually producing a message. At this stage a choice of message +% \emph{class} has to be made, for example \texttt{error}, +% \texttt{warning} or \texttt{info}. +% +% By separating out the creation and use of messages, several benefits +% are available. First, the messages can be altered later without +% needing details of where they are used in the code. This makes it +% possible to alter the language used, the detail level and so on. +% Secondly, the output which results from a given message can be +% altered. This can be done on a message class, module or message name +% basis. In this way, message behaviour can be altered and messages can +% be entirely suppressed. +% +% \section{Creating new messages} +% +% All messages have to be created before they can be used. All message +% setting is local, with the general assumption that messages will +% be managed as part of module set up outside of any \TeX{} grouping. +% +% The text of messages will automatically by wrapped to the length +% available in the console. As a result, formatting is only needed +% where it will help to show meaning. In particular, |\\| may be +% used to force a new line and \verb*|\ | forces an explicit space. +% +% \begin{function}{\msg_new:nnnn, \msg_new:nnn} +% \begin{syntax} +% \cs{msg_new:nnnn} \Arg{module} \Arg{message} \Arg{text} +% ~~\Arg{more text} +% \end{syntax} +% Creates a \meta{message} for a given \meta{module}. +% The message will be defined to first give \meta{text} and then +% \meta{more text} if the user requests it. If no \meta{more text} is +% available then a standard text is given instead. Within \meta{text} +% and \meta{more text} four parameters (|#1| to |#4|) can be used: +% these will be supplied at the time the message is used. The +% parameters will be expanded when the message is used. Within the +% \meta{text} and \meta{more text} |\\| can be used to start a new +% line. An error will be raised if the \meta{message} already exists. +% \end{function} +% +% \begin{function}{\msg_set:nnnn, \msg_set:nnn} +% \begin{syntax} +% \cs{msg_set:nnnn} \Arg{module} \Arg{message} \Arg{text} +% ~~\Arg{more text} +% \end{syntax} +% Sets up the text for a \meta{message} for a given \meta{module}. +% The message will be defined to first give \meta{text} and then +% \meta{more text} if the user requests it. If no \meta{more text} is +% available then a standard text is given instead. Within \meta{text} +% and \meta{more text} four parameters (|#1| to |#4|) can be used: +% these will be supplied at the time the message is used. The +% parameters will be expanded when the message is used. Within the +% \meta{text} and \meta{more text} |\\| can be used to start a new +% line. +% \end{function} +% +% \section{Contextual information for messages} +% +% \begin{function}[EXP]{\msg_line_context:} +% \begin{syntax} +% \cs{msg_line_context:} +% \end{syntax} +% Prints the current line number when a message is given, and +% thus suitable for giving context to messages. The number itself +% is proceeded by the text |on line|. +% \end{function} +% +% \begin{function}[EXP]{\msg_line_number:} +% \begin{syntax} +% \cs{msg_line_number:} +% \end{syntax} +% Prints the current line number when a message is given. +% \end{function} +% +% \begin{variable}{\c_msg_return_text_tl} +% Standard text to indicate that the user should try pressing +% \meta{return} to continue. The standard definition reads: +% \begin{verbatim} +% Try typing <return> to proceed. +% +% If that doesn't work, type X <return> to quit. +% \end{verbatim} +% \end{variable} +% +% \begin{variable}{\c_msg_trouble_text_tl} +% Standard text to indicate that the more errors are likely and +% that aborting the run is advised. The standard definition reads: +% \begin{verbatim} +% More errors will almost certainly follow: +% the LaTeX run should be aborted. +% \end{verbatim} +% \end{variable} +% +% \begin{function}[EXP]{\msg_fatal_text:n} +% \begin{syntax} +% \cs{msg_fatal_text:n} \Arg{module} +% \end{syntax} +% Produces the standard text: +% \begin{verbatim} +% Fatal <module> error +% \end{verbatim} +% This function can be redefined to alter the language in which the +% message is give, using |#1| as the name of the \meta{module} to +% be included. +% \end{function} +% +% \begin{function}[EXP]{\msg_critical_text:n} +% \begin{syntax} +% \cs{msg_critical_text:n} \Arg{module} +% \end{syntax} +% Produces the standard text: +% \begin{verbatim} +% Critical <module> error +% \end{verbatim} +% This function can be redefined to alter the language in which the +% message is give, using |#1| as the name of the \meta{module} to +% be included. +% \end{function} +% +% \begin{function}[EXP]{\msg_error_text:n} +% \begin{syntax} +% \cs{msg_error_text:n} \Arg{module} +% \end{syntax} +% Produces the standard text: +% \begin{verbatim} +% <module> error +% \end{verbatim} +% This function can be redefined to alter the language in which the +% message is give, using |#1| as the name of the \meta{module} to +% be included. +% \end{function} +% +% \begin{function}[EXP]{\msg_warning_text:n} +% \begin{syntax} +% \cs{msg_warning_text:n} \Arg{module} +% \end{syntax} +% Produces the standard text: +% \begin{verbatim} +% <module> warning +% \end{verbatim} +% This function can be redefined to alter the language in which the +% message is give, using |#1| as the name of the \meta{module} to +% be included. +% \end{function} +% +% \begin{function}[EXP]{\msg_info_text:n} +% \begin{syntax} +% \cs{msg_info_text:n} \Arg{module} +% \end{syntax} +% Produces the standard text: +% \begin{verbatim} +% <module> info +% \end{verbatim} +% This function can be redefined to alter the language in which the +% message is give, using |#1| as the name of the \meta{module} to +% be included. +% \end{function} +% +% \section{Issuing messages} +% +% Messages behave differently depending on the message class. A number +% of standard message classes are supplied, but more can be +% created. +% +% When issuing messages, any arguments passed should use +% \cs{tl_to_str:n} or \cs{token_to_str:N} to prevent unwanted expansion +% of the material. +% +% \begin{function}{\msg_class_set:nn} +% \begin{syntax} +% \cs{msg_class_set:nn} \Arg{class} \Arg{code} +% \end{syntax} +% Sets a \meta{class} to output a message, using \meta{code} +% to process the message text. The \meta{class} should be a text +% value, while the \meta{code} may be any arbitrary material. +% The \meta{code} will receive $6$ arguments: the module +% name (|#1|), the message name (|#2|) and the four arguments +% taken by the message text (|#3| to |#6|). +% \end{function} +% +% The kernel defines several common message classes. The following +% describes the standard behaviour of each class if no redirection of +% the class or message is active. In all cases, the message may be +% issued supplying $0$ to $4$ arguments. The code will +% ensure that there an no errors if the number of arguments supplied +% here does not match the number in the definition of the message +% (although of course the sense of the message may be impaired). +% +% \begin{function} +% { +% \msg_fatal:nnxxxx , +% \msg_fatal:nnxxx , +% \msg_fatal:nnxx , +% \msg_fatal:nnx , +% \msg_fatal:nn +% } +% \begin{syntax} +% \cs{msg_fatal:nnxxxx} \Arg{module} \Arg{message} \Arg{arg one} +% ~~\Arg{arg two} \Arg{arg three} \Arg{arg four} +% \end{syntax} +% Issues \meta{module} error \meta{message}, passing \meta{arg one} to +% \meta{arg four} to the text-creating functions. After issuing a +% fatal error the \TeX{} run will halt. +% \end{function} +% +% \begin{function} +% { +% \msg_critical:nnxxxx , +% \msg_critical:nnxxx , +% \msg_critical:nnxx , +% \msg_critical:nnx , +% \msg_critical:nn +% } +% \begin{syntax} +% \cs{msg_critical:nnxxxx} \Arg{module} \Arg{message} \Arg{arg one} +% ~~\Arg{arg two} \Arg{arg three} \Arg{arg four} +% \end{syntax} +% Issues \meta{module} error \meta{message}, passing \meta{arg one} to +% \meta{arg four} to the text-creating functions. After issuing the +% message reading the current input file will stop. This may halt +% the \TeX{} run (if the current file is the main file) or +% may abort reading a sub-file. +% \end{function} +% +% \begin{function} +% { +% \msg_error:nnxxxx , +% \msg_error:nnxxx , +% \msg_error:nnxx , +% \msg_error:nnx , +% \msg_error:nn +% } +% \begin{syntax} +% \cs{msg_error:nnxxxx} \Arg{module} \Arg{message} \Arg{arg one} +% ~~\Arg{arg two} \Arg{arg three} \Arg{arg four} +% \end{syntax} +% Issues \meta{module} error \meta{message}, passing \meta{arg one} to +% \meta{arg four} to the text-creating functions. The error will +% stop processing and issue the text at the terminal. After user input, +% the run will continue. +% \end{function} +% +% \begin{function} +% { +% \msg_warning:nnxxxx , +% \msg_warning:nnxxx , +% \msg_warning:nnxx , +% \msg_warning:nnx , +% \msg_warning:nn +% } +% \begin{syntax} +% \cs{msg_warning:nnxxxx} \Arg{module} \Arg{message} \Arg{arg one} +% ~~\Arg{arg two} \Arg{arg three} \Arg{arg four} +% \end{syntax} +% Issues \meta{module} warning \meta{message}, passing \meta{arg one} to +% \meta{arg four} to the text-creating functions. The warning text +% will be added to the log file, but the \TeX{} run will not be +% interrupted. +% \end{function} +% +% \begin{function} +% { +% \msg_info:nnxxxx , +% \msg_info:nnxxx , +% \msg_info:nnxx , +% \msg_info:nnx , +% \msg_info:nn +% } +% \begin{syntax} +% \cs{msg_info:nnxxxx} \Arg{module} \Arg{message} \Arg{arg one} +% ~~\Arg{arg two} \Arg{arg three} \Arg{arg four} +% \end{syntax} +% Issues \meta{module} information \meta{message}, passing +% \meta{arg one} to \meta{arg four} to the text-creating functions. +% The information text will be added to the log file. +% \end{function} +% +% \begin{function} +% { +% \msg_log:nnxxxx , +% \msg_log:nnxxx , +% \msg_log:nnxx , +% \msg_log:nnx , +% \msg_log:nn +% } +% \begin{syntax} +% \cs{msg_log:nnxxxx} \Arg{module} \Arg{message} \Arg{arg one} +% ~~\Arg{arg two} \Arg{arg three} \Arg{arg four} +% \end{syntax} +% Issues \meta{module} information \meta{message}, passing +% \meta{arg one} to \meta{arg four} to the text-creating functions. +% The information text will be added to the log file: the output +% is briefer than \cs{msg_info:nnxxxx}. +% \end{function} +% +% \begin{function} +% { +% \msg_none:nnxxxx , +% \msg_none:nnxxx , +% \msg_none:nnxx , +% \msg_none:nnx , +% \msg_none:nn +% } +% \begin{syntax} +% \cs{msg_none:nnxxxx} \Arg{module} \Arg{message} \Arg{arg one} +% ~~\Arg{arg two} \Arg{arg three} \Arg{arg four} +% \end{syntax} +% Does nothing: used as a message class to prevent any output at +% all (see the discussion of message redirection). +% \end{function} +% +% \section{Redirecting messages} +% +% \begin{function}{\msg_redirect_class:nn} +% \begin{syntax} +% \cs{msg_redirect_class:nn} \Arg{class one} \Arg{class two} +% \end{syntax} +% Changes the behaviour of messages of \meta{class one} so that they +% are processed using the code for those of \meta{class two}. Multiple +% redirections are possible. Redirection to a missing class or +% infinite loops will raise errors when the messages are used, +% rather than at the point of redirection. +% \end{function} +% +% \begin{function}{\msg_redirect_module:nnn} +% \begin{syntax} +% \cs{msg_redirect_module:nnn} \Arg{module} \Arg{class one} +% ~~\Arg{class two} +% \end{syntax} +% Redirects message of \meta{class one} for \meta{module} to act as +% though they were from \meta{class two}. Messages of \meta{class one} +% from sources other than \meta{module} are not affected by this +% redirection. This function can be used to make some messages +% \enquote{silent} by default. For example, all of the +% \texttt{trace} messages of \meta{module} could be turned off with: +% \begin{verbatim} +% \msg_redirect_module:nnn { module } { trace } { none } +% \end{verbatim} +% \end{function} +% +% \begin{function}{\msg_redirect_name:nnn} +% \begin{syntax} +% \cs{msg_redirect_name:nn} \Arg{module} \Arg{message} \Arg{class} +% \end{syntax} +% Redirects a specific \meta{message} from a specific \meta{module} +% to act as a member of \meta{class} of messages. This function can +% be used to make a selected message \enquote{silent} without +% changing global parameters: +% \begin{verbatim} +% \msg_redirect_name:nnn { module } { annoying-message } { none } +% \end{verbatim} +% \end{function} +% +% \section{Low-level message functions} +% +% The lower-level message functions should usually be accessed from the +% higher-level system. However, there are occasions where direct +% access to these functions is desirable. +% +% \begin{function}[EXP]{\msg_newline:, \msg_two_newlines:} +% \begin{syntax} +% \cs{msg_newline:} +% \end{syntax} +% Forces a new line in a message. This is a low-level function, which +% will not include any additional printing information in the message: +% contrast with |\\| in messages. The |two| version adds two lines. +% \end{function} +% +% \begin{function}{\msg_interrupt:xxx} +% \begin{syntax} +% \cs{msg_interrupt:xxx} \Arg{first line} \Arg{text} \Arg{extra text} +% \end{syntax} +% Interrupts the \TeX{} run, issuing a formatted message comprising +% \meta{first line} and \meta{text} laid out in the format +% \begin{verbatim} +% !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +% ! +% ! <first line> +% ! +% ! <text> +% !............................................... +% \end{verbatim} +% where the \meta{text} will be wrapped to fit within the current +% line length. The user may then request more information, at which +% stage the \meta{extra text} will be shown in the terminal in the +% format +% \begin{verbatim} +% |''''''''''''''''''''''''''''''''''''''''''''''' +% | <extra text> +% |............................................... +% \end{verbatim} +% where the \meta{extra text} will be wrapped to fit within the current +% line length. +% \end{function} +% +% \begin{function}{\msg_log:x} +% \begin{syntax} +% \cs{msg_log:x} \Arg{text} +% \end{syntax} +% Writes to the log file with the \meta{text} laid out in the format +% \begin{verbatim} +% ................................................. +% . <text> +% ................................................. +% \end{verbatim} +% where the \meta{text} will be wrapped to fit within the current +% line length. +% \end{function} +% +% \begin{function}{\msg_term:x} +% \begin{syntax} +% \cs{msg_term:x} \Arg{text} +% \end{syntax} +% Writes to the terminal and log file with the \meta{text} laid out in the +% format +% \begin{verbatim} +% ************************************************* +% * <text> +% ************************************************* +% \end{verbatim} +% where the \meta{text} will be wrapped to fit within the current +% line length. +% \end{function} +% +% \section{Kernel-specific functions} +% +% Messages from \LaTeX3 itself are handled by the general message system, +% but have their own functions. This allows some text to be pre-defined, +% and also ensures that serious errors can be handled properly. +% +% \begin{function}{\msg_kernel_new:nnnn, \msg_kernel_new:nnn} +% \begin{syntax} +% \cs{msg_kernel_new:nnnn} \Arg{module} \Arg{message} \Arg{text} +% ~~\Arg{more text} +% \end{syntax} +% Creates a kernel \meta{message} for a given \meta{module}. +% The message will be defined to first give \meta{text} and then +% \meta{more text} if the user requests it. If no \meta{more text} is +% available then a standard text is given instead. Within \meta{text} +% and \meta{more text} four parameters (|#1| to |#4|) can be used: +% these will be supplied at the time the message is used. The +% parameters will be expanded when the message is used. Within the +% \meta{text} and \meta{more text} |\\| can be used to start a new +% line. An error will be raised if the \meta{message} already exists. +% \end{function} +% +% \begin{function}{\msg_kernel_set:nnnn, \msg_kernel_set:nnn} +% \begin{syntax} +% \cs{msg_kernel_set:nnnn} \Arg{module} \Arg{message} \Arg{text} +% ~~\Arg{more text} +% \end{syntax} +% Sets up the text for a kernel \meta{message} for a given \meta{module}. +% The message will be defined to first give \meta{text} and then +% \meta{more text} if the user requests it. If no \meta{more text} is +% available then a standard text is given instead. Within \meta{text} +% and \meta{more text} four parameters (|#1| to |#4|) can be used: +% these will be supplied at the time the message is used. The +% parameters will be expanded when the message is used. Within the +% \meta{text} and \meta{more text} |\\| can be used to start a new +% line. +% \end{function} +% +% \begin{function} +% { +% \msg_kernel_fatal:nnxxxx , +% \msg_kernel_fatal:nnxxx , +% \msg_kernel_fatal:nnxx , +% \msg_kernel_fatal:nnx , +% \msg_kernel_fatal:nn +% } +% \begin{syntax} +% \cs{msg_kernel_fatal:nnxxxx} \Arg{module} \Arg{message} \Arg{arg one} +% ~~\Arg{arg two} \Arg{arg three} \Arg{arg four} +% \end{syntax} +% Issues kernel \meta{module} error \meta{message}, passing \meta{arg one} +% to \meta{arg four} to the text-creating functions. After issuing a +% fatal error the \TeX{} run will halt. Cannot be redirected. +% \end{function} +% +% \begin{function} +% { +% \msg_kernel_error:nnxxxx , +% \msg_kernel_error:nnxxx , +% \msg_kernel_error:nnxx , +% \msg_kernel_error:nnx , +% \msg_kernel_error:nn +% } +% \begin{syntax} +% \cs{msg_kernel_error:nnxxxx} \Arg{module} \Arg{message} \Arg{arg one} +% ~~\Arg{arg two} \Arg{arg three} \Arg{arg four} +% \end{syntax} +% Issues kernel \meta{module} error \meta{message}, passing \meta{arg one} +% to +% \meta{arg four} to the text-creating functions. The error will +% stop processing and issue the text at the terminal. After user input, +% the run will continue. Cannot be redirected. +% \end{function} +% +% \begin{function} +% { +% \msg_kernel_warning:nnxxxx , +% \msg_kernel_warning:nnxxx , +% \msg_kernel_warning:nnxx , +% \msg_kernel_warning:nnx , +% \msg_kernel_warning:nn +% } +% \begin{syntax} +% \cs{msg_kernel_warning:nnxxxx} \Arg{module} \Arg{message} \Arg{arg one} +% ~~\Arg{arg two} \Arg{arg three} \Arg{arg four} +% \end{syntax} +% Issues kernel \meta{module} warning \meta{message}, passing +% \meta{arg one} to +% \meta{arg four} to the text-creating functions. The warning text +% will be added to the log file, but the \TeX{} run will not be +% interrupted. +% \end{function} +% +% \begin{function} +% { +% \msg_kernel_info:nnxxxx , +% \msg_kernel_info:nnxxx , +% \msg_kernel_info:nnxx , +% \msg_kernel_info:nnx , +% \msg_kernel_info:nn +% } +% \begin{syntax} +% \cs{msg_kernel_info:nnxxxx} \Arg{module} \Arg{message} \Arg{arg one} +% ~~\Arg{arg two} \Arg{arg three} \Arg{arg four} +% \end{syntax} +% Issues kernel \meta{module} information \meta{message}, passing +% \meta{arg one} to \meta{arg four} to the text-creating functions. +% The information text will be added to the log file. +% \end{function} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{l3msg} implementation} +% +% \begin{macrocode} +%<*initex|package> +% \end{macrocode} +% +% \begin{macrocode} +%<*package> +\ProvidesExplPackage + {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +\package_check_loaded_expl: +%</package> +% \end{macrocode} +% +% \begin{variable}{\l_msg_tmp_tl} +% A general scratch for the module. +% \begin{macrocode} +\tl_new:N \l_msg_tmp_tl +% \end{macrocode} +% \end{variable} +% +%\section{Creating messages} +% +% Messages are created and used separately, so there two parts to +% the code here. First, a mechanism for creating message text. +% This is pretty simple, as there is not actually a lot to do. +% +%\begin{variable}{\c_msg_text_prefix_tl, \c_msg_more_text_prefix_tl} +% Locations for the text of messages. +% \begin{macrocode} +\tl_const:Nn \c_msg_text_prefix_tl { msg~text~>~ } +\tl_const:Nn \c_msg_more_text_prefix_tl { msg~extra~text~>~ } +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\msg_new:nnnn, \msg_new:nnn} +% \begin{macro}{\msg_set:nnnn, \msg_set:nnn} +% Setting a message simply means saving the appropriate text +% into two functions. A sanity check first. +% \begin{macrocode} +\cs_new_protected:Npn \msg_new:nnnn #1#2 + { + \cs_if_exist:cT { \c_msg_text_prefix_tl #1 / #2 } + { + \msg_kernel_error:nn { msg } { message-already-defined } + {#1} {#2} + } + \msg_set:nnnn {#1} {#2} + } +\cs_new_protected:Npn \msg_new:nnn #1#2#3 + { \msg_new:nnnn {#1} {#2} {#3} { } } +\cs_new_protected:Npn \msg_set:nnnn #1#2#3#4 + { + \cs_set:cpn { \c_msg_text_prefix_tl #1 / #2 } + ##1##2##3##4 {#3} + \cs_set:cpn { \c_msg_more_text_prefix_tl #1 / #2 } + ##1##2##3##4 {#4} + } +\cs_new_protected:Npn \msg_set:nnn #1#2#3 + { \msg_set:nnnn {#1} {#2} {#3} { } } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Messages: support functions and text} +% +% \begin{variable} +% { +% \c_msg_coding_error_text_tl , +% \c_msg_continue_text_tl , +% \c_msg_critical_text_tl , +% \c_msg_fatal_text_tl , +% \c_msg_help_text_tl , +% \c_msg_no_info_text_tl , +% \c_msg_on_line_tl , +% \c_msg_return_text_tl , +% \c_msg_trouble_text_tl +% } +% Simple pieces of text for messages. +% \begin{macrocode} +\tl_const:Nn \c_msg_coding_error_text_tl + { + This~is~a~coding~error. + \\ \\ + } +\tl_const:Nn \c_msg_continue_text_tl + { Type~<return>~to~continue } +\tl_const:Nn \c_msg_critical_text_tl + { Reading~the~current~file~will~stop } +\tl_const:Nn \c_msg_fatal_text_tl + { This~is~a~fatal~error:~LaTeX~will~abort } +\tl_const:Nn \c_msg_help_text_tl + { For~immediate~help~type~H~<return> } +\tl_const:Nn \c_msg_no_info_text_tl + { + LaTeX~does~not~know~anything~more~about~this~error,~sorry. + \c_msg_return_text_tl + } +\tl_const:Nn \c_msg_on_line_text_tl { on~line } +\tl_const:Nn \c_msg_return_text_tl + { + \\ \\ + Try~typing~<return>~to~proceed. + \\ + If~that~doesn't~work,~type~X~<return>~to~quit. + } +\tl_const:Nn \c_msg_trouble_text_tl + { + \\ \\ + More~errors~will~almost~certainly~follow: \\ + the~LaTeX~run~should~be~aborted. + } +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\msg_newline:, \msg_two_newlines:} +% New lines are printed in the same way as for low-level file writing. +% \begin{macrocode} +\cs_new_nopar:Npn \msg_newline: { ^^J } +\cs_new_nopar:Npn \msg_two_newlines: { ^^J ^^J } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\msg_line_number:} +% \begin{macro}{\msg_line_context:} +% For writing the line number nicely. +% \begin{macrocode} +\cs_new_nopar:Npn \msg_line_number: { \int_use:N \tex_inputlineno:D } +\cs_set_nopar:Npn \msg_line_context: + { + \c_msg_on_line_text_tl + \c_space_tl + \msg_line_number: + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Showing messages: low level mechanism} +% +% \begin{variable}{\c_msg_hide_tl} +% \begin{variable}[aux]{\c_msg_hide_tl<dots>} +% An empty variable with a number of (category code 11) periods at the +% end of its name. This is used to push the \TeX{} part of an error +% message \enquote{off the screen}. Using two variables here means that +% later life is a little easier. +% \begin{macrocode} +\char_set_catcode_letter:N \. +\tl_new:N + \c_msg_hide_tl.......................................................... +\tl_const:Nn \c_msg_hide_tl + { \c_msg_hide_tl.......................................................... } +\char_set_catcode_other:N \. +% \end{macrocode} +% \end{variable} +% \end{variable} +% +% \begin{macro}{\msg_interrupt:xxx} +% \begin{macro}[aux]{\msg_interrupt_no_details:xx} +% \begin{macro}[aux]{\msg_interrupt_details:xxx} +% \begin{macro}[aux]{\msg_interrupt_text:n} +% \begin{macro}[aux]{\msg_interrupt_more_text:n} +% \begin{macro}[aux]{\msg_interrupt_aux:} +% The low-level interruption macro is rather opaque, unfortunately. The +% idea here is to create a a message which hides all of \TeX{}'s own +% information by filling the output up with dots. To achieve this, +% dots have to be letters. The odd +% \cs{c_msg_hide_tl<dots>} actually does the hiding: it is the +% large run of dots in the name that is important here. The meaning +% of |\\| is altered so that the explanation text is a simple run +% whilst the initial error has line-continuation shown. +% \begin{macrocode} +\cs_new_protected:Npn \msg_interrupt:xxx #1#2#3 + { + \group_begin: + \tl_if_empty:nTF {#3} + { \msg_interrupt_no_details:xx {#1} {#2} } + { \msg_interrupt_details:xxx {#1} {#2} {#3} } + \msg_interrupt_aux: + \group_end: + } +% \end{macrocode} +% \begin{macrocode} +% Depending on the availability of more information there is a choice of +% how to set up the further help. The extra help text has to be set +% before the message itself can be issued. Everything is done using +% \texttt{x}-type expansion as the new line markers are different for +% the two type of text and need to be correctly set up. +% \begin{macrocode} +\cs_new_protected:Npn \msg_interrupt_no_details:xx #1#2 + { + \iow_wrap:xnnnN + { \\ \c_msg_no_info_text_tl } + { |~ } { 2 } { } \msg_interrupt_more_text:n + \iow_wrap:xnnnN { #1 \\ \\ #2 \\ \\ \c_msg_continue_text_tl } + { ! ~ } { 2 } {} \msg_interrupt_text:n + } +\cs_new_protected:Npn \msg_interrupt_details:xxx #1#2#3 + { + \iow_wrap:xnnnN + { \\ #3 } + { |~ } { 2 } { } \msg_interrupt_more_text:n + \iow_wrap:xnnnN { #1 \\ \\ #2 \\ \\ \c_msg_help_text_tl } + { ! ~ } { 2 } { } \msg_interrupt_text:n + } +\cs_new_protected:Npn \msg_interrupt_text:n #1 + { \tl_set:Nn \l_msg_text_tl {#1} } +\cs_new_protected:Npn \msg_interrupt_more_text:n #1 + { +%<*initex> + \tl_set:Nx \l_msg_tmp_tl +%</initex> +%<*package> + \protected@edef \l_msg_tmp_tl +%</package> + { + |''''''''''''''''''''''''''''''''''''''''''''''' + #1 + \msg_newline: + |............................................... + } + \tex_errhelp:D \exp_after:wN { \l_msg_tmp_tl } + } +% \end{macrocode} +% The business end of the process starts by producing some visual +% separation of the message from the main part of the log. It then +% adds the hiding text to the message to print. The error message needs +% to be printed with everything made \enquote{invisible}: this is where +% the strange business with |&| comes in: this is made into another +% |!|. There is also a closing brace that will show up in the output, +% which is turned into a blank space. +% \begin{macrocode} +\group_begin: % { + \char_set_lccode:w `\} = `\ \scan_stop: + \char_set_lccode:w `\& = `\! \scan_stop: + \char_set_catcode_active:N \& +\tl_to_lowercase:n + { + \group_end: + \cs_new_protected:Npn \msg_interrupt_aux: + { + \iow_term:x + { + \iow_newline: + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + \iow_newline: + ! + } + \tl_put_right:No \l_msg_text_tl { \c_msg_hide_tl } + \cs_set_protected_nopar:Npx & + { \tex_errmessage:D { \exp_not:o { \l_msg_text_tl } } } + & + } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\msg_log:x} +% \begin{macro}{\msg_term:x} +% Printing to the log or terminal without a stop is rather easier. +% A bit of simple visual work sets things off nicely. +% \begin{macrocode} +\cs_new_protected:Npn \msg_log:x #1 + { + \iow_log:x { ................................................. } + \iow_wrap:xnnnN { . ~ #1} { . ~ } { 2 } { } + \iow_log:x + \iow_log:x { ................................................. } + } +\cs_new_protected:Npn \msg_term:x #1 + { + \iow_term:x { ************************************************* } + \iow_wrap:xnnnN { * ~ #1} { * ~ } { 2 } { } + \iow_term:x + \iow_term:x { ************************************************* } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \subsection{Displaying messages} +% +% \LaTeX{} is handling error messages and so the \TeX{} ones are disabled. +% \begin{macrocode} +\int_set:Nn \tex_errorcontextlines:D { -1 } +% \end{macrocode} +% +% \begin{macro} +% { +% \msg_fatal_text:n , +% \msg_critical_text:n , +% \msg_error_text:n , +% \msg_warning_text:n , +% \msg_info_text:n +% } +% A function for issuing messages: both the text and order could +% in principal vary. +% \begin{macrocode} +\cs_new_nopar:Npn \msg_fatal_text:n #1 { Fatal~#1~error } +\cs_new_nopar:Npn \msg_critical_text:n #1 { Critical~#1~error } +\cs_new_nopar:Npn \msg_error_text:n #1 { #1~error } +\cs_new_nopar:Npn \msg_warning_text:n #1 { #1~warning } +\cs_new_nopar:Npn \msg_info_text:n #1 { #1~info } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\msg_see_documentation_text:n} +% Contextual footer information. +% \begin{macrocode} +\cs_new_nopar:Npn \msg_see_documentation_text:n #1 + { \\ \\ See~the~#1~documentation~for~further~information. } +% \end{macrocode} +% \end{macro} +% +% \begin{variable}{\l_msg_redirect_classes_prop, \l_msg_redirect_names_prop} +% For filtering messages, a list of all messages and of those which have +% to be modified is required. +% \begin{macrocode} +\prop_new:N \l_msg_redirect_classes_prop +\prop_new:N \l_msg_redirect_names_prop +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\msg_class_set:nn} +% Setting up a message class does two tasks. Any existing redirection +% is cleared, and the various message functions are created +% to simply use the code stored for the message. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \msg_class_set:nn #1#2 + { + \prop_clear_new:c { l_msg_redirect_ #1 _prop } + \cs_set_protected:cpn { msg_ #1 :nnxxxx } ##1##2##3##4##5##6 + { \msg_use:nnnnxxxx {#1} {#2} {##1} {##2} {##3} {##4} {##5} {##6} } + \cs_set_protected:cpx { msg_ #1 :nnxxx } ##1##2##3##4##5 + { \exp_not:c { msg_ #1 :nnxxxx } {##1} {##2} {##3} {##4} {##5} { } } + \cs_set_protected:cpx { msg_ #1 :nnxx } ##1##2##3##4 + { \exp_not:c { msg_ #1 :nnxxxx } {##1} {##2} {##3} {##4} { } { } } + \cs_set_protected:cpx { msg_ #1 :nnx } ##1##2##3 + { \exp_not:c { msg_ #1 :nnxxxx } {##1} {##2} {##3} { } { } { } } + \cs_set_protected:cpx { msg_ #1 :nn } ##1##2 + { \exp_not:c { msg_ #1 :nnxxxx } {##1} {##2} { } { } { } { } } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[pTF]{\msg_if_more_text:N, \msg_if_more_text:c} +% \begin{macro}[aux]{\msg_no_more_text:xxxx} +% A test to see if any more text is available, using a +% permanently-empty text function. +% \begin{macrocode} +\prg_set_conditional:Npnn \msg_if_more_text:N #1 { p , T , F , TF } + { + \cs_if_eq:NNTF #1 \msg_no_more_text:xxxx + { \prg_return_false: } + { \prg_return_true: } + } +\cs_new:Npn \msg_no_more_text:xxxx #1#2#3#4 { } +\cs_generate_variant:Nn \msg_if_more_text_p:N { c } +\cs_generate_variant:Nn \msg_if_more_text:NT { c } +\cs_generate_variant:Nn \msg_if_more_text:NF { c } +\cs_generate_variant:Nn \msg_if_more_text:NTF { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +%\begin{macro} +% { +% \msg_fatal:nnxxxx , +% \msg_fatal:nnxxx , +% \msg_fatal:nnxx , +% \msg_fatal:nnx , +% \msg_fatal:nn +% } +% For fatal errors, after the error message \TeX{} bails out. +% \begin{macrocode} +\msg_class_set:nn { fatal } + { + \msg_interrupt:xxx + { \msg_fatal_text:n {#1} : ~ "#2" } + { + \use:c { \c_msg_text_prefix_tl #1 / #2 } {#3} {#4} {#5} {#6} + \msg_see_documentation_text:n {#1} + } + { \c_msg_fatal_text_tl } + \tex_end:D + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro} +% { +% \msg_critical:nnxxxx , +% \msg_critical:nnxxx , +% \msg_critical:nnxx , +% \msg_critical:nnx , +% \msg_critical:nn +% } +% Not quite so bad: just end the current file. +% \begin{macrocode} +\msg_class_set:nn { critical } + { + \msg_interrupt:xxx + { \msg_critical_text:n {#1} : ~ "#2" } + { + \use:c { \c_msg_text_prefix_tl #1 / #2 } {#3} {#4} {#5} {#6} + \msg_see_documentation_text:n {#1} + } + { \c_msg_critical_text_tl } + \tex_endinput:D + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro} +% { +% \msg_error:nnxxxx , +% \msg_error:nnxxx , +% \msg_error:nnxx , +% \msg_error:nnx , +% \msg_error:nn +% } +% For an error, the interrupt routine is called, then any recovery code +% is tried. +% \begin{macrocode} +\msg_class_set:nn { error } + { + \msg_if_more_text:cTF { \c_msg_more_text_prefix_tl #1 / #2 } + { + \msg_interrupt:xxx + { \msg_error_text:n {#1} : ~ "#2" } + { + \use:c { \c_msg_text_prefix_tl #1 / #2 } {#3} {#4} {#5} {#6} + \msg_see_documentation_text:n {#1} + } + { \use:c { \c_msg_more_text_prefix_tl #1 / #2 } {#3} {#4} {#5} {#6} } + } + { + \msg_interrupt:xxx + { \msg_error_text:n {#1} : ~ "#2" } + { + \use:c { \c_msg_text_prefix_tl #1 / #2 } {#3} {#4} {#5} {#6} + \msg_see_documentation_text:n {#1} + } + { } + } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro} +% { +% \msg_warning:nnxxxx , +% \msg_warning:nnxxx , +% \msg_warning:nnxx , +% \msg_warning:nnx , +% \msg_warning:nn +% } +% Warnings are printed to the terminal. +% \begin{macrocode} +\msg_class_set:nn { warning } + { + \msg_term:x + { + \msg_warning_text:n {#1} : ~ "#2" \\ \\ + \use:c { \c_msg_text_prefix_tl #1 / #2 } {#3} {#4} {#5} {#6} + } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro} +% { +% \msg_info:nnxxxx , +% \msg_info:nnxxx , +% \msg_info:nnxx , +% \msg_info:nnx , +% \msg_info:nn +% } +% Information only goes into the log. +% \begin{macrocode} +\msg_class_set:nn { info } + { + \msg_log:x + { + \msg_info_text:n {#1} : ~ "#2" \\ \\ + \use:c { \c_msg_text_prefix_tl #1 / #2 } {#3} {#4} {#5} {#6} + } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro} +% { +% \msg_log:nnxxxx , +% \msg_log:nnxxx , +% \msg_log:nnxx , +% \msg_log:nnx , +% \msg_log:nn +% } +% \enquote{Log} data is very similar to information, but with no extras +% added. +% \begin{macrocode} +\msg_class_set:nn { log } + { + \msg_log:x + { \use:c { \c_msg_text_prefix_tl #1 / #2 } {#3} {#4} {#5} {#6} } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro} +% { +% \msg_none:nnxxxx , +% \msg_none:nnxxx , +% \msg_none:nnxx , +% \msg_none:nnx , +% \msg_none:nn +% } +% The \texttt{none} message type is needed so that input can be gobbled. +% \begin{macrocode} +\msg_class_set:nn { none } { } +% \end{macrocode} +% \end{macro} +% +% \begin{variable} +% { +% \l_msg_redirect_classes_seq , +% \l_msg_class_tl , +% \l_msg_current_class_tl , +% \l_msg_current_module_tl +% } +% Support variables needed for the redirection system. +% \begin{macrocode} +\seq_new:N \l_msg_redirect_classes_seq +\tl_new:N \l_msg_class_tl +\tl_new:N \l_msg_current_class_tl +\tl_new:N \l_msg_current_module_tl +% \end{macrocode} +%\end{variable} +% +% \begin{macro}[int]{\msg_use:nnnnxxxx} +% \begin{macro}[aux]{\msg_use_aux:nnn} +% \begin{macro}[aux]{\msg_use_aux:nn} +% \begin{macro}[aux]{\msg_use_loop_check:nn} +% \begin{macro}[aux]{\msg_use_code:} +% \begin{macro}[aux]{\msg_use_loop:n, \msg_use_loop:o} +% The main message-using macro creates two auxiliary functions: one +% containing the code for the message, and the second a loop function. +% There is then a hand-off to the system for checking if redirection is +% needed. +% \begin{macrocode} +\cs_new_protected:Npn \msg_use:nnnnxxxx #1#2#3#4#5#6#7#8 + { + \cs_set_protected_nopar:Npx \msg_use_code: + { + \seq_clear:N \exp_not:N \l_msg_redirect_classes_seq + \exp_not:n {#2} + } + \cs_set_protected:Npx \msg_use_loop:n ##1 + { + \seq_if_in:NnTF \exp_not:n \l_msg_redirect_classes_seq {#1} + { \msg_kernel_error:nn { msg } { message-loop } {#1} } + { + \seq_put_right:Nn \exp_not:N \l_msg_redirect_classes_seq {#1} + \exp_not:N \cs_if_exist:cTF { msg_ ##1 :nnxxxx } + { + \exp_not:N \use:c { msg_ ##1 :nnxxxx } + \exp_not:n { {#3} {#4} {#5} {#6} {#7} {#8} } + } + { + \msg_kernel_error:nnx { msg } { message-class-unknown } {##1} + } + } + } + \cs_if_exist:cTF { \c_msg_text_prefix_tl #3 / #4 } + { \msg_use_aux:nnn {#1} {#3} {#4} } + { \msg_kernel_error:nnxx { msg } { message-unknown } {#3} {#4} } + } +% \end{macrocode} +% The first auxiliary macro looks for a match by name: the most +% restrictive check. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \msg_use_aux:nnn #1#2#3 + { + \tl_set:Nn \l_msg_current_class_tl {#1} + \tl_set:Nn \l_msg_current_module_tl {#2} + \prop_if_in:NnTF \l_msg_redirect_names_prop { // #2 / #3 / } + { \msg_use_loop_check:nn { names } { // #2 / #3 / } } + { \msg_use_aux:nn {#1} {#2} } + } +% \end{macrocode} +% The second function checks for general matches by module or for +% all modules. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \msg_use_aux:nn #1#2 + { + \prop_if_in:cnTF { l_msg_redirect_ #1 _prop } {#2} + { \msg_use_loop_check:nn {#1} {#2} } + { + \prop_if_in:cnTF { l_msg_redirect_ #1 _prop } { * } + { \msg_use_loop_check:nn {#1} { * } } + { \msg_use_code: } + } + } +% \end{macrocode} +% When checking whether to loop, the same code is needed in a few +% places. +% \begin{macrocode} +\cs_new_protected:Npn \msg_use_loop_check:nn #1#2 + { + \prop_get:cnN { l_msg_redirect_ #1 _prop } {#2} \l_msg_class_tl + \tl_if_eq:NNTF \l_msg_current_class_tl \l_msg_class_tl + { + { \msg_use_code: } + { \msg_use_loop:o \l_msg_class_tl } + } + } +\cs_new_protected_nopar:Npn \msg_use_code: { } +\cs_new_protected:Npn \msg_use_loop:n #1 { } +\cs_generate_variant:Nn \msg_use_loop:n { o } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\msg_redirect_class:nn} +% Converts class one into class two. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \msg_redirect_class:nn #1#2 + { \prop_put:cnn { l_msg_redirect_ #1 _prop } { * } {#2} } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\msg_redirect_module:nnn} +% For when all messages of a class should be altered for a given module. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \msg_redirect_module:nnn #1#2#3 + { \prop_put:cnn { l_msg_redirect_ #2 _prop } {#1} {#3} } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\msg_redirect_name:nnn} +% Named message will always use the given class. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \msg_redirect_name:nnn #1#2#3 + { \prop_put:Nnn \l_msg_redirect_names_prop { // #1 / #2 / } {#3} } +% \end{macrocode} +%\end{macro} +% +% \subsection{Kernel-specific functions} +% +% \begin{macro}{\msg_kernel_new:nnnn} +% \begin{macro}{\msg_kernel_new:nnn} +% \begin{macro}{\msg_kernel_set:nnnn} +% \begin{macro}{\msg_kernel_set:nnn} +% The kernel needs some messages of its own. These are created using +% pre-built functions. Two functions are provided: one more general +% and one which only has the short text part. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \msg_kernel_new:nnnn #1#2 + { \msg_new:nnnn { LaTeX } { #1 / #2 } } +\cs_new_protected_nopar:Npn \msg_kernel_new:nnn #1#2 + { \msg_new:nnn { LaTeX } { #1 / #2 } } +\cs_new_protected_nopar:Npn \msg_kernel_set:nnnn #1#2 + { \msg_set:nnnn { LaTeX } { #1 / #2 } } +\cs_new_protected_nopar:Npn \msg_kernel_set:nnn #1#2 + { \msg_set:nnn { LaTeX } { #1 / #2 } } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\msg_kernel_fatal:nnxxxx} +% \begin{macro}{\msg_kernel_fatal:nnxxx} +% \begin{macro}{\msg_kernel_fatal:nnxx} +% \begin{macro}{\msg_kernel_fatal:nnx} +% \begin{macro}{\msg_kernel_fatal:nn} +% Fatal kernel errors cannot be re-defined. +% \begin{macrocode} +\cs_new_protected:Npn \msg_kernel_fatal:nnxxxx #1#2#3#4#5#6 + { + \msg_interrupt:xxx + { \msg_fatal_text:n { LaTeX } : ~ "#1 / #2" } + { + \use:c { \c_msg_text_prefix_tl LaTeX / #1 / #2 } + {#3} {#4} {#5} {#6} + \msg_see_documentation_text:n { LaTeX3 } + } + { \c_msg_fatal_text_tl } + \tex_end:D + } +\cs_new_protected:Npn \msg_kernel_fatal:nnxxx #1#2#3#4#5 + {\msg_kernel_fatal:nnxxxx {#1} {#2} {#3} {#4} {#5} { } } +\cs_new_protected:Npn \msg_kernel_fatal:nnxx #1#2#3#4 + { \msg_kernel_fatal:nnxxxx {#1} {#2} {#3} {#4} { } { } } +\cs_new_protected:Npn \msg_kernel_fatal:nnx #1#2#3 + { \msg_kernel_fatal:nnxxxx {#1} {#2} {#3} { } { } { } } +\cs_new_protected:Npn \msg_kernel_fatal:nn #1#2 + { \msg_kernel_fatal:nnxxxx {#1} {#2} { } { } { } { } } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\msg_kernel_error:nnxxxx} +% \begin{macro}{\msg_kernel_error:nnxxx} +% \begin{macro}{\msg_kernel_error:nnxx} +% \begin{macro}{\msg_kernel_error:nnx} +% \begin{macro}{\msg_kernel_error:nn} +% Neither can kernel errors. +% \begin{macrocode} +\cs_new_protected:Npn \msg_kernel_error:nnxxxx #1#2#3#4#5#6 + { + \msg_if_more_text:cTF { \c_msg_more_text_prefix_tl LaTeX / #1 / #2 } + { + \msg_interrupt:xxx + { \msg_error_text:n { LaTeX } : ~ " #1 / #2 " } + { + \use:c { \c_msg_text_prefix_tl LaTeX / #1 / #2 } + {#3} {#4} {#5} {#6} + \msg_see_documentation_text:n { LaTeX3 } + } + { + \use:c { \c_msg_more_text_prefix_tl LaTeX / #1 / #2 } + {#3} {#4} {#5} {#6} + } + } + { + \msg_interrupt:xxx + { \msg_error_text:n { LaTeX } : ~ " #1 / #2 " } + { + \use:c { \c_msg_text_prefix_tl LaTeX / #1 / #2 } + {#3} {#4} {#5} {#6} + \msg_see_documentation_text:n { LaTeX3 } + } + { } + } + } +\cs_new_protected:Npn \msg_kernel_error:nnxxx #1#2#3#4#5 + {\msg_kernel_error:nnxxxx {#1} {#2} {#3} {#4} {#5} { } } +\cs_set_protected:Npn \msg_kernel_error:nnxx #1#2#3#4 + { \msg_kernel_error:nnxxxx {#1} {#2} {#3} {#4} { } { } } +\cs_set_protected:Npn \msg_kernel_error:nnx #1#2#3 + { \msg_kernel_error:nnxxxx {#1} {#2} {#3} { } { } { } } +\cs_set_protected:Npn \msg_kernel_error:nn #1#2 + { \msg_kernel_error:nnxxxx {#1} {#2} { } { } { } { } } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\msg_kernel_warning:nnxxxx} +% \begin{macro}{\msg_kernel_warning:nnxxx} +% \begin{macro}{\msg_kernel_warning:nnxx} +% \begin{macro}{\msg_kernel_warning:nnx} +% \begin{macro}{\msg_kernel_warning:nn} +% \begin{macro}{\msg_kernel_info:nnxxxx} +% \begin{macro}{\msg_kernel_info:nnxxx} +% \begin{macro}{\msg_kernel_info:nnxx} +% \begin{macro}{\msg_kernel_info:nnx} +% \begin{macro}{\msg_kernel_info:nn} +% Kernel messages which can be redirected. +% \begin{macrocode} +\prop_new:N \l_msg_redirect_kernel_warning_prop +\cs_new_protected:Npn \msg_kernel_warning:nnxxxx #1#2#3#4#5#6 + { + \msg_use:nnnnxxxx { warning } + { + \msg_term:x + { + \msg_warning_text:n { LaTeX } : ~ " #1 / #2 " \\ \\ + \use:c { \c_msg_text_prefix_tl LaTeX / #1 / #2 } + {#3} {#4} {#5} {#6} + } + } + { LaTeX } { #1 / #2 } {#3} {#4} {#5} {#6} + } +\cs_new_protected:Npn \msg_kernel_warning:nnxxx #1#2#3#4#5 + { \msg_kernel_warning:nnxxxx {#1} {#2} {#3} {#4} {#5} { } } +\cs_new_protected:Npn \msg_kernel_warning:nnxx #1#2#3#4 + { \msg_kernel_warning:nnxxxx {#1} {#2} {#3} {#4} { } { } } +\cs_new_protected:Npn \msg_kernel_warning:nnx #1#2#3 + { \msg_kernel_warning:nnxxxx {#1} {#2} {#3} { } { } { } } +\cs_new_protected:Npn \msg_kernel_warning:nn #1#2 + { \msg_kernel_warning:nnxxxx {#1} {#2} { } { } { } { } } +\prop_new:N \l_msg_redirect_kernel_info_prop +\cs_new_protected:Npn \msg_kernel_info:nnxxxx #1#2#3#4#5#6 + { + \msg_use:nnnnxxxx { info } + { + \msg_log:x + { + \msg_info_text:n { LaTeX } : ~ " #1 / #2 " \\ \\ + \use:c { \c_msg_text_prefix_tl LaTeX / #1 / #2 } + {#3} {#4} {#5} {#6} + } + } + { LaTeX } { #1 / #2 } {#3} {#4} {#5} {#6} + } +\cs_new_protected:Npn \msg_kernel_info:nnxxx #1#2#3#4#5 + { \msg_kernel_info:nnxxxx {#1} {#2} {#3} {#4} {#5} { } } +\cs_new_protected:Npn \msg_kernel_info:nnxx #1#2#3#4 + { \msg_kernel_info:nnxxxx {#1} {#2} {#3} {#4} { } { } } +\cs_new_protected:Npn \msg_kernel_info:nnx #1#2#3 + { \msg_kernel_info:nnxxxx {#1} {#2} {#3} { } { } { } } +\cs_new_protected:Npn \msg_kernel_info:nn #1#2 + { \msg_kernel_info:nnxxxx {#1} {#2} { } { } { } { } } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% Error messages needed to actually implement the message system +% itself. +% \begin{macrocode} +\msg_kernel_new:nnnn { msg } { message-already-defined } + { Message~'#2'~for~module~'#1'~already~defined. } + { + \c_msg_coding_error_text_tl + LaTeX~was~asked~to~define~a~new~message~called~'#2' + by~the~module~'#1'~module:\\ + this~message~already~exists. + \c_msg_return_text_tl + } +\msg_kernel_new:nnnn { msg } { message-unknown } + { Unknown~message~'#2'~for~module~'#1'. } + { + \c_msg_coding_error_text_tl + LaTeX~was~asked~to~display~a~message~called~'#2'\\ + by~the~module~'#1'~module:~this~message~does~not~exist. + \c_msg_return_text_tl + } +\msg_kernel_new:nnnn { msg } { message-class-unknown } + { Unknown~message~class~'#1'. } + { + LaTeX~has~been~asked~to~redirect~messages~to~a~class~'#1':\\ + this~was~never~defined. + \c_msg_return_text_tl + } +\msg_kernel_new:nnnn { msg } { redirect-loop } + { Message~redirection~loop~for~message~class~'#1'. } + { + LaTeX~has~been~asked~to~redirect~messages~in~an~infinite~loop.\\ + The~original~message~here~has~been~lost. + \c_msg_return_text_tl + } +% \end{macrocode} +% +% Messages for earlier kernel modules. +% \begin{macrocode} +\msg_kernel_new:nnnn { kernel } { bad-number-of-arguments } + { Function~'#1'~cannot~be~defined~with~#2~arguments. } + { + \c_msg_coding_error_text_tl + LaTeX~has~been~asked~to~define~a~function~'#1'~with~ + #2~arguments. \\ + TeX~allows~between~0~and~9~arguments~for~a~single~function. + } +\msg_kernel_new:nnnn { kernel } { command-already-defined } + { Control~sequence~#1~already~defined. } + { + \c_msg_coding_error_text_tl + LaTeX~has~been~asked~to~create~a~new~control~sequence~'#1'~ + but~this~name~has~already~been~used~elsewhere. \\ \\ + The~current~meaning~is:\\ + \ \ #2 + } +\msg_kernel_new:nnnn { kernel } { command-not-defined } + { Control~sequence~#1~undefined. } + { + \c_msg_coding_error_text_tl + LaTeX~has~been~asked~to~use~a~command~#1,~but~this~has~not~ + been~defined~yet. + } +\msg_kernel_new:nnnn { kernel } { variable-not-defined } + { Variable~#1~undefined. } + { + \c_msg_coding_error_text_tl + LaTeX~has~been~asked~to~show~a~variable~#1,~but~this~has~not~ + been~defined~yet. + } +\msg_kernel_new:nnnn { seq } { empty-sequence } + { Empty~sequence~#1. } + { + \c_msg_coding_error_text_tl + LaTeX~has~been~asked~to~recover~an~entry~from~a~sequence~that~ + has~no~content:~that~cannot~happen! + } +% \end{macrocode} +% +% \begin{macro}{\msg_kernel_bug:x} +% \begin{variable}{\c_msg_kernel_bug_text_tl, \c_msg_kernel_bug_more_text_tl} +% The \LaTeX{} coding bug error gets re-visited here. +% \begin{macrocode} +\cs_set_protected:Npn \msg_kernel_bug:x #1 + { + \msg_interrupt:xxx { \c_msg_kernel_bug_text_tl } + { + #1 + \msg_see_documentation_text:n { LaTeX3 } + } + { \c_msg_kernel_bug_more_text_tl } + } +\tl_const:Nn \c_msg_kernel_bug_text_tl + { This~is~a~LaTeX~bug:~check~coding! } +\tl_const:Nn \c_msg_kernel_bug_more_text_tl + { + There~is~a~coding~bug~somewhere~around~here. \\ + This~probably~needs~examining~by~an~expert. + \c_msg_return_text_tl + } +% \end{macrocode} +% \end{variable} +% \end{macro} +% +% \subsection{Deprecated functions} +% +% Deprecated on 2011-05-27, for removal by 2011-08-31. +% +% \begin{macro}{\msg_class_new:nn} +% This is only ever used in a |set| fashion. +% \begin{macrocode} +\cs_new_eq:NN \msg_class_new:nn \msg_class_set:nn +% \end{macrocode} +% \end{macro} +% +% \begin{macro} +% { +% \msg_trace:nnxxxx, \msg_trace:nnxxx, \msg_trace:nnxx, +% \msg_trace:nnx, \msg_trace:nn +% } +% The performance here is never going to be good enough for tracing +% code, so let's be realistic. +% \begin{macrocode} +\cs_new_eq:NN \msg_trace:nnxxxx \msg_log:nnxxxx +\cs_new_eq:NN \msg_trace:nnxxx \msg_log:nnxxx +\cs_new_eq:NN \msg_trace:nnxx \msg_log:nnxx +\cs_new_eq:NN \msg_trace:nnx \msg_log:nnx +\cs_new_eq:NN \msg_trace:nn \msg_log:nn +% \end{macrocode} +%\end{macro} +% +% \begin{macro}{\msg_generic_new:nnn} +% \begin{macro}{\msg_generic_new:nn} +% \begin{macro}{\msg_generic_set:nnn} +% \begin{macro}{\msg_generic_set:nn} +% \begin{macro}{\msg_direct_interrupt:xxxxx} +% \begin{macro}{\msg_direct_log:xx} +% \begin{macro}{\msg_direct_term:xx} +% These were all too low-level. +% \begin{macrocode} +\cs_new_protected:Npn \msg_generic_new:nnn #1#2#3 { \deprecated } +\cs_new_protected:Npn \msg_generic_new:nn #1#2 { \deprecated } +\cs_new_protected:Npn \msg_generic_set:nnn #1#2#3 { \deprecated } +\cs_new_protected:Npn \msg_generic_set:nn #1#2 { \deprecated } +\cs_new_protected:Npn \msg_direct_interrupt:xxxxx #1#2#3#4#5 { \deprecated } +\cs_new_protected:Npn \msg_direct_log:xx #1#2 { \deprecated } +\cs_new_protected:Npn \msg_direct_term:xx #1#2 { \deprecated } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macrocode} +%</initex|package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintIndex diff --git a/Master/texmf-dist/source/latex/l3kernel/l3names.dtx b/Master/texmf-dist/source/latex/l3kernel/l3names.dtx new file mode 100644 index 00000000000..d8a33196962 --- /dev/null +++ b/Master/texmf-dist/source/latex/l3kernel/l3names.dtx @@ -0,0 +1,629 @@ +% \iffalse meta-comment +% +%% File: l3names.dtx Copyright (C) 1990-2011 The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +% +%<*package> +\RequirePackage{l3bootstrap} +\GetIdInfo$Id: l3names.dtx 2478 2011-06-19 21:34:23Z joseph $ + {L3 Experimental namespace for primitives} +%</package> +%<*driver> +\documentclass[full]{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{^^A +% The \pkg{l3names} package\\ Namespace for primitives^^A +% \thanks{This file describes v\ExplFileVersion, +% last revised \ExplFileDate.}^^A +% } +% +% \author{^^A +% The \LaTeX3 Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% +% \date{Released \ExplFileDate} +% +% \maketitle +% +% \begin{documentation} +% +% \section{Setting up the \LaTeX3 programming language} +% +% This module is at the core of the \LaTeX3 programming language. It +% performs the following tasks: +% \begin{itemize} +% \item defines new names for all \TeX{} primitives; +% \item switches to the category code regime for programming; +% \item provides support settings for building the code as a \TeX{} format. +% \end{itemize} +% +% This module is entirely dedicated to primitives, which should not +% be used directly within \LaTeX3 code (outside of \enquote{kernel-level} +% code). As such, the primitives are not documented here: +% \emph{The \TeX{}book}, \emph{\TeX{} by Topic} and the manuals for +% \pdfTeX{}, \XeTeX{} and \LuaTeX{} should be consulted for details of +% the primitives. These are named based on the engine which first introduced +% them: +% \begin{itemize} +% \item[\cs{tex_\ldots}] Introduced by \TeX{} itself; +% \item[\cs{etex_\ldots}] Introduced by the \eTeX{} extensions; +% \item[\cs{pdftex_\ldots}] Introduced by \pdfTeX{}; +% \item[\cs{xetex_\ldots}] Introduced by \XeTeX{}; +% \item[\cs{luatex_\ldots}] Introduced by \LuaTeX{}. +% \end{itemize} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{l3names} implementation} +% +% \begin{macrocode} +%<*initex|package> +% \end{macrocode} +% +% \begin{macrocode} +%<*package> +\ProvidesExplPackage + {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +%</package> +% \end{macrocode} +% +% The code here simply renames all of the primitives to new, internal, +% names. In format mode, it also deletes all of the existing names (although +% some od come back later). +% +% \begin{macro}{\tex_undefined:D} +% This function does not exist at all, but is the name used by the +% plain \TeX{} format for an undefined function. So it should +% be marked here as \enquote{taken}. +% \end{macro} +% +% The \cs{let} primitive is renamed by hand first as it is essential for +% the entire process to follow. This also uses \cs{global}, as that way +% we avoid leaving an unneeded csname in the hash table. +% \begin{macrocode} +\let \tex_global:D \global +\let \tex_let:D \let +% \end{macrocode} +% +% Everything is inside a (rather long) group, which kees \cs{name_primitve:NN} +% trapped. +% \begin{macrocode} +\begingroup +% \end{macrocode} +% +% \begin{macro}[aux]{\name_primitive:NN} +% A temporary function to actually do the renaming. This also allows the +% original names to be removed in format mode. +% \begin{macrocode} + \long \def \name_primitive:NN #1#2 + { + \tex_global:D \tex_let:D #2 #1 +%<*initex> + \tex_global:D \tex_let:D #1 \tex_undefined:D +%</initex> + } +% \end{macrocode} +%\end{macro} +% +% In the current incarnation of this package, all \TeX{} primitives +% are given a new name of the form |\tex_|\emph{oldname}|:D|. +% But first three special cases which have symbolic original names. +% These are given modified new names, so that they may be entered +% without catcode tricks. +% \begin{macrocode} + \name_primitive:NN \ \tex_space:D + \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 + \name_primitive:NN \def \tex_def:D + \name_primitive:NN \edef \tex_edef:D + \name_primitive:NN \gdef \tex_gdef:D + \name_primitive:NN \xdef \tex_xdef:D + \name_primitive:NN \chardef \tex_chardef:D + \name_primitive:NN \countdef \tex_countdef:D + \name_primitive:NN \dimendef \tex_dimendef:D + \name_primitive:NN \skipdef \tex_skipdef:D + \name_primitive:NN \muskipdef \tex_muskipdef:D + \name_primitive:NN \mathchardef \tex_mathchardef:D + \name_primitive:NN \toksdef \tex_toksdef:D + \name_primitive:NN \futurelet \tex_futurelet:D + \name_primitive:NN \advance \tex_advance:D + \name_primitive:NN \divide \tex_divide:D + \name_primitive:NN \multiply \tex_multiply:D + \name_primitive:NN \font \tex_font:D + \name_primitive:NN \fam \tex_fam:D + \name_primitive:NN \global \tex_global:D + \name_primitive:NN \long \tex_long:D + \name_primitive:NN \outer \tex_outer:D + \name_primitive:NN \setlanguage \tex_setlanguage:D + \name_primitive:NN \globaldefs \tex_globaldefs:D + \name_primitive:NN \afterassignment \tex_afterassignment:D + \name_primitive:NN \aftergroup \tex_aftergroup:D + \name_primitive:NN \expandafter \tex_expandafter:D + \name_primitive:NN \noexpand \tex_noexpand:D + \name_primitive:NN \begingroup \tex_begingroup:D + \name_primitive:NN \endgroup \tex_endgroup:D + \name_primitive:NN \halign \tex_halign:D + \name_primitive:NN \valign \tex_valign:D + \name_primitive:NN \cr \tex_cr:D + \name_primitive:NN \crcr \tex_crcr:D + \name_primitive:NN \noalign \tex_noalign:D + \name_primitive:NN \omit \tex_omit:D + \name_primitive:NN \span \tex_span:D + \name_primitive:NN \tabskip \tex_tabskip:D + \name_primitive:NN \everycr \tex_everycr:D + \name_primitive:NN \if \tex_if:D + \name_primitive:NN \ifcase \tex_ifcase:D + \name_primitive:NN \ifcat \tex_ifcat:D + \name_primitive:NN \ifnum \tex_ifnum:D + \name_primitive:NN \ifodd \tex_ifodd:D + \name_primitive:NN \ifdim \tex_ifdim:D + \name_primitive:NN \ifeof \tex_ifeof:D + \name_primitive:NN \ifhbox \tex_ifhbox:D + \name_primitive:NN \ifvbox \tex_ifvbox:D + \name_primitive:NN \ifvoid \tex_ifvoid:D + \name_primitive:NN \ifx \tex_ifx:D + \name_primitive:NN \iffalse \tex_iffalse:D + \name_primitive:NN \iftrue \tex_iftrue:D + \name_primitive:NN \ifhmode \tex_ifhmode:D + \name_primitive:NN \ifmmode \tex_ifmmode:D + \name_primitive:NN \ifvmode \tex_ifvmode:D + \name_primitive:NN \ifinner \tex_ifinner:D + \name_primitive:NN \else \tex_else:D + \name_primitive:NN \fi \tex_fi:D + \name_primitive:NN \or \tex_or:D + \name_primitive:NN \immediate \tex_immediate:D + \name_primitive:NN \closeout \tex_closeout:D + \name_primitive:NN \openin \tex_openin:D + \name_primitive:NN \openout \tex_openout:D + \name_primitive:NN \read \tex_read:D + \name_primitive:NN \write \tex_write:D + \name_primitive:NN \closein \tex_closein:D + \name_primitive:NN \newlinechar \tex_newlinechar:D + \name_primitive:NN \input \tex_input:D + \name_primitive:NN \endinput \tex_endinput:D + \name_primitive:NN \inputlineno \tex_inputlineno:D + \name_primitive:NN \errmessage \tex_errmessage:D + \name_primitive:NN \message \tex_message:D + \name_primitive:NN \show \tex_show:D + \name_primitive:NN \showthe \tex_showthe:D + \name_primitive:NN \showbox \tex_showbox:D + \name_primitive:NN \showlists \tex_showlists:D + \name_primitive:NN \errhelp \tex_errhelp:D + \name_primitive:NN \errorcontextlines \tex_errorcontextlines:D + \name_primitive:NN \tracingcommands \tex_tracingcommands:D + \name_primitive:NN \tracinglostchars \tex_tracinglostchars:D + \name_primitive:NN \tracingmacros \tex_tracingmacros:D + \name_primitive:NN \tracingonline \tex_tracingonline:D + \name_primitive:NN \tracingoutput \tex_tracingoutput:D + \name_primitive:NN \tracingpages \tex_tracingpages:D + \name_primitive:NN \tracingparagraphs \tex_tracingparagraphs:D + \name_primitive:NN \tracingrestores \tex_tracingrestores:D + \name_primitive:NN \tracingstats \tex_tracingstats:D + \name_primitive:NN \pausing \tex_pausing:D + \name_primitive:NN \showboxbreadth \tex_showboxbreadth:D + \name_primitive:NN \showboxdepth \tex_showboxdepth:D + \name_primitive:NN \batchmode \tex_batchmode:D + \name_primitive:NN \errorstopmode \tex_errorstopmode:D + \name_primitive:NN \nonstopmode \tex_nonstopmode:D + \name_primitive:NN \scrollmode \tex_scrollmode:D + \name_primitive:NN \end \tex_end:D + \name_primitive:NN \csname \tex_csname:D + \name_primitive:NN \endcsname \tex_endcsname:D + \name_primitive:NN \ignorespaces \tex_ignorespaces:D + \name_primitive:NN \relax \tex_relax:D + \name_primitive:NN \the \tex_the:D + \name_primitive:NN \mag \tex_mag:D + \name_primitive:NN \language \tex_language:D + \name_primitive:NN \mark \tex_mark:D + \name_primitive:NN \topmark \tex_topmark:D + \name_primitive:NN \firstmark \tex_firstmark:D + \name_primitive:NN \botmark \tex_botmark:D + \name_primitive:NN \splitfirstmark \tex_splitfirstmark:D + \name_primitive:NN \splitbotmark \tex_splitbotmark:D + \name_primitive:NN \fontname \tex_fontname:D + \name_primitive:NN \escapechar \tex_escapechar:D + \name_primitive:NN \endlinechar \tex_endlinechar:D + \name_primitive:NN \mathchoice \tex_mathchoice:D + \name_primitive:NN \delimiter \tex_delimiter:D + \name_primitive:NN \mathaccent \tex_mathaccent:D + \name_primitive:NN \mathchar \tex_mathchar:D + \name_primitive:NN \mskip \tex_mskip:D + \name_primitive:NN \radical \tex_radical:D + \name_primitive:NN \vcenter \tex_vcenter:D + \name_primitive:NN \mkern \tex_mkern:D + \name_primitive:NN \above \tex_above:D + \name_primitive:NN \abovewithdelims \tex_abovewithdelims:D + \name_primitive:NN \atop \tex_atop:D + \name_primitive:NN \atopwithdelims \tex_atopwithdelims:D + \name_primitive:NN \over \tex_over:D + \name_primitive:NN \overwithdelims \tex_overwithdelims:D + \name_primitive:NN \displaystyle \tex_displaystyle:D + \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 + \name_primitive:NN \abovedisplayskip \tex_abovedisplayskip:D + \name_primitive:NN \belowdisplayshortskip \tex_belowdisplayshortskip:D + \name_primitive:NN \belowdisplayskip \tex_belowdisplayskip:D + \name_primitive:NN \displaywidowpenalty \tex_displaywidowpenalty:D + \name_primitive:NN \displayindent \tex_displayindent:D + \name_primitive:NN \displaywidth \tex_displaywidth:D + \name_primitive:NN \everydisplay \tex_everydisplay:D + \name_primitive:NN \predisplaysize \tex_predisplaysize:D + \name_primitive:NN \predisplaypenalty \tex_predisplaypenalty:D + \name_primitive:NN \postdisplaypenalty \tex_postdisplaypenalty:D + \name_primitive:NN \mathbin \tex_mathbin:D + \name_primitive:NN \mathclose \tex_mathclose:D + \name_primitive:NN \mathinner \tex_mathinner:D + \name_primitive:NN \mathop \tex_mathop:D + \name_primitive:NN \displaylimits \tex_displaylimits:D + \name_primitive:NN \limits \tex_limits:D + \name_primitive:NN \nolimits \tex_nolimits:D + \name_primitive:NN \mathopen \tex_mathopen:D + \name_primitive:NN \mathord \tex_mathord:D + \name_primitive:NN \mathpunct \tex_mathpunct:D + \name_primitive:NN \mathrel \tex_mathrel:D + \name_primitive:NN \overline \tex_overline:D + \name_primitive:NN \underline \tex_underline:D + \name_primitive:NN \left \tex_left:D + \name_primitive:NN \right \tex_right:D + \name_primitive:NN \binoppenalty \tex_binoppenalty:D + \name_primitive:NN \relpenalty \tex_relpenalty:D + \name_primitive:NN \delimitershortfall \tex_delimitershortfall:D + \name_primitive:NN \delimiterfactor \tex_delimiterfactor:D + \name_primitive:NN \nulldelimiterspace \tex_nulldelimiterspace:D + \name_primitive:NN \everymath \tex_everymath:D + \name_primitive:NN \mathsurround \tex_mathsurround:D + \name_primitive:NN \medmuskip \tex_medmuskip:D + \name_primitive:NN \thinmuskip \tex_thinmuskip:D + \name_primitive:NN \thickmuskip \tex_thickmuskip:D + \name_primitive:NN \scriptspace \tex_scriptspace:D + \name_primitive:NN \noboundary \tex_noboundary:D + \name_primitive:NN \accent \tex_accent:D + \name_primitive:NN \char \tex_char:D + \name_primitive:NN \discretionary \tex_discretionary:D + \name_primitive:NN \hfil \tex_hfil:D + \name_primitive:NN \hfilneg \tex_hfilneg:D + \name_primitive:NN \hfill \tex_hfill:D + \name_primitive:NN \hskip \tex_hskip:D + \name_primitive:NN \hss \tex_hss:D + \name_primitive:NN \vfil \tex_vfil:D + \name_primitive:NN \vfilneg \tex_vfilneg:D + \name_primitive:NN \vfill \tex_vfill:D + \name_primitive:NN \vskip \tex_vskip:D + \name_primitive:NN \vss \tex_vss:D + \name_primitive:NN \unskip \tex_unskip:D + \name_primitive:NN \kern \tex_kern:D + \name_primitive:NN \unkern \tex_unkern:D + \name_primitive:NN \hrule \tex_hrule:D + \name_primitive:NN \vrule \tex_vrule:D + \name_primitive:NN \leaders \tex_leaders:D + \name_primitive:NN \cleaders \tex_cleaders:D + \name_primitive:NN \xleaders \tex_xleaders:D + \name_primitive:NN \lastkern \tex_lastkern:D + \name_primitive:NN \lastskip \tex_lastskip:D + \name_primitive:NN \indent \tex_indent:D + \name_primitive:NN \par \tex_par:D + \name_primitive:NN \noindent \tex_noindent:D + \name_primitive:NN \vadjust \tex_vadjust:D + \name_primitive:NN \baselineskip \tex_baselineskip:D + \name_primitive:NN \lineskip \tex_lineskip:D + \name_primitive:NN \lineskiplimit \tex_lineskiplimit:D + \name_primitive:NN \clubpenalty \tex_clubpenalty:D + \name_primitive:NN \widowpenalty \tex_widowpenalty:D + \name_primitive:NN \exhyphenpenalty \tex_exhyphenpenalty:D + \name_primitive:NN \hyphenpenalty \tex_hyphenpenalty:D + \name_primitive:NN \linepenalty \tex_linepenalty:D + \name_primitive:NN \doublehyphendemerits \tex_doublehyphendemerits:D + \name_primitive:NN \finalhyphendemerits \tex_finalhyphendemerits:D + \name_primitive:NN \adjdemerits \tex_adjdemerits:D + \name_primitive:NN \hangafter \tex_hangafter:D + \name_primitive:NN \hangindent \tex_hangindent:D + \name_primitive:NN \parshape \tex_parshape:D + \name_primitive:NN \hsize \tex_hsize:D + \name_primitive:NN \lefthyphenmin \tex_lefthyphenmin:D + \name_primitive:NN \righthyphenmin \tex_righthyphenmin:D + \name_primitive:NN \leftskip \tex_leftskip:D + \name_primitive:NN \rightskip \tex_rightskip:D + \name_primitive:NN \looseness \tex_looseness:D + \name_primitive:NN \parskip \tex_parskip:D + \name_primitive:NN \parindent \tex_parindent:D + \name_primitive:NN \uchyph \tex_uchyph:D + \name_primitive:NN \emergencystretch \tex_emergencystretch:D + \name_primitive:NN \pretolerance \tex_pretolerance:D + \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 + \name_primitive:NN \shipout \tex_shipout:D + \name_primitive:NN \vsize \tex_vsize:D + \name_primitive:NN \interlinepenalty \tex_interlinepenalty:D + \name_primitive:NN \brokenpenalty \tex_brokenpenalty:D + \name_primitive:NN \topskip \tex_topskip:D + \name_primitive:NN \maxdeadcycles \tex_maxdeadcycles:D + \name_primitive:NN \maxdepth \tex_maxdepth:D + \name_primitive:NN \output \tex_output:D + \name_primitive:NN \deadcycles \tex_deadcycles:D + \name_primitive:NN \pagedepth \tex_pagedepth:D + \name_primitive:NN \pagestretch \tex_pagestretch:D + \name_primitive:NN \pagefilstretch \tex_pagefilstretch:D + \name_primitive:NN \pagefillstretch \tex_pagefillstretch:D + \name_primitive:NN \pagefilllstretch \tex_pagefilllstretch:D + \name_primitive:NN \pageshrink \tex_pageshrink:D + \name_primitive:NN \pagegoal \tex_pagegoal:D + \name_primitive:NN \pagetotal \tex_pagetotal:D + \name_primitive:NN \outputpenalty \tex_outputpenalty:D + \name_primitive:NN \hoffset \tex_hoffset:D + \name_primitive:NN \voffset \tex_voffset:D + \name_primitive:NN \insert \tex_insert:D + \name_primitive:NN \holdinginserts \tex_holdinginserts:D + \name_primitive:NN \floatingpenalty \tex_floatingpenalty:D + \name_primitive:NN \insertpenalties \tex_insertpenalties:D + \name_primitive:NN \lower \tex_lower:D + \name_primitive:NN \moveleft \tex_moveleft:D + \name_primitive:NN \moveright \tex_moveright:D + \name_primitive:NN \raise \tex_raise:D + \name_primitive:NN \copy \tex_copy:D + \name_primitive:NN \lastbox \tex_lastbox:D + \name_primitive:NN \vsplit \tex_vsplit:D + \name_primitive:NN \unhbox \tex_unhbox:D + \name_primitive:NN \unhcopy \tex_unhcopy:D + \name_primitive:NN \unvbox \tex_unvbox:D + \name_primitive:NN \unvcopy \tex_unvcopy:D + \name_primitive:NN \setbox \tex_setbox:D + \name_primitive:NN \hbox \tex_hbox:D + \name_primitive:NN \vbox \tex_vbox:D + \name_primitive:NN \vtop \tex_vtop:D + \name_primitive:NN \prevdepth \tex_prevdepth:D + \name_primitive:NN \badness \tex_badness:D + \name_primitive:NN \hbadness \tex_hbadness:D + \name_primitive:NN \vbadness \tex_vbadness:D + \name_primitive:NN \hfuzz \tex_hfuzz:D + \name_primitive:NN \vfuzz \tex_vfuzz:D + \name_primitive:NN \overfullrule \tex_overfullrule:D + \name_primitive:NN \boxmaxdepth \tex_boxmaxdepth:D + \name_primitive:NN \splitmaxdepth \tex_splitmaxdepth:D + \name_primitive:NN \splittopskip \tex_splittopskip:D + \name_primitive:NN \everyhbox \tex_everyhbox:D + \name_primitive:NN \everyvbox \tex_everyvbox:D + \name_primitive:NN \nullfont \tex_nullfont:D + \name_primitive:NN \textfont \tex_textfont:D + \name_primitive:NN \scriptfont \tex_scriptfont:D + \name_primitive:NN \scriptscriptfont \tex_scriptscriptfont:D + \name_primitive:NN \fontdimen \tex_fontdimen:D + \name_primitive:NN \hyphenchar \tex_hyphenchar:D + \name_primitive:NN \skewchar \tex_skewchar:D + \name_primitive:NN \defaulthyphenchar \tex_defaulthyphenchar:D + \name_primitive:NN \defaultskewchar \tex_defaultskewchar:D + \name_primitive:NN \number \tex_number:D + \name_primitive:NN \romannumeral \tex_romannumeral:D + \name_primitive:NN \string \tex_string:D + \name_primitive:NN \lowercase \tex_lowercase:D + \name_primitive:NN \uppercase \tex_uppercase:D + \name_primitive:NN \meaning \tex_meaning:D + \name_primitive:NN \penalty \tex_penalty:D + \name_primitive:NN \unpenalty \tex_unpenalty:D + \name_primitive:NN \lastpenalty \tex_lastpenalty:D + \name_primitive:NN \special \tex_special:D + \name_primitive:NN \dump \tex_dump:D + \name_primitive:NN \patterns \tex_patterns:D + \name_primitive:NN \hyphenation \tex_hyphenation:D + \name_primitive:NN \time \tex_time:D + \name_primitive:NN \day \tex_day:D + \name_primitive:NN \month \tex_month:D + \name_primitive:NN \year \tex_year:D + \name_primitive:NN \jobname \tex_jobname:D + \name_primitive:NN \everyjob \tex_everyjob:D + \name_primitive:NN \count \tex_count:D + \name_primitive:NN \dimen \tex_dimen:D + \name_primitive:NN \skip \tex_skip:D + \name_primitive:NN \toks \tex_toks:D + \name_primitive:NN \muskip \tex_muskip:D + \name_primitive:NN \box \tex_box:D + \name_primitive:NN \wd \tex_wd:D + \name_primitive:NN \ht \tex_ht:D + \name_primitive:NN \dp \tex_dp:D + \name_primitive:NN \catcode \tex_catcode:D + \name_primitive:NN \delcode \tex_delcode:D + \name_primitive:NN \sfcode \tex_sfcode:D + \name_primitive:NN \lccode \tex_lccode:D + \name_primitive:NN \uccode \tex_uccode:D + \name_primitive:NN \mathcode \tex_mathcode:D +% \end{macrocode} +% Since \LaTeX3 requires 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} +% The newer primitives are more complex: there are an awful lot of them, +% and we don't use them all at the moment. So the following is selective. +% In the case of the \pdfTeX{} primitives, we retain |pdf| at the start +% of the names \emph{only} for directly PDF-related primitives, as +% there are a lot of \pdfTeX{} primitives that start \cs{pdf\ldots} but +% are not related to PDF output. These ones re +% \begin{macrocode} + \name_primitive:NN \pdfcreationdate \pdftex_pdfcreationdate:D + \name_primitive:NN \pdfcolorstack \pdftex_pdfcolorstack:D + \name_primitive:NN \pdfcompresslevel \pdftex_pdfcompresslevel:D + \name_primitive:NN \pdfdecimaldigits \pdftex_pdfdecimaldigits:D + \name_primitive:NN \pdfhorigin \pdftex_pdfhorigin:D + \name_primitive:NN \pdfinfo \pdftex_pdfinfo:D + \name_primitive:NN \pdfliteral \pdftex_pdfliteral:D + \name_primitive:NN \pdfminorversion \pdftex_pdfminorversion:D + \name_primitive:NN \pdfobjcompresslevel \pdftex_pdfobjcompresslevel:D + \name_primitive:NN \pdfoutput \pdftex_pdfoutput:D + \name_primitive:NN \pdfrestore \pdftex_pdfrestore:D + \name_primitive:NN \pdfsave \pdftex_pdfsave:D + \name_primitive:NN \pdfsetmatrix \pdftex_pdfsetmatrix:D + \name_primitive:NN \pdfpkresolution \pdftex_pdfpkresolution:D + \name_primitive:NN \pdftexrevision \pdftex_pdftextrevision:D + \name_primitive:NN \pdfvorigin \pdftex_pdfvorigin:D +% \end{macrocode} +% While these are not. +% \begin{macrocode} + \name_primitive:NN \pdfstrcmp \pdftex_strcmp:D +% \end{macrocode} +% \XeTeX{}-specific primitives. +% \begin{macrocode} + \name_primitive:NN \XeTeXversion \xetex_XeTeXversion:D +% \end{macrocode} +% Primitives from \LuaTeX. +% \begin{macrocode} + \name_primitive:NN \catcodetable \luatex_catcodetable:D + \name_primitive:NN \directlua \luatex_directlua:D + \name_primitive:NN \initcatcodetable \luatex_initcatcodetable:D + \name_primitive:NN \latelua \luatex_latelua:D + \name_primitive:NN \luatexversion \luatex_luatexversion:D + \name_primitive:NN \savecatcodetable \luatex_savecatcodetable:D +% \end{macrocode} +% The job is done: close the group (using the primitive renamed!). +% \begin{macrocode} +\tex_endgroup:D +% \end{macrocode} +% +% \LaTeXe{} will have moved a few primitives, so these are sorted out. +% \begin{macrocode} +%<*package> +\tex_let:D \tex_end:D \@@end +\tex_let:D \tex_everydisplay:D \frozen@everydisplay +\tex_let:D \tex_everymath:D \frozen@everymath +\tex_let:D \tex_hyphen:D \@@hyph +\tex_let:D \tex_input:D \@@input +\tex_let:D \tex_italic_correction:D \@@italiccorr +\tex_let:D \tex_underline:D \@@underline +% \end{macrocode} +% That is also true for the \pkg{luatex} package for \LaTeXe{}. +% \begin{macrocode} +\tex_let:D \luatex_catcodetable:D \luatexcatcodetable +\tex_let:D \luatex_initcatcodetable:D \luatexinitcatcodetable +\tex_let:D \luatex_latelua:D \luatexlatelua +\tex_let:D \luatex_savecatcodetable:D \luatexsavecatcodetable +%</package> +% \end{macrocode} +% +% \begin{macrocode} +%</initex|package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintIndex
\ No newline at end of file diff --git a/Master/texmf-dist/source/latex/l3kernel/l3prg.dtx b/Master/texmf-dist/source/latex/l3kernel/l3prg.dtx new file mode 100644 index 00000000000..b4cf9368f2a --- /dev/null +++ b/Master/texmf-dist/source/latex/l3kernel/l3prg.dtx @@ -0,0 +1,2046 @@ +% \iffalse meta-comment +% +%% File: l3prg.dtx Copyright (C) 2005-2011 The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +% +%<*driver|package> +\RequirePackage{l3names} +\GetIdInfo$Id: l3prg.dtx 2495 2011-07-06 16:57:08Z bruno $ + {L3 Experimental control structures} +%</driver|package> +%<*driver> +\documentclass[full]{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{^^A +% The \pkg{l3prg} package\\ Control structures^^A +% \thanks{This file describes v\ExplFileVersion, +% last revised \ExplFileDate.}^^A +% } +% +% \author{^^A +% The \LaTeX3 Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% +% \date{Released \ExplFileDate} +% +% \maketitle +% +% \begin{documentation} +% +% Conditional processing in \LaTeX3 is defined as something that +% performs a series of tests, possibly involving assignments and +% calling other functions that do not read further ahead in the input +% stream. After processing the input, a \emph{state} is returned. The +% typical states returned are \meta{true} and \meta{false} but other +% states are possible, say an \meta{error} state for erroneous +% input, \emph{e.g.}, text as input in a function comparing integers. +% +% \LaTeX3 has two primary forms of conditional flow processing based +% on these states. One type is predicate functions that turn the +% returned state into a boolean \meta{true} or \meta{false}. For +% example, the function |\cs_if_free_p:N| checks whether the control +% sequence given as its argument is free and then returns the boolean +% \meta{true} or \meta{false} values to be used in testing with +% |\if_predicate:w| or in functions to be described below. The other type +% is the kind of functions choosing a particular argument from the +% input stream based on the result of the testing as in +% |\cs_if_free:NTF| which also takes one argument (the |N|) and then +% executes either \meta{true} or \meta{false} depending on the +% result. Important to note here is that the arguments are executed +% after exiting the underlying |\if...\fi:| structure +% +% \section{Defining a set of conditional functions} +% +% \begin{function} +% { +% \prg_new_conditional:Npnn, \prg_set_conditional:Npnn, +% \prg_new_conditional:Nnn, \prg_set_conditional:Nnn +% } +% \begin{syntax} +% \cs{prg_set_conditional:Npnn} \cs{\meta{name}:\meta{arg spec}} +% ~~\meta{parameters} \Arg{conditions} \Arg{code} +% \cs{prg_set_conditional:Nnn} \cs{\meta{name}:\meta{arg spec}} +% ~~\Arg{conditions} \Arg{code} +% \end{syntax} +% These functions creates a family of conditionals using the same +% \Arg{code} to perform the test created. The \texttt{new} version will +% check for existing definitions (\emph{cf.}~\cs{cs_new:Npn}) whereas +% the \texttt{set} version will not (\emph{cf.}~\cs{cs_set:Npn}). The +% conditionals created are depended on the comma-separated list of +% \meta{conditions}, which should be one or more of \texttt{p}, +% \texttt{T}, \texttt{F} and \texttt{TF}. The conditionals are then +% defined in the obvious way as: +% \begin{itemize} +% \item \cs{\meta{name}_p:\meta{arg spec}}, a predicate function +% which will supply either a logical \texttt{true} or +% logical \texttt{false}. This function is intended for use +% in cases where one or more logical tests are combined to +% lead to a final outcome. +% \item \cs{\meta{name}:\meta{arg spec}T}, a function with one +% more argument than the original \meta{arg spec} demands. The +% \meta{true branch} code in this additional argument will be +% left on the input stream only if the test is \texttt{true}. +% \item \cs{\meta{name}:\meta{arg spec}F}, a function with one +% more argument than the original \meta{arg spec} demands. The +% \meta{false branch} code in this additional argument will be +% left on the input stream only if the test is \texttt{false}. +% \item \cs{\meta{name}:\meta{arg spec}TF} , a function with two +% more argument than the original \meta{arg spec} demands. The +% \meta{true branch} code in the first additional argument will +% be left on the input stream if the test is \texttt{true}, while +% the \meta{false branch} code in the second argument will be +% left on the input stream if the test is \texttt{false}. +% \end{itemize} +% The \meta{code} of the test may use \meta{parameters} as specified +% by the second argument to \cs{prg_set_conditional:Npnn}: this should +% match the \meta{argument specification} but this is not enforced. +% The |Nnn| versions infer the number of arguments from the argument +% specification given (\emph{cf.}~\cs{cs_new:Nn}, \emph{etc.}). +% Within the \meta{code}, the functions \cs{prg_return_true:} and +% \cs{prg_return_false:} are used to indicate the logical outcomes of +% the test. If \meta{code} is expandable then +% \cs{prg_set_conditional:Npnn} will generate a family of conditionals +% which are also expandable. All of the functions are created globally. +% +% An example can easily clarify matters here: +% \begin{verbatim} +% \prg_set_conditional:Nnn \foo_if_bar:NN { p , T , TF } +% { +% \if_meaning:w \l_tmpa_tl #1 +% \prg_return_true: +% \else: +% \if_meaning:w \l_tmpa_tl #2 +% \prg_return_true: +% \else: +% \prg_return_false: +% \fi: +% \fi: +% } +% \end{verbatim} +% This defines the function |\foo_if_bar_p:NN|, |\foo_if_bar:NNTF|, +% |\foo_if_bar:NNT| but not |\foo_if_bar:NNF| (because |F| is missing from +% the \meta{conds} list). The return statements +% take care of resolving the remaining |\else:| and |\fi:| before +% returning the state. There must be a return statement for each +% branch, failing to do so will result in an error if that branch is +% executed. +% \end{function} +% +% \begin{function} +% { +% \prg_new_protected_conditional:Npnn, \prg_set_protected_conditional:Npnn, +% \prg_new_protected_conditional:Nnn, \prg_set_protected_conditional:Nnn +% } +% \begin{syntax} +% \cs{prg_set_protected_conditional:Npnn} +% ~~\cs{\meta{name}:\meta{arg spec}} \meta{parameters} +% ~~\meta{conditions} \Arg{code} +% \cs{prg_set_protected_conditional:Nnn} +% ~~\cs{\meta{name}:\meta{arg spec}} \meta{conditions} \Arg{code} +% \end{syntax} +% These functions creates a family of conditionals using the same +% \Arg{code} to perform the test created. The \texttt{new} version will +% check for existing definitions (\emph{cf.}~\cs{cs_new:Npn}) whereas +% the \texttt{set} version will not (\emph{cf.}~\cs{cs_set:Npn}). The +% conditionals created are depended on the comma-separated list of +% \meta{conditions}, which should be one or more of \texttt{T}, +% \texttt{F} and \texttt{TF}. The conditionals are then defined in the +% obvious way as: +% \begin{itemize} +% \item \cs{\meta{name}:\meta{arg spec}T}, a function with one +% more argument than the original \meta{arg spec} demands. The +% \meta{true branch} code in this additional argument will be +% left on the input stream only if the test is \texttt{true}. +% \item \cs{\meta{name}:\meta{arg spec}F}, a function with one +% more argument than the original \meta{arg spec} demands. The +% \meta{false branch} code in this additional argument will be +% left on the input stream only if the test is \texttt{false}. +% \item \cs{\meta{name}:\meta{arg spec}TF} , a function with two +% more argument than the original \meta{arg spec} demands. The +% \meta{true branch} code in the first additional argument will +% be left on the input stream if the test is \texttt{true}, while +% the \meta{false branch} code in the second argument will be +% left on the input stream if the test is \texttt{false}. +% \end{itemize} +% The \meta{code} of the test may use \meta{parameters} as specified +% by the second argument to \cs{prg_set_conditional:Npn}: this should +% match the \meta{argument specification} but this is not enforced. +% The |Nnn| versions infer the number of arguments from the argument +% specification given (\emph{cf.}~\cs{cs_new:Nn}, \emph{etc.}). +% Within the \meta{code}, the functions \cs{prg_return_true:} and +% \cs{prg_return_false:} are used to indicate the logical outcomes of +% the test. \cs{prg_set_protected_conditional:Npn} will generate +% a family of protected conditional functions, and so \meta{code} +% does not need to be expandable. All of the functions are created +% globally. +%\end{function} +% +% \begin{function}{\prg_new_eq_conditional:NN, \prg_set_eq_conditional:NN} +% \begin{syntax} +% \cs{prg_new_eq_conditional:NN} +% ~~\cs{\meta{name1}:\meta{arg spec1}} \cs{\meta{name2}:\meta{arg spec2}} +% \end{syntax} +% These will set the definitions of the functions +% \begin{itemize} +% \item \cs{\meta{name1}_p:\meta{arg spec1}} +% \item \cs{\meta{name1}:\meta{arg spec1}T} +% \item \cs{\meta{name1}:\meta{arg spec1}F} +% \item \cs{\meta{name1}:\meta{arg spec1}TF} +% \end{itemize} +% equal to those for +% \begin{itemize} +% \item \cs{\meta{name2}_p:\meta{arg spec2}} +% \item \cs{\meta{name2}:\meta{arg spec2}T} +% \item \cs{\meta{name2}:\meta{arg spec2}F} +% \item \cs{\meta{name2}:\meta{arg spec2}TF} +% \end{itemize} +% In most cases, the two \meta{arg specs} will be identical, although +% this is not enforced. In the case of the \texttt{new} function, a +% check is made for any existing definitions for \meta{name1}. The +% functions are set globally. +% \end{function} +% +% \begin{function}[EXP]{\prg_return_true:, \prg_return_false:} +% \begin{syntax} +% \cs{prg_return_true:} +% \cs{prg_return_false:} +% \end{syntax} +% These functions define the logical state at the end of a conditional. +% As such, they should appear within the code for a conditional +% statement generated by \cs{prg_set_conditional:Npnn}, \emph{etc}. +% \end{function} +% +% \section{The boolean data type} +% +% This section describes a boolean data type which is closely +% connected to conditional processing as sometimes you want to +% execute some code depending on the value of a switch +% (\emph{e.g.},~draft/final) and other times you perhaps want to use it as a +% predicate function in an |\if_predicate:w| test. The problem of the +% primitive |\if_false:| and |\if_true:| tokens is that it is not +% always safe to pass them around as they may interfere with scanning +% for termination of primitive conditional processing. Therefore, we +% employ two canonical booleans: |\c_true_bool| or +% |\c_false_bool|. Besides preventing problems as described above, it +% also allows us to implement a simple boolean parser supporting the +% logical operations And, Or, Not, \emph{etc.}\ which can then be used on +% both the boolean type and predicate functions. +% +% All conditional |\bool_| functions are expandable and expect the +% input to also be fully expandable (which will generally mean being +% constructed from predicate functions, possibly nested). +% +% \begin{function}{\bool_new:N, \bool_new:c} +% \begin{syntax} +% \cs{bool_new:N} \meta{boolean} +% \end{syntax} +% Creates a new \meta{boolean} or raises an error if the +% name is already taken. The declaration is global. The +% \meta{boolean} will initially be \texttt{false}. +% \end{function} +% +% \begin{function}{\bool_set_false:N, \bool_set_false:c} +% \begin{syntax} +% \cs{bool_set_false:N} \meta{boolean} +% \end{syntax} +% Sets \meta{boolean} logically \texttt{false} within the current +% \TeX{} group. +% \end{function} +% +% \begin{function}{\bool_gset_false:N, \bool_gset_false:c} +% \begin{syntax} +% \cs{bool_sget_false:N} \meta{boolean} +% \end{syntax} +% Sets \meta{boolean} logically \texttt{false} globally. +% \end{function} +% +% \begin{function}{\bool_set_true:N, \bool_set_true:c} +% \begin{syntax} +% \cs{bool_set_true:N} \meta{boolean} +% \end{syntax} +% Sets \meta{boolean} logically \texttt{true} within the current +% \TeX{} group. +% \end{function} +% +% \begin{function}{\bool_gset_true:N, \bool_gset_true:c} +% \begin{syntax} +% \cs{bool_gset_true:N} \meta{boolean} +% \end{syntax} +% Sets \meta{boolean} logically \texttt{true} globally. +% \end{function} +% +% \begin{function} +% {\bool_set_eq:NN, \bool_set_eq:cN, \bool_set_eq:Nc, \bool_set_eq:cc} +% \begin{syntax} +% \cs{bool_set_eq:NN} \meta{boolean1} \meta{boolean2} +% \end{syntax} +% Sets the content of \meta{boolean1} equal to that of \meta{boolean2}. +% This assignment is restricted to the current \TeX{} group level. +% \end{function} +% +% \begin{function} +% {\bool_gset_eq:NN, \bool_gset_eq:cN, \bool_gset_eq:Nc, \bool_gset_eq:cc} +% \begin{syntax} +% \cs{bool_gset_eq:NN} \meta{boolean1} \meta{boolean2} +% \end{syntax} +% Sets the content of \meta{boolean1} equal to that of \meta{boolean2}. +% This assignment is global and so is not limited by the current +% \TeX{} group level. +% \end{function} +% +% \begin{function}{\bool_set:Nn, \bool_set:cn} +% \begin{syntax} +% \cs{bool_set:Nn} \meta{boolean} \Arg{boolexpr} +% \end{syntax} +% Evaluates the \meta{boolean expression} as described for +% \cs{bool_if:n(TF)}, and sets the \meta{boolean} variable to +% the logical truth of this evaluation. This assignment is local. +% \end{function} +% +% \begin{function}{\bool_gset:Nn, \bool_gset:cn} +% \begin{syntax} +% \cs{bool_gset:Nn} \meta{boolean} \Arg{boolexpr} +% \end{syntax} +% Evaluates the \meta{boolean expression} as described for +% \cs{bool_if:n(TF)}, and sets the \meta{boolean} variable to +% the logical truth of this evaluation. This assignment is global. +% \end{function} +% +% \begin{function}[EXP,pTF]{\bool_if:N, \bool_if:c} +% \begin{syntax} +% \cs{bool_if_p:N} \Arg{boolean} +% \cs{bool_if:NTF} \Arg{boolean} \Arg{true code} \Arg{false code} +% \end{syntax} +% Tests the current truth of \meta{boolean}, and continues expansion +% based on this result. The branching versions then leave either +% \meta{true code} or \meta{false code} in the input stream, as +% appropriate to the truth of the test and the variant of the function +% chosen. The logical truth of the test is left in the input stream by +% the predicate version. +% \end{function} +% +% \begin{variable}{\l_tmpa_bool} +% A scratch boolean for local assignment. It is never used by +% the kernel code, and so is safe for use with any \LaTeX3-defined +% function. However, it may be overwritten by other non-kernel +% code and so should only be used for short-term storage. +% \end{variable} +% +% \begin{variable}{\g_tmpa_bool} +% A scratch boolean for global assignment. It is never used by +% the kernel code, and so is safe for use with any \LaTeX3-defined +% function. However, it may be overwritten by other non-kernel +% code and so should only be used for short-term storage. +% \end{variable} +% +% \section{Boolean expressions} +% +% As we have a boolean datatype and predicate functions returning +% boolean \meta{true} or \meta{false} values, it seems only fitting +% that we also provide a parser for \meta{boolean expressions}. +% +% A boolean expression is an expression which given input in the form +% of predicate functions and boolean variables, return boolean +% \meta{true} or \meta{false}. It supports the logical operations And, +% Or and Not as the well-known infix operators |&&|, \verb"||" and |!|. In +% addition to this, parentheses can be used to isolate +% sub-expressions. For example, +% \begin{verbatim} +% \int_compare_p:n { 1 = 1 } && +% ( +% \int_compare_p:n { 2 = 3 } || +% \int_compare_p:n { 4 = 4 } || +% \int_compare_p:n { 1 = \error } % is skipped +% ) && +% ! ( \int_compare_p:n { 2 = 4 } ) +% \end{verbatim} +% is a valid boolean expression. Note that minimal evaluation is +% carried out whenever possible so that whenever a truth value cannot +% be changed any more, the remaining tests within the current group +% are skipped. +% +% \begin{function}[EXP,pTF]{\bool_if:n} +% \begin{syntax} +% \cs{bool_if_p:n} \Arg{boolean expression} +% \cs{bool_if:nTF} \Arg{boolean expression} \Arg{true code} +% ~~\Arg{false code} +% \end{syntax} +% Tests the current truth of \meta{boolean expression}, and +% continues expansion based on this result. The +% \meta{boolean expression} should consist of a series of predicates +% or boolean variables with the logical relationship between these +% defined using |&&| (\enquote{And}), \verb"||" (\enquote{Or}), +% |!| (\enquote{Not}) and parentheses. Minimal evaluation is used +% in the processing, so that once a result is defined there is +% not further expansion of the tests. For example +% \begin{verbatim} +% \bool_if_p:n +% { +% \int_compare_p:nNn { 1 } = { 1 } +% && +% ( +% \int_compare_p:nNn { 2 } = { 3 } || +% \int_compare_p:nNn { 4 } = { 4 } || +% \int_compare_p:nNn { 1 } = { \error } % is skipped +% ) +% && +% ! ( \int_compare_p:nNn { 2 } = { 4 } ) +% } +% \end{verbatim} +% will be \texttt{true} and will not evaluate +% |\int_compare_p:nNn { 1 } = { \error }|. The logical Not applies to +% the next single predicate or group. As shown above, this means that +% any predicates requiring an argument have to be given within +% parentheses. The branching versions then leave either +% \meta{true code} or \meta{false code} in the input stream, as +% appropriate to the truth of the test and the variant of the function +% chosen. The logical truth of the test is left in the input stream by +% the predicate version. +% \end{function} +% +% \begin{function}[EXP]{\bool_not_p:n} +% \begin{syntax} +% \cs{bool_not_p:n} \Arg{boolean expression} +% \end{syntax} +% Function version of |!(|\meta{boolean expression}|)| within a boolean +% expression. +% \end{function} +% +% \begin{function}[EXP]{\bool_xor_p:nn} +% \begin{syntax} +% \cs{bool_xor_p:nn} \Arg{boolexpr1} \Arg{boolexpr1} +% \end{syntax} +% Implements an \enquote{exclusive or} operation between two boolean +% expressions. There is no infix operation for this logical +% operator. +% \end{function} +% +% \section{Logical loops} +% +% Loops using either boolean expressions or stored boolean values. +% +% \begin{function}[EXP]{\bool_until_do:Nn, \bool_until_do:cn} +% \begin{syntax} +% \cs{bool_until_do:Nn} \Arg{boolean} \Arg{code} +% \end{syntax} +% This function firsts checks the logical value of the \meta{boolean}. +% If it is \texttt{false} the \meta{code} is placed in the input stream +% and expanded. After the completion of the \meta{code} the truth +% of the \meta{boolean} is re-evaluated. The process will then loop +% until the \meta{boolean} is \texttt{true}. +% \end{function} +% +% \begin{function}[EXP]{\bool_while_do:Nn, \bool_while_do:cn} +% \begin{syntax} +% \cs{bool_while_do:Nn} \Arg{boolean} \Arg{code} +% \end{syntax} +% This function firsts checks the logical value of the \meta{boolean}. +% If it is \texttt{true} the \meta{code} is placed in the input stream +% and expanded. After the completion of the \meta{code} the truth +% of the \meta{boolean} is re-evaluated. The process will then loop +% until the \meta{boolean} is \texttt{false}. +% \end{function} +% +% \begin{function}[EXP]{\bool_until_do:nn} +% \begin{syntax} +% \cs{bool_until_do:nn} \Arg{boolean expression} \Arg{code} +% \end{syntax} +% This function firsts checks the logical value of the +% \meta{boolean expression} (as described for \cs{bool_if:nTF}). +% If it is \texttt{false} the \meta{code} is placed in the input stream +% and expanded. After the completion of the \meta{code} the truth +% of the \meta{boolean expression} is re-evaluated. The process will +% then loop until the \meta{boolean expression} is \texttt{true}. +% \end{function} +% +% \begin{function}[EXP]{\bool_while_do:nn} +% \begin{syntax} +% \cs{bool_while_do:nn} \Arg{boolean expression} \Arg{code} +% \end{syntax} +% This function firsts checks the logical value of the +% \meta{boolean expression} (as described for \cs{bool_if:nTF}). +% If it is \texttt{true} the \meta{code} is placed in the input stream +% and expanded. After the completion of the \meta{code} the truth +% of the \meta{boolean expression} is re-evaluated. The process will +% then loop until the \meta{boolean expression} is \texttt{false}. +% \end{function} +% +% \section{Switching by case} +% +% For cases where a number of cases need to be considered a family of +% case-selecting functions are available. +% +% \begin{function}[EXP]{\prg_case_int:nnn} +% \begin{syntax} +% \cs{prg_case_int:nnn} +% ~~\Arg{test integer expression} +% ~~|{| +% ~~~~\Arg{intexpr case1} \Arg{code case1} +% ~~~~\Arg{intexpr case2} \Arg{code case2} +% ~~~~\ldots +% ~~~~\Arg{intexpr case$_n$} \Arg{code case$_n$} +% ~~|}| +% ~~\Arg{else case} +% \end{syntax} +% This function evaluates the \meta{test integer expression} and +% compares this in turn to each of the +% \meta{integer expression cases}. If the two are equal then the +% associated \meta{code} is left in the input stream. If none of +% the tests are \texttt{true} then the \texttt{else code} will be +% left in the input stream. For example +% \begin{verbatim} +% \prg_case_int:nnn +% { 2 * 5 } +% { +% { 5 } { Small } +% { 4 + 6 } { Medium } +% { -2 * 10 } { Negative } +% } +% { No idea! } +% \end{verbatim} +% will leave \enquote{\texttt{Medium}} in the input stream. +% \end{function} +% +% \begin{function}[EXP]{\prg_case_dim:nnn} +% \begin{syntax} +% \cs{prg_case_dim:nnn} +% ~~\Arg{test dimension expression} +% ~~|{| +% ~~~~\Arg{dimexpr case1} \Arg{code case1} +% ~~~~\Arg{dimexpr case2} \Arg{code case2} +% ~~~~\ldots +% ~~~~\Arg{dimexpr case$_n$} \Arg{code case$_n$} +% ~~|}| +% ~~\Arg{else case} +% \end{syntax} +% This function evaluates the \meta{test dimension expression} and +% compares this in turn to each of the +% \meta{dimension expression cases}. If the two are equal then the +% associated \meta{code} is left in the input stream. If none of +% the tests are \texttt{true} then the \texttt{else code} will be +% left in the input stream. +% \end{function} +% +% \begin{function}[EXP] +% {\prg_case_str:nnn, \prg_case_str:onn, \prg_case_str:xxn} +% \begin{syntax} +% \cs{prg_case_str:nnn} +% ~~\Arg{test string} +% ~~|{| +% ~~~~\Arg{string case1} \Arg{code case1} +% ~~~~\Arg{string case2} \Arg{code case2} +% ~~~~\ldots +% ~~~~\Arg{string case$_n$} \Arg{code case$_n$} +% ~~|}| +% ~~\Arg{else case} +% \end{syntax} +% This function compares the \meta{test string} in turn with each +% of the \meta{string cases}. If the two are equal (as described for +% \cs{str_if_eq:nnTF} then the +% associated \meta{code} is left in the input stream. If none of +% the tests are \texttt{true} then the \texttt{else code} will be +% left in the input stream. The |xx| variant is fully expandable, +% in the same way as the underlying \cs{str_if_eq:xxTF} test. +% \end{function} +% +% \begin{function}[EXP]{\prg_case_tl:Nnn, \prg_case_tl:cnn} +% \begin{syntax} +% \cs{prg_case_tl:Nnn} +% ~~\meta{test token list variable} +% ~~"{" +% ~~~~\meta{token list variable case1} \Arg{code case1} +% ~~~~\meta{token list variable case2} \Arg{code case2} +% ~~~~\ldots +% ~~~~\meta{token list variable case$_n$} \Arg{code case$_n$} +% ~~"}" +% ~~\Arg{else case} +% \end{syntax} +% This function compares the \meta{test token list variable} in turn +% with each of the \meta{token list variable cases}. If the two +% are equal (as described for +% \cs{tl_if_eq:nnTF} +% then the associated \meta{code} is left in the input +% stream. If none of the tests are \texttt{true} then the +% \texttt{else code} will be left in the input stream. +% \end{function} +% +% \section{Producing $n$ copies} +% +% \begin{function}[EXP]{\prg_replicate:nn} +% \begin{syntax} +% \cs{prg_replicate:nn} \Arg{integer expression} \Arg{tokens} +% \end{syntax} +% Evaluates the \meta{integer expression} (which should be +% zero or positive) and creates the resulting number of copies +% of the \meta{tokens}. The function is both expandable and safe for +% nesting. It yields its result after two expansion steps. +% \end{function} +% +% \begin{function}[EXP]{\prg_stepwise_function:nnnN} +% \begin{syntax} +% \cs{prg_stepwise_function:nnnN} \Arg{initial value} \Arg{step} +% ~~\Arg{final value} \meta{function} +% \end{syntax} +% This function first evaluates the \meta{initial value}, \meta{step} +% and \meta{final value}, all of which should be integer expressions. +% The \meta{function} is then placed in front of each \meta{value} +% from the \meta{initial value} to the \meta{final value} in turn +% (using \meta{step} between each \meta{value}). Thus \meta{function} +% should absorb one numerical argument. For example +% \begin{verbatim} +% \cs_set_nopar:Npn \my_func:n #1 { I~saw~#1 \\ } +% \prg_stepwise_function:nnnN { 1 } { 5 } { 1 } \my_func:n +% \end{verbatim} +% would print +% \begin{quote} +% I saw 1 \\ +% I saw 2 \\ +% I saw 3 \\ +% I saw 4 \\ +% I saw 5 \\ +% \end{quote} +% \end{function} +% +% \begin{function}{\prg_stepwise_inline:nnnn} +% \begin{syntax} +% \cs{prg_stepwise_inline:nnnn} \Arg{initial value} \Arg{step} +% ~~\Arg{final value} \Arg{code} +% \end{syntax} +% This function first evaluates the \meta{initial value}, \meta{step} +% and \meta{final value}, all of which should be integer expressions. +% The \meta{code} is then placed in front of each \meta{value} +% from the \meta{initial value} to the \meta{final value} in turn +% (using \meta{step} between each \meta{value}). Thus the \meta{code} +% should define a function of one argument (|#1|). +% \end{function} +% +% \begin{function}{\prg_stepwise_variable:nnnn} +% \begin{syntax} +% \cs{prg_stepwise_inline:nnnn} \Arg{initial value} \Arg{step} +% ~~\Arg{final value} \meta{tl~var} \Arg{code} +% \end{syntax} +% This function first evaluates the \meta{initial value}, \meta{step} +% and \meta{final value}, all of which should be integer expressions. +% The \meta{code} is inserted into the input stream, with the +% \meta{tl~var} defined as the current \meta{value}. Thus the +% \meta{code} should make use of the \meta{tl~var}. +% \end{function} +% +% \section{Detecting \TeX{}'s mode} +% +% \begin{function}[EXP,pTF]{\mode_if_horizontal:} +% \begin{syntax} +% \cs{mode_if_horizontal_p:} +% \cs{mode_if_horizontal:TF} \Arg{true code} \Arg{false code} +% \end{syntax} +% Detects if \TeX{} is currently in horizontal mode. The branching +% versions then leave either \meta{true code} or \meta{false code} +% in the input stream, as appropriate to the truth of the test and +% the variant of the function chosen. The logical truth of the test +% is left in the input stream by the predicate version. +% \end{function} +% +% \begin{function}[EXP,pTF]{\mode_if_inner:} +% \begin{syntax} +% \cs{mode_if_inner_p:} +% \cs{mode_if_inner:TF} \Arg{true code} \Arg{false code} +% \end{syntax} +% Detects if \TeX{} is currently in inner mode. The branching +% versions then leave either \meta{true code} or \meta{false code} +% in the input stream, as appropriate to the truth of the test and +% the variant of the function chosen. The logical truth of the test +% is left in the input stream by the predicate version. +% \end{function} +% +% \begin{function}[EXP,TF]{\mode_if_math:} +% \begin{syntax} +% \cs{mode_if_math:TF} \Arg{true code} \Arg{false code} +% \end{syntax} +% Detects if \TeX{} is currently in maths mode. The branching +% versions then leave either \meta{true code} or \meta{false code} +% in the input stream, as appropriate to the truth of the test and +% the variant of the function chosen. +% \end{function} +% +% \begin{function}[EXP,pTF]{\mode_if_vertical:} +% \begin{syntax} +% \cs{mode_if_vertical_p:} +% \cs{mode_if_vertical:TF} \Arg{true code} \Arg{false code} +% \end{syntax} +% Detects if \TeX{} is currently in vertical mode. The branching +% versions then leave either \meta{true code} or \meta{false code} +% in the input stream, as appropriate to the truth of the test and +% the variant of the function chosen. The logical truth of the test +% is left in the input stream by the predicate version. +% \end{function} +% +% \section{Internal programming functions} +% +% \begin{function}[EXP]{\group_align_safe_begin:, \group_align_safe_end:} +% \begin{syntax} +% \cs{group_align_safe_begin:} +% \ldots +% \cs{group_align_safe_end:} +% \end{syntax} +% These functions are used to enclose material in a \TeX{} alignment +% environment within a specially-constructed group. This group is +% designed in such a way that it does not add brace groups to the +% output but does act as a group for the |&| token inside +% \cs{tex_halign:D}. This is necessary to allow grabbing of tokens +% for testing purposes, as \TeX{} uses group level to determine the +% effect of alignment tokens. Without the special grouping, the use of +% a function such as \cs{peek_after:Nw} will result in a forbidden +% comparison of the internal \cs{endtemplate} token, yielding a +% fatal error. Each \cs{group_align_safe_begin:} must be matched by a +% \cs{group_align_safe_end:}, although this does not have to occur +% within the same function. +% \end{function} +% +% \begin{function}{\scan_align_safe_stop:} +% \begin{syntax} +% \cs{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}[EXP]{\prg_variable_get_scope:N} +% \begin{syntax} +% \cs{prg_variable_get_scope:N} \meta{variable} +% \end{syntax} +% Returns the scope (\texttt{g} for global, blank otherwise) for the +% \meta{variable}. +% \end{function} +% +% \begin{function}[EXP]{\prg_variable_get_type:N} +% \begin{syntax} +% \cs{prg_variable_get_type:N} \meta{variable} +% \end{syntax} +% Returns the type of \meta{variable} (\texttt{tl}, \texttt{int}, +% \emph{etc.}) +% \end{function} +% +% \section{Experimental programmings functions} +% +% \begin{function}{\prg_quicksort:n} +% \begin{syntax} +% \cs{prg_quicksort:n} |{| \Arg{item~1} \Arg{item~2} \dots \Arg{item~n} |}| +% \end{syntax} +% Performs a quicksort on the token list. The comparisons are +% performed by the function \cs{prg_quicksort_compare:nnTF} which is up +% to the programmer to define. When the sorting process is over, all +% items are given as argument to the function +% \cs{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" \Arg{element} \\ +% "\prg_quicksort_compare:nnTF" \Arg{element 1} \Arg{element 2}\\ +% \end{syntax} +% The two functions the programmer must define before calling +% |\prg_quicksort:n|. As an example we could define +% \begin{quote} +% |\cs_set_nopar:Npn\prg_quicksort_function:n #1{{#1}}|\\ +% |\cs_set_nopar:Npn\prg_quicksort_compare:nnTF #1#2#3#4 {\int_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} +% |\cs_set_nopar:Npn\prg_quicksort_compare:nnTF #1#2 {|\\ +% | \int_compare:nNnTF{\tl_compare:nn{#1}{#2}}>\c_zero }| +% \end{quote} +% +% \end{function} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{l3prg} implementation} +% +% \TestFiles{m3prg001.lvt,m3prg002.lvt,m3prg003.lvt} +%% +% \begin{macrocode} +%<*initex|package> +% \end{macrocode} +% +% \begin{macrocode} +%<*package> +\ProvidesExplPackage + {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +\package_check_loaded_expl: +%</package> +% \end{macrocode} +% +% \subsection{Defining a set of conditional functions} +% +% \begin{macro} +% { +% \prg_set_conditional:Npnn, +% \prg_new_conditional:Npnn, +% \prg_set_protected_conditional:Npnn, +% \prg_new_protected_conditional:Npnn +% } +% \begin{macro} +% { +% \prg_set_conditional:Nnn, +% \prg_new_conditional:Nnn, +% \prg_set_protected_conditional:Nnn, +% \prg_new_protected_conditional:Nnn +% } +% \begin{macro}{\prg_set_eq_conditional:NNn, \prg_new_eq_conditional:NNn} +% \begin{macro}{\prg_return_true:} +% \TestMissing +% {This function is implicitly tested with all other conditionals!} +% \begin{macro}{\prg_return_false:} +% \TestMissing +% {This function is also implicitly tested with all other conditionals!} +% These are all defined in \pkg{l3basics}, as they are needed +% \enquote{early}. This is just a reminder that that is the case! +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{The boolean data type} +% +% \begin{macro}{\bool_new:N, \bool_new:c} +% \UnitTested +% Boolean variables have to be initiated when they are created. Other +% than that there is not much to say here. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \bool_new:N #1 { \cs_new_eq:NN #1 \c_false_bool } +\cs_generate_variant:Nn \bool_new:N { c } +% \end{macrocode} +% \end{macro} +% +% \begin{macro} +% { +% \bool_set_true:N, \bool_set_true:c, +% \bool_gset_true:N, \bool_gset_true:c, +% \bool_set_false:N, \bool_set_false:c, +% \bool_gset_false:N, \bool_gset_false:c +% } +% \UnitTested +% Setting is already pretty easy. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \bool_set_true:N #1 + { \cs_set_eq:NN #1 \c_true_bool } +\cs_new_protected_nopar:Npn \bool_set_false:N #1 + { \cs_set_eq:NN #1 \c_false_bool } +\cs_new_protected_nopar:Npn \bool_gset_true:N #1 + { \cs_gset_eq:NN #1 \c_true_bool } +\cs_new_protected_nopar:Npn \bool_gset_false:N #1 + { \cs_gset_eq:NN #1 \c_false_bool } +\cs_generate_variant:Nn \bool_set_true:N { c } +\cs_generate_variant:Nn \bool_set_false:N { c } +\cs_generate_variant:Nn \bool_gset_true:N { c } +\cs_generate_variant:Nn \bool_gset_false:N { c } +% \end{macrocode} +% \end{macro} +% +% \begin{macro} +% { +% \bool_set_eq:NN, \bool_set_eq:cN, +% \bool_set_eq:Nc, \bool_set_eq:cc, +% \bool_gset_eq:NN, \bool_gset_eq:cN, +% \bool_gset_eq:Nc, \bool_gset_eq:cc +% } +% \UnitTested +% The usual copy code. +% \begin{macrocode} +\cs_new_eq:NN \bool_set_eq:NN \cs_set_eq:NN +\cs_new_eq:NN \bool_set_eq:Nc \cs_set_eq:Nc +\cs_new_eq:NN \bool_set_eq:cN \cs_set_eq:cN +\cs_new_eq:NN \bool_set_eq:cc \cs_set_eq:cc +\cs_new_eq:NN \bool_gset_eq:NN \cs_gset_eq:NN +\cs_new_eq:NN \bool_gset_eq:Nc \cs_gset_eq:Nc +\cs_new_eq:NN \bool_gset_eq:cN \cs_gset_eq:cN +\cs_new_eq:NN \bool_gset_eq:cc \cs_gset_eq:cc +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\bool_set:Nn,\bool_set:cn} +% \begin{macro}{\bool_gset:Nn,\bool_gset:cn} +% This function evaluates a boolean expression and assigns the first +% argument the meaning |\c_true_bool| or |\c_false_bool|. +% \begin{macrocode} +\cs_new:Npn \bool_set:Nn #1#2 + { \tex_chardef:D #1 = \bool_if_p:n {#2} } +\cs_new:Npn \bool_gset:Nn #1#2 + { \tex_global:D \tex_chardef:D #1 = \bool_if_p:n {#2} } +\cs_generate_variant:Nn \bool_set:Nn { c } +\cs_generate_variant:Nn \bool_gset:Nn { c } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[pTF]{\bool_if:N, \bool_if:c} +% \UnitTested +% Straight forward here. We could optimize here if we wanted to as +% the boolean can just be input directly. +% \begin{macrocode} +\prg_new_conditional:Npnn \bool_if:N #1 { p , T , F , TF } + { + \if_bool:N #1 + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +\cs_generate_variant:Nn \bool_if_p:N { c } +\cs_generate_variant:Nn \bool_if:NT { c } +\cs_generate_variant:Nn \bool_if:NF { c } +\cs_generate_variant:Nn \bool_if:NTF { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{variable}{\l_tmpa_bool, \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{variable} +% +% \subsection{Boolean expressions} +% +% \begin{macro}[pTF]{\bool_if:n} +% \UnitTested +% \begin{macro}[aux]{\bool_get_next:N} +% \begin{macro}[aux]{\bool_cleanup:N} +% \begin{macro}[aux]{\bool_choose:NN} +% \begin{macro}[aux] +% { +% bool_!:w, +% \bool_Not:w, +% \bool_Not:w, +% \bool_(:w, +% \bool_p:w, +% \bool_8_1:w, +% \bool_I_1:w, +% \bool_8_0:w, +% \bool_I_0:w, +% \bool_)_0:w, +% \bool_)_1:w, +% \bool_S_0:w, +% \bool_S_1:w +% } +% \begin{macro}[aux] +% { +% \bool_eval_skip_to_end:Nw, \bool_eval_skip_to_end_aux:Nw, +% \bool_eval_skip_to_end_aux_ii:Nw +% } +% Evaluating the truth value of a list of predicates is done using +% an input syntax somewhat similar to the one found in other +% programming languages with |(| and |)| for grouping, |!| for +% logical \enquote{Not}, |&&| for logical \enquote{And} and \verb"||" +% for logical \enquote{Or}. We shall use the terms Not, And, Or, Open and +% Close for these operations. +% +% Any expression is terminated by a Close operation. Evaluation +% happens from left to right in the following manner using a GetNext +% function: +% \begin{itemize} +% \item If an Open is seen, start evaluating a new expression using +% the Eval function and call GetNext again. +% \item If a Not is seen, insert a negating function (if-even in +% this case) and call GetNext. +% \item If none of the above, start evaluating a new expression by +% reinserting the token found (this is supposed to be a predicate +% function) in front of Eval. +% \end{itemize} +% The Eval function then contains a post-processing operation which +% grabs the instruction following the predicate. This is either And, +% Or or Close. In each case the truth value is used to determine +% where to go next. The following situations can arise: +% \begin{description} +% \item[\meta{true}And] Current truth value is true, logical And +% seen, continue with GetNext to examine truth value of next +% boolean (sub-)expression. +% \item[\meta{false}And] Current truth value is false, logical And +% seen, stop evaluating the predicates within this sub-expression +% and break to the nearest Close. Then return \meta{false}. +% \item[\meta{true}Or] Current truth value is true, logical Or +% seen, stop evaluating the predicates within this sub-expression +% and break to the nearest Close. Then return \meta{true}. +% \item[\meta{false}Or] Current truth value is false, logical Or +% seen, continue with GetNext to examine truth value of next +% boolean (sub-)expression. +% \item[\meta{true}Close] Current truth value is true, Close +% seen, return \meta{true}. +% \item[\meta{false}Close] Current truth value is false, Close +% seen, return \meta{false}. +% \end{description} +% We introduce an additional Stop operation with the following +% semantics: +% \begin{description} +% \item[\meta{true}Stop] Current truth value is true, return +% \meta{true}. +% \item[\meta{false}Stop] Current truth value is false, return +% \meta{false}. +% \end{description} +% The reasons for this follow below. +% +% Now for how these works in practice. The canonical true and false +% values have numerical values $1$ and $0$ respectively. We evaluate +% this using the primitive |\int_value:w:D| operation. First we +% issue a |\group_align_safe_begin:| as we are using |&&| as syntax +% shorthand for the And operation and we need to hide it for \TeX{}. +% We also need to finish this special group before finally +% returning a |\c_true_bool| or |\c_false_bool| as there might +% otherwise be something left in front in the input stream. For +% this we call the Stop operation, denoted simply by a |S| +% following the last Close operation. +% \begin{macrocode} +\prg_new_conditional:Npnn \bool_if:n #1 { T , F , TF } + { + \if_predicate:w \bool_if_p:n {#1} + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +\cs_new:Npn \bool_if_p:n #1 + { + \group_align_safe_begin: + \bool_get_next:N ( #1 ) S + } +% \end{macrocode} +% The GetNext operation. We make it a switch: If not a |!| or |(|, we +% assume it is a predicate. +% \begin{macrocode} +\cs_new:Npn \bool_get_next:N #1 + { + \use:c + { + bool_ + \if_meaning:w !#1 ! \else: \if_meaning:w (#1 ( \else: p \fi: \fi: + :w + } + #1 + } +% \end{macrocode} +% This variant gets called when a Not has just been entered. +% It (eventually) results in a reversal of the logic of the directly +% following material. +% \begin{macrocode} +\cs_new:Npn \bool_get_not_next:N #1 + { + \use:c + { + bool_not_ + \if_meaning:w !#1 ! \else: \if_meaning:w (#1 ( \else: p \fi: \fi: + :w + } + #1 + } +% \end{macrocode} +% We need these later on to nullify the unity operation |!!|. +% \begin{macrocode} +\cs_new:Npn \bool_get_next:NN #1#2 { \bool_get_next:N #2 } +\cs_new:Npn \bool_get_not_next:NN #1#2 { \bool_get_not_next:N #2 } +% \end{macrocode} +% The Not operation. Discard the token read and reverse the truth +% value of the next expression if there +% are brackets; otherwise +% if we're coming up to a |!| then we don't need to reverse anything +% (but we then want to continue scanning ahead in case some fool has written +% |!!(...)|); +% otherwise we have a boolean that we can reverse here and now. +% \begin{macrocode} +\cs_new:cpn { bool_!:w } #1#2 + { + \if_meaning:w ( #2 + \exp_after:wN \bool_Not:w + \else: + \if_meaning:w ! #2 + \exp_after:wN \exp_after:wN \exp_after:wN \bool_get_next:NN + \else: + \exp_after:wN \exp_after:wN \exp_after:wN \bool_Not:N + \fi: + \fi: + #2 + } +% \end{macrocode} +% Variant called when already inside a Not. +% Essentially the opposite of the above. +% \begin{macrocode} +\cs_new:cpn { bool_not_!:w } #1#2 + { + \if_meaning:w ( #2 + \exp_after:wN \bool_not_Not:w + \else: + \if_meaning:w ! #2 + \exp_after:wN \exp_after:wN \exp_after:wN \bool_get_not_next:NN + \else: + \exp_after:wN \exp_after:wN \exp_after:wN \bool_not_Not:N + \fi: + \fi: + #2 + } +% \end{macrocode} +% These occur when processing |!(...)|. The idea is to use a variant +% of |\bool_get_next:N| that finishes its parsing with a logic reversal. +% Of course, the double logic reversal gets us back to where we started. +% \begin{macrocode} +\cs_new:Npn \bool_Not:w { \exp_after:wN \int_value:w \bool_get_not_next:N } +\cs_new:Npn \bool_not_Not:w { \exp_after:wN \int_value:w \bool_get_next:N } +% \end{macrocode} +% These occur when processing |!<bool>| and can be evaluated directly. +% \begin{macrocode} +\cs_new:Npn \bool_Not:N #1 + { + \exp_after:wN \bool_p:w + \if_meaning:w #1 \c_true_bool + \c_false_bool + \else: + \c_true_bool + \fi: + } +\cs_new:Npn \bool_not_Not:N #1 + { + \exp_after:wN \bool_p:w + \if_meaning:w #1 \c_true_bool + \c_true_bool + \else: + \c_false_bool + \fi: + } +% \end{macrocode} +% The Open operation. Discard the token read and start a +% sub-expression. +% |\bool_get_next:N| continues building up the logical expressions as usual; +% |\bool_not_cleanup:N| is what reverses the logic if we're inside |!(...)|. +% \begin{macrocode} +\cs_new:cpn { bool_(:w } #1 + { \exp_after:wN \bool_cleanup:N \int_value:w \bool_get_next:N } +\cs_new:cpn { bool_not_(:w } #1 + { \exp_after:wN \bool_not_cleanup:N \int_value:w \bool_get_next:N } +% \end{macrocode} +% Otherwise just evaluate the predicate and look for And, Or or Close +% afterwards. +% \begin{macrocode} +\cs_new:cpn { bool_p:w } { \exp_after:wN \bool_cleanup:N \int_value:w } +\cs_new:cpn { bool_not_p:w } {\exp_after:wN \bool_not_cleanup:N \int_value:w } +% \end{macrocode} +% This cleanup function can be omitted once predicates return their +% true/false booleans outside the conditionals. +% \begin{macrocode} +\cs_new:Npn \bool_cleanup:N #1 + { + \exp_after:wN \bool_choose:NN \exp_after:wN #1 + \int_to_roman:w - `\q + } +\cs_new:Npn \bool_not_cleanup:N #1 + { + \exp_after:wN \bool_not_choose:NN \exp_after:wN #1 + \int_to_roman:w - `\q + } +% \end{macrocode} +% Branching the six way switch. +% Reversals should be reasonably straightforward. +% \begin{macrocode} +\cs_new_nopar:Npn \bool_choose:NN #1#2 { \use:c { bool_ #2 _ #1 :w } } +\cs_new_nopar:Npn \bool_not_choose:NN #1#2 { \use:c { bool_not_ #2 _ #1 :w } } +% \end{macrocode} +% Continues scanning. Must remove the second "&" or \verb"|". +% \begin{macrocode} +\cs_new_nopar:cpn { bool_&_1:w } & { \bool_get_next:N } +\cs_new_nopar:cpn { bool_|_0:w } | { \bool_get_next:N } +\cs_new_nopar:cpn { bool_not_&_0:w } & { \bool_get_next:N } +\cs_new_nopar:cpn { bool_not_|_1:w } | { \bool_get_next:N } +% \end{macrocode} +% Closing a group is just about returning the result. The Stop +% operation is similar except it closes the special alignment group +% before returning the boolean. +% \begin{macrocode} +\cs_new_nopar:cpn { bool_)_0:w } { \c_false_bool } +\cs_new_nopar:cpn { bool_)_1:w } { \c_true_bool } +\cs_new_nopar:cpn { bool_not_)_0:w } { \c_true_bool } +\cs_new_nopar:cpn { bool_not_)_1:w } { \c_false_bool } +\cs_new_nopar:cpn { bool_S_0:w } { \group_align_safe_end: \c_false_bool } +\cs_new_nopar:cpn { bool_S_1:w } { \group_align_safe_end: \c_true_bool } +% \end{macrocode} +% When the truth value has already been decided, we have to throw away +% the remainder of the current group as we are doing minimal +% evaluation. This is slightly tricky as there are no braces so we +% have to play match the |()| manually. +% \begin{macrocode} +\cs_new_nopar:cpn { bool_&_0:w } & { \bool_eval_skip_to_end:Nw \c_false_bool } +\cs_new_nopar:cpn { bool_|_1:w } | { \bool_eval_skip_to_end:Nw \c_true_bool } +\cs_new_nopar:cpn { bool_not_&_1:w } & + { \bool_eval_skip_to_end:Nw \c_false_bool } +\cs_new_nopar:cpn { bool_not_|_0:w } | + { \bool_eval_skip_to_end:Nw \c_true_bool } +% \end{macrocode} +% There is always at least one |)| waiting, namely the outer +% one. However, we are facing the problem that there may be more than +% one that need to be finished off and we have to detect the correct +% number of them. Here is a complicated example showing how this is +% done. After evaluating the following, we realize we must skip +% everything after the first And. Note the extra Close at the end. +% \begin{quote} +% |\c_false_bool && ((abc) && xyz) && ((xyz) && (def)))| +% \end{quote} +% First read up to the first Close. This gives us the list we first +% read up until the first right parenthesis so we are looking at the +% token list +% \begin{quote} +% |((abc| +% \end{quote} +% This contains two Open markers so we must remove two groups. Since +% no evaluation of the contents is to be carried out, it doesn't +% matter how we remove the groups as long as we wind up with the +% correct result. We therefore first remove a |()| pair and what +% preceded the Open -- but leave the contents as it may contain Open +% tokens itself -- leaving +% \begin{quote} +% |(abc && xyz) && ((xyz) && (def)))| +% \end{quote} +% Another round of this gives us +% \begin{quote} +% |(abc && xyz| +% \end{quote} +% which still contains an Open so we remove another |()| pair, giving us +% \begin{quote} +% |abc && xyz && ((xyz) && (def)))| +% \end{quote} +% Again we read up to a Close and again find Open tokens: +% \begin{quote} +% |abc && xyz && ((xyz| +% \end{quote} +% Further reduction gives us +% \begin{quote} +% |(xyz && (def)))| +% \end{quote} +% and then +% \begin{quote} +% |(xyz && (def| +% \end{quote} +% with reduction to +% \begin{quote} +% |xyz && (def))| +% \end{quote} +% and ultimately we arrive at no Open tokens being skipped and we can +% finally close the group nicely. +% \begin{macrocode} +%% ( +\cs_new:Npn \bool_eval_skip_to_end:Nw #1#2 ) + { + \bool_eval_skip_to_end_aux:Nw #1#2 ( % ) + \q_no_value \q_stop + {#2} + } +% \end{macrocode} +% If no right parenthesis, then |#3| is no_value and we are done, return +% the boolean |#1|. If there is, we need to grab a |()| pair and then +% recurse +% \begin{macrocode} +\cs_new:Npn \bool_eval_skip_to_end_aux:Nw #1#2 ( #3#4 \q_stop #5 % ) + { + \quark_if_no_value:NTF #3 + {#1} + { \bool_eval_skip_to_end_aux_ii:Nw #1 #5 } + } +% \end{macrocode} +% Keep the boolean, throw away anything up to the |(| as it is +% irrelevant, remove a |()| pair but remember to reinsert |#3| as it may +% contain |(| tokens! +% \begin{macrocode} +\cs_new:Npn \bool_eval_skip_to_end_aux_ii:Nw #1#2 ( #3 ) + { % ( + \bool_eval_skip_to_end:Nw #1#3 ) + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\bool_not_p:n} +% \UnitTested +% The Not variant just reverses the outcome of |\bool_if_p:n|. Can +% be optimized but this is nice and simple and according to the +% implementation plan. Not even particularly useful to have it when +% the infix notation is easier to use. +% \begin{macrocode} +\cs_new:Npn \bool_not_p:n #1 { \bool_if_p:n { ! ( #1 ) } } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\bool_xor_p:nn} +% \UnitTested +% Exclusive or. If the boolean expressions have same truth value, +% return false, otherwise return true. +% \begin{macrocode} +\cs_new:Npn \bool_xor_p:nn #1#2 + { + \int_compare:nNnTF { \bool_if_p:n {#1} } = { \bool_if_p:n {#2} } + \c_false_bool + \c_true_bool + } +% \end{macrocode} +% \end{macro} +% +% \subsection{Logical loops} +% +% \begin{macro}{\bool_while_do:Nn,\bool_while_do:cn} +% \UnitTested +% \begin{macro}{\bool_until_do:Nn,\bool_until_do:cn} +% \UnitTested +% A |while| loop where the boolean is tested before executing the +% statement. The \enquote{while} version executes the code as long as the +% boolean is true; the \enquote{until} version executes the code as +% long as the boolean is false. +% \begin{macrocode} +\cs_new:Npn \bool_while_do:Nn #1#2 + { \bool_if:NT #1 { #2 \bool_while_do:Nn #1 {#2} } } +\cs_new:Npn \bool_until_do:Nn #1#2 + { \bool_if:NF #1 { #2 \bool_until_do:Nn #1 {#2} } } +\cs_generate_variant:Nn \bool_while_do:Nn { c } +\cs_generate_variant:Nn \bool_until_do:Nn { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\bool_do_while:Nn,\bool_do_while:cn} +% \UnitTested +% \begin{macro}{\bool_do_until:Nn,\bool_do_until:cn} +% \UnitTested +% 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} +\cs_new:Npn \bool_do_while:Nn #1#2 + { #2 \bool_if:NT #1 { \bool_do_while:Nn #1 {#2} } } +\cs_new:Npn \bool_do_until:Nn #1#2 + { #2 \bool_if:NF #1 { \bool_do_until:Nn #1 {#2} } } +\cs_generate_variant:Nn \bool_do_while:Nn { c } +\cs_generate_variant:Nn \bool_do_until:Nn { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro} +% { +% \bool_while_do:nn, \bool_do_while:nn , +% \bool_until_do:nn, \bool_do_until:nn +% } +% \UnitTested +% Loop functions with the test either before or after the first body +% expansion. +% \begin{macrocode} +\cs_new:Npn \bool_while_do:nn #1#2 + { + \bool_if:nT {#1} + { + #2 + \bool_while_do:nn {#1} {#2} + } + } +\cs_new:Npn \bool_do_while:nn #1#2 + { + #2 + \bool_if:nT {#1} { \bool_do_while:nn {#1} {#2} } + } +\cs_new:Npn \bool_until_do:nn #1#2 + { + \bool_if:nF {#1} + { + #2 + \bool_until_do:nn {#1} {#2} + } + } +\cs_new:Npn \bool_do_until:nn #1#2 + { + #2 + \bool_if:nF {#1} { \bool_do_until:nn {#1} {#2} } + } +% \end{macrocode} +% \end{macro} +% +% \subsection{Switching by case} +% +% A family of functions to select one case of a number: the same ideas +% are used for a number of different situations. +% +% \begin{macro}[aux]{\prg_case_end:nw} +% In all cases the end statement is the same. Here, |#1| will be the +% code needed, |#2| the other cases to throw away, including the +% \enquote{else} case. +% \begin{macrocode} +\cs_new_eq:NN \prg_case_end:nw \use_i_delimit_by_q_recursion_stop:nw +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\prg_case_int:nnn} +% \UnitTested +% \begin{macro}[aux]{\prg_case_int_aux:nnn,\prg_case_int_aux:nw} +% For integer cases, the first task to fully expand the check +% condition. After that, a loop is started to compare each possible +% value and stop if the test is true. The tested value is put at the +% end to ensure that there is necessarily a match, which will fire the +% \enquote{else} pathway. +% \begin{macrocode} +\cs_new:Npn \prg_case_int:nnn #1 + { \exp_args:Nf \prg_case_int_aux:nnn { \int_eval:n {#1} } } +\cs_new:Npn \prg_case_int_aux:nnn #1 #2 #3 + { \prg_case_int_aux:nw {#1} #2 {#1} {#3} \q_recursion_stop } +\cs_new:Npn \prg_case_int_aux:nw #1#2#3 + { + \int_compare:nNnTF {#1} = {#2} + { \prg_case_end:nw {#3} } + { \prg_case_int_aux:nw {#1} } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\prg_case_dim:nnn} +% \UnitTested +% \begin{macro}[aux]{\prg_case_dim_aux:nnn,\prg_case_dim_aux:nw} +% The dimension function is the same, just a change of calculation +% method. +% \begin{macrocode} +\cs_new:Npn \prg_case_dim:nnn #1 + { \exp_args:Nf \prg_case_dim_aux:nnn { \dim_eval:n {#1} } } +\cs_new:Npn \prg_case_dim_aux:nnn #1 #2 #3 + { \prg_case_dim_aux:nw {#1} #2 {#1} {#3} \q_recursion_stop } +\cs_new:Npn \prg_case_dim_aux:nw #1#2#3 + { + \dim_compare:nNnTF {#1} = {#2} + { \prg_case_end:nw {#3} } + { \prg_case_dim_aux:nw {#1} } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\prg_case_str:nnn, \prg_case_str:onn, \prg_case_str:xxn} +% \UnitTested +% \begin{macro}[aux]{\prg_case_str_aux:nw, \prg_case_str_x_aux:nw} +% No calculations for strings, otherwise no surprises. +% \begin{macrocode} +\cs_new:Npn \prg_case_str:nnn #1#2#3 + { \prg_case_str_aux:nw {#1} #2 {#1} {#3} \q_recursion_stop } +\cs_new:Npn \prg_case_str_aux:nw #1#2#3 + { + \str_if_eq:nnTF {#1} {#2} + { \prg_case_end:nw {#3} } + { \prg_case_str_aux:nw {#1} } + } +\cs_generate_variant:Nn \prg_case_str:nnn { o } +\cs_new:Npn \prg_case_str:xxn #1#2#3 + { \prg_case_str_x_aux:nw {#1} #2 {#1} {#3} \q_recursion_stop } +\cs_new:Npn \prg_case_str_x_aux:nw #1#2#3 + { + \str_if_eq:xxTF {#1} {#2} + { \prg_case_end:nw {#3} } + { \prg_case_str_aux:nw {#1} } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\prg_case_tl:Nnn, \prg_case_tl:cnn} +% \UnitTested +% \begin{macro}[aux]{\prg_case_tl_aux:Nw} +% Similar again, but this time with some variants. +% \begin{macrocode} +\cs_new:Npn \prg_case_tl:Nnn #1#2#3 + { \prg_case_tl_aux:Nw #1 #2 #1 {#3} \q_recursion_stop } +\cs_new:Npn \prg_case_tl_aux:Nw #1#2#3 + { + \tl_if_eq:NNTF #1 #2 + { \prg_case_end:nw {#3} } + { \prg_case_tl_aux:Nw #1 } + } +\cs_generate_variant:Nn \prg_case_tl:Nnn { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Producing $n$ copies} +% +% \begin{macro}{\prg_replicate:nn} +% \UnitTested +% \begin{macro}[aux]{\prg_replicate_aux:N, \prg_replicate_first_aux:N} +% \begin{macro}[aux]{\prg_replicate_} +% \begin{macro}[aux] +% { +% \prg_replicate_0:n, +% \prg_replicate_1:n, +% \prg_replicate_2:n, +% \prg_replicate_3:n, +% \prg_replicate_4:n, +% \prg_replicate_5:n, +% \prg_replicate_6:n, +% \prg_replicate_7:n, +% \prg_replicate_8:n, +% \prg_replicate_9:n +% } +% \begin{macro}[aux] +% { +% \prg_replicate_first_-:n, +% \prg_replicate_first_0:n, +% \prg_replicate_first_1:n, +% \prg_replicate_first_2:n, +% \prg_replicate_first_3:n, +% \prg_replicate_first_4:n, +% \prg_replicate_first_5:n, +% \prg_replicate_first_6:n, +% \prg_replicate_first_7:n, +% \prg_replicate_first_8:n, +% \prg_replicate_first_9: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. These functions also close the expansion of +% \cs{int_to_roman:w}, which ensures that \cs{prg_replicate:nn} only +% requires two steps of expansion. +% +% 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, and if +% necessary, it is possible to write +% |\prg_replicate:nn{1000}{\prg_replicate:nn{1000}{|\meta{code}|}}|. An +% alternative approach is to create a string of |m|'s with +% \cs{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} +\cs_new_nopar:Npn \prg_replicate:nn #1 + { + \int_to_roman:w + \exp_after:wN \prg_replicate_first_aux:N + \int_value:w \int_eval:w #1 \int_eval_end: + \cs_end: + } +\cs_new_nopar:Npn \prg_replicate_aux:N #1 + { \cs:w prg_replicate_#1 :n \prg_replicate_aux:N } +\cs_new_nopar:Npn \prg_replicate_first_aux:N #1 + { \cs:w prg_replicate_first_ #1 :n \prg_replicate_aux:N } +% \end{macrocode} +% \end{macro} +% Then comes all the functions that do the hard work of inserting all +% the copies. +% \begin{macrocode} +\cs_new_nopar:Npn \prg_replicate_ :n #1 { \cs_end: } +\cs_new:cpn { prg_replicate_0:n } #1 { \cs_end: {#1#1#1#1#1#1#1#1#1#1} } +\cs_new:cpn { prg_replicate_1:n } #1 { \cs_end: {#1#1#1#1#1#1#1#1#1#1} #1 } +\cs_new:cpn { prg_replicate_2:n } #1 { \cs_end: {#1#1#1#1#1#1#1#1#1#1} #1#1 } +\cs_new:cpn { prg_replicate_3:n } #1 + { \cs_end: {#1#1#1#1#1#1#1#1#1#1} #1#1#1 } +\cs_new:cpn { prg_replicate_4:n } #1 + { \cs_end: {#1#1#1#1#1#1#1#1#1#1} #1#1#1#1 } +\cs_new:cpn { prg_replicate_5:n } #1 + { \cs_end: {#1#1#1#1#1#1#1#1#1#1} #1#1#1#1#1 } +\cs_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 } +\cs_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 } +\cs_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 } +\cs_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} +\cs_new:cpn { prg_replicate_first_-:n } #1 { \c_zero \negative_replication } +\cs_new:cpn { prg_replicate_first_0:n } #1 { \c_zero } +\cs_new:cpn { prg_replicate_first_1:n } #1 { \c_zero #1 } +\cs_new:cpn { prg_replicate_first_2:n } #1 { \c_zero #1#1 } +\cs_new:cpn { prg_replicate_first_3:n } #1 { \c_zero #1#1#1 } +\cs_new:cpn { prg_replicate_first_4:n } #1 { \c_zero #1#1#1#1 } +\cs_new:cpn { prg_replicate_first_5:n } #1 { \c_zero #1#1#1#1#1 } +\cs_new:cpn { prg_replicate_first_6:n } #1 { \c_zero #1#1#1#1#1#1 } +\cs_new:cpn { prg_replicate_first_7:n } #1 { \c_zero #1#1#1#1#1#1#1 } +\cs_new:cpn { prg_replicate_first_8:n } #1 { \c_zero #1#1#1#1#1#1#1#1 } +\cs_new:cpn { prg_replicate_first_9:n } #1 { \c_zero #1#1#1#1#1#1#1#1#1 } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\prg_stepwise_function:nnnN} +% \begin{macro}[aux] +% {\prg_stepwise_function_incr:nnnN, \prg_stepwise_function_decr:nnnN} +% Repeating a function by steps fist needs a check on the direction +% of the steps. After that, do the function for the start value +% then step and loop around. +% \begin{macrocode} +\cs_new:Npn \prg_stepwise_function:nnnN #1#2 + { + \int_compare:nNnTF {#2} > { 0 } + { \exp_args:Nf \prg_stepwise_function_incr:nnnN } + { \exp_args:Nf \prg_stepwise_function_decr:nnnN } + { \int_eval:n {#1} } {#2} + } +\cs_new:Npn \prg_stepwise_function_incr:nnnN #1#2#3#4 + { + \int_compare:nNnF {#1} > {#3} + { + #4 {#1} + \exp_args:Nf \prg_stepwise_function_incr:nnnN + { \int_eval:n { #1 + #2 } } {#2} {#3} #4 + } + } +\cs_new:Npn \prg_stepwise_function_decr:nnnN #1#2#3#4 + { + \int_compare:nNnF {#1} < {#3} + { + #4 {#1} + \exp_args:Nf \prg_stepwise_function_decr:nnnN + { \int_eval:n { #1 + #2 } } {#2} {#3} #4 + } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +%\begin{macro}[aux]{\g_prg_stepwise_level_int} +% For nesting, the usual approach of using a counter. +% \begin{macrocode} +\int_new:N \g_prg_stepwise_level_int +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\prg_stepwise_inline:nnnn} +%\begin{macro}[aux] +% {\prg_stepwise_inline_incr:Nnnn, \prg_stepwise_inline_decr:Nnnn} +% The approach here is similar but with a global integer required +% to make the nesting safe (as seen in other in line functions). +% \begin{macrocode} +\cs_new_protected:Npn \prg_stepwise_inline:nnnn #1#2#3#4 + { + \int_gincr:N \g_prg_stepwise_level_int + \cs_gset_nopar:cpn + { g_prg_stepwise_ \int_use:N \g_prg_stepwise_level_int :n } + ##1 {#4} + \int_compare:nNnTF {#2} > { 0 } + { \exp_args:Ncf \prg_stepwise_inline_incr:Nnnn } + { \exp_args:Ncf \prg_stepwise_inline_decr:Nnnn } + { g_prg_stepwise_ \int_use:N \g_prg_stepwise_level_int :n } + { \int_eval:n {#1} } {#2} {#3} + \int_gdecr:N \g_prg_stepwise_level_int + } +\cs_new_protected:Npn \prg_stepwise_inline_incr:Nnnn #1#2#3#4 + { + \int_compare:nNnF {#2} > {#4} + { + #1 {#2} + \exp_args:NNf \prg_stepwise_inline_incr:Nnnn #1 + { \int_eval:n { #2 + #3 } } {#3} {#4} + } + } +\cs_new_protected:Npn \prg_stepwise_inline_decr:Nnnn #1#2#3#4 + { + \int_compare:nNnF {#2} < {#4} + { + #1 {#2} + \exp_args:NNf \prg_stepwise_inline_decr:Nnnn #1 + { \int_eval:n { #2 + #3 } } {#3} {#4} + } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\prg_stepwise_variable:nnnNn} +% \UnitTested +% A wrapper for the above. +% \begin{macrocode} +\cs_new_protected:Npn \prg_stepwise_variable:nnnNn #1#2#3#4#5 + { + \prg_stepwise_inline:nnnn {#1} {#2} {#3} + { + \tl_set:Nn #4 {##1} + #5 + } + } +% \end{macrocode} +% \end{macro} +% +% \subsection{Detecting \TeX{}'s mode} +% +% \begin{macro}[pTF]{\mode_if_vertical:} +% \UnitTested +% For testing vertical mode. Strikes me here on the bus with David, +% that as long as we are just talking about returning true and +% false states, we can just use the primitive conditionals for this +% and gobbling the |\c_zero| in the input stream. However this +% requires knowledge of the implementation so we keep things nice +% and clean and use the return statements. +% \begin{macrocode} +\prg_new_conditional:Npnn \mode_if_vertical: { p , T , F , TF } + { \if_mode_vertical: \prg_return_true: \else: \prg_return_false: \fi: } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[pTF]{\mode_if_horizontal:} +% \UnitTested +% For testing horizontal mode. +% \begin{macrocode} +\prg_new_conditional:Npnn \mode_if_horizontal: { p , T , F , TF } + { \if_mode_horizontal: \prg_return_true: \else: \prg_return_false: \fi: } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[pTF]{\mode_if_inner:} +% \UnitTested +% For testing inner mode. +% \begin{macrocode} +\prg_new_conditional:Npnn \mode_if_inner: { p , T , F , TF } + { \if_mode_inner: \prg_return_true: \else: \prg_return_false: \fi: } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[pTF]{\mode_if_math:} +% \UnitTested +% For testing math mode: without \cs{} things go wrong in alignments. +% \begin{macrocode} +\prg_new_conditional:Npnn \mode_if_math: { p , T , F , TF } + { + \scan_align_safe_stop: + \if_mode_math: \prg_return_true: \else: \prg_return_false: \fi: + } +% \end{macrocode} +% \end{macro} +% +% \subsection{Internal programming functions} +% +% \begin{macro}[int]{\group_align_safe_begin:, \group_align_safe_end:} +% \TeX{}'s alignment structures present many problems. As Knuth says +% himself in \emph{\TeX : The Program}: \enquote{It's sort of a miracle +% whenever \cs{halign} or \cs{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 |&|$_4$ 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} +\cs_new_nopar:Npn \group_align_safe_begin: + { \if_false: { \fi: \if_int_compare:w `} = \c_zero \fi: } +\cs_new_nopar:Npn \group_align_safe_end: + { \if_int_compare:w `{ = \c_zero } \fi: } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int]{\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 \cs{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, \emph{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 if an only +% if 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} +\cs_new_nopar:Npn \scan_align_safe_stop: + { + \int_compare:nNnT \etex_currentgrouptype:D = \c_six + { + \int_compare:nNnF \etex_lastnodetype:D = \c_zero + { \int_compare:nNnF \etex_lastnodetype:D = \c_seven { \scan_stop: } } + } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int]{\prg_variable_get_scope:N} +% \begin{macro}[aux]{\prg_variable_get_scope_aux:w} +% \begin{macro}[int]{\prg_variable_get_type:N} +% \begin{macro}[aux]{\prg_variable_get_type:w} +% Expandable functions to find the type of a variable, and to +% return \texttt{g} if the variable is global. The trick for +% \cs{prg_variable_get_scope:N} is the same as that in +% \cs{cs_split_function:NN}, but it can be simplified as the +% requirements here are less complex. +% \begin{macrocode} +\group_begin: + \tex_lccode:D `\& = `\g \scan_stop: + \tex_catcode:D `\& = \c_twelve +\tl_to_lowercase:n + { + \group_end: + \cs_new_nopar:Npn \prg_variable_get_scope:N #1 + { + \exp_last_unbraced:Nf \prg_variable_get_scope_aux:w + { \cs_to_str:N #1 \exp_stop_f: \q_stop } + } + \cs_new_nopar:Npn \prg_variable_get_scope_aux:w #1#2 \q_stop + { \token_if_eq_meaning:NNT & #1 { g } } + } +\group_begin: + \tex_lccode:D `\& = `\_ \scan_stop: + \tex_catcode:D `\& = \c_twelve +\tl_to_lowercase:n + { + \group_end: + \cs_new_nopar:Npn \prg_variable_get_type:N #1 + { + \exp_after:wN \prg_variable_get_type_aux:w + \token_to_str:N #1 & a \q_stop + } + \cs_new_nopar:Npn \prg_variable_get_type_aux:w #1 & #2#3 \q_stop + { + \token_if_eq_meaning:NNTF a #2 + {#1} + { \prg_variable_get_type_aux:w #2#3 \q_stop } + } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Experimental programmings functions} +% +% +% \begin{macro}[aux]{\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 variable, so one additionally has to define +% \begin{quote} +% |\cs_set_nopar:Npn \seq_quicksort:N{\exp_args:No\seq_quicksort:n}| +% \end{quote} +% +% +% For details on the implementation see \enquote{Sorting in \TeX{}'s Mouth} +% by Bernd Raichle. Firstly we define the function for parsing the +% initial list and then the braced list afterwards. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \prg_define_quicksort:nnn #1#2#3 { + \cs_set:cpx{#1_quicksort:n}##1{ + \exp_not:c{#1_quicksort_start_partition:w} ##1 + \exp_not:n{#2\q_nil#3\q_stop} + } + \cs_set:cpx{#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 + } + \cs_set: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}{}{} + } + \cs_set:cpx {#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} + \cs_set: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} + } + \cs_set:cpx {#1_quicksort_do_partition_i_braced:nnnn} ##1##2##3##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} + } + \cs_set: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} + } + \cs_set:cpx {#1_quicksort_do_partition_ii_braced:nnnn} ##1##2##3##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} + \cs_set:cpx {#1_quicksort_partition_less_i:nnnn} ##1##2##3##4{ + \exp_not:c{#1_quicksort_do_partition_i:nnnw}{##1}{##2}{{##4}##3}} + \cs_set:cpx {#1_quicksort_partition_less_ii:nnnn} ##1##2##3##4{ + \exp_not:c{#1_quicksort_do_partition_ii:nnnw}{##1}{##2}{##3{##4}}} + \cs_set:cpx {#1_quicksort_partition_greater_i:nnnn} ##1##2##3##4{ + \exp_not:c{#1_quicksort_do_partition_i:nnnw}{##1}{{##4}##2}{##3}} + \cs_set:cpx {#1_quicksort_partition_greater_ii:nnnn} ##1##2##3##4{ + \exp_not:c{#1_quicksort_do_partition_ii:nnnw}{##1}{##2{##4}}{##3}} + \cs_set:cpx {#1_quicksort_partition_less_i_braced:nnnn} ##1##2##3##4{ + \exp_not:c{#1_quicksort_do_partition_i_braced:nnnn}{##1}{##2}{{##4}##3}} + \cs_set:cpx {#1_quicksort_partition_less_ii_braced:nnnn} ##1##2##3##4{ + \exp_not:c{#1_quicksort_do_partition_ii_braced:nnnn}{##1}{##2}{##3{##4}}} + \cs_set:cpx {#1_quicksort_partition_greater_i_braced:nnnn} ##1##2##3##4{ + \exp_not:c{#1_quicksort_do_partition_i_braced:nnnn}{##1}{{##4}##2}{##3}} + \cs_set:cpx {#1_quicksort_partition_greater_ii_braced:nnnn} ##1##2##3##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} + \cs_set: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} +% \UnitTested +% 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} +% \UnitTested +% \begin{macro}{\prg_quicksort_compare:nnTF} +% \UnitTested +% \begin{macrocode} +\cs_set:Npn \prg_quicksort_function:n {\ERROR} +\cs_set:Npn \prg_quicksort_compare:nnTF {\ERROR} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Deprecated functions} +% +% These were depreciated on 2011-05-27 and will be removed entirely by +% 2011-08-31. +% +% \begin{macro}{\prg_new_map_functions:Nn} +% \begin{macro}{\prg_set_map_functions:Nn} +% As we have restructured the structured variables, these are no +% longer needed. +% \begin{macrocode} +\cs_new_protected:Npn \prg_new_map_functions:Nn #1#2 { \deprectiated } +\cs_new_protected:Npn \prg_set_map_functions:Nn #1#2 { \deprectiated } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macrocode} +%</initex|package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintIndex
\ No newline at end of file diff --git a/Master/texmf-dist/source/latex/l3kernel/l3prop.dtx b/Master/texmf-dist/source/latex/l3kernel/l3prop.dtx new file mode 100644 index 00000000000..744cea629fc --- /dev/null +++ b/Master/texmf-dist/source/latex/l3kernel/l3prop.dtx @@ -0,0 +1,1206 @@ +% \iffalse meta-comment +% +%% File: l3prop.dtx Copyright (C) 1990-2011 The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +% +%<*driver|package> +\RequirePackage{l3names} +\GetIdInfo$Id: l3prop.dtx 2478 2011-06-19 21:34:23Z joseph $ + {L3 Experimental property lists} +%</driver|package> +%<*driver> +\documentclass[full]{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{^^A +% The \pkg{l3prop} package\\ Property lists^^A +% \thanks{This file describes v\ExplFileVersion, +% last revised \ExplFileDate.}^^A +% } +% +% \author{^^A +% The \LaTeX3 Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% +% \date{Released \ExplFileDate} +% +% \maketitle +% +% \begin{documentation} +% +% \LaTeX3 implements a \enquote{property list} data type, which contain +% an unordered list of entries each of which consists of a \meta{key} and +% an associated \meta{value}. The \meta{key} and \meta{value} may both be +% any \meta{balanced text}. It is possible to map functions to property lists +% such that the function is applied to every key--value pair within +% the list. +% +% Each entry in a property list must have a unique \meta{key}: if an entry is +% added to a property list which already contains the \meta{key} then the new +% entry will overwrite the existing one. The \meta{keys} are compared on a +% string basis, using the same method as \cs{str_if_eq:nn}. +% +% \section{Creating and initialising property lists} +% +% \begin{function}{\prop_new:N, \prop_new:c} +% \begin{syntax} +% \cs{prop_new:N} \meta{property list} +% \end{syntax} +% Creates a new \meta{property list} or raises an error if the name is +% already taken. The declaration is global. The \meta{property lists} will +% initially contain no entries. +% \end{function} +% +% \begin{function}{\prop_clear:N, \prop_clear:c} +% \begin{syntax} +% \cs{prop_clear:N} \meta{property list} +% \end{syntax} +% Clears all entries from the \meta{property list} within the scope of +% the current \TeX{} group. +% \end{function} +% +% \begin{function}{\prop_gclear:N, \prop_gclear:c} +% \begin{syntax} +% \cs{prop_gclear:N} \meta{property list} +% \end{syntax} +% Clears all entries from the \meta{property list} globally. +% \end{function} +% +% \begin{function}{\prop_clear_new:N, \prop_clear_new:c} +% \begin{syntax} +% \cs{prop_clear_new:N} \meta{property list} +% \end{syntax} +% If the \meta{property list} already exists, clears it within the scope +% of the current \TeX{} group. If the \meta{property list} is not defined, +% it will be created (using \cs{prop_new:N}). Thus the property list is +% guaranteed to be available and clear within the current \TeX{} +% group. The \meta{property list} will exist globally, but the content +% outside of the current \TeX{} group is not specified. +% \end{function} +% +% \begin{function}{\prop_gclear_new:N, \prop_gclear_new:c} +% \begin{syntax} +% \cs{prop_gclear_new:N} \meta{property list} +% \end{syntax} +% If the \meta{property list} already exists, clears it globally. If the +% \meta{property list} is not defined, it will be created (using +% \cs{prop_new:N}). Thus the property list is guaranteed to be available +% and globally clear. +% \end{function} +% +% \begin{function} +% {\prop_set_eq:NN, \prop_set_eq:cN, \prop_set_eq:Nc, \prop_set_eq:cc} +% \begin{syntax} +% \cs{prop_set_eq:NN} \meta{property list1} \meta{property list2} +% \end{syntax} +% Sets the content of \meta{property list1} equal to that of +% \meta{property list2}. This assignment is restricted to the current +% \TeX{} group level. +% \end{function} +% +% \begin{function} +% {\prop_gset_eq:NN, \prop_gset_eq:cN, \prop_gset_eq:Nc, \prop_gset_eq:cc} +% \begin{syntax} +% \cs{prop_gset_eq:NN} \meta{property list1} \meta{property list2} +% \end{syntax} +% Sets the content of \meta{property list1} equal to that of +% \meta{property list2}. This assignment is global and so is not +% limited by the current \TeX{} group level. +% \end{function} +% +% \section{Adding entries to property lists} +% +% \begin{function} +% { +% \prop_put:Nnn, \prop_put:NnV, \prop_put:Nno, \prop_put:Nnx, +% \prop_put:NVn, \prop_put:NVV, \prop_put:Non, \prop_put:Noo, +% \prop_put:cnn, \prop_put:cnV, \prop_put:cno, \prop_put:cnx, +% \prop_put:cVn, \prop_put:cVV, \prop_put:con, \prop_put:coo +% } +% \begin{syntax} +% \cs{prop_put:Nnn} \meta{property list} \Arg{key} \Arg{value} +% \end{syntax} +% Adds an entry to the \meta{property list} which may be accessed +% using the \meta{key} and which has \meta{value}. Both the \meta{key} +% and \meta{value} may contain any \meta{balanced text}. The \meta{key} +% is stored after processing with \cs{tl_to_str:n}, meaning that +% category codes are ignored. If the \meta{key} is already present +% in the \meta{property list}, the existing entry is overwritten +% by the new \meta{value}. The assignment is restricted to the current +% \TeX{} group. +% \end{function} +% +% \begin{function} +% { +% \prop_gput:Nnn, \prop_gput:NnV, \prop_gput:Nno, \prop_gput:Nnx, +% \prop_gput:NVn, \prop_gput:NVV, \prop_gput:Non, \prop_gput:Noo, +% \prop_gput:cnn, \prop_gput:cnV, \prop_gput:cno, \prop_gput:cnx, +% \prop_gput:cVn, \prop_gput:cVV, \prop_gput:con, \prop_gput:coo +% } +% \begin{syntax} +% \cs{prop_gput:Nnn} \meta{property list} \Arg{key} \Arg{value} +% \end{syntax} +% Adds an entry to the \meta{property list} which may be accessed +% using the \meta{key} and which has \meta{value}. Both the \meta{key} +% and \meta{value} may contain any \meta{balanced text}. The \meta{key} +% is stored after processing with \cs{tl_to_str:n}, meaning that +% category codes are ignored. If the \meta{key} is already present +% in the \meta{property list}, the existing entry is overwritten +% by the new \meta{value}. The assignment is global. +% \end{function} +% +% \begin{function}{\prop_put_if_new:Nnn, \prop_put_if_new:cnn} +% \begin{syntax} +% \cs{prop_put_if_new:Nnn} \meta{property list} \Arg{key} \Arg{value} +% \end{syntax} +% If the \meta{key} is present in the \meta{property list} then +% no action is taken. If the \meta{key} is not present in the +% \meta{property list} then a new entry is added. Both the \meta{key} +% and \meta{value} may contain any \meta{balanced text}. The \meta{key} +% is stored after processing with \cs{tl_to_str:n}, meaning that +% category codes are ignored. The assignment is restricted to the current +% \TeX{} group. +% \end{function} +% +% \begin{function}{\prop_gput_if_new:Nnn, \prop_gput_if_new:cnn} +% \begin{syntax} +% \cs{prop_gput_if_new:Nnn} \meta{property list} \Arg{key} \Arg{value} +% \end{syntax} +% If the \meta{key} is present in the \meta{property list} then +% no action is taken. If the \meta{key} is not present in the +% \meta{property list} then a new entry is added. Both the \meta{key} +% and \meta{value} may contain any \meta{balanced text}. The \meta{key} +% is stored after processing with \cs{tl_to_str:n}, meaning that +% category codes are ignored. The assignment is global. +% \end{function} +% +% \section{Recovering values from property lists} +% +% \begin{function} +% { +% \prop_get:NnN, \prop_get:NVN, \prop_get:NoN, +% \prop_get:cnN, \prop_get:cVN, \prop_get:coN, +% } +% \begin{syntax} +% \cs{prop_get:NnN} \meta{property list} \Arg{key} \meta{tl var} +% \end{syntax} +% Recovers the \meta{value} stored with \meta{key} from the +% \meta{property list}, and places this in the \meta{token list +% variable}. If the \meta{key} is not found in the +% \meta{property list} then the \meta{token list variable} will +% contain the special marker \cs{q_no_value}. The \meta{token list +% variable} is set within the current \TeX{} group. +% \end{function} +% +% \begin{function}{\prop_pop:NnN, \prop_pop:NoN, \prop_pop:cnN, \prop_pop:coN} +% \begin{syntax} +% \cs{prop_pop:NnN} \meta{property list} \Arg{key} \meta{tl var} +% \end{syntax} +% Recovers the \meta{value} stored with \meta{key} from the +% \meta{property list}, and places this in the \meta{token list +% variable}. If the \meta{key} is not found in the +% \meta{property list} then the \meta{token list variable} will +% contain the special marker \cs{q_no_value}. The \meta{key} and +% \meta{value} are then deleted from the property list. Both +% assignments are local. +% \end{function} +% +% \begin{function} +% {\prop_gpop:NnN, \prop_gpop:NoN, \prop_gpop:cnN, \prop_gpop:coN} +% \begin{syntax} +% \cs{prop_gpop:NnN} \meta{property list} \Arg{key} \meta{tl var} +% \end{syntax} +% Recovers the \meta{value} stored with \meta{key} from the +% \meta{property list}, and places this in the \meta{token list +% variable}. If the \meta{key} is not found in the +% \meta{property list} then the \meta{token list variable} will +% contain the special marker \cs{q_no_value}. The \meta{key} and +% \meta{value} are then deleted from the property list. +% The \meta{property list} is modified globally, while the assignment of +% the \meta{token list variable} is local. +% \end{function} +% +% \section{Modifying property lists} +% +% \begin{function}{\prop_del:Nn, \prop_del:NV, \prop_del:cn, \prop_del:cV} +% \begin{syntax} +% \cs{prop_del:Nn} \meta{property list} \Arg{key} +% \end{syntax} +% Deletes the entry listed under \meta{key} from the +% \meta{property list} which may be accessed. If the \meta{key} is +% not found in the \meta{property list} no change occurs, +% \emph{i.e}~there is no need to test for the existence of a key before +% deleting it. The deletion is restricted to the current \TeX{} group. +% \end{function} +% +% \begin{function}{\prop_gdel:Nn, \prop_gdel:NV, \prop_gdel:cn, \prop_gdel:cV} +% \begin{syntax} +% \cs{prop_gdel:Nn} \meta{property list} \Arg{key} +% \end{syntax} +% Deletes the entry listed under \meta{key} from the +% \meta{property list} which may be accessed. If the \meta{key} is +% not found in the \meta{property list} no change occurs, +% \emph{i.e}~there is no need to test for the existence of a key before +% deleting it. The deletion is not restricted to the current \TeX{} +% group: it is global. +% \end{function} +% +% \section{Property list conditionals} +% +% \begin{function}[EXP,pTF]{\prop_if_empty:N, \prop_if_empty:c} +% \begin{syntax} +% \cs{prop_if_empty_p:N} \meta{property list} +% \cs{prop_if_empty:NTF} \meta{property list} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the \meta{property list} is empty (containing no entries). The +% branching versions then leave either \meta{true code} or +% \meta{false code} in the input stream, as appropriate to the truth of +% the test and the variant of the function chosen. The logical truth of +% the test is left in the input stream by the predicate version. +% \end{function} +% +% \begin{function}[EXP,pTF]{ +% \prop_if_in:Nn, \prop_if_in:NV, \prop_if_in:No, +% \prop_if_in:cn, \prop_if_in:cV, \prop_if_in:co +% } +% \begin{syntax} +% \cs{prop_if_in:NnTF} \meta{property list} \Arg{key} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the \meta{key} is present in the \meta{property list}, +% making the comparison using the method described by \cs{str_if_eq:nnTF}. +% Either the \meta{true code} or \meta{false code} in the input stream, as +% appropriate to the truth of the test and the variant of the function +% chosen. +% \begin{texnote} +% This function iterates through every key--value pair in the +% \meta{property list} and is therefore slower than using the +% non-expandable \cs{prop_get:NnNTF}. +% \end{texnote} +% \end{function} +% +% \section{Mapping to property lists} +% +% \begin{function}[EXP]{\prop_map_function:NN, \prop_map_function:cN} +% \begin{syntax} +% \cs{prop_map_function:NN} \meta{property list} \meta{function} +% \end{syntax} +% Applies \meta{function} to every \meta{entry} stored in the +% \meta{property list}. The \meta{function} will receive two argument for +% each iteration.: the \meta{key} and associated \meta{value}. +% The order in which \meta{entries} are returned is not defined and +% should not be relied upon. +% \end{function} +% +% \begin{function}{\prop_map_inline:Nn, \prop_map_inline:cn} +% \begin{syntax} +% \cs{prop_map_inline:Nn} \meta{property list} \Arg{inline function} +% \end{syntax} +% Applies \meta{inline function} to every \meta{entry} stored +% within the \meta{property list}. The \meta{inline function} should +% consist of code which will receive the \meta{key} as |#1| and the +% \meta{value} as |#2|. +% The order in which \meta{entries} are returned is not defined and +% should not be relied upon. +% \end{function} +% +% \begin{function}[EXP]{\prop_map_break:} +% \begin{syntax} +% \cs{prop_map_break:} +% \end{syntax} +% Used to terminate a \cs{prop_map_\ldots} function before all +% entries in the \meta{property list} have been processed. This will +% normally take place within a conditional statement, for example +% \begin{verbatim} +% \prop_map_inline:Nn \l_my_prop +% { +% \str_if_eq:nnTF { #1 } { bingo } +% { \prop_map_break: } +% { +% % Do something useful +% } +% } +% \end{verbatim} +% Use outside of a \cs{prop_map_\ldots} scenario will lead low +% level \TeX{} errors. +% \end{function} +% +% \begin{function}[EXP]{\prop_map_break:n} +% \begin{syntax} +% \cs{prop_map_break:n} \Arg{tokens} +% \end{syntax} +% Used to terminate a \cs{prop_map_\ldots} function before all +% entries in the \meta{property list} have been processed, inserting +% the \meta{tokens} after the mapping has ended. This will +% normally take place within a conditional statement, for example +% \begin{verbatim} +% \prop_map_inline:Nn \l_my_prop +% { +% \str_if_eq:nnTF { #1 } { bingo } +% { \prop_map_break:n { <tokens> } } +% { +% % Do something useful +% } +% } +% \end{verbatim} +% Use outside of a \cs{prop_map_\ldots} scenario will lead low +% level \TeX{} errors. +% \end{function} +% +% \section{Viewing property lists} +% +% \begin{function}{\prop_show:N, \prop_show:c} +% \begin{syntax} +% \cs{prop_show:N} \meta{property list} +% \end{syntax} +% Displays the entries in the \meta{property list} in the terminal. +% \end{function} +% +% \section{Experimental property list functions} +% +% This section contains functions which may or may not be retained, depending +% on how useful they are found to be. +% +% \begin{function}[TF]{\prop_get:NnN} +% \begin{syntax} +% \cs{prop_get:NnNTF} \meta{property list} \Arg{key} +% ~~\meta{token list variable} \Arg{true code} \Arg{false code} +% \end{syntax} +% If the \meta{key} is not present in the \meta{property list}, leaves +% the \meta{false code} in the input stream and leaves the +% \meta{token list variable} unchanged. If the \meta{key} is present in +% the \meta{property list}, stores the corresponding \meta{value} +% in the \meta{token list variable} without removing it from the +% \meta{property list}. The \meta{true code} is then left in the input +% stream. The \meta{token list variable} is assigned locally. +% \end{function} +% +% \begin{function}[TF]{\prop_pop:NnN} +% \begin{syntax} +% \cs{prop_pop:NnNTF} \meta{property list} \Arg{key} +% ~~\meta{token list variable} \Arg{true code} \Arg{false code} +% \end{syntax} +% If the \meta{key} is not present in the \meta{property list}, leaves +% the \meta{false code} in the input stream and leaves the +% \meta{token list variable} unchanged. If the \meta{key} is present in +% the \meta{property list}, pops the corresponding \meta{value} +% in the \meta{token list variable}, \emph{i.e.}~removes the item from +% the \meta{property list}. The \meta{true code} is then left in the input +% stream. Both the \meta{property list} and the \meta{token list variable} +% are assigned locally. +% \end{function} +% +% \begin{function}[TF]{\prop_gpop:NnN} +% \begin{syntax} +% \cs{prop_gpop:NnNTF} \meta{property list} \Arg{key} +% ~~\meta{token list variable} \Arg{true code} \Arg{false code} +% \end{syntax} +% If the \meta{key} is not present in the \meta{property list}, leaves +% the \meta{false code} in the input stream and leaves the +% \meta{token list variable} unchanged. If the \meta{key} is present in +% the \meta{property list}, pops the corresponding \meta{value} +% in the \meta{token list variable}, \emph{i.e.}~removes the item from +% the \meta{property list}. The \meta{true code} is then left in the input +% stream. The \meta{property list} is modified globally, while the +% \meta{token list variable} is assigned locally. +% \end{function} +% +% \begin{function}[EXP]{\prop_map_tokens:Nn} +% \begin{syntax} +% \cs{prop_map_tokens:Nn} \meta{property list} \Arg{code} +% \end{syntax} +% Analogue of \cs{prop_map_function:NN} which maps several tokens instead +% of a single function. Useful in particular when mapping through a +% property list while keeping track of a given key. +% \end{function} +% +% \begin{function}[EXP]{\prop_get:Nn} +% \begin{syntax} +% \cs{prop_get:Nn} \meta{property list} \Arg{key} +% \end{syntax} +% Expands to the \meta{value} corresponding to the \meta{key} in +% the \meta{property list}. If the \meta{key} is missing, this has +% an empty expansion. +% \begin{texnote} +% This function is slower than the non-expandable analogue +% \cs{prop_get:NnN}. +% \end{texnote} +% \end{function} +% +% \section{Internal property list functions} +% +% \begin{function}{\q_prop} +% The internal token used to separate out property list entries, separating +% both the \meta{key} from the \meta{value} and also one entry from another. +% \end{function} +% +% \begin{function}{\c_empty_prop} +% A permanently-empty property list used for internal comparisons. +% \end{function} +% +% \begin{function}{\prop_split:Nnn} +% \begin{syntax} +% \cs{prop_spilt:Nnn} \meta{property list} \Arg{key} \Arg{code} +% \end{syntax} +% Splits the \meta{property list} at the \meta{key}, giving three +% groups: the \meta{extract} of \meta{property list} before the +% \meta{key}, the \meta{value} associated with the \meta{key} and the +% \meta{extract} of the \meta{property list} after the \meta{value}. +% The first \meta{extract} retains the internal structure of a property +% list. The second is only missing the leading separator \cs{q_prop}. +% This ensures that the concatenation of the two \meta{extracts} is a +% property list. +% If the \meta{key} is not present in the \meta{property list} then +% the second group will contain the marker \cs{q_no_value} and the third +% is empty. +% Once the split has occurred, the \meta{code} is inserted followed by the +% three groups: thus the \meta{code} should properly absorb three +% arguments. +% The \meta{key} comparison takes place as described for \cs{str_if_eq:nn}. +% \end{function} +% +% \begin{function}{\prop_split:NnTF} +% \begin{syntax} +% \cs{prop_spilt:NnTF} \meta{property list} \Arg{key} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% Splits the \meta{property list} at the \meta{key}, giving three +% groups: the \meta{extract} of \meta{property list} before the +% \meta{key}, the \meta{value} associated with the \meta{key} and the +% \meta{extract} of the \meta{property list} after the \meta{value}. +% The first \meta{extract} retains the internal structure of a property +% list. The second is only missing the leading separator \cs{q_prop}. +% This ensures that the concatenation of the two \meta{extracts} is a +% property list. +% If the \meta{key} is present in the \meta{property list} then the +% \meta{true code} is left in the input stream, followed by the three +% groups: thus the \meta{true code} should properly absorb three arguments. +% If the \meta{key} is not present in the \meta{property list} then +% the \meta{false code} is left in the input stream, with no trailing +% material. +% The \meta{key} comparison takes place as described for \cs{str_if_eq:nn}. +% \end{function} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{l3prop} implementation} +% +% \TestFiles{m3prop001} +% +% \begin{macrocode} +%<*initex|package> +% \end{macrocode} +% +% \begin{macrocode} +%<*package> +\ProvidesExplPackage + {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +\package_check_loaded_expl: +%</package> +% \end{macrocode} +% +% A property list is a macro whose top-level expansion is for the form +% \enquote{\cs{q_prop} \meta{key$_0$} \cs{q_prop} \Arg{value$_0$} \cs{q_prop} +% \ldots \cs{q_prop} \meta{key$_{n-1}$} \cs{q_prop} \Arg{value$_{n-1}$} +% \cs{q_prop}}. +% The trailing \cs{q_prop} is always present for performance reasons: this +% means that empty property lists are not actually empty. +% +% \begin{macro}[int]{\q_prop} +% A private quark is used as a marker between entries. +% \begin{macrocode} +\quark_new:N \q_prop +% \end{macrocode} +% \end{macro} +% +% \begin{variable}{\c_empty_prop} +% An empty prop contains exactly one \cs{q_prop}. +% \begin{macrocode} +\tl_const:Nn \c_empty_prop { \q_prop } +% \end{macrocode} +% \end{variable} +% +% \subsection{Allocation and initialisation} +% +% \begin{macro}{\prop_new:N,\prop_new:c} +% Internally, property lists are token lists, but an empty prop +% is not an empty tl, so we need to do things by hand. +% \begin{macrocode} +\cs_new_protected:Npn \prop_new:N #1 { \cs_new_eq:NN #1 \c_empty_prop } +\cs_new_protected:Npn \prop_new:c #1 { \cs_new_eq:cN {#1} \c_empty_prop } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\prop_clear:N, \prop_clear:c} +% \begin{macro}{\prop_gclear:N, \prop_gclear:c} +% The same idea for clearing +% \begin{macrocode} +\cs_new_protected:Npn \prop_clear:N #1 { \cs_set_eq:NN #1 \c_empty_prop } +\cs_new_protected:Npn \prop_clear:c #1 { \cs_set_eq:cN {#1} \c_empty_prop } +\cs_new_protected:Npn \prop_gclear:N #1 { \cs_gset_eq:NN #1 \c_empty_prop } +\cs_new_protected:Npn \prop_gclear:c #1 { \cs_gset_eq:cN {#1} \c_empty_prop } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\prop_clear_new:N, \prop_clear_new:c} +% \begin{macro}{\prop_gclear_new:N, \prop_gclear_new:c} +% Once again a simple copy from the token list functions. +% \begin{macrocode} +\cs_new_protected:Npn \prop_clear_new:N #1 + { \cs_if_exist:NTF #1 { \prop_clear:N #1 } { \prop_new:N #1 } } +\cs_generate_variant:Nn \prop_clear_new:N {c} +\cs_new_protected:Npn \prop_gclear_new:N #1 + { \cs_if_exist:NTF #1 { \prop_gclear:N #1 } { \prop_new:N #1 } } +\cs_new_eq:NN \prop_gclear_new:c \prop_gclear:c +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro} +% {\prop_set_eq:NN, \prop_set_eq:cN, \prop_set_eq:Nc, \prop_set_eq:cc} +% \begin{macro} +% {\prop_gset_eq:NN, \prop_gset_eq:cN, \prop_gset_eq:Nc, \prop_gset_eq:cc} +% Once again, these are simply copies from the token list functions. +% \begin{macrocode} +\cs_new_eq:NN \prop_set_eq:NN \tl_set_eq:NN +\cs_new_eq:NN \prop_set_eq:Nc \tl_set_eq:Nc +\cs_new_eq:NN \prop_set_eq:cN \tl_set_eq:cN +\cs_new_eq:NN \prop_set_eq:cc \tl_set_eq:cc +\cs_new_eq:NN \prop_gset_eq:NN \tl_gset_eq:NN +\cs_new_eq:NN \prop_gset_eq:Nc \tl_gset_eq:Nc +\cs_new_eq:NN \prop_gset_eq:cN \tl_gset_eq:cN +\cs_new_eq:NN \prop_gset_eq:cc \tl_gset_eq:cc +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Accessing data in property lists} +% +% \begin{macro}[int]{\prop_split:NnTF} +% \begin{macro}[aux]{\prop_split_aux:NnTF} +% \begin{macro}[aux]{\prop_split_aux:nnnn} +% \begin{macro}[aux]{\prop_split_aux:w} +% This function is used by most of the module, and hence must be fast. +% The aim here is to split a property list at a given key into the part +% before the key--value pair, the value associated with the key and the part +% after the key--value pair. To do this, the key is first detokenized (to +% avoid repeatedly doing this), then a delimited function is constructed to +% match the key. It will match \cs{q_prop} \meta{detokenized key} \cs{q_prop} +% \marg{value} \meta{extra argument}, effectively separating an +% \meta{extract1} before the key in the property list and an \meta{extract2} +% after the key. +% +% If the key is present in the property list, then \meta{extra argument} +% is simply \cs{q_prop}, and \cs{prop_splot_aux:nnnn} will gobble this +% and the false branch (|#4|), leaving the correct code on the input +% stream. More precisely, it leaves the user code (true branch), followed +% by three groups, \Arg{extract1} \Arg{value} \Arg{extract2}. +% In order for \meta{extract1}\meta{extract2} to be a well-formed +% property list, \meta{extract1} has a leading and trailing \cs{q_prop}, +% retaining exactly the structure of a property list, while \meta{extract2} +% omits the leading \cs{q_prop}. +% +% If the key is not there, then \meta{extra argument} is +% |? \use_ii:nn { }|, and |\prop_split_aux:nnnn ? \use_ii:nn { }| removes +% the three brace groups that just follow. Then \cs{use_ii:nn} removes +% the true branch, leaving the false branch, with no trailing material. +% \begin{macrocode} +\cs_set_protected:Npn \prop_split:NnTF #1#2 + { \exp_args:NNo \prop_split_aux:NnTF #1 { \tl_to_str:n {#2} } } +\cs_new_protected:Npn \prop_split_aux:NnTF #1#2 + { + \cs_set_protected:Npn \prop_split_aux:w + ##1 \q_prop #2 \q_prop ##2 ##3 ##4 \q_mark ##5 \q_stop + { \prop_split_aux:nnnn ##3 { {##1 \q_prop } {##2} {##4} } } + \exp_after:wN \prop_split_aux:w #1 \q_mark + \q_prop #2 \q_prop { } { ? \use_ii:nn { } } \q_mark \q_stop + } +\cs_new:Npn \prop_split_aux:nnnn #1#2#3#4 { #3 #2 } +\cs_new_protected:Npn \prop_split_aux:w { } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}[int]{\prop_split:Nnn} +% The goal here is to provide a common interface for both true and false +% branches of \cs{prop_split:NnTF}. In both cases, the code given by the +% user will be placed in front of three brace groups, \Arg{extract1} +% \Arg{value} \Arg{extract2}. +% If the key was missing from the property list, then \meta{extract1} +% is the full property list, \meta{value} is \cs{q_no_value}, and +% \meta{extract2} is empty. +% Otherwise, \meta{extract1} is the part of the property list before the +% \meta{key}, and has the structure of a property list, \meta{value} is +% the value corresponding to the \meta{key}, and \meta{extract2} (the part +% after the \meta{key}) is missing the leading \cs{q_prop}. +% \begin{macrocode} +\cs_set_protected:Npn \prop_split:Nnn #1#2#3 + { + \prop_split:NnTF #1 {#2} + {#3} + { \exp_args:Nno \use:n {#3} {#1} { \q_no_value } { } } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\prop_del:Nn, \prop_del:NV, \prop_del:cn, \prop_del:cV} +% \begin{macro}{\prop_gdel:Nn, \prop_gdel:NV, \prop_gdel:cn, \prop_gdel:cV} +% \begin{macro}[aux]{\prop_del_aux:NNnnn} +% Deleting from a property starts by splitting the list. +% If the key is present in the property list, the returned value is ignored. +% If the key is missing, nothing happens. +% \begin{macrocode} +\cs_new_protected:Npn \prop_del:Nn #1#2 + { \prop_split:NnTF #1 {#2} { \prop_del_aux:NNnnn \tl_set:Nn #1 } { } } +\cs_new_protected:Npn \prop_gdel:Nn #1#2 + { \prop_split:NnTF #1 {#2} { \prop_del_aux:NNnnn \tl_gset:Nn #1 } { } } +\cs_new_protected:Npn \prop_del_aux:NNnnn #1#2#3#4#5 + { #1 #2 { #3 #5 } } +\cs_generate_variant:Nn \prop_del:Nn { NV } +\cs_generate_variant:Nn \prop_del:Nn { c , cV } +\cs_generate_variant:Nn \prop_gdel:Nn { NV } +\cs_generate_variant:Nn \prop_gdel:Nn { c , cV } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro} +% { +% \prop_get:NnN, \prop_get:NVN, \prop_get:NoN, +% \prop_get:cnN, \prop_get:cVN, \prop_get:NoN +% } +% \begin{macro}[aux]{\prop_get_aux:Nnnn} +% Getting an item from a list is very easy: after splitting, +% if the key is in the property list, just set the token list variable +% to the return value, otherwise to \cs{q_no_value}. +% \begin{macrocode} +\cs_new_protected:Npn \prop_get:NnN #1#2#3 + { + \prop_split:NnTF #1 {#2} + { \prop_get_aux:Nnnn #3 } + { \tl_set:Nn #3 { \q_no_value } } + } +\cs_new_protected:Npn \prop_get_aux:Nnnn #1#2#3#4 + { \tl_set:Nn #1 {#3} } +\cs_generate_variant:Nn \prop_get:NnN { NV , No } +\cs_generate_variant:Nn \prop_get:NnN { c , cV , co } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\prop_pop:NnN, \prop_pop:NoN, \prop_pop:cnN, \prop_pop:coN} +% \begin{macro}{\prop_gpop:NnN, \prop_gpop:NoN, \prop_gpop:cnN, \prop_gpop:coN} +% \begin{macro}[aux]{\prop_pop_aux:NNNnnn} +% Popping a value also starts by doing the split. +% If the key is present, save the value in the token list and update the +% property list as when deleting. +% If the key is missing, save \cs{q_no_value} in the token list. +% \begin{macrocode} +\cs_new_protected:Npn \prop_pop:NnN #1#2#3 + { + \prop_split:NnTF #1 {#2} + { \prop_pop_aux:NNNnnn \tl_set:Nn #1 #3 } + { \tl_set:Nn #3 { \q_no_value } } + } +\cs_new_protected:Npn \prop_gpop:NnN #1#2#3 + { + \prop_split:NnTF #1 {#2} + { \prop_pop_aux:NNNnnn \tl_gset:Nn #1 #3 } + { \tl_set:Nn #3 { \q_no_value } } + } +\cs_new_protected:Npn \prop_pop_aux:NNNnnn #1#2#3#4#5#6 + { + \tl_set:Nn #3 {#5} + #1 #2 { #4 #6 } + } +\cs_generate_variant:Nn \prop_pop:NnN { No } +\cs_generate_variant:Nn \prop_pop:NnN { c , co } +\cs_generate_variant:Nn \prop_gpop:NnN { No } +\cs_generate_variant:Nn \prop_gpop:NnN { c , co } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro} +% { +% \prop_put:Nnn, \prop_put:NnV, \prop_put:Nno, \prop_put:Nnx, +% \prop_put:NVn, \prop_put:NVV, \prop_put:Non, \prop_put:Noo, +% \prop_put:cnn, \prop_put:cnV, \prop_put:cno, \prop_put:cnx, +% \prop_put:cVn, \prop_put:cVV, \prop_put:con, \prop_put:coo +% } +% \begin{macro} +% { +% \prop_gput:Nnn, \prop_gput:NnV, \prop_gput:Nno, \prop_gput:Nnx, +% \prop_gput:NVn, \prop_gput:NVV, \prop_gput:Non, \prop_gput:Noo, +% \prop_gput:cnn, \prop_gput:cnV, \prop_gput:cno, \prop_gput:cnx, +% \prop_gput:cVn, \prop_gput:cVV, \prop_gput:con, \prop_gput:coo +% } +% \begin{macro}[aux]{\prop_put_aux:NNnnnnn} +% Putting a key--value pair in a property list starts by splitting +% to remove any existing value. The property list is then +% reconstructed with the two remaining parts |#5| and |#7| first, +% followed by the new or updated entry. +% \begin{macrocode} +\cs_new_protected:Npn \prop_put:Nnn { \prop_put_aux:NNnn \tl_set:Nx } +\cs_new_protected:Npn \prop_gput:Nnn { \prop_put_aux:NNnn \tl_gset:Nx } +\cs_new_protected:Npn \prop_put_aux:NNnn #1#2#3#4 + { + \prop_split:Nnn #2 {#3} { \prop_put_aux:NNnnnnn #1 #2 {#3} {#4} } + } +\cs_new_protected:Npn \prop_put_aux:NNnnnnn #1#2#3#4#5#6#7 + { + #1 #2 + { + \exp_not:n { #5 #7 } + \tl_to_str:n {#3} \exp_not:n { \q_prop {#4} \q_prop } + } + } +\cs_generate_variant:Nn \prop_put:Nnn + { NnV , Nno , Nnx , NV , NVV , No , Noo } +\cs_generate_variant:Nn \prop_put:Nnn + { c , cnV , cno , cnx , cV , cVV , co , coo } +\cs_generate_variant:Nn \prop_gput:Nnn + { NnV , Nno , Nnx , NV , NVV , No , Noo } +\cs_generate_variant:Nn \prop_gput:Nnn + { c , cnV , cno , cnx , cV , cVV , co , coo } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\prop_put_if_new:Nnn, \prop_put_if_new:cnn} +% \begin{macro}{\prop_gput_if_new:Nnn, \prop_gput_if_new:cnn} +% Adding conditionally also splits. If the key is already present, +% the three brace groups given by \cs{prop_split:NnTF} are removed. +% If the key is new, then the value is added, being careful to +% convert the key to a string using \cs{tl_to_str:n}. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \prop_put_if_new:Nnn + { \prop_put_if_new_aux:NNnn \tl_put_right:Nx } +\cs_new_protected_nopar:Npn \prop_gput_if_new:Nnn + { \prop_put_if_new_aux:NNnn \tl_gput_right:Nx } +\cs_new_protected:Npn \prop_put_if_new_aux:NNnn #1#2#3#4 + { + \prop_split:NnTF #2 {#3} + { \use_none:nnn } + { + #1 #2 + { \tl_to_str:n {#3} \exp_not:n { \q_prop {#4} \q_prop } } + } + } +\cs_generate_variant:Nn \prop_put_if_new:Nnn { c } +\cs_generate_variant:Nn \prop_gput_if_new:Nnn { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Property list conditionals} +% +% \begin{macro}[pTF]{\prop_if_empty:N, \prop_if_empty:c} +% The test here uses \cs{c_empty_prop} as it is not really empty! +% \begin{macrocode} +\prg_new_conditional:Npnn \prop_if_empty:N #1 { p, T , F , TF } + { + \if_meaning:w #1 \c_empty_prop + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +\cs_generate_variant:Nn \prop_if_empty_p:N {c} +\cs_generate_variant:Nn \prop_if_empty:NTF {c} +\cs_generate_variant:Nn \prop_if_empty:NT {c} +\cs_generate_variant:Nn \prop_if_empty:NF {c} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[pTF] +% { +% \prop_if_in:Nn, \prop_if_in:NV, \prop_if_in:No, +% \prop_if_in:cn, \prop_if_in:cV, \prop_if_in:co +% } +% \begin{macro}[aux]{\prop_if_in_aux:w} +% Testing expandably if a key is in a property list +% requires to go through the key--value pairs one by one. +% This is rather slow, and a faster test would be +% \begin{verbatim} +% \prg_new_protected_conditional:Npnn \prop_if_in:Nn #1 #2 +% { +% \prop_split:NnTF #1 {#2} +% { +% \prg_return_true: +% \use_none:nnn +% } +% { \prg_return_false: } +% } +% \end{verbatim} +% but \cs{prop_split:NnTF} is non-expandable. +% +% Instead, the key is compared to each key in turn using \cs{str_if_eq:nn}, +% which is expandable. The mapping is stopped using |A|, which cannot appear +% within a key of the property list, since keys are strings. +% Here, \cs{prop_map_function:NN} is not sufficient for the mapping, +% since it can only map a single token, and cannot carry the key that +% is searched for. +% \begin{macrocode} +\prg_new_conditional:Npnn \prop_if_in:Nn #1#2 { p , T , F , TF } + { + \exp_last_unbraced:Noo \prop_if_in_aux:nwn + { \tl_to_str:n {#2} } #1 + A \q_prop { } \q_stop + } +\cs_new:Npn \prop_if_in_aux:nwn #1 \q_prop #2 \q_prop #3 + { + \if_catcode:w A #2 + \prg_return_false: + \exp_after:wN \use_none_delimit_by_q_stop:w + \fi: + \str_if_eq:nnT {#1} {#2} + { + \prg_return_true: + \use_none_delimit_by_q_stop:w + } + \prop_if_in_aux:nwn {#1} + } +\cs_generate_variant:Nn \prop_if_in_p:Nn { NV , No } +\cs_generate_variant:Nn \prop_if_in_p:Nn { c , cV , co } +\cs_generate_variant:Nn \prop_if_in:NnT { NV , No } +\cs_generate_variant:Nn \prop_if_in:NnT { c , cV , co } +\cs_generate_variant:Nn \prop_if_in:NnF { NV , No } +\cs_generate_variant:Nn \prop_if_in:NnF { c , cV , co } +\cs_generate_variant:Nn \prop_if_in:NnTF { NV , No } +\cs_generate_variant:Nn \prop_if_in:NnTF { c , cV , co } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Mapping to property lists} +% +% \begin{macro} +% { +% \prop_map_function:NN, \prop_map_function:Nc, +% \prop_map_function:cN, \prop_map_function:cc +% } +% \begin{macro}[aux]{\prop_map_function_aux:Nwn} +% The fastest way to do a recursion here is to use an +% \cs{if_catcode:w} test: the keys are strings, and thus +% cannot match the marker |A| (which has catcode \enquote{letter}). +% \begin{macrocode} +\cs_new_nopar:Npn \prop_map_function:NN #1#2 + { + \exp_last_unbraced:NNo \prop_map_function_aux:Nwn #2 + #1 A \q_prop { } \q_recursion_stop + } +\cs_new:Npn \prop_map_function_aux:Nwn #1 \q_prop #2 \q_prop #3 + { + \if_catcode:w A #2 + \exp_after:wN \prop_map_break: + \fi: + #1 {#2} {#3} + \prop_map_function_aux:Nwn #1 + } +\cs_generate_variant:Nn \prop_map_function:NN { Nc } +\cs_generate_variant:Nn \prop_map_function:NN { c , cc } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{variable}{\g_prop_map_inline_int} +% A nesting counter for mapping. +% \begin{macrocode} +\int_new:N \g_prop_map_inline_int +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\prop_map_inline:Nn, \prop_map_inline:cn} +% Mapping in line requires a nesting level counter. +% \begin{macrocode} +\cs_new_protected:Npn \prop_map_inline:Nn #1#2 + { + \int_gincr:N \g_prop_map_inline_int + \cs_gset:cpn { prop_map_inline_ \int_use:N \g_prop_map_inline_int :nn } + ##1##2 {#2} + \prop_map_function:Nc #1 + { prop_map_inline_ \int_use:N \g_prop_map_inline_int :nn } + \int_gdecr:N \g_prop_map_inline_int + } +\cs_generate_variant:Nn \prop_map_inline:Nn { c } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\prop_map_break:} +% Breaking the map function simply means removing everything up to +% the \cs{q_stop} marker. +% \begin{macrocode} +\cs_new_eq:NN \prop_map_break: \use_none_delimit_by_q_recursion_stop:w +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\prop_map_break:n} +% The same idea for using one set of tokens. +% \begin{macrocode} +\cs_new_eq:NN \prop_map_break:n \use_i_delimit_by_q_recursion_stop:nw +% \end{macrocode} +% \end{macro} +% +% \subsection{Viewing property lists} +% +% \begin{variable}{\l_prop_show_tl} +% Used to store the material for display. +% \begin{macrocode} +\tl_new:N \l_prop_show_tl +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\prop_show:N, \prop_show:c} +% \begin{macro}[aux]{\prop_show_aux:n} +% \begin{macro}[aux]{\prop_show_aux:w} +% The aim of the mapping here is to create a token list containing the +% formatted property list. The very first item needs the new line and +% \verb*|> | removing, which is achieved using a \texttt{w}-type auxiliary. +% To avoid a low-level \TeX{} error if there is an empty property list, a +% simple test is used to keep the output \enquote{clean}. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \prop_show:N #1 + { + \prop_if_empty:NTF #1 + { + \iow_term:x { Property~list~\token_to_str:N #1 \c_space_tl is~empty } + \tl_show:n { } + } + { + \iow_term:x + { + Property~list~\token_to_str:N #1 \c_space_tl + contains~the~pairs~(without~outer~braces): + } + \tl_set:Nx \l_prop_show_tl + { \prop_map_function:NN #1 \prop_show_aux:nn } + \tl_show:n \exp_after:wN \exp_after:wN \exp_after:wN + { \exp_after:wN \prop_show_aux:w \l_prop_show_tl } + } + } +\cs_new:Npn \prop_show_aux:nn #1#2 + { + \iow_newline: > \c_space_tl \c_space_tl + \iow_char:N \{ #1 \iow_char:N \} + \c_space_tl \c_space_tl => \c_space_tl \c_space_tl + \iow_char:N \{ \exp_not:n {#2} \iow_char:N \} + } +\cs_new:Npn \prop_show_aux:w #1 > ~ { } +\cs_generate_variant:Nn \prop_show:N { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Experimental functions} +% +% \begin{macro}[TF]{\prop_get:NnN} +% \begin{macro}[aux]{\prop_get_aux_true:Nnnn} +% Getting the value corresponding to a key, keeping track of whether +% the key was present or not, is implemented as a conditional (with +% side effects). If the key was absent, the token list is not altered. +% \begin{macrocode} +\prg_new_protected_conditional:Npnn \prop_get:NnN #1#2#3 { T , F , TF } + { + \prop_split:NnTF #1 {#2} + { \prop_get_aux_true:Nnnn #3 } + { \prg_return_false: } + } +\cs_new_protected:Npn \prop_get_aux_true:Nnnn #1#2#3#4 + { + \tl_set:Nn #1 {#3} + \prg_return_true: + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[TF]{\prop_pop:NnN,\prop_gpop:NnN} +% \begin{macro}[aux]{\prop_pop_aux_true:NNNnnn} +% Popping an item from a property list, keeping track of whether +% the key was present or not, is implemented as a conditional. +% If the key was missing, neither the property list, nor the token +% list are altered. Otherwise, \cs{prg_return_true:} is used after +% the assignments. +% \begin{macrocode} +\prg_new_protected_conditional:Npnn \prop_pop:NnN #1#2#3 {T,F,TF} + { + \prop_split:NnTF #1 {#2} + { \prop_pop_aux_true:NNNnnn \tl_set:Nn #1 #3 } + { \prg_return_false: } + } +\prg_new_protected_conditional:Npnn \prop_gpop:NnN #1#2#3 {T,F,TF} + { + \prop_split:NnTF #1 {#2} + { \prop_pop_aux_true:NNNnnn \tl_gset:Nn #1 #3 } + { \prg_return_false: } + } +\cs_new_protected:Npn \prop_pop_aux_true:NNNnnn #1#2#3#4#5#6 + { + \tl_set:Nn #3 {#5} + #1 #2 { #4 #6 } + \prg_return_true: + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[EXP]{\prop_map_tokens:Nn} +% \begin{macro}[aux]{\prop_map_tokens_aux:nwn} +% The mapping grabs one key--value pair at a time, and stops when +% reaching the marker key |A|, with catcode \enquote{letter}, which +% cannot appear in normal keys since those are strings. The odd +% construction |\use:n {#1}| allows |#1| to contain any token. +% \begin{macrocode} +\cs_new:Npn \prop_map_tokens:Nn #1#2 + { + \exp_last_unbraced:Nno \prop_map_tokens_aux:nwn {#2} #1 + A \q_prop { } \q_recursion_stop + } +\cs_new:Npn \prop_map_tokens_aux:nwn #1 \q_prop #2 \q_prop #3 + { + \if_catcode:w A #2 + \exp_after:wN \prop_map_break: + \fi: + \use:n {#1} {#2} {#3} + \prop_map_tokens_aux:nwn {#1} + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[EXP]{\prop_get:Nn} +% \begin{macro}[aux]{\prop_get_aux:nnn} +% Getting expandably the value corresponding to a key in a property list +% is a simple instance of mapping some tokens. +% Map the function \cs{prop_get_aux:nnn} which takes as its three +% arguments the \meta{key} that we are looking for, the current +% \meta{key} and the current \meta{value}. If the \meta{keys} match, +% the \meta{value} is returned. If none of the keys match, this expands +% to nothing. +% \begin{macrocode} +\cs_new:Npn \prop_get:Nn #1 #2 + { \prop_map_tokens:Nn #1 { \prop_get_aux:nnn {#2} } } +\cs_new:Npn \prop_get_aux:nnn #1 #2 #3 + { \str_if_eq:nnT {#1} {#2} { \prop_map_break:n {#3} } } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Deprecated interfaces} +% +% Deprecated on 2011-05-27, for removal by 2011-08-31. +% +% \begin{macro}{\prop_display:N, \prop_display:c} +% An older name for \cs{prop_show:N}. +% \begin{macrocode} +\cs_new_eq:NN \prop_display:N \prop_show:N +\cs_new_eq:NN \prop_display:c \prop_show:c +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\prop_gget:NnN, \prop_gget:NVN, \prop_gget:cnN, \prop_gget:cVN} +% \begin{macro}[aux]{\prop_gget_aux:Nnnn} +% Getting globally is no longer supported: this is a conceptual change, so +% the necessary code for the transition is provided directly. +% \begin{macrocode} +\cs_new_protected:Npn \prop_gget:NnN #1#2#3 + { \prop_split:Nnn #1 {#2} { \prop_gget_aux:Nnnn #3 } } +\cs_new_protected:Npn \prop_gget_aux:Nnnn #1#2#3#4 + { \tl_gset:Nn #1 {#3} } +\cs_generate_variant:Nn \prop_gget:NnN { NV } +\cs_generate_variant:Nn \prop_gget:NnN { c , cV } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\prop_get_gdel:NnN} +% This name seems very odd. +% \begin{macrocode} +\cs_new_eq:NN \prop_get_gdel:NnN \prop_gpop:NnN +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[TF]{\prop_if_in:cc} +% A hang-over from an ancient implementation +% \begin{macrocode} +\cs_generate_variant:Nn \prop_if_in:NnT { cc } +\cs_generate_variant:Nn \prop_if_in:NnF { cc } +\cs_generate_variant:Nn \prop_if_in:NnTF { cc } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\prop_gput:ccx} +% Another one. +% \begin{macrocode} +\cs_generate_variant:Nn \prop_gput:Nnn { ccx } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[pTF] +% {\prop_if_eq:NN, \prop_if_eq:Nc, \prop_if_eq:cN, \prop_if_eq:cc} +% These ones do no even make sense! +% \begin{macrocode} +\prg_new_eq_conditional:NNn \prop_if_eq:NN \tl_if_eq:NN { p , T , F , TF } +\prg_new_eq_conditional:NNn \prop_if_eq:cN \tl_if_eq:cN { p , T , F , TF } +\prg_new_eq_conditional:NNn \prop_if_eq:Nc \tl_if_eq:Nc { p , T , F , TF } +\prg_new_eq_conditional:NNn \prop_if_eq:cc \tl_if_eq:cc { p , T , F , TF } +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +%</initex|package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintIndex
\ No newline at end of file diff --git a/Master/texmf-dist/source/latex/l3kernel/l3quark.dtx b/Master/texmf-dist/source/latex/l3kernel/l3quark.dtx new file mode 100644 index 00000000000..2326fd4519d --- /dev/null +++ b/Master/texmf-dist/source/latex/l3kernel/l3quark.dtx @@ -0,0 +1,486 @@ +% \iffalse meta-comment +% +%% File: l3quark.dtx Copyright (C) 1990-2011 The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +% +%<*driver|package> +\RequirePackage{l3names} +\GetIdInfo$Id: l3quark.dtx 2478 2011-06-19 21:34:23Z joseph $ + {L3 Experimental quarks} +%</driver|package> +%<*driver> +\documentclass[full]{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{^^A +% The \pkg{l3quark} package\\ Quarks^^A +% \thanks{This file describes v\ExplFileVersion, +% last revised \ExplFileDate.}^^A +% } +% +% \author{^^A +% The \LaTeX3 Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% +% \date{Released \ExplFileDate} +% +% \maketitle +% +% \begin{documentation} +% +% A special type of constants in \LaTeX3 are \enquote{quarks}. These are +% control +% sequences that expand to themselves and should therefore \emph{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 (\emph{i.e.}~\cs{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 +% \cs{if_meaning:w}. 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_|. +% +% \section{Defining quarks} +% +% \begin{function}{\quark_new:N} +% \begin{syntax} +% \cs{quark_new:N} \meta{quark} +% \end{syntax} +% Creates a new \meta{quark} which expands only to \meta{quark}. +% The \meta{quark} will be defined globally, and an error message +% will be raised if the name was already taken. +% \end{function} +% +% \begin{variable}{\q_stop} +% Used as a marker for delimited arguments, such as +% \begin{verbatim} +% \cs_set:Npn \tmp:w #1#2 \q_stop {#1} +% \end{verbatim} +% \end{variable} +% +% \begin{variable}{\q_mark} +% Used as a marker for delimited arguments when \cs{q_stop} is +% already in use. +% \end{variable} +% +% \begin{variable}{\q_nil} +% Quark to mark a null value in structured variables or functions. Used +% as an end delimiter when this may itself may need to be tested +% (in contrast to \cs{q_stop}, which is only ever used as a delimiter). +% \end{variable} +% +% \begin{variable}{\q_no_value} +% A canonical value for a missing value, when one is requested from +% a data structure. This is therefore used as a \enquote{return} value +% by functions such as \cs{prop_get:NnN} if there is no data to +% return. +% \end{variable} +% +% \section{Quark tests} +% +% The method used to define quarks means that the single token (\texttt{N}) +% tests are faster than the multi-token (\texttt{n}) tests. The later +% should therefore only be used when the argument can definitely take +% more than a single token. +% +% \begin{function}[EXP,pTF]{\quark_if_nil:N} +% \begin{syntax} +% \cs{quark_if_nil_p:N} \meta{token} +% \cs{quark_if_nil:NTF} \meta{token} \Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the \meta{token} is equal to \cs{q_nil}. The branching +% versions then leave either \meta{true code} or \meta{false code} in +% the input stream, as appropriate to the truth of the test and the +% variant of the function chosen. The logical truth of the test is +% left in the input stream by the predicate version. +% \end{function} +% +% \begin{function}[EXP,pTF]{\quark_if_nil:n, \quark_if_nil:o, \quark_if_nil:V} +% \begin{syntax} +% \cs{quark_if_nil_p:n} \Arg{token list} +% \cs{quark_if_nil:nTF} \Arg{token list} \Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the \meta{token list} contains only \cs{q_nil} (distinct +% from \meta{token list} being empty or containing \cs{q_nil} plus one +% or more other tokens). The branching versions then leave either +% \meta{true code} or \meta{false code} in the input stream, as +% appropriate to the truth of the test and the variant of the +% function chosen. The logical truth of the test is left in the input +% stream by the predicate version. +% \end{function} +% +% \begin{function}[EXP,pTF]{\quark_if_no_value:N, \quark_if_no_value:c} +% \begin{syntax} +% \cs{quark_if_no_value_p:N} \meta{token} +% \cs{quark_if_no_value:NTF} \meta{token} \Arg{true code} +% ~~\Arg{false code} +% \end{syntax} +% Tests if the \meta{token} is equal to \cs{q_no_value}. The branching +% versions then leave either \meta{true code} or \meta{false code} in +% the input stream, as appropriate to the truth of the test and the +% variant of the function chosen. The logical truth of the test is +% left in the input stream by the predicate version. +% \end{function} +% +% \begin{function}[EXP,pTF]{\quark_if_no_value:n} +% \begin{syntax} +% \cs{quark_if_no_value_p:n} \Arg{token list} +% \cs{quark_if_no_value:nTF} \Arg{token list} \Arg{true code} +% ~~\Arg{false code} +% \end{syntax} +% Tests if the \meta{token list} contains only \cs{q_no_value} +% (distinct from \meta{token list} being empty or containing +% \cs{q_no_value} plus one or more other tokens). The branching +% versions then leave either \meta{true code} or \meta{false code} in +% the input stream, as appropriate to the truth of the test and the +% variant of the function chosen. The logical truth of the test is +% left in the input stream by the predicate version. +% \end{function} +% +% \section{Recursion} +% +% This module provides a uniform interface to intercepting and +% terminating loops as when one is doing tail recursion. The building +% blocks follow below. +% +% \begin{variable}{\q_recursion_tail} +% This quark is appended to the data structure in question and +% appears as a real element there. This means it gets any list +% separators around it. +% \end{variable} +% +% \begin{variable}{\q_recursion_stop} +% This quark is added \emph{after} the data structure. Its purpose +% is to make it possible to terminate the recursion at any point +% easily. +% \end{variable} +% +% \begin{function}{\quark_if_recursion_tail_stop:N} +% \begin{syntax} +% \cs{quark_if_recursion_tail_stop:N} \Arg{token} +% \end{syntax} +% Tests if \meta{token} contains only the marker +% \cs{q_recursion_tail}, and if so terminates the recursion this is +% part of using \cs{use_none_delimit_by_q_recursion_stop:w}. The +% recursion input must include the marker tokens \cs{q_recursion_tail} +% and \cs{q_recursion_stop} as the last two items. +% \end{function} +% +% \begin{function} +% {\quark_if_recursion_tail_stop:n, \quark_if_recursion_tail_stop:o} +% \begin{syntax} +% \cs{quark_if_recursion_tail_stop:n} \Arg{tokens} +% \end{syntax} +% Tests if \meta{tokens} consists of the single token +% \cs{q_recursion_tail}, and if so terminates the recursion this is +% part of using \cs{use_none_delimit_by_q_recursion_stop:w}. The +% recursion input must include the marker tokens \cs{q_recursion_tail} +% and \cs{q_recursion_stop} as the last two items. +% \end{function} +% +% \begin{function}{\quark_if_recursion_tail_stop_do:Nn} +% \begin{syntax} +% \cs{quark_if_recursion_tail_stop_do:nn} \Arg{token} \Arg{insertion} +% \end{syntax} +% Tests if \meta{token} contains only the marker +% \cs{q_recursion_tail}, and if so terminates the recursion this is +% part of using \cs{use_none_delimit_by_q_recursion_stop:w}. The +% recursion input must include the marker tokens \cs{q_recursion_tail} +% and \cs{q_recursion_stop} as the last two items. The \meta{insertion} +% code is then added to the input stream after the recursion has +% ended. +% \end{function} +% +% \begin{function} +% {\quark_if_recursion_tail_stop_do:nn, \quark_if_recursion_tail_stop_do:on} +% \begin{syntax} +% \cs{quark_if_recursion_tail_stop_do:nn} \Arg{tokens} \Arg{insertion} +% \end{syntax} +% Tests if \meta{tokens} consists of the single token +% \cs{q_recursion_tail}, and if so terminates the recursion this is +% part of using \cs{use_none_delimit_by_q_recursion_stop:w}. The +% recursion input must include the marker tokens \cs{q_recursion_tail} +% and \cs{q_recursion_stop} as the last two items. The \meta{insertion} +% code is then added to the input stream after the recursion has +% ended. +% \end{function} +% +% \section{Internal quark functions} +% +% \begin{function}{\use_none_delimit_by_q_recursion_stop:w} +% \begin{syntax} +% \cs{use_none_delimit_by_q_recursion_stop:w} +% ~~\meta{tokens} \cs{q_recursion_stop} +% \end{syntax} +% Used to prematurely terminate a recursion using \cs{q_recursion_stop} +% as the end marker, removing any remaining \meta{tokens} from the +% input stream. +% \end{function} +% +% \begin{function}{\use_i_delimit_by_q_recursion_stop:nw} +% \begin{syntax} +% \cs{use_i_delimit_by_q_recursion_stop:nw} \Arg{insertion} +% ~~\meta{tokens} \cs{q_recursion_stop} +% \end{syntax} +% Used to prematurely terminate a recursion using \cs{q_recursion_stop} +% as the end marker, removing any remaining \meta{tokens} from the +% input stream. The \meta{insertion} is then made into the input +% stream after the end of the recursion. +% \end{function} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{l3quark} implementation} +% +% \TestFiles{m3quark001.lvt} +% +% \begin{macrocode} +%<*initex|package> +% \end{macrocode} +% +% \begin{macrocode} +%<*package> +\ProvidesExplPackage + {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +\package_check_loaded_expl: +%</package> +% \end{macrocode} +% +% \begin{macro}{\quark_new:N} +% \UnitTested +% Allocate a new quark. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \quark_new:N #1 { \tl_const:Nn #1 {#1} } +% \end{macrocode} +% \end{macro} +% +% \begin{variable}{\q_nil, \q_mark, \q_no_value, \q_stop} +% Some \enquote{public} quarks. \cs{q_stop} is an \enquote{end of +% argument} marker, \cs{q_nil} is a empty value and \cs{q_no_value} +% marks an empty argument. +% \begin{macrocode} +\quark_new:N \q_nil +\quark_new:N \q_mark +\quark_new:N \q_no_value +\quark_new:N \q_stop +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\q_recursion_tail,\q_recursion_stop} +% Quarks for ending recursions. Only ever used there! +% \cs{q_recursion_tail} is appended to whatever list structure we are +% doing recursion on, meaning it is added as a proper list item with +% whatever list separator is in use. \cs{q_recursion_stop} is placed +% directly after the list. +% \begin{macrocode} +\quark_new:N \q_recursion_tail +\quark_new:N \q_recursion_stop +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\quark_if_recursion_tail_stop:N} +% \UnitTested +% \begin{macro}{\quark_if_recursion_tail_stop_do:Nn} +% \UnitTested +% When doing recursions, it is easy to spend a lot of time testing if the +% end marker has been found. To avoid this, a dedicated end marker is used +% each time a recursion is set up. Thus if the marker is found everything +% can be wrapper up and finished off. The simple case is when the test +% can guarantee that only a single token is being tested. In this case, +% there is just a dedicated copy of the standard quark test. Both a gobbling +% version and one inserting end code are provided. +% \begin{macrocode} +\cs_new:Npn \quark_if_recursion_tail_stop:N #1 + { + \if_meaning:w #1 \q_recursion_tail + \exp_after:wN \use_none_delimit_by_q_recursion_stop:w + \fi: + } +\cs_new:Npn \quark_if_recursion_tail_stop_do:Nn #1#2 + { + \if_meaning:w #1 \q_recursion_tail + \exp_after:wN \use_i_delimit_by_q_recursion_stop:nw + \else: + \exp_after:wN \use_none:n + \fi: + {#2} + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro} +% {\quark_if_recursion_tail_stop:n,\quark_if_recursion_tail_stop:o} +% \UnitTested +% \begin{macro} +% {\quark_if_recursion_tail_stop_do:nn,\quark_if_recursion_tail_stop_do:on} +% \UnitTested +% \begin{macro}[aux]{\quark_if_recursion_tail_aux:w} +% The same idea applies when testing multiple tokens, but here a little more +% care is needed. It is possible that |#1| might be something like +% |{{{a}}}| or |{ab\iffalse}\fi|, which will therefore need to be tested +% in a detokenized manner. The way that this is done is using +% \cs{if_catcode:w}, with the idea being that this test will be \texttt{true} +% provided the auxiliary function returns nothing at all. If the auxiliary +% returns anything, it will be detokenized and so the test will be both +% \texttt{false} and safe. +% \begin{macrocode} +\cs_new:Npn \quark_if_recursion_tail_stop:n #1 + { + \if_catcode:w + A + \etex_detokenize:D \exp_after:wN + { + \quark_if_recursion_tail_aux:w #1 \q_recursion_stop + \q_recursion_tail \q_recursion_stop \q_stop + } + A + \exp_after:wN \use_none_delimit_by_q_recursion_stop:w + \fi: + } +\cs_new:Npn \quark_if_recursion_tail_stop_do:nn #1#2 + { + \if_catcode:w + A + \etex_detokenize:D \exp_after:wN + { + \quark_if_recursion_tail_aux:w #1 \q_recursion_stop + \q_recursion_tail \q_recursion_stop \q_stop + } + A + \exp_after:wN \use_i_delimit_by_q_recursion_stop:nw + \else: + \exp_after:wN \use_none:n + \fi: + {#2} + } +\cs_new:Npn \quark_if_recursion_tail_aux:w + #1 \q_recursion_tail #2 \q_recursion_stop #3 \q_stop + { #1 #2 } +\cs_generate_variant:Nn \quark_if_recursion_tail_stop:n { o } +\cs_generate_variant:Nn \quark_if_recursion_tail_stop_do:nn { o } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}[pTF]{\quark_if_nil:N} +% \UnitTested +% \begin{macro}[pTF]{\quark_if_no_value:N., \quark_if_no_value:c} +% \UnitTested +% Here we test if we found a special quark as the first argument. +% We better start with \cs{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} +\prg_new_conditional:Nnn \quark_if_nil:N { p, T , F , TF } + { + \if_meaning:w \q_nil #1 + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +\prg_new_conditional:Nnn \quark_if_no_value:N { p, T , F , TF } + { + \if_meaning:w \q_no_value #1 + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +\cs_generate_variant:Nn \quark_if_no_value_p:N { c } +\cs_generate_variant:Nn \quark_if_no_value:NT { c } +\cs_generate_variant:Nn \quark_if_no_value:NF { c } +\cs_generate_variant:Nn \quark_if_no_value:NTF { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[pTF]{\quark_if_nil:n, \quark_if_nil:V, \quark_if_nil:o} +% \UnitTested +% \begin{macro}[pTF]{\quark_if_no_value:n} +% \UnitTested +% These are essentially \cs{str_if_eq:nn} tests but done directly. +% \begin{macrocode} +\prg_new_conditional:Nnn \quark_if_nil:n { p, T , F , TF } + { + \if_int_compare:w \pdftex_strcmp:D + { \exp_not:N \q_nil } { \exp_not:n {#1} } = \c_zero + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +\prg_new_conditional:Nnn \quark_if_no_value:n { p, T , F , TF } + { + \if_int_compare:w \pdftex_strcmp:D + { \exp_not:N \q_no_value } { \exp_not:n {#1} } = \c_zero + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +\cs_generate_variant:Nn \quark_if_nil_p:n { V , o } +\cs_generate_variant:Nn \quark_if_nil:nTF { V , o } +\cs_generate_variant:Nn \quark_if_nil:nT { V , o } +\cs_generate_variant:Nn \quark_if_nil:nF { V , o } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macrocode} +%</initex|package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintIndex +% +% \endinput diff --git a/Master/texmf-dist/source/latex/l3kernel/l3seq.dtx b/Master/texmf-dist/source/latex/l3kernel/l3seq.dtx new file mode 100644 index 00000000000..088165a02fc --- /dev/null +++ b/Master/texmf-dist/source/latex/l3kernel/l3seq.dtx @@ -0,0 +1,1812 @@ +% \iffalse meta-comment +% +%% File: l3seq.dtx Copyright (C) 1990-2011 The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +% +%<*driver|package> +\RequirePackage{l3names} +\GetIdInfo$Id: l3seq.dtx 2478 2011-06-19 21:34:23Z joseph $ + {L3 Experimental sequences and stacks} +%</driver|package> +%<*driver> +\documentclass[full]{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{^^A +% The \pkg{l3seq} package\\ Sequences and stacks^^A +% \thanks{This file describes v\ExplFileVersion, +% last revised \ExplFileDate.}^^A +% } +% +% \author{^^A +% The \LaTeX3 Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% +% \date{Released \ExplFileDate} +% +% \maketitle +% +% \begin{documentation} +% +% \LaTeX3 implements a \enquote{sequence} data type, which contain +% an ordered list of entries which may contain any \meta{balanced text}. +% It is possible to map functions to sequences such that the function +% is applied to every item in the sequence. +% +% Sequences are also used to implement stack functions in \LaTeX3. This +% is achieved using a number of dedicated stack functions. +% +% \section{Creating and initialising sequences} +% +% \begin{function}{\seq_new:N, \seq_new:c} +% \begin{syntax} +% \cs{seq_new:N} \meta{sequence} +% \end{syntax} +% Creates a new \meta{sequence} or raises an error if the name is +% already taken. The declaration is global. The \meta{sequence} will +% initially contain no items. +% \end{function} +% +% \begin{function}{\seq_clear:N, \seq_clear:c} +% \begin{syntax} +% \cs{seq_clear:N} \meta{sequence} +% \end{syntax} +% Clears all items from the \meta{sequence} within the scope of +% the current \TeX{} group. +% \end{function} +% +% \begin{function}{\seq_gclear:N, \seq_gclear:c} +% \begin{syntax} +% \cs{seq_gclear:N} \meta{sequence} +% \end{syntax} +% Clears all entries from the \meta{sequence} globally. +% \end{function} +% +% \begin{function}{\seq_clear_new:N, \seq_clear_new:c} +% \begin{syntax} +% \cs{seq_clear_new:N} \meta{sequence} +% \end{syntax} +% If the \meta{sequence} already exists, clears it within the scope +% of the current \TeX{} group. If the \meta{sequence} is not defined, +% it will be created (using \cs{seq_new:N}). Thus the sequence is +% guaranteed to be available and clear within the current \TeX{} +% group. The \meta{sequence} will exist globally, but the content +% outside of the current \TeX{} group is not specified. +% \end{function} +% +% \begin{function}{\seq_gclear_new:N, \seq_gclear_new:c} +% \begin{syntax} +% \cs{seq_gclear_new:N} \meta{sequence} +% \end{syntax} +% If the \meta{sequence} already exists, clears it globally. If the +% \meta{sequence} is not defined, it will be created (using +% \cs{seq_new:N}). Thus the sequence is guaranteed to be available +% and globally clear. +% \end{function} +% +% \begin{function} +% {\seq_set_eq:NN, \seq_set_eq:cN, \seq_set_eq:Nc, \seq_set_eq:cc} +% \begin{syntax} +% \cs{seq_set_eq:NN} \meta{sequence1} \meta{sequence2} +% \end{syntax} +% Sets the content of \meta{sequence1} equal to that of +% \meta{sequence2}. This assignment is restricted to the current +% \TeX{} group level. +% \end{function} +% +% \begin{function} +% {\seq_gset_eq:NN, \seq_gset_eq:cN, \seq_gset_eq:Nc, \seq_gset_eq:cc} +% \begin{syntax} +% \cs{seq_gset_eq:NN} \meta{sequence1} \meta{sequence2} +% \end{syntax} +% Sets the content of \meta{sequence1} equal to that of +% \meta{sequence2}. This assignment is global and so is not +% limited by the current \TeX{} group level. +% \end{function} +% +% \begin{function}{\seq_concat:NNN, \seq_concat:ccc} +% \begin{syntax} +% \cs{seq_concat:NNN} \meta{sequence1} \meta{sequence2} \meta{sequence3} +% \end{syntax} +% Concatenates the content of \meta{sequence2} and \meta{sequence3} +% together and saves the result in \meta{sequence1}. The items in +% \meta{sequence2} will be placed at the left side of the new sequence. +% This operation is local to the current \TeX{} group and will +% remove any existing content in \meta{sequence1}. +% \end{function} +% +% \begin{function}{\seq_gconcat:NNN, \seq_gconcat:ccc} +% \begin{syntax} +% \cs{seq_gconcat:NNN} \meta{sequence1} \meta{sequence2} \meta{sequence3} +% \end{syntax} +% Concatenates the content of \meta{sequence2} and \meta{sequence3} +% together and saves the result in \meta{sequence1}. The items in +% \meta{sequence2} will be placed at the left side of the new sequence. +% This operation is global and will remove any existing content in +% \meta{sequence1}. +% \end{function} +% +% \section{Appending data to sequences} +% +% \begin{function}{ +% \seq_put_left:Nn, \seq_put_left:NV, \seq_put_left:Nv, +% \seq_put_left:No, \seq_put_left:Nx, +% \seq_put_left:cn, \seq_put_left:cV, \seq_put_left:cv, +% \seq_put_left:co, \seq_put_left:cx +% } +% \begin{syntax} +% \cs{seq_put_left:Nn} \meta{sequence} \Arg{item} +% \end{syntax} +% Appends the \meta{item} to the left of the \meta{sequence}. +% The assignment is restricted to the current \TeX{} group. +% \end{function} +% +% \begin{function}{ +% \seq_gput_left:Nn, \seq_gput_left:NV, \seq_gput_left:Nv, +% \seq_gput_left:No, \seq_gput_left:Nx, +% \seq_gput_left:cn, \seq_gput_left:cV, \seq_gput_left:cv, +% \seq_gput_left:co, \seq_gput_left:cx +% } +% \begin{syntax} +% \cs{seq_gput_left:Nn} \meta{sequence} \Arg{item} +% \end{syntax} +% Appends the \meta{item} to the left of the \meta{sequence}. +% The assignment is global. +% \end{function} +% +% \begin{function}{ +% \seq_put_right:Nn, \seq_put_right:NV, \seq_put_right:Nv, +% \seq_put_right:No, \seq_put_right:Nx, +% \seq_put_right:cn, \seq_put_right:cV, \seq_put_right:cv, +% \seq_put_right:co, \seq_put_right:cx +% } +% \begin{syntax} +% \cs{seq_put_right:Nn} \meta{sequence} \Arg{item} +% \end{syntax} +% Appends the \meta{item} to the right of the \meta{sequence}. +% The assignment is restricted to the current \TeX{} group. +% \end{function} +% +% \begin{function}{ +% \seq_gput_right:Nn, \seq_gput_right:NV, \seq_gput_right:Nv, +% \seq_gput_right:No, \seq_gput_right:Nx, +% \seq_gput_right:cn, \seq_gput_right:cV, \seq_gput_right:cv, +% \seq_gput_right:co, \seq_gput_right:cx +% } +% \begin{syntax} +% \cs{seq_gput_right:Nn} \meta{sequence} \Arg{item} +% \end{syntax} +% Appends the \meta{item} to the right of the \meta{sequence}. +% The assignment is global. +% \end{function} +% +% \section{Recovering items from sequences} +% +% Items can be recovered from either the left or the right of sequences. +% For implementation reasons, the actions at the left of the sequence are +% faster than those acting on the right. These functions all assign the +% recovered material locally, \emph{i.e.}~setting the +% \meta{token list variable} used with \cs{tl_set:Nn} and \emph{never} +% \cs{tl_gset:Nn}. +% +% \begin{function}{\seq_get_left:NN, \seq_get_left:cN} +% \begin{syntax} +% \cs{seq_get_left:NN} \meta{sequence} \meta{token list variable} +% \end{syntax} +% Stores the left-most item from a \meta{sequence} in the +% \meta{token list variable} without removing it from the +% \meta{sequence}. The \meta{token list variable} is assigned locally. +% If \meta{sequence} is empty an error will be raised. +% \end{function} +% +% \begin{function}{\seq_get_right:NN, \seq_get_right:cN} +% \begin{syntax} +% \cs{seq_get_right:NN} \meta{sequence} \meta{token list variable} +% \end{syntax} +% Stores the right-most item from a \meta{sequence} in the +% \meta{token list variable} without removing it from the +% \meta{sequence}. The \meta{token list variable} is assigned locally. +% If \meta{sequence} is empty an error will be raised. +% \end{function} +% +% \begin{function}{\seq_pop_left:NN, \seq_pop_left:cN} +% \begin{syntax} +% \cs{seq_pop_left:NN} \meta{sequence} \meta{token list variable} +% \end{syntax} +% Pops the left-most item from a \meta{sequence} into the +% \meta{token list variable}, \emph{i.e.}~removes the item from the +% sequence and stores it in the \meta{token list variable}. +% Both of the variables are assigned locally. If \meta{sequence} is +% empty an error will be raised. +% \end{function} +% +% \begin{function}{\seq_gpop_left:NN, \seq_gpop_left:cN} +% \begin{syntax} +% \cs{seq_gpop_left:NN} \meta{sequence} \meta{token list variable} +% \end{syntax} +% Pops the left-most item from a \meta{sequence} into the +% \meta{token list variable}, \emph{i.e.}~removes the item from the +% sequence and stores it in the \meta{token list variable}. +% The \meta{sequence} is modified globally, while the assignment of +% the \meta{token list variable} is local. +% If \meta{sequence} is empty an error will be raised. +% \end{function} +% +% \begin{function}{\seq_pop_right:NN, \seq_pop_right:cN} +% \begin{syntax} +% \cs{seq_pop_right:NN} \meta{sequence} \meta{token list variable} +% \end{syntax} +% Pops the right-most item from a \meta{sequence} into the +% \meta{token list variable}, \emph{i.e.}~removes the item from the +% sequence and stores it in in the \meta{token list variable}. +% Both of the variables are assigned locally. If \meta{sequence} is +% empty an error will be raised. +% \end{function} +% +% \begin{function}{\seq_gpop_right:NN, \seq_gpop_right:cN} +% \begin{syntax} +% \cs{seq_gpop_right:NN} \meta{sequence} \meta{token list variable} +% \end{syntax} +% Pops the right-most item from a \meta{sequence} into the +% \meta{token list variable}, \emph{i.e.}~removes the item from the +% sequence and stores it in the \meta{token list variable}. +% The \meta{sequence} is modified globally, while the assignment of +% the \meta{token list variable} is local. +% If \meta{sequence} is empty an error will be raised. +% \end{function} +% +% \section{Modifying sequences} +% +% While sequences are normally used as ordered lists, it may be +% necessary to modify the content. The functions here may be used +% to update sequences, while retaining the order of the unaffected +% entries. +% +% \begin{function}{\seq_remove_duplicates:N, \seq_remove_duplicates:c} +% \begin{syntax} +% \cs{seq_remove_duplicates:N} \meta{sequence} +% \end{syntax} +% Removes duplicate items from the \meta{sequence}, leaving the +% left most copy of each item in the \meta{sequence}. The \meta{item} +% comparison takes place on a token basis, as for \cs{tl_if_eq:nn(TF)}. +% The removal is local to the current \TeX{} group. +% \begin{texnote} +% This function iterates through every item in the \meta{sequence} and +% does a comparison with the \meta{items} already checked. It is therefore +% relatively slow with large sequences. +% \end{texnote} +% \end{function} +% +% \begin{function}{\seq_gremove_duplicates:N, \seq_gremove_duplicates:c} +% \begin{syntax} +% \cs{seq_gremove_duplicates:N} \meta{sequence} +% \end{syntax} +% Removes duplicate items from the \meta{sequence}, leaving the +% left most copy of each item in the \meta{sequence}. The \meta{item} +% comparison takes place on a token basis, as for \cs{tl_if_eq:nn(TF)}. +% The removal is applied globally. +% \begin{texnote} +% This function iterates through every item in the \meta{sequence} and +% does a comparison with the \meta{items} already checked. It is therefore +% relatively slow with large sequences. +% \end{texnote} +% \end{function} +% +% \begin{function}{\seq_remove_all:Nn, \seq_remove_all:cn} +% \begin{syntax} +% \cs{seq_remove_all:Nn} \meta{sequence} \Arg{item} +% \end{syntax} +% Removes every occurrence of \meta{item} from the \meta{sequence}. +% The \meta{item} comparison takes place on a token basis, as for +% \cs{tl_if_eq:nn(TF)}. The removal is local to the current \TeX{} group. +% \end{function} +% +% \begin{function}{\seq_gremove_all:Nn, \seq_gremove_all:cn} +% \begin{syntax} +% \cs{seq_gremove_all:Nn} \meta{sequence} \Arg{item} +% \end{syntax} +% Removes each occurrence of \meta{item} from the \meta{sequence}. +% The \meta{item} comparison takes place on a token basis, as for +% \cs{tl_if_eq:nn(TF)}. The removal is applied globally. +% \end{function} +% +% \section{Sequence conditionals} +% +% \begin{function}[EXP,pTF]{\seq_if_empty:N, \seq_if_empty:c} +% \begin{syntax} +% \cs{seq_if_empty_p:N} \meta{sequence} +% \cs{seq_if_empty:NTF} \meta{sequence} \Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the \meta{sequence} is empty (containing no items). The +% branching versions then leave either \meta{true code} or +% \meta{false code} in the input stream, as appropriate to the truth of +% the test and the variant of the function chosen. The logical truth of +% the test is left in the input stream by the predicate version. +% \end{function} +% +% \begin{function}[TF]{ +% \seq_if_in:Nn, \seq_if_in:NV, \seq_if_in:Nv, \seq_if_in:No, \seq_if_in:Nx, +% \seq_if_in:cn, \seq_if_in:cV, \seq_if_in:cv, \seq_if_in:co, \seq_if_in:cx +% } +% \begin{syntax} +% \cs{seq_if_in:NnTF} \meta{sequence} \Arg{item} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the \meta{item} is present in the \meta{sequence}. +% Either the \meta{true code} or \meta{false code} is left in the input +% stream, as appropriate to the truth of the test and the variant of the +% function +% chosen. +% \end{function} +% +% \section{Mapping to sequences} +% +% \begin{function}[EXP]{\seq_map_function:NN, \seq_map_function:cN} +% \begin{syntax} +% \cs{seq_map_function:NN} \meta{sequence} \meta{function} +% \end{syntax} +% Applies \meta{function} to every \meta{item} stored in the +% \meta{sequence}. The \meta{function} will receive one argument for +% each iteration. The \meta{items} are returned from left to right. +% The function \cs{seq_map_inline:Nn} is in general more efficient +% than \cs{seq_map_function:NN}. +% One mapping may be nested inside another. +% \end{function} +% +% \begin{function}{\seq_map_inline:Nn, \seq_map_inline:cn} +% \begin{syntax} +% \cs{seq_map_inline:Nn} \meta{sequence} \Arg{inline function} +% \end{syntax} +% Applies \meta{inline function} to every \meta{item} stored +% within the \meta{sequence}. The \meta{inline function} should +% consist of code which will receive the \meta{item} as |#1|. +% One in line mapping can be nested inside another. The \meta{items} +% are returned from left to right. +% \end{function} +% +% \begin{function}{ +% \seq_map_variable:NNn, \seq_map_variable:Ncn, +% \seq_map_variable:cNn, \seq_map_variable:ccn +% } +% \begin{syntax} +% \cs{seq_map_variable:NNn} \meta{sequence} +% ~~\meta{tl~var.} \Arg{function using tl~var.} +% \end{syntax} +% Stores each entry in the \meta{sequence} in turn in the +% \meta{tl~var.}\ and applies the \meta{function using tl~var.} +% The \meta{function} will usually consist of code making use of +% the \meta{tl~var.}, but this is not enforced. One variable +% mapping can be nested inside another. The \meta{items} +% are returned from left to right. +% \end{function} +% +% \begin{function}[EXP]{\seq_map_break:} +% \begin{syntax} +% \cs{seq_map_break:} +% \end{syntax} +% Used to terminate a \cs{seq_map_\ldots} function before all +% entries in the \meta{sequence} have been processed. This will +% normally take place within a conditional statement, for example +% \begin{verbatim} +% \seq_map_inline:Nn \l_my_seq +% { +% \str_if_eq:nnTF { #1 } { bingo } +% { \seq_map_break: } +% { +% % Do something useful +% } +% } +% \end{verbatim} +% Use outside of a \cs{seq_map_\ldots} scenario will lead to low +% level \TeX{} errors. +% \begin{texnote} +% When the mapping is broken, additional tokens may be inserted by the +% internal macro \cs{seq_break_point:n} before further items are taken +% from the input stream. This will depend on the design of the mapping +% function. +% \end{texnote} +% \end{function} +% +% \begin{function}[EXP]{\seq_map_break:n} +% \begin{syntax} +% \cs{seq_map_break:n} \Arg{tokens} +% \end{syntax} +% Used to terminate a \cs{seq_map_\ldots} function before all +% entries in the \meta{sequence} have been processed, inserting +% the \meta{tokens} after the mapping has ended. This will +% normally take place within a conditional statement, for example +% \begin{verbatim} +% \seq_map_inline:Nn \l_my_seq +% { +% \str_if_eq:nnTF { #1 } { bingo } +% { \seq_map_break:n { <tokens> } } +% { +% % Do something useful +% } +% } +% \end{verbatim} +% Use outside of a \cs{seq_map_\ldots} scenario will lead to low +% level \TeX{} errors. +% \begin{texnote} +% When the mapping is broken, additional tokens may be inserted by the +% internal macro \cs{seq_break_point:n} before the \meta{tokens} are +% inserted into the input stream. +% This will depend on the design of the mapping function. +% \end{texnote} +% \end{function} +% +% \section{Sequences as stacks} +% +% Sequences can be used as stacks, where data is pushed to and popped +% from the top of the sequence. (The left of a sequence is the top, for +% performance reasons.) The stack functions for sequences are not +% intended to be mixed with the general ordered data functions detailed +% in the previous section: a sequence should either be used as an +% ordered data type or as a stack, but not in both ways. +% +% \begin{function}{\seq_get:NN, \seq_get:cN} +% \begin{syntax} +% \cs{seq_get:NN} \meta{sequence} \meta{token list variable} +% \end{syntax} +% Reads the top item from a \meta{sequence} into the +% \meta{token list variable} without removing it from the +% \meta{sequence}. The \meta{token list variable} is assigned locally. +% If \meta{sequence} is empty an error will be raised. +% \end{function} +% +% \begin{function}{\seq_pop:NN, \seq_pop:cN} +% \begin{syntax} +% \cs{seq_pop:NN} \meta{sequence} \meta{token list variable} +% \end{syntax} +% Pops the top item from a \meta{sequence} into the +% \meta{token list variable}. Both of the variables are assigned +% locally. If \meta{sequence} is empty an error will be raised. +% \end{function} +% +% \begin{function}{\seq_gpop:NN, \seq_gpop:cN} +% \begin{syntax} +% \cs{seq_gpop:NN} \meta{sequence} \meta{token list variable} +% \end{syntax} +% Pops the top item from a \meta{sequence} into the +% \meta{token list variable}. The \meta{sequence} is modified globally, +% while the \meta{token list variable} is assigned locally. If +% \meta{sequence} is empty an error will be raised. +% \end{function} +% +% \begin{function} +% { +% \seq_push:Nn, \seq_push:NV, \seq_push:Nv, \seq_push:No, \seq_push:Nx, +% seq_push:cn, \seq_push:cV, \seq_push:cv, \seq_push:co, \seq_push:cx +% } +% \begin{syntax} +% \cs{seq_push:Nn} \meta{sequence} \Arg{item} +% \end{syntax} +% Adds the \Arg{item} to the top of the \meta{sequence}. +% The assignment is restricted to the current \TeX{} group. +% \end{function} +% +% \begin{function} +% { +% \seq_gpush:Nn, \seq_gpush:NV, \seq_gpush:Nv, +% \seq_gpush:No, \seq_gpush:Nx, +% \seq_gpush:cn, \seq_gpush:cV, \seq_gpush:cv, +% \seq_gpush:co, \seq_gpush:cx +% } +% \begin{syntax} +% \cs{seq_gpush:Nn} \meta{sequence} \Arg{item} +% \end{syntax} +% Pushes the \meta{item} onto the end of the top of the +% \meta{sequence}. The assignment is global. +% \end{function} +% +% \section{Viewing sequences} +% +% \begin{function}{\seq_show:N, \seq_show:c} +% \begin{syntax} +% \cs{seq_show:N} \meta{sequence} +% \end{syntax} +% Displays the entries in the \meta{sequence} in the terminal. +% \end{function} +% +% \section{Experimental sequence functions} +% +% This section contains functions which may or may not be retained, depending +% on how useful they are found to be. +% +% \begin{function}[TF]{\seq_get_left:NN, \seq_get_left:cN} +% \begin{syntax} +% \cs{seq_get_left:NNTF} \meta{sequence} \meta{token list variable} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% If the \meta{sequence} is empty, leaves the \meta{false code} in the +% input stream and leaves the \meta{token list variable} unchanged. If the +% \meta{sequence} is non-empty, stores the left-most item from a \meta{sequence} +% in the \meta{token list variable} without removing it from a +% \meta{sequence}. The \meta{true code} is then left in the input stream. +% The \meta{token list variable} is assigned locally. +% \end{function} +% +% \begin{function}[TF]{\seq_get_right:NN, \seq_get_right:cN} +% \begin{syntax} +% \cs{seq_get_right:NNTF} \meta{sequence} \meta{token list variable} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% If the \meta{sequence} is empty, leaves the \meta{false code} in the +% input stream and leaves the \meta{token list variable} unchanged. If the +% \meta{sequence} is non-empty, stores the right-most item from a \meta{sequence} +% in the \meta{token list variable} without removing it from a +% \meta{sequence}. The \meta{true code} is then left in the input stream. +% The \meta{token list variable} is assigned locally. +% \end{function} +% +% \begin{function}[TF]{\seq_pop_left:NN, \seq_pop_left:cN} +% \begin{syntax} +% \cs{seq_pop_left:NNTF} \meta{sequence} \meta{token list variable} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% If the \meta{sequence} is empty, leaves the \meta{false code} in the +% input stream and leaves the \meta{token list variable} unchanged. If the +% \meta{sequence} is non-empty, pops the left-most item from a \meta{sequence} +% in the \meta{token list variable}, \emph{i.e.}~removes the item from a +% \meta{sequence}. The \meta{true code} is then left in the input stream. +% Both the \meta{sequence} and the \meta{token list variable} are assigned +% locally. +% \end{function} +% +% \begin{function}[TF]{\seq_gpop_left:NN, \seq_gpop_left:cN} +% \begin{syntax} +% \cs{seq_gpop_left:NNTF} \meta{sequence} \meta{token list variable} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% If the \meta{sequence} is empty, leaves the \meta{false code} in the +% input stream and leaves the \meta{token list variable} unchanged. If the +% \meta{sequence} is non-empty, pops the left-most item from a \meta{sequence} +% in the \meta{token list variable}, \emph{i.e.}~removes the item from a +% \meta{sequence}. The \meta{true code} is then left in the input stream. +% The \meta{sequence} is modified globally, while the \meta{token list variable} +% is assigned locally. +% \end{function} +% +% \begin{function}[TF]{\seq_pop_right:NN, \seq_pop_right:cN} +% \begin{syntax} +% \cs{seq_pop_right:NNTF} \meta{sequence} \meta{token list variable} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% If the \meta{sequence} is empty, leaves the \meta{false code} in the +% input stream and leaves the \meta{token list variable} unchanged. If the +% \meta{sequence} is non-empty, pops the right-most item from a \meta{sequence} +% in the \meta{token list variable}, \emph{i.e.}~removes the item from a +% \meta{sequence}. The \meta{true code} is then left in the input stream. +% Both the \meta{sequence} and the \meta{token list variable} are assigned +% locally. +% \end{function} +% +% \begin{function}[TF]{\seq_gpop_right:NN, \seq_gpop_right:cN} +% \begin{syntax} +% \cs{seq_gpop_right:NNTF} \meta{sequence} \meta{token list variable} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% If the \meta{sequence} is empty, leaves the \meta{false code} in the +% input stream and leaves the \meta{token list variable} unchanged. If the +% \meta{sequence} is non-empty, pops the right-most item from a \meta{sequence} +% in the \meta{token list variable}, \emph{i.e.}~removes the item from a +% \meta{sequence}. The \meta{true code} is then left in the input stream. +% The \meta{sequence} is modified globally, while the \meta{token list variable} +% is assigned locally. +% \end{function} +% +% \begin{function}[EXP]{\seq_length:N, \seq_length:c} +% \begin{syntax} +% \cs{seq_length:N} \meta{sequence} +% \end{syntax} +% Leaves the number of items in the \meta{sequence} in the input +% stream as an \meta{integer denotation}. The total number of items +% in a \meta{sequence} will include those which are empty and duplicates, +% \emph{i.e.}~every item in a \meta{sequence} is unique. +% \end{function} +% +% \begin{function}[EXP]{\seq_item:Nn, \seq_item:cn} +% \begin{syntax} +% \cs{seq_item:Nn} \meta{sequence} \Arg{integer expression} +% \end{syntax} +% Indexing items in the \meta{sequence} from $0$ at the top (left), this +% function will evaluate the \meta{integer expression} and leave the +% appropriate item from the sequence in the input stream. If the +% \meta{integer expression} is negative, indexing occurs from the +% bottom (right) of the sequence. When the \meta{integer expression} +% is larger than the number of items in the \meta{sequence} (as +% calculated by \cs{seq_length:N}) then the function will expand to +% nothing. +% \end{function} +% +% \begin{function}[EXP]{\seq_use:N, \seq_use:c} +% \begin{syntax} +% \cs{seq_use:N} \meta{sequence} +% \end{syntax} +% Places each \meta{item} in the \meta{sequence} in turn in the input stream. +% This occurs in an expandable fashion, and is implemented as a mapping. +% This means that the process may be prematurely terminated using +% \cs{seq_map_break:} or \cs{seq_map_break:n}. The \meta{items} in the +% \meta{sequence} will be used from left (top) to right (bottom). +% \end{function} +% +% \begin{function}[EXP] +% { +% \seq_mapthread_function:NNN, \seq_mapthread_function:NcN, +% \seq_mapthread_function:cNN, \seq_mapthread_function:ccN +% } +% \begin{syntax} +% \cs{seq_mapthread_function:NNN} \meta{seq1} \meta{seq2} \meta{function} +% \end{syntax} +% Applies \meta{function} to every pair of items +% \meta{seq1-item}--\meta{seq2-item} from the two sequences, returning +% items from both sequences from left to right. The \meta{function} will +% receive two \texttt{n}-type arguments for each iteration. The mapping +% will terminate when +% the end of either sequence is reached (\emph{i.e.}~whichever sequence has +% fewer items determines how many iterations +% occur). +% \end{function} +% +% \begin{function} +% { +% \seq_set_from_clist:NN, \seq_set_from_clist:cN, +% \seq_set_from_clist:Nc, \seq_set_from_clist:cc, +% \seq_set_from_clist:Nn, \seq_set_from_clist:cn +% } +% \begin{syntax} +% \cs{seq_set_from_clist:NN} \meta{sequence} \meta{comma-list} +% \end{syntax} +% Sets the \meta{sequence} within the current \TeX{} group to be equal +% to the content of the \meta{comma-list}. +% \end{function} +% +% \begin{function} +% { +% \seq_gset_from_clist:NN, \seq_gset_from_clist:cN, +% \seq_gset_from_clist:Nc, \seq_gset_from_clist:cc, +% \seq_gset_from_clist:Nn, \seq_gset_from_clist:cn +% } +% \begin{syntax} +% \cs{seq_gset_from_clist:NN} \meta{sequence} \meta{comma-list} +% \end{syntax} +% Sets the \meta{sequence} globally to equal to the content of the +% \meta{comma-list}. +% \end{function} +% +% \section{Internal sequence functions} +% +% \begin{function}{\seq_if_empty_err_break:N} +% \begin{syntax} +% \cs{seq_if_empty_err_break:N} \meta{sequence} +% \end{syntax} +% Tests if the \meta{sequence} is empty, and if so issues an error +% message before skipping over any tokens up to \cs{seq_break_point:n}. +% This function is used to avoid more serious errors which would +% otherwise occur if some internal functions were applied to an +% empty \meta{sequence}. +% \end{function} +% +% \begin{function}[EXP]{\seq_item:n} +% \begin{syntax} +% \cs{seq_item:n} \meta{item} +% \end{syntax} +% The internal token used to begin each sequence entry. If expanded +% outside of a mapping or manipulation function, an error will be +% raised. The definition should always be set globally. +% \end{function} +% +% \begin{function}{\seq_push_item_def:n, \seq_push_item_def:x} +% \begin{syntax} +% \cs{seq_push_item_def:n} \Arg{code} +% \end{syntax} +% Saves the definition of \cs{seq_item:n} and redefines it to +% accept one parameter and expand to \meta{code}. This function +% should always be balanced by use of \cs{seq_pop_item_def:}. +% \end{function} +% +% \begin{function}{\seq_pop_item_def:} +% \begin{syntax} +% \cs{seq_pop_item_def:} +% \end{syntax} +% Restores the definition of \cs{seq_item:n} most recently saved by +% \cs{seq_push_item_def:n}. This function should always be used in +% a balanced pair with \cs{seq_push_item_def:n}. +% \end{function} +% +% \begin{function}[EXP]{\seq_break:} +% \begin{syntax} +% \cs{seq_break:} +% \end{syntax} +% Used to terminate sequence functions by gobbling all tokens +% up to \cs{seq_break_point:n}. This function is a copy of +% \cs{seq_map_break:}, but is used in situations which are +% not mappings. +% \end{function} +% +% \begin{function}[EXP]{\seq_break:n} +% \begin{syntax} +% \cs{seq_break:n} \Arg{tokens} +% \end{syntax} +% Used to terminate sequence functions by gobbling all tokens +% up to \cs{seq_break_point:n}, then inserting the \meta{tokens} +% before continuing reading the input stream. This function is a copy +% of \cs{seq_map_break:n}, but is used in situations which are +% not mappings. +% \end{function} +% +% \begin{function}[EXP]{\seq_break_point:n} +% \begin{syntax} +% \cs{seq_break_point:n} \meta{tokens} +% \end{syntax} +% Used to mark the end of a recursion or mapping: the functions +% \cs{seq_map_break:} and \cs{seq_map_break:n} use this to break out +% of the loop. After the loop ends, the \meta{tokens} are inserted into +% the input stream. This occurs even if the the break functions are +% \emph{not} applied: \cs{seq_break_point:n} is functionally-equivalent +% in these cases to \cs{use:n}. +% \end{function} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{l3seq} implementation} +% +% \TestFiles{m3seq002,m3seq003} +% +% \begin{macrocode} +%<*initex|package> +% \end{macrocode} +% +% \begin{macrocode} +%<*package> +\ProvidesExplPackage + {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +\package_check_loaded_expl: +%</package> +% \end{macrocode} +% +% A sequence is a control sequence whose top-level expansion is of +% the form \enquote{\cs{seq_item:n} \marg{item$_0$} +% \ldots \cs{seq_item:n} \marg{item$_{n-1}$}}. An earlier implementation +% used the structure \enquote{\cs{seq_elt:w} \meta{item$_1$} +% \cs{seq_elt_end:} \ldots \cs{seq_elt:w} \meta{item$_n$} +% \cs{seq_elt_end:}}. This allows rapid searching using a delimited +% function, but is not suitable for items containing |{|, |}| and |#| +% tokens, and also leads to the loss of surrounding braces +% around items. +% +% \begin{macro}[int]{\seq_item:n} +% The delimiter is always defined, but when used incorrectly simply +% removes its argument and hits an undefined control sequence to +% raise an error. +% \begin{macrocode} +\cs_new:Npn \seq_item:n + { + \seq_use_error: + \use_none:n + } +% \end{macrocode} +% \end{macro} +% +% \begin{variable}{\l_seq_tmpa_tl, \l_seq_tmpb_tl} +% Scratch space for various internal uses. +% \begin{macrocode} +\tl_new:N \l_seq_tmpa_tl +\tl_new:N \l_seq_tmpb_tl +% \end{macrocode} +% \end{variable} +% +% \subsection{Allocation and initialisation} +% +% \begin{macro}{\seq_new:N,\seq_new:c} +% \UnitTested +% Internally, sequences are just token lists. +% \begin{macrocode} +\cs_new_eq:NN \seq_new:N \tl_new:N +\cs_new_eq:NN \seq_new:c \tl_new:c +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\seq_clear:N, \seq_clear:c} +% \UnitTested +% \begin{macro}{\seq_gclear:N, \seq_gclear:c} +% \UnitTested +% Clearing sequences is just the same as clearing token lists. +% \begin{macrocode} +\cs_new_eq:NN \seq_clear:N \tl_clear:N +\cs_new_eq:NN \seq_clear:c \tl_clear:c +\cs_new_eq:NN \seq_gclear:N \tl_gclear:N +\cs_new_eq:NN \seq_gclear:c \tl_gclear:c +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\seq_clear_new:N, \seq_clear_new:c} +% \UnitTested +% \begin{macro}{\seq_gclear_new:N, \seq_gclear_new:c} +% \UnitTested +% Once again a copy from the token list functions. +% \begin{macrocode} +\cs_new_eq:NN \seq_clear_new:N \tl_clear_new:N +\cs_new_eq:NN \seq_clear_new:c \tl_clear_new:c +\cs_new_eq:NN \seq_gclear_new:N \tl_gclear_new:N +\cs_new_eq:NN \seq_gclear_new:c \tl_gclear_new:c +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\seq_set_eq:NN, \seq_set_eq:cN, \seq_set_eq:Nc, \seq_set_eq:cc} +% \UnitTested +% \begin{macro} +% {\seq_gset_eq:NN, \seq_gset_eq:cN, \seq_gset_eq:Nc, \seq_gset_eq:cc} +% \UnitTested +% Once again, these are simple copies from the token list functions. +% \begin{macrocode} +\cs_new_eq:NN \seq_set_eq:NN \tl_set_eq:NN +\cs_new_eq:NN \seq_set_eq:Nc \tl_set_eq:Nc +\cs_new_eq:NN \seq_set_eq:cN \tl_set_eq:cN +\cs_new_eq:NN \seq_set_eq:cc \tl_set_eq:cc +\cs_new_eq:NN \seq_gset_eq:NN \tl_gset_eq:NN +\cs_new_eq:NN \seq_gset_eq:Nc \tl_gset_eq:Nc +\cs_new_eq:NN \seq_gset_eq:cN \tl_gset_eq:cN +\cs_new_eq:NN \seq_gset_eq:cc \tl_gset_eq:cc +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\seq_concat:NNN, \seq_concat:ccc} +% \UnitTested +% \begin{macro}{\seq_gconcat:NNN, \seq_gconcat:ccc} +% \UnitTested +% Concatenating sequences is easy. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \seq_concat:NNN #1#2#3 + { \tl_set:Nx #1 { \exp_not:o {#2} \exp_not:o {#3} } } +\cs_new_protected_nopar:Npn \seq_gconcat:NNN #1#2#3 + { \tl_gset:Nx #1 { \exp_not:o {#2} \exp_not:o {#3} } } +\cs_generate_variant:Nn \seq_concat:NNN { ccc } +\cs_generate_variant:Nn \seq_gconcat:NNN { ccc } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Appending data to either end} +% +% \begin{macro}{ +% \seq_put_left:Nn, \seq_put_left:NV, \seq_put_left:Nv, +% \seq_put_left:No, \seq_put_left:Nx, +% \seq_put_left:cn, \seq_put_left:cV, \seq_put_left:cv, +% \seq_put_left:co, \seq_put_left:cx +% } +% \UnitTested +% \begin{macro}{ +% \seq_put_right:Nn, \seq_put_right:NV, \seq_put_right:Nv, +% \seq_put_right:No, \seq_put_right:Nx, +% \seq_put_right:cn, \seq_put_right:cV, \seq_put_right:cv, +% \seq_put_right:co, \seq_put_right:cx +% } +% \UnitTested +% The code here is just a wrapper for adding to token lists. +% \begin{macrocode} +\cs_new_protected:Npn \seq_put_left:Nn #1#2 + { \tl_put_left:Nn #1 { \seq_item:n {#2} } } +\cs_new_protected:Npn \seq_put_right:Nn #1#2 + { \tl_put_right:Nn #1 { \seq_item:n {#2} } } +\cs_generate_variant:Nn \seq_put_left:Nn { NV , Nv , No , Nx } +\cs_generate_variant:Nn \seq_put_left:Nn { c , cV , cv , co , cx } +\cs_generate_variant:Nn \seq_put_right:Nn { NV , Nv , No , Nx } +\cs_generate_variant:Nn \seq_put_right:Nn { c , cV , cv , co , cx } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{ +% \seq_gput_left:Nn, \seq_gput_left:NV, \seq_gput_left:Nv, +% \seq_gput_left:No, \seq_gput_left:Nx, +% \seq_gput_left:cn, \seq_gput_left:cV, \seq_gput_left:cv, +% \seq_gput_left:co, \seq_gput_left:cx +% } +% \begin{macro}{ +% \seq_gput_right:Nn, \seq_gput_right:NV, \seq_gput_right:Nv, +% \seq_gput_right:No, \seq_gput_right:Nx, +% \seq_gput_right:cn, \seq_gput_right:cV,\seq_gput_right:cv, +% \seq_gput_right:co, \seq_gput_right:cx +% } +% The same for global addition. +% \begin{macrocode} +\cs_new_protected:Npn \seq_gput_left:Nn #1#2 + { \tl_gput_left:Nn #1 { \seq_item:n {#2} } } +\cs_new_protected:Npn \seq_gput_right:Nn #1#2 + { \tl_gput_right:Nn #1 { \seq_item:n {#2} } } +\cs_generate_variant:Nn \seq_gput_left:Nn { NV , Nv , No , Nx } +\cs_generate_variant:Nn \seq_gput_left:Nn { c , cV , cv , co , cx } +\cs_generate_variant:Nn \seq_gput_right:Nn { NV , Nv , No , Nx } +\cs_generate_variant:Nn \seq_gput_right:Nn { c , cV , cv , co , cx } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Modifying sequences} +% +% \begin{variable}{\l_seq_remove_seq} +% An internal sequence for the removal routines. +% \begin{macrocode} +\seq_new:N \l_seq_remove_seq +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\seq_remove_duplicates:N, \seq_remove_duplicates:c} +% \UnitTested +% \begin{macro}{\seq_gremove_duplicates:N, \seq_gremove_duplicates:c} +% \UnitTested +% \begin{macro}[aux]{\seq_remove_duplicates_aux:NN} +% Removing duplicates means making a new list then copying it. +% \begin{macrocode} +\cs_new_protected:Npn \seq_remove_duplicates:N + { \seq_remove_duplicates_aux:NN \seq_set_eq:NN } +\cs_new_protected:Npn \seq_gremove_duplicates:N + { \seq_remove_duplicates_aux:NN \seq_gset_eq:NN } +\cs_new_protected:Npn \seq_remove_duplicates_aux:NN #1#2 + { + \seq_clear:N \l_seq_remove_seq + \seq_map_inline:Nn #2 + { + \seq_if_in:NnF \l_seq_remove_seq {##1} + { \seq_put_right:Nn \l_seq_remove_seq {##1} } + } + #1 #2 \l_seq_remove_seq + } +\cs_generate_variant:Nn \seq_remove_duplicates:N { c } +\cs_generate_variant:Nn \seq_gremove_duplicates:N { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\seq_remove_all:Nn, \seq_remove_all:cn} +% \UnitTested +% \begin{macro}{\seq_gremove_all:Nn, \seq_gremove_all:cn} +% \UnitTested +% \begin{macro}[aux]{\seq_remove_all_aux:NNn} +% The idea of the code here is to avoid a relatively expensive addition of +% items one at a time to an intermediate sequence. +% The approach taken is therefore similar to +% that in \cs{seq_pop_right_aux_ii:NNN}, using a \enquote{flexible} +% \texttt{x}-type expansion to do most of the work. As \cs{tl_if_eq:nnT} +% is not expandable, a two-part strategy is needed. First, the +% \texttt{x}-type expansion uses \cs{str_if_eq:nnT} to find potential +% matches. If one is found, the expansion is halted and the necessary +% set up takes place to use the \cs{tl_if_eq:NNT} test. The \texttt{x}-type +% is started again, including all of the items copied already. This will +% happen repeatedly until the entire sequence has been scanned. The code +% is set up to avoid needing and intermediate scratch list: the lead-off +% \texttt{x}-type expansion (|#1 #2 {#2}|) will ensure that nothing is +% lost. +% \begin{macrocode} +\cs_new_protected:Npn \seq_remove_all:Nn + { \seq_remove_all_aux:NNn \tl_set:Nx } +\cs_new_protected:Npn \seq_gremove_all:Nn + { \seq_remove_all_aux:NNn \tl_gset:Nx } +\cs_new_protected:Npn \seq_remove_all_aux:NNn #1#2#3 + { + \seq_push_item_def:n + { + \str_if_eq:nnT {##1} {#3} + { + \if_false: { \fi: } + \tl_set:Nn \l_seq_tmpb_tl {##1} + #1 #2 + { \if_false: } \fi: + \exp_not:o {#2} + \tl_if_eq:NNT \l_seq_tmpa_tl \l_seq_tmpb_tl + { \use_none:nn } + } + \exp_not:n { \seq_item:n {##1} } + } + \tl_set:Nn \l_seq_tmpa_tl {#3} + #1 #2 {#2} + \seq_pop_item_def: + } +\cs_generate_variant:Nn \seq_remove_all:Nn { c } +\cs_generate_variant:Nn \seq_gremove_all:Nn { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Sequence conditionals} +% +% \begin{macro}[pTF]{\seq_if_empty:N, \seq_if_empty:c} +% \UnitTested +% Simple copies from the token list variable material. +% \begin{macrocode} +\prg_new_eq_conditional:NNn \seq_if_empty:N \tl_if_empty:N + { p , T , F , TF } +\prg_new_eq_conditional:NNn \seq_if_empty:c \tl_if_empty:c + { p , T , F , TF } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[TF]{ +% \seq_if_in:Nn, \seq_if_in:NV, \seq_if_in:Nv, \seq_if_in:No, \seq_if_in:Nx, +% \seq_if_in:cn, \seq_if_in:cV, \seq_if_in:cv, \seq_if_in:co, \seq_if_in:cx +% } +% \UnitTested +% \begin{macro}[aux]{\seq_if_in_aux:} +% The approach here is to define \cs{seq_item:n} to compare its +% argument with the test sequence. If the two items are equal, the +% mapping is terminated and \cs{prg_return_true:} is inserted. On the +% other hand, if there is no match then the loop will break returning +% \cs{prg_return_false:}. In either case, \cs{seq_break_point:n} +% ensures that the group ends before the logical value is returned. +% Everything is inside a group so that \cs{seq_item:n} is preserved +% in nested situations. +% \begin{macrocode} +\prg_new_protected_conditional:Npnn \seq_if_in:Nn #1#2 + { T , F , TF } + { + \group_begin: + \tl_set:Nn \l_seq_tmpa_tl {#2} + \cs_set_protected:Npn \seq_item:n ##1 + { + \tl_set:Nn \l_seq_tmpb_tl {##1} + \if_meaning:w \l_seq_tmpa_tl \l_seq_tmpb_tl + \exp_after:wN \seq_if_in_aux: + \fi: + } + #1 + \seq_break:n { \prg_return_false: } + \seq_break_point:n { \group_end: } + } +\cs_new_nopar:Npn \seq_if_in_aux: { \seq_break:n { \prg_return_true: } } +\cs_generate_variant:Nn \seq_if_in:NnT { NV , Nv , No , Nx } +\cs_generate_variant:Nn \seq_if_in:NnT { c , cV , cv , co , cx } +\cs_generate_variant:Nn \seq_if_in:NnF { NV , Nv , No , Nx } +\cs_generate_variant:Nn \seq_if_in:NnF { c , cV , cv , co , cx } +\cs_generate_variant:Nn \seq_if_in:NnTF { NV , Nv , No , Nx } +\cs_generate_variant:Nn \seq_if_in:NnTF { c , cV , cv , co , cx } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Recovering data from sequences} +% +% \begin{macro}{\seq_get_left:NN, \seq_get_left:cN} +% \UnitTested +% \begin{macro}[aux]{\seq_get_left_aux:NnwN} +% Getting an item from the left of a sequence is pretty easy: just +% trim off the first item after removing the \cs{seq_item:n} at +% the start. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \seq_get_left:NN #1#2 + { + \seq_if_empty_err_break:N #1 + \exp_after:wN \seq_get_left_aux:NnwN #1 \q_stop #2 + \seq_break_point:n { } + } +\cs_new_protected:Npn \seq_get_left_aux:NnwN \seq_item:n #1#2 \q_stop #3 + { \tl_set:Nn #3 {#1} } +\cs_generate_variant:Nn \seq_get_left:NN { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\seq_pop_left:NN, \seq_pop_left:cN} +% \UnitTested +% \begin{macro}{\seq_gpop_left:NN, \seq_gpop_left:cN} +% \UnitTested +% \begin{macro}[aux]{\seq_pop_left_aux:NNN} +% \begin{macro}[aux]{\seq_pop_left_aux:NnwNNN} +% The approach to popping an item is pretty similar to that to get +% an item, with the only difference being that the sequence itself has +% to be redefined. This makes it more sensible to use an auxiliary +% function for the local and global cases. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \seq_pop_left:NN + { \seq_pop_left_aux:NNN \tl_set:Nn } +\cs_new_protected_nopar:Npn \seq_gpop_left:NN + { \seq_pop_left_aux:NNN \tl_gset:Nn } +\cs_new_protected_nopar:Npn \seq_pop_left_aux:NNN #1#2#3 + { + \seq_if_empty_err_break:N #2 + \exp_after:wN \seq_pop_left_aux:NnwNNN #2 \q_stop #1#2#3 + \seq_break_point:n { } + } +\cs_new_protected:Npn \seq_pop_left_aux:NnwNNN \seq_item:n #1#2 \q_stop #3#4#5 + { + #3 #4 {#2} + \tl_set:Nn #5 {#1} + } +\cs_generate_variant:Nn \seq_pop_left:NN { c } +\cs_generate_variant:Nn \seq_gpop_left:NN { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\seq_get_right:NN, \seq_get_right:cN} +% \UnitTested +% \begin{macro}[aux]{\seq_get_right_aux:NN} +% \begin{macro}[aux]{\seq_get_right_loop:nn} +% The idea here is to remove the very first \cs{seq_item:n} from the +% sequence, leaving a token list starting with the first braced entry. +% Two arguments at a time are then grabbed: apart from the right-hand end of +% the sequence, this will be a brace group followed by \cs{seq_item:n}. The +% set up code means that these all disappear. At the end of the sequence, +% the assignment is placed in front of the very last entry in the sequence, +% before a tidying-up step takes place to remove the loop and reset the +% meaning of \cs{seq_item:n}. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \seq_get_right:NN #1#2 + { + \seq_if_empty_err_break:N #1 + \seq_get_right_aux:NN #1#2 + \seq_break_point:n { } + } +\cs_new_protected_nopar:Npn \seq_get_right_aux:NN #1#2 + { + \seq_push_item_def:n { } + \exp_after:wN \exp_after:wN \exp_after:wN \seq_get_right_loop:nn + \exp_after:wN \use_none:n #1 + { \tl_set:Nn #2 } + { } + { + \seq_pop_item_def: + \seq_break: + } +} +\cs_new:Npn \seq_get_right_loop:nn #1#2 + { + #2 {#1} + \seq_get_right_loop:nn + } +\cs_generate_variant:Nn \seq_get_right:NN { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\seq_pop_right:NN, \seq_pop_right:cN} +% \UnitTested +% \begin{macro}{\seq_gpop_right:NN, \seq_gpop_right:cN} +% \UnitTested +% \begin{macro}[aux]{\seq_pop_right_aux:NNN, \seq_pop_right_aux_ii:NNN} +% The approach to popping from the right is a bit more involved, but does +% use some of the same ideas as getting from the right. What is needed is a +% \enquote{flexible length} way to set a token list variable. This is +% supplied by the |{ \if_false:} \fi:| \ldots +% |\if_false: { \fi: }| construct. Using an \texttt{x}-type +% expansion and a \enquote{non-expanding} definition for \cs{seq_item:n}, +% the left-most $n - 1$ entries in a sequence of $n$ items will be stored +% back in the sequence. That needs a loop of unknown length, hence using the +% strange \cs{if_false:} way of including brackets. When the last item +% of the sequence is reached, the closing bracket for the assignment is +% inserted, and |\tl_set:Nn #3| is inserted in front of the final entry. +% This therefore does the pop assignment, then a final loop clears up the +% code. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \seq_pop_right:NN + { \seq_pop_right_aux:NNN \tl_set:Nx } +\cs_new_protected_nopar:Npn \seq_gpop_right:NN + { \seq_pop_right_aux:NNN \tl_gset:Nx } +\cs_new_protected_nopar:Npn \seq_pop_right_aux:NNN #1#2#3 + { + \seq_if_empty_err_break:N #2 + \seq_pop_right_aux_ii:NNN #1 #2 #3 + \seq_break_point:n { } + } +\cs_new_protected_nopar:Npn \seq_pop_right_aux_ii:NNN #1#2#3 + { + \seq_push_item_def:n { \exp_not:n { \seq_item:n {##1} } } + #1 #2 { \if_false: } \fi: + \exp_after:wN \exp_after:wN \exp_after:wN \seq_get_right_loop:nn + \exp_after:wN \use_none:n #2 + { + \if_false: { \fi: } + \tl_set:Nn #3 + } + { } + { + \seq_pop_item_def: + \seq_break: + } + } +\cs_generate_variant:Nn \seq_pop_right:NN { c } +\cs_generate_variant:Nn \seq_gpop_right:NN { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Mapping to sequences} +% +% \begin{macro}[int]{\seq_break:} +% \begin{macro}[int]{\seq_break:n} +% To break a function, the special token \cs{seq_break_point:n} is +% used to find the end of the code. Any ending code is then inserted +% before the return value of \cs{seq_map_break:n} is inserted. +% \begin{macrocode} +\cs_new:Npn \seq_break: #1 \seq_break_point:n #2 {#2} +\cs_new:Npn \seq_break:n #1#2 \seq_break_point:n #3 { #3 #1 } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\seq_map_break:} +% \UnitTested +% \begin{macro}{\seq_map_break:n} +% \UnitTested +% Semantically-logical copies of the break functions for use inside +% mappings. +% \begin{macrocode} +\cs_new_eq:NN \seq_map_break: \seq_break: +\cs_new_eq:NN \seq_map_break:n \seq_break:n +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[int]{\seq_break_point:n} +% Normally, the marker token will not be executed, but if it is then +% the end code is simply inserted. +% \begin{macrocode} +\cs_new_eq:NN \seq_break_point:n \use:n +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int]{\seq_if_empty_err_break:N} +% A function to check that sequences really have some content. This +% is optimised for speed, hence the direct primitive use. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \seq_if_empty_err_break:N #1 + { + \if_meaning:w #1 \c_empty_tl + \msg_kernel_error:nnx { seq } { empty-sequence } { \token_to_str:N #1 } + \exp_after:wN \seq_break: + \fi: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\seq_map_function:NN, \seq_map_function:cN} +% \UnitTested +% \begin{macro}[aux]{\seq_map_function_aux:NNn} +% The idea here is to apply the code of |#2| to each item in the +% sequence without altering the definition of \cs{seq_item:n}. This +% is done as by noting that every odd token in the sequence must be +% \cs{seq_item:n}, which can be gobbled by \cs{use_none:n}. At the end of +% the loop, |#2| is instead |? \seq_map_break:|, which therefore breaks the +% loop without needing to do a (relatively-expensive) quark test. +% \begin{macrocode} +\cs_new:Npn \seq_map_function:NN #1#2 + { + \exp_after:wN \seq_map_function_aux:NNn \exp_after:wN #2 #1 + { ? \seq_map_break: } { } + \seq_break_point:n { } + } +\cs_new:Npn \seq_map_function_aux:NNn #1#2#3 + { + \use_none:n #2 + #1 {#3} + \seq_map_function_aux:NNn #1 + } +\cs_generate_variant:Nn \seq_map_function:NN { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{variable}{\g_seq_nesting_depth_int} +% A counter to keep track of nested functions: defined in \pkg{l3int}. +% \end{variable} +% +% \begin{macro}[int]{\seq_push_item_def:n, \seq_push_item_def:x} +% \begin{macro}[aux]{\seq_push_item_def_aux:} +% \begin{macro}[int]{\seq_pop_item_def:} +% The definition of \cs{seq_item:n} needs to be saved and restored at +% various points within the mapping and manipulation code. That is handled +% here: as always, this approach uses global assignments. +% \begin{macrocode} +\cs_new_protected:Npn \seq_push_item_def:n + { + \seq_push_item_def_aux: + \cs_gset:Npn \seq_item:n ##1 + } +\cs_new_protected:Npn \seq_push_item_def:x + { + \seq_push_item_def_aux: + \cs_gset:Npx \seq_item:n ##1 + } +\cs_new_protected:Npn \seq_push_item_def_aux: + { + \cs_gset_eq:cN { seq_item_ \int_use:N \g_seq_nesting_depth_int :n } + \seq_item:n + \int_gincr:N \g_seq_nesting_depth_int + } +\cs_new_protected_nopar:Npn \seq_pop_item_def: + { + \int_gdecr:N \g_seq_nesting_depth_int + \cs_gset_eq:Nc \seq_item:n + { seq_item_ \int_use:N \g_seq_nesting_depth_int :n } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\seq_map_inline:Nn, \seq_map_inline:cn} +% \UnitTested +% The idea here is that \cs{seq_item:n} is already \enquote{applied} to +% each item in a sequence, and so an in-line mapping is just a case of +% redefining \cs{seq_item:n}. +% \begin{macrocode} +\cs_new_protected:Npn \seq_map_inline:Nn #1#2 + { + \seq_push_item_def:n {#2} + #1 + \seq_break_point:n { \seq_pop_item_def: } + } +\cs_generate_variant:Nn \seq_map_inline:Nn { c } +% \end{macrocode} +% \end{macro} +% +% \begin{macro} +% { +% \seq_map_variable:NNn,\seq_map_variable:Ncn, +% \seq_map_variable:cNn,\seq_map_variable:ccn +% } +% \UnitTested +% This is just a specialised version of the in-line mapping function, +% using an \texttt{x}-type expansion for the code set up so that the +% number of |#| tokens required is as expected. +% \begin{macrocode} +\cs_new_protected:Npn \seq_map_variable:NNn #1#2#3 + { + \seq_push_item_def:x + { + \tl_set:Nn \exp_not:N #2 {##1} + \exp_not:n {#3} + } + #1 + \seq_break_point:n { \seq_pop_item_def: } + } +\cs_generate_variant:Nn \seq_map_variable:NNn { Nc } +\cs_generate_variant:Nn \seq_map_variable:NNn { c , cc } +% \end{macrocode} +% \end{macro} +% +% \subsection{Sequence stacks} +% +% The same functions as for sequences, but with the correct naming. +% +% \begin{macro}{ +% \seq_push:Nn, \seq_push:NV, \seq_push:Nv, \seq_push:No, \seq_push:Nx, +% \seq_push:cn, \seq_push:cV, \seq_push:cV, \seq_push:co, \seq_push:cx +% } +% \UnitTested +% \begin{macro}{ +% \seq_gpush:Nn, \seq_gpush:NV, \seq_gpush:Nv, \seq_gpush:No, \seq_gpush:Nx, +% \seq_gpush:cn, \seq_gpush:cV, \seq_gpush:cv, \seq_gpush:co, \seq_gpush:cx +% } +% \UnitTested +% Pushing to a sequence is the same as adding on the left. +% \begin{macrocode} +\cs_new_eq:NN \seq_push:Nn \seq_put_left:Nn +\cs_new_eq:NN \seq_push:NV \seq_put_left:NV +\cs_new_eq:NN \seq_push:Nv \seq_put_left:Nv +\cs_new_eq:NN \seq_push:No \seq_put_left:No +\cs_new_eq:NN \seq_push:Nx \seq_put_left:Nx +\cs_new_eq:NN \seq_push:cn \seq_put_left:cn +\cs_new_eq:NN \seq_push:cV \seq_put_left:cV +\cs_new_eq:NN \seq_push:cv \seq_put_left:cv +\cs_new_eq:NN \seq_push:co \seq_put_left:co +\cs_new_eq:NN \seq_push:cx \seq_put_left:cx +\cs_new_eq:NN \seq_gpush:Nn \seq_gput_left:Nn +\cs_new_eq:NN \seq_gpush:NV \seq_gput_left:NV +\cs_new_eq:NN \seq_gpush:Nv \seq_gput_left:Nv +\cs_new_eq:NN \seq_gpush:No \seq_gput_left:No +\cs_new_eq:NN \seq_gpush:Nx \seq_gput_left:Nx +\cs_new_eq:NN \seq_gpush:cn \seq_gput_left:cn +\cs_new_eq:NN \seq_gpush:cV \seq_gput_left:cV +\cs_new_eq:NN \seq_gpush:cv \seq_gput_left:cv +\cs_new_eq:NN \seq_gpush:co \seq_gput_left:co +\cs_new_eq:NN \seq_gpush:cx \seq_gput_left:cx +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\seq_get:NN, \seq_get:cN} +% \UnitTested +% \begin{macro}{\seq_pop:NN, \seq_pop:cN} +% \UnitTested +% \begin{macro}{\seq_gpop:NN, \seq_gpop:cN} +% \UnitTested +% In most cases, getting items from the stack does not need to specify +% that this is from the left. So alias are provided. +% \begin{macrocode} +\cs_new_eq:NN \seq_get:NN \seq_get_left:NN +\cs_new_eq:NN \seq_get:cN \seq_get_left:cN +\cs_new_eq:NN \seq_pop:NN \seq_pop_left:NN +\cs_new_eq:NN \seq_pop:cN \seq_pop_left:cN +\cs_new_eq:NN \seq_gpop:NN \seq_gpop_left:NN +\cs_new_eq:NN \seq_gpop:cN \seq_gpop_left:cN +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Viewing sequences} +% +% \begin{variable}{\l_seq_show_tl} +% Used to store the material for display. +% \begin{macrocode} +\tl_new:N \l_seq_show_tl +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\seq_show:N, \seq_show:c} +% \UnitTested +% \begin{macro}[aux]{\seq_show_aux:n} +% \begin{macro}[aux]{\seq_show_aux:w} +% The aim of the mapping here is to create a token list containing the +% formatted sequence. The very first item needs the new line and \verb*|> | +% removing, which is achieved using a \texttt{w}-type auxiliary. To avoid +% a low-level \TeX{} error if there is an empty sequence, a simple test is +% used to keep the output \enquote{clean}. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \seq_show:N #1 + { + \seq_if_empty:NTF #1 + { + \iow_term:x { Sequence~\token_to_str:N #1 \c_space_tl is~empty } + \tl_show:n { } + } + { + \iow_term:x + { + Sequence~\token_to_str:N #1 \c_space_tl + contains~the~items~(without~outer~braces): + } + \tl_set:Nx \l_seq_show_tl + { \seq_map_function:NN #1 \seq_show_aux:n } + \etex_showtokens:D \exp_after:wN \exp_after:wN \exp_after:wN + { \exp_after:wN \seq_show_aux:w \l_seq_show_tl } + } + } +\cs_new:Npn \seq_show_aux:n #1 + { + \iow_newline: > \c_space_tl \c_space_tl + \iow_char:N \{ \exp_not:n {#1} \iow_char:N \} + } +\cs_new:Npn \seq_show_aux:w #1 > ~ { } +\cs_generate_variant:Nn \seq_show:N { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Experimental functions} +% +% \begin{macro}[aux]{\seq_if_empty_break_return_false:N} +% The name says it all: of the sequence is empty, returns logical +% \texttt{false}. +% \begin{macrocode} +\cs_new_nopar:Npn \seq_if_empty_break_return_false:N #1 + { + \if_meaning:w #1 \c_empty_tl + \prg_return_false: + \exp_after:wN \seq_break: + \fi: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[TF]{\seq_get_left:NN, \seq_get_left:cN} +% \begin{macro}[TF]{\seq_get_right:NN, \seq_get_right:cN} +% Getting from the left or right with a check on the results. +% \begin{macrocode} +\prg_new_protected_conditional:Npnn \seq_get_left:NN #1 #2 { T , F , TF } + { + \seq_if_empty_break_return_false:N #1 + \exp_after:wN \seq_get_left_aux:Nw #1 \q_stop #2 + \prg_return_true: + \seq_break: + \seq_break_point:n { } + } +\prg_new_protected_conditional:Npnn \seq_get_right:NN #1#2 { T , F , TF } + { + \seq_if_empty_break_return_false:N #1 + \seq_get_right_aux:NN #1#2 + \prg_return_true: \seq_break: + \seq_break_point:n { } + } +\cs_generate_variant:Nn \seq_get_left:NNT { c } +\cs_generate_variant:Nn \seq_get_left:NNF { c } +\cs_generate_variant:Nn \seq_get_left:NNTF { c } +\cs_generate_variant:Nn \seq_get_right:NNT { c } +\cs_generate_variant:Nn \seq_get_right:NNF { c } +\cs_generate_variant:Nn \seq_get_right:NNTF { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[TF]{\seq_pop_left:NN, \seq_pop_left:cN} +% \begin{macro}[TF]{\seq_gpop_left:NN, \seq_gpop_left:cN} +% \begin{macro}[TF]{\seq_pop_right:NN, \seq_pop_right:cN} +% \begin{macro}[TF]{\seq_gpop_right:NN, \seq_gpop_right:cN} +% More or less the same for popping. +% \begin{macrocode} +\prg_new_protected_conditional:Npnn \seq_pop_left:NN #1#2 { T , F , TF } + { + \seq_if_empty_break_return_false:N #1 + \exp_after:wN \seq_pop_left_aux:NnwNNN #1 \q_stop \tl_set:Nn #1#2 + \prg_return_true: \seq_break: + \seq_break_point:n { } + } +\prg_new_protected_conditional:Npnn \seq_gpop_left:NN #1#2 { T , F , TF } + { + \seq_if_empty_break_return_false:N #1 + \exp_after:wN \seq_pop_left_aux:NnwNNN #1 \q_stop \tl_gset:Nn #1#2 + \prg_return_true: \seq_break: + \seq_break_point:n { } + } +\prg_new_protected_conditional:Npnn \seq_pop_right:NN #1#2 { T , F , TF } + { + \seq_if_empty_break_return_false:N #1 + \seq_pop_right_aux_ii:NNN \tl_set:Nx #1 #2 + \prg_return_true: \seq_break: + \seq_break_point:n { } + } +\prg_new_protected_conditional:Npnn \seq_gpop_right:NN #1#2 { T , F , TF } + { + \seq_if_empty_break_return_false:N #1 + \seq_pop_right_aux_ii:NNN \tl_gset:Nx #1 #2 + \prg_return_true: \seq_break: + \seq_break_point:n { } + } +\cs_generate_variant:Nn \seq_pop_left:NNT { c } +\cs_generate_variant:Nn \seq_pop_left:NNF { c } +\cs_generate_variant:Nn \seq_pop_left:NNTF { c } +\cs_generate_variant:Nn \seq_gpop_left:NNT { c } +\cs_generate_variant:Nn \seq_gpop_left:NNF { c } +\cs_generate_variant:Nn \seq_gpop_left:NNTF { c } +\cs_generate_variant:Nn \seq_pop_right:NNT { c } +\cs_generate_variant:Nn \seq_pop_right:NNF { c } +\cs_generate_variant:Nn \seq_pop_right:NNTF { c } +\cs_generate_variant:Nn \seq_gpop_right:NNT { c } +\cs_generate_variant:Nn \seq_gpop_right:NNF { c } +\cs_generate_variant:Nn \seq_gpop_right:NNTF { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\seq_length:N, \seq_length:c} +% \begin{macro}[aux]{\seq_length_aux:n} +% Counting the items in a sequence is done using the same approach as for +% other length functions: turn each entry into a \texttt{+1} then use +% integer evaluation to actually do the mathematics. +% \begin{macrocode} +\cs_new:Npn \seq_length:N #1 + { + \int_eval:n + { + 0 + \seq_map_function:NN #1 \seq_length_aux:n + } + } +\cs_new:Npn \seq_length_aux:n #1 { +1 } +\cs_generate_variant:Nn \seq_length:N { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\seq_item:Nn, \seq_item:cn} +% \begin{macro}[aux]{\seq_item_aux:nnn} +% The idea here is to find the offset of the item from the left, then use +% a loop to grab the correct item. If the resulting offset is too large, +% then the stop code |{ ? \seq_break } { }| will be used by the auxiliary, +% terminating the loop and returning nothing at all. +% \begin{macrocode} +\cs_new_nopar:Npn \seq_item:Nn #1#2 + { + \exp_last_unbraced:Nfo \seq_item_aux:nnn + { + \int_eval:n + { + \int_compare:nNnT {#2} < \c_zero + { \seq_length:N #1 + } + #2 + } + } + #1 + { ? \seq_break: } + { } + \seq_break_point:n { } + } +\cs_new_nopar:Npn \seq_item_aux:nnn #1#2#3 + { + \use_none:n #2 + \int_compare:nNnTF {#1} = \c_zero + { \seq_break:n {#3} } + { \exp_args:Nf \seq_item_aux:nnn { #1 - 1 } } + } +\cs_generate_variant:Nn \seq_item:Nn { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\seq_use:N, \seq_use:c} +% A simple short cut for a mapping. +% \begin{macrocode} +\cs_new_nopar:Npn \seq_use:N #1 { \seq_map_function:NN #1 \use:n } +\cs_generate_variant:Nn \seq_use:N { c } +% \end{macrocode} +% \end{macro} +% +% \begin{macro} +% { +% \seq_mapthread_function:NNN, \seq_mapthread_function:NcN, +% \seq_mapthread_function:cNN, \seq_mapthread_function:ccN +% } +% \begin{macro}[aux]{\seq_mapthread_function_aux:NN} +% \begin{macro}[aux]{\seq_mapthread_function_aux:Nnnwnn} +% The idea here is to first expand both of the sequences, adding the usual +% |{ ? \seq_break: } { }| to the end of each on. This is most conveniently +% done in two steps using an auxiliary function. The mapping then throws +% away the first token of |#2| and |#5|, which for items in the sequences +% will both be \cs{seq_item:n}. The function to be mapped will then be +% applied to the two entries. When the code hits the end of one of the +% sequences, the break material will stop the entire loop and tidy up. This +% avoids needing to find the length of the two sequences, or worrying about +% which is longer. +% \begin{macrocode} +\cs_new_nopar:Npn \seq_mapthread_function:NNN #1#2#3 + { + \exp_after:wN \seq_mapthread_function_aux:NN + \exp_after:wN #3 + \exp_after:wN #1 + #2 + { ? \seq_break: } { } + \seq_break_point:n { } + } +\cs_new_nopar:Npn \seq_mapthread_function_aux:NN #1#2 + { + \exp_after:wN \seq_mapthread_function_aux:Nnnwnn + \exp_after:wN #1 + #2 + { ? \seq_break: } { } + \q_stop + } +\cs_new:Npn \seq_mapthread_function_aux:Nnnwnn #1#2#3#4 \q_stop #5#6 + { + \use_none:n #2 + \use_none:n #5 + #1 {#3} {#6} + \seq_mapthread_function_aux:Nnnwnn #1 #4 \q_stop + } +\cs_generate_variant:Nn \seq_mapthread_function:NNN { Nc } +\cs_generate_variant:Nn \seq_mapthread_function:NNN { c , cc } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro} +% { +% \seq_set_from_clist:NN, \seq_set_from_clist:cN, +% \seq_set_from_clist:Nc, \seq_set_from_clist:cc, +% \seq_set_from_clist:Nn, \seq_set_from_clist:cn +% } +% \begin{macro} +% { +% \seq_gset_from_clist:NN, \seq_gset_from_clist:cN, +% \seq_gset_from_clist:Nc, \seq_gset_from_clist:cc, +% \seq_gset_from_clist:Nn, \seq_gset_from_clist:cn +% } +% \begin{macro}[aux]{\seq_wrap_item:n} +% Setting a sequence from a comma-separated list is done using a simple +% mapping. +% \begin{macrocode} +\cs_new_protected:Npn \seq_set_from_clist:NN #1#2 + { + \tl_set:Nx #1 + { \clist_map_function:NN #2 \seq_wrap_item:n } + } +\cs_new_protected:Npn \seq_set_from_clist:Nn #1#2 + { + \tl_set:Nx #1 + { \clist_map_function:nN {#2} \seq_wrap_item:n } + } +\cs_new_protected:Npn \seq_gset_from_clist:NN #1#2 + { + \tl_gset:Nx #1 + { \clist_map_function:NN #2 \seq_wrap_item:n } + } +\cs_new_protected:Npn \seq_gset_from_clist:Nn #1#2 + { + \tl_gset:Nx #1 + { \clist_map_function:nN {#2} \seq_wrap_item:n } + } +\cs_new:Npn \seq_wrap_item:n #1 { \exp_not:n { \seq_item:n {#1} } } +\cs_generate_variant:Nn \seq_set_from_clist:NN { Nc } +\cs_generate_variant:Nn \seq_set_from_clist:NN { c , cc } +\cs_generate_variant:Nn \seq_set_from_clist:Nn { c } +\cs_generate_variant:Nn \seq_gset_from_clist:NN { Nc } +\cs_generate_variant:Nn \seq_gset_from_clist:NN { c , cc } +\cs_generate_variant:Nn \seq_gset_from_clist:Nn { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Deprecated interfaces} +% +% A few functions which are no longer documented: these were moved +% here on or before 2011-04-20, and will be removed entirely by +% 2011-07-20. +% +% \begin{macro}{\seq_top:NN, \seq_top:cN} +% These are old stack functions. +% \begin{macrocode} +\cs_new_eq:NN \seq_top:NN \seq_get_left:NN +\cs_new_eq:NN \seq_top:cN \seq_get_left:cN +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\seq_display:N, \seq_display:c} +% An older name for \cs{seq_show:N}. +% \begin{macrocode} +\cs_new_eq:NN \seq_display:N \seq_show:N +\cs_new_eq:NN \seq_display:c \seq_show:c +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +%</initex|package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintIndex
\ No newline at end of file diff --git a/Master/texmf-dist/source/latex/l3kernel/l3skip.dtx b/Master/texmf-dist/source/latex/l3kernel/l3skip.dtx new file mode 100644 index 00000000000..ecd3ca2e397 --- /dev/null +++ b/Master/texmf-dist/source/latex/l3kernel/l3skip.dtx @@ -0,0 +1,1675 @@ +% \iffalse meta-comment +% +%% File: l3skip.dtx Copyright (C) 2004-2011 Frank Mittelbach, The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +% +%<*driver|package> +\RequirePackage{l3names} +\GetIdInfo$Id: l3skip.dtx 2478 2011-06-19 21:34:23Z joseph $ + {L3 Experimental dimensions and skips} +%</driver|package> +%<*driver> +\documentclass[full]{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{^^A +% The \pkg{l3skip} package\\ Dimensions and skips^^A +% \thanks{This file describes v\ExplFileVersion, +% last revised \ExplFileDate.}^^A +% } +% +% \author{^^A +% The \LaTeX3 Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% +% \date{Released \ExplFileDate} +% +% \maketitle +% +% \begin{documentation} +% +% \LaTeX3 provides two general length variables: \texttt{dim} and +% \texttt{skip}. Lengths stored as \texttt{dim} variables have a fixed +% length, whereas \texttt{skip} lengths have a rubber (stretch/shrink) +% component. In addition, the \texttt{muskip} type is available for +% use in math mode: this is a special form of \texttt{skip} where the +% lengths involved are determined by the current math font (in +% \texttt{mu)}. There are common features in the creation and setting of +% length variables, but for clarity the functions are grouped by variable +% type. +% +% \section{Creating and initialising \texttt{dim} variables} +% +% \begin{function}{\dim_new:N, \dim_new:c} +% \begin{syntax} +% \cs{dim_new:N} \meta{dimension} +% \end{syntax} +% Creates a new \meta{dimension} or raises an error if the name is +% already taken. The declaration is global. The \meta{dimension} +% will initially be equal to $0$\,pt. +% \end{function} +% +% \begin{function}{\dim_zero:N, \dim_zero:c} +% \begin{syntax} +% \cs{dim_zero:N} \meta{dimension} +% \end{syntax} +% Sets \meta{dimension} to $0$\,pt within the scope of the current +% \TeX{} group. +% \end{function} +% +% \begin{function}{\dim_gzero:N, \dim_gzero:c} +% \begin{syntax} +% \cs{dim_gzero:N} \meta{dimension} +% \end{syntax} +% Sets \meta{dimension} to $0$\,pt globally, \emph{i.e.}~not +% restricted by the current \TeX{} group level. +% \end{function} +% +% \section{Setting \texttt{dim} variables} +% +% \begin{function}{\dim_add:Nn, \dim_add:cn} +% \begin{syntax} +% \cs{dim_add:Nn} \meta{dimension} \Arg{dimension expression} +% \end{syntax} +% Adds the result of the \meta{dimension expression} to the current +% content of the \meta{dimension}. This assignment is local. +% \end{function} +% +% \begin{function}{\dim_gadd:Nn, \dim_gadd:cn} +% \begin{syntax} +% \cs{dim_gadd:Nn} \meta{dimension} \Arg{dimension expression} +% \end{syntax} +% Adds the result of the \meta{dimension expression} to the +% current content of the \meta{dimension}. This assignment is global. +% \end{function} +% +% \begin{function}{\dim_set:Nn, \dim_set:cn} +% \begin{syntax} +% \cs{dim_set:Nn} \meta{dimension} \Arg{dimension expression} +% \end{syntax} +% Sets \meta{dimension} to the value of \meta{dimension expression}, which +% must evaluate to a length with units. This assignment is +% restricted to the current \TeX{} group. +% \end{function} +% +% \begin{function}{\dim_gset:Nn, \dim_gset:cn} +% \begin{syntax} +% \cs{dim_gset:Nn} \meta{dimension} \Arg{dimension expression} +% \end{syntax} +% Sets \meta{dimension} to the value of \meta{dimension expression}, which +% must evaluate to a length with units and may include a rubber +% component (for example |1 cm plus 0.5 cm|. This assignment is +% global and is not limited to the current \TeX{} group level. +% \end{function} +% +% \begin{function} +% {\dim_set_eq:NN, \dim_set_eq:cN, \dim_set_eq:Nc, \dim_set_eq:cc} +% \begin{syntax} +% \cs{dim_set_eq:NN} \meta{dimension1} \meta{dimension2} +% \end{syntax} +% Sets the content of \meta{dimension1} equal to that of +% \meta{dimension2}. This assignment is restricted to the current +% \TeX{} group level. +% \end{function} +% +% \begin{function} +% {\dim_gset_eq:NN, \dim_gset_eq:cN, \dim_gset_eq:Nc, \dim_gset_eq:cc} +% \begin{syntax} +% \cs{dim_gset_eq:NN} \meta{dimension1} \meta{dimension2} +% \end{syntax} +% Sets the content of \meta{dimension1} equal to that of \meta{dimension2}. +% This assignment is global and so is not limited by the current +% \TeX{} group level. +% \end{function} +% +% \begin{function}{\dim_set_max:Nn, \dim_set_max:cn} +% \begin{syntax} +% \cs{dim_set_max:Nn} \meta{dimension} \Arg{dimension expression} +% \end{syntax} +% Compares the current value of the \meta{dimension} with that of the +% \meta{dimension expression}, and sets the \meta{dimension} to the +% larger of these two value. This assignment is local to the current +% \TeX{} group. +% \end{function} +% +% \begin{function}{\dim_gset_max:Nn, \dim_gset_max:cn} +% \begin{syntax} +% \cs{dim_gset_max:Nn} \meta{dimension} \Arg{dimension expression} +% \end{syntax} +% Compares the current value of the \meta{dimension} with that of the +% \meta{dimension expression}, and sets the \meta{dimension} to the +% larger of these two value. This assignment is global. +% \end{function} +% +% \begin{function}{\dim_set_min:Nn, \dim_set_min:cn} +% \begin{syntax} +% \cs{dim_set_min:Nn} \meta{dimension} \Arg{dimension expression} +% \end{syntax} +% Compares the current value of the \meta{dimension} with that of the +% \meta{dimension expression}, and sets the \meta{dimension} to the +% smaller of these two value. This assignment is local to the current +% \TeX{} group. +% \end{function} +% +% \begin{function}{\dim_gset_min:Nn, \dim_gset_min:cn} +% \begin{syntax} +% \cs{dim_gset_min:Nn} \meta{dimension} \Arg{dimension expression} +% \end{syntax} +% Compares the current value of the \meta{dimension} with that of the +% \meta{dimension expression}, and sets the \meta{dimension} to the +% smaller of these two value. This assignment is global. +% \end{function} +% +% \begin{function}{\dim_sub:Nn, \dim_sub:cn} +% \begin{syntax} +% \cs{dim_sub:Nn} \meta{dimension} \Arg{dimension expression} +% \end{syntax} +% Subtracts the result of the \meta{dimension expression} to the +% current content of the \meta{dimension}. This assignment is local. +% \end{function} +% +% \begin{function}{\dim_gsub:Nn, \dim_gsub:cn} +% \begin{syntax} +% \cs{dim_gsub:Nn} \meta{dimension} \Arg{dimension expression} +% \end{syntax} +% Subtracts the result of the \meta{dimension expression} to the +% current content of the \meta{dimension}. This assignment is global. +% \end{function} +% +% \section{Utilities for dimension calculations} +% +% \begin{function}[EXP]{\dim_ratio:nn} +% \begin{syntax} +% \cs{dim_ratio:nn} \Arg{dimexpr1} \Arg{dimexpr2} +% \end{syntax} +% Parses the two \meta{dimension expressions} and converts the ratio of +% the two to a form suitable for use inside a \meta{dimension expression}. +% This ratio is then left in the input stream, allowing syntax such as +% \begin{verbatim} +% \dim_set:Nn \l_my_dim +% { 10 pt * \dim_ratio:nn { 5 pt } { 10 pt } } +% \end{verbatim} +% The output of \cs{dim_ratio:nn} on full expansion is a ration expression +% between two integers, with all distances converted to scaled points. +% Thus +% \begin{verbatim} +% \tl_set:Nx \l_my_tl { \dim_ratio:nn { 5 pt } { 10 pt } } +% \tl_show:N \l_my_tl +% \end{verbatim} +% will display |327680/655360| on the terminal. +% \end{function} +% +% \section{Dimension expression conditionals} +% +% \begin{function}[EXP,pTF]{\dim_compare:nNn} +% \begin{syntax} +% \cs{dim_compare_p:nNn} +% ~~\Arg{dimexpr1} \meta{relation} \Arg{dimexpr2} +% \cs{dim_compare:nNnTF} +% ~~\Arg{dimexpr1} \meta{relation} \Arg{dimexpr2} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% This function first evaluates each of the \meta{dimension expressions} +% as described for \cs{dim_eval:n}. The two results are then +% compared using the \meta{relation}: +% \begin{center} +% \begin{tabular}{ll} +% Equal & |=| \\ +% Greater than & |>| \\ +% Less than & |<| \\ +% \end{tabular} +% \end{center} +% The branching versions then leave either \meta{true code} or +% \meta{false code} in the input stream, as appropriate to the truth +% of the test and the variant of the function chosen. The logical +% truth of the test is left in the input stream by the predicate +% version. +% \end{function} +% +% \begin{function}[EXP,pTF]{\dim_compare:n} +% \begin{syntax} +% \cs{dim_compare_p:n} +% ~~\{ \meta{dimexpr1} \meta{relation} \meta{dimexpr2} \} +% \cs{dim_compare:nTF} +% ~~\{ \meta{dimexpr1} \meta{relation} \meta{dimexpr2} \} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% This function first evaluates each of the \meta{dimension expressions} +% as described for \cs{dim_eval:n}. The two results are then +% compared using the \meta{relation}: +% \begin{center} +% \begin{tabular}{ll} +% Equal & |=| or |==| \\ +% Greater than or equal to & |=>| \\ +% Greater than & |>| \\ +% Less than or equal to & |=<| \\ +% Less than & |<| \\ +% Not equal & |!=| \\ +% \end{tabular} +% \end{center} +% The branching versions then leave either \meta{true code} or +% \meta{false code} in the input stream, as appropriate to the truth +% of the test and the variant of the function chosen. The logical +% truth of the test is left in the input stream by the predicate +% version. +% \end{function} +% +% \section{Dimension expression loops} +% +% \begin{function}[EXP]{\dim_do_while:nNnn} +% \begin{syntax} +% \cs{dim_do_while:nNnn} +% ~~\Arg{dimexpr1} \meta{relation} \Arg{dimexpr2} \Arg{code} +% \end{syntax} +% Evaluates the relationship between the two \meta{dimension expressions} +% as described for \cs{dim_compare:nNnTF}, and then places the +% \meta{code} in the input stream if the \meta{relation} is +% \texttt{true}. After the \meta{code} has been processed by \TeX{} the +% test will be repeated, and a loop will occur until the test is +% \texttt{false}. +% \end{function} +% +% \begin{function}[EXP]{\dim_do_until:nNnn} +% \begin{syntax} +% \cs{dim_do_until:nNnn} +% ~~\Arg{dimexpr1} \meta{relation} \Arg{dimexpr2} \Arg{code} +% \end{syntax} +% Evaluates the relationship between the two \meta{dimension expressions} +% as described for \cs{dim_compare:nNnTF}, and then places the +% \meta{code} in the input stream if the \meta{relation} is +% \texttt{false}. After the \meta{code} has been processed by \TeX{} the +% test will be repeated, and a loop will occur until the test is +% \texttt{true}. +% \end{function} +% +% \begin{function}[EXP]{\dim_until_do:nNnn} +% \begin{syntax} +% \cs{dim_until_do:nNnn} +% ~~\Arg{dimexpr1} \meta{relation} \Arg{dimexpr2} \Arg{code} +% \end{syntax} +% Places the \meta{code} in the input stream for \TeX{} to process, and +% then evaluates the relationship between the two +% \meta{dimension expressions} as described for \cs{dim_compare:nNnTF}. +% If the test is \texttt{false} then the \meta{code} will be inserted +% into the input stream again and a loop will occur until the +% \meta{relation} is \texttt{true}. +% \end{function} +% +% \begin{function}[EXP]{\dim_while_do:nNnn} +% \begin{syntax} +% \cs{dim_while_do:nNnn} +% ~~\Arg{dimexpr1} \meta{relation} \Arg{dimexpr2} \Arg{code} +% \end{syntax} +% Places the \meta{code} in the input stream for \TeX{} to process, and +% then evaluates the relationship between the two +% \meta{dimension expressions} as described for \cs{dim_compare:nNnTF}. +% If the test is \texttt{true} then the \meta{code} will be inserted +% into the input stream again and a loop will occur until the +% \meta{relation} is \texttt{false}. +% \end{function} +% +% \begin{function}[EXP]{\dim_do_while:nn} +% \begin{syntax} +% \cs{dim_do_while:nNnn} +% ~~\{ \meta{dimexpr1} \meta{relation} \meta{dimexpr2} \} \Arg{code} +% \end{syntax} +% Evaluates the relationship between the two \meta{dimension expressions} +% as described for \cs{dim_compare:nTF}, and then places the +% \meta{code} in the input stream if the \meta{relation} is +% \texttt{true}. After the \meta{code} has been processed by \TeX{} the +% test will be repeated, and a loop will occur until the test is +% \texttt{false}. +% \end{function} +% +% \begin{function}[EXP]{\dim_do_until:nn} +% \begin{syntax} +% \cs{dim_do_until:nn} +% ~~\{ \meta{dimexpr1} \meta{relation} \meta{dimexpr2} \} \Arg{code} +% \end{syntax} +% Evaluates the relationship between the two \meta{dimension expressions} +% as described for \cs{dim_compare:nTF}, and then places the +% \meta{code} in the input stream if the \meta{relation} is +% \texttt{false}. After the \meta{code} has been processed by \TeX{} the +% test will be repeated, and a loop will occur until the test is +% \texttt{true}. +% \end{function} +% +% \begin{function}[EXP]{\dim_until_do:nn} +% \begin{syntax} +% \cs{dim_until_do:nn} +% ~~\{ \meta{dimexpr1} \meta{relation} \meta{dimexpr2} \} \Arg{code} +% \end{syntax} +% Places the \meta{code} in the input stream for \TeX{} to process, and +% then evaluates the relationship between the two +% \meta{dimension expressions} as described for \cs{dim_compare:nTF}. +% If the test is \texttt{false} then the \meta{code} will be inserted +% into the input stream again and a loop will occur until the +% \meta{relation} is \texttt{true}. +% \end{function} +% +% \begin{function}[EXP]{\dim_while_do:nn} +% \begin{syntax} +% \cs{dim_while_do:nn} +% ~~\{ \meta{dimexpr1} \meta{relation} \meta{dimexpr2} \} \Arg{code} +% \end{syntax} +% Places the \meta{code} in the input stream for \TeX{} to process, and +% then evaluates the relationship between the two +% \meta{dimension expressions} as described for \cs{dim_compare:nTF}. +% If the test is \texttt{true} then the \meta{code} will be inserted +% into the input stream again and a loop will occur until the +% \meta{relation} is \texttt{false}. +% \end{function} +% +% \section{Using \texttt{dim} expressions and variables} +% +% \begin{function}[EXP]{\dim_eval:n} +% \begin{syntax} +% \cs{dim_eval:n} \Arg{dimension expression} +% \end{syntax} +% Evaluates the \meta{dimension expression}, expanding any +% dimensions and token list variables within the \meta{expression} +% to their content (without requiring \cs{dim_use:N}/\cs{tl_use:N}) +% and applying the standard mathematical rules. The result of the +% calculation is left in the input stream as a +% \meta{dimension denotation} after two expansions. This will be +% expressed in points (\texttt{pt}), and will require suitable +% termination if used in a \TeX{}-style assignment as it is \emph{not} +% an \meta{internal dimension}. +% \end{function} +% +% \begin{function}[EXP]{\dim_use:N, \dim_use:c} +% \begin{syntax} +% \cs{dim_use:N} \meta{dimension} +% \end{syntax} +% Recovers the content of a \meta{dimension} and places it directly +% in the input stream. An error will be raised if the variable does +% not exist or if it is invalid. Can be omitted in places where a +% \meta{dimension} is required (such as in the argument of +% \cs{dim_eval:n}). +% \begin{texnote} +% \cs{dim_use:N} is the \TeX{} primitive \cs{the}: this is one of +% several \LaTeX3 names for this primitive. +% \end{texnote} +% \end{function} +% +% \section{Viewing \texttt{dim} variables} +% +% \begin{function}{\dim_show:N, \dim_show:c} +% \begin{syntax} +% \cs{dim_show:N} \meta{dimension} +% \end{syntax} +% Displays the value of the \meta{dimension} on the terminal. +% \end{function} +% +% \section{Constant dimensions} +% +% \begin{variable}{\c_max_dim} +% The maximum value that can be stored as a dimension or skip (these +% are equivalent). +% \end{variable} +% +% \begin{variable}{\c_zero_dim} +% A zero length as a dimension or a skip (these are equivalent). +% \end{variable} +% +% \section{Scratch dimensions} +% +% \begin{variable}{\l_tmpa_dim, \l_tmpb_dim, \l_tmpc_dim} +% Scratch dimension for local assignment. These are never used by +% the kernel code, and so are safe for use with any \LaTeX3-defined +% function. However, they may be overwritten by other non-kernel +% code and so should only be used for short-term storage. +% \end{variable} +% +% \begin{variable}{\g_tmpa_dim, \g_tmpb_dim} +% Scratch dimension for global assignment. These are never used by +% the kernel code, and so are safe for use with any \LaTeX3-defined +% function. However, they may be overwritten by other non-kernel +% code and so should only be used for short-term storage. +% \end{variable} +% +% \section{Creating and initialising \texttt{skip} variables} +% +% \begin{function}{\skip_new:N, \skip_new:c} +% \begin{syntax} +% \cs{skip_new:N} \meta{skip} +% \end{syntax} +% Creates a new \meta{skip} or raises an error if the name is +% already taken. The declaration is global. The \meta{skip} +% will initially be equal to $0$\,pt. +% \end{function} +% +% \begin{function}{\skip_zero:N, \skip_zero:c} +% \begin{syntax} +% \cs{skip_zero:N} \meta{skip} +% \end{syntax} +% Sets \meta{skip} to $0$\,pt within the scope of the current +% \TeX{} group. +% \end{function} +% +% \begin{function}{\skip_gzero:N, \skip_gzero:c} +% \begin{syntax} +% \cs{skip_gzero:N} \meta{skip} +% \end{syntax} +% Sets \meta{skip} to $0$\,pt globally, \emph{i.e.}~not +% restricted by the current \TeX{} group level. +% \end{function} +% +% \section{Setting \texttt{skip} variables} +% +% \begin{function}{\skip_add:Nn, \skip_add:cn} +% \begin{syntax} +% \cs{skip_add:Nn} \meta{skip} \Arg{skip expression} +% \end{syntax} +% Adds the result of the \meta{skip expression} to the current +% content of the \meta{skip}. This assignment is local. +% \end{function} +% +% \begin{function}{\skip_gadd:Nn, \skip_gadd:cn} +% \begin{syntax} +% \cs{skip_gadd:Nn} \meta{skip} \Arg{skip expression} +% \end{syntax} +% Adds the result of the \meta{skip expression} to the +% current content of the \meta{skip}. This assignment is global. +% \end{function} +% +% \begin{function}{\skip_set:Nn, \skip_set:cn} +% \begin{syntax} +% \cs{skip_set:Nn} \meta{skip} \Arg{skip expression} +% \end{syntax} +% Sets \meta{skip} to the value of \meta{skip expression}, which +% must evaluate to a length with units and may include a rubber +% component (for example |1 cm plus 0.5 cm|. This assignment is +% restricted to the current \TeX{} group. +% \end{function} +% +% \begin{function} +% {\skip_gset_eq:NN, \skip_gset_eq:cN, \skip_gset_eq:Nc, \skip_gset_eq:cc} +% \begin{syntax} +% \cs{skip_gset_eq:NN} \meta{skip1} \meta{skip2} +% \end{syntax} +% Sets the content of \meta{skip1} equal to that of \meta{skip2}. +% This assignment is global and so is not limited by the current +% \TeX{} group level. +% \end{function} +% +% \begin{function}{\skip_gset:Nn, \skip_gset:cn} +% \begin{syntax} +% \cs{skip_gset:Nn} \meta{skip} \Arg{skip expression} +% \end{syntax} +% Sets \meta{skip} to the value of \meta{skip expression}, which +% must evaluate to a length with units and may include a rubber +% component (for example |1 cm plus 0.5 cm|. This assignment is +% global and is not limited to the current \TeX{} group level. +% \end{function} +% +% \begin{function} +% {\skip_set_eq:NN, \skip_set_eq:cN, \skip_set_eq:Nc, \skip_set_eq:cc} +% \begin{syntax} +% \cs{skip_set_eq:NN} \meta{skip1} \meta{skip2} +% \end{syntax} +% Sets the content of \meta{skip1} equal to that of +% \meta{skip2}. This assignment is restricted to the current +% \TeX{} group level. +% \end{function} +% +% \begin{function}{\skip_sub:Nn, \skip_sub:cn} +% \begin{syntax} +% \cs{skip_sub:Nn} \meta{skip} \Arg{skip expression} +% \end{syntax} +% Subtracts the result of the \meta{skip expression} to the +% current content of the \meta{skip}. This assignment is local. +% \end{function} +% +% \begin{function}{\skip_gsub:Nn, \skip_gsub:cn} +% \begin{syntax} +% \cs{skip_gsub:Nn} \meta{skip} \Arg{skip expression} +% \end{syntax} +% Subtracts the result of the \meta{skip expression} to the +% current content of the \meta{skip}. This assignment is global. +% \end{function} +% +% \section{Skip expression conditionals} +% +% \begin{function}[EXP,pTF]{\skip_if_eq:nn} +% \begin{syntax} +% \cs{skip_if_eq_p:nn} +% ~~\Arg{skipexpr1} \Arg{skipexpr2} +% \cs{dim_compare:nTF} +% ~~\Arg{skipexpr1} \Arg{skipexpr2} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% This function first evaluates each of the +% \meta{skip expressions} as described for \cs{skip_eval:n}. +% The two results are then compared for exact equality, +% \emph{i.e.}~both the fixed and rubber components must be the same +% for the test to be true. The branching versions then leave either +% \meta{true code} or \meta{false code} in the input stream, as +% appropriate to the truth of the test and the variant of the function +% chosen. The logical truth of the test is left in the input stream by +% the predicate version. +% \end{function} +% +% \begin{function}[EXP,pTF]{\skip_if_infinite_glue:n} +% \begin{syntax} +% \cs{skip_if_infinite_glue_p:n} \Arg{skipexpr} +% \cs{skip_if_infinite_glue:nTF} \Arg{skipexpr} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% Evaluates the \meta{skip expression} as described for \cs{skip_eval:n}, +% and then tests if this contains an infinite stretch or shrink +% component (or both). +% The branching versions then leave either \meta{true code} or +% \meta{false code} in the input stream, as appropriate to the truth +% of the test and the variant of the function chosen. The logical +% truth of the test is left in the input stream by the predicate +% \end{function} +% +% \section{Using \texttt{skip} expressions and variables} +% +% \begin{function}[EXP]{\skip_eval:n} +% \begin{syntax} +% \cs{skip_eval:n} \Arg{skip expression} +% \end{syntax} +% Evaluates the \meta{skip expression}, expanding any skips +% and token list variables within the \meta{expression} +% to their content (without requiring \cs{skip_use:N}/\cs{tl_use:N}) +% and applying the standard mathematical rules. The result of the +% calculation is left in the input stream as a \meta{glue denotation} +% after two expansions. This will be expressed in points (\texttt{pt}), +% and will require suitable termination if used in a \TeX{}-style +% assignment as it is \emph{not} an \meta{internal glue}. +% \end{function} +% +% \begin{function}[EXP]{\skip_use:N, \skip_use:c} +% \begin{syntax} +% \cs{skip_use:N} \meta{skip} +% \end{syntax} +% Recovers the content of a \meta{skip} and places it directly +% in the input stream. An error will be raised if the variable does +% not exist or if it is invalid. Can be omitted in places where a +% \meta{dimension} is required (such as in the argument of +% \cs{skip_eval:n}). +% \begin{texnote} +% \cs{skip_use:N} is the \TeX{} primitive \cs{the}: this is one of +% several \LaTeX3 names for this primitive. +% \end{texnote} +% \end{function} +% +% \section{Viewing \texttt{skip} variables} +% +% \begin{function}{\skip_show:N, \skip_show:c} +% \begin{syntax} +% \cs{skip_show:N} \meta{skip} +% \end{syntax} +% Displays the value of the \meta{skip} on the terminal. +% \end{function} +% +% \section{Constant skips} +% +% \begin{variable}{\c_max_skip} +% The maximum value that can be stored as a dimension or skip (these +% are equivalent). +% \end{variable} +% +% \begin{variable}{\c_zero_skip} +% A zero length as a dimension or a skip (these are equivalent). +% \end{variable} +% +% \section{Scratch skips} +% +% \begin{variable}{\l_tmpa_skip, \l_tmpb_skip, \l_tmpc_skip} +% Scratch skip for local assignment. These are never used by +% the kernel code, and so are safe for use with any \LaTeX3-defined +% function. However, they may be overwritten by other non-kernel +% code and so should only be used for short-term storage. +% \end{variable} +% +% \begin{variable}{\g_tmpa_skip, \g_tmpb_skip} +% Scratch skip for global assignment. These are never used by +% the kernel code, and so are safe for use with any \LaTeX3-defined +% function. However, they may be overwritten by other non-kernel +% code and so should only be used for short-term storage. +% \end{variable} +% +% \section{Creating and initialising \texttt{muskip} variables} +% +% \begin{function}{\muskip_new:N, \muskip_new:c} +% \begin{syntax} +% \cs{muskip_new:N} \meta{muskip} +% \end{syntax} +% Creates a new \meta{muskip} or raises an error if the name is +% already taken. The declaration is global. The \meta{muskip} +% will initially be equal to $0$\,mu. +% \end{function} +% +% \begin{function}{\muskip_zero:N, \muskip_zero:c} +% \begin{syntax} +% \cs{skip_zero:N} \meta{muskip} +% \end{syntax} +% Sets \meta{muskip} to $0$\,mu within the scope of the current +% \TeX{} group. +% \end{function} +% +% \begin{function}{\muskip_gzero:N, \muskip_gzero:c} +% \begin{syntax} +% \cs{muskip_gzero:N} \meta{muskip} +% \end{syntax} +% Sets \meta{muskip} to $0$\,mu globally, \emph{i.e.}~not +% restricted by the current \TeX{} group level. +% \end{function} +% +% \section{Setting \texttt{muskip} variables} +% +% \begin{function}{\muskip_add:Nn, \muskip_add:cn} +% \begin{syntax} +% \cs{muskip_add:Nn} \meta{muskip} \Arg{muskip expression} +% \end{syntax} +% Adds the result of the \meta{muskip expression} to the current +% content of the \meta{muskip}. This assignment is local. +% \end{function} +% +% \begin{function}{\muskip_gadd:Nn, \muskip_gadd:cn} +% \begin{syntax} +% \cs{muskip_gadd:Nn} \meta{muskip} \Arg{muskip expression} +% \end{syntax} +% Adds the result of the \meta{muskip expression} to the +% current content of the \meta{muskip}. This assignment is global. +% \end{function} +% +% \begin{function}{\muskip_set:Nn, \muskip_set:cn} +% \begin{syntax} +% \cs{muskip_set:Nn} \meta{muskip} \Arg{muskip expression} +% \end{syntax} +% Sets \meta{muskip} to the value of \meta{muskip expression}, which +% must evaluate to a math length with units and may include a rubber +% component (for example |1 mu plus 0.5 mu|. This assignment is +% restricted to the current \TeX{} group. +% \end{function} +% +% \begin{function}{\muskip_gset:Nn, \muskip_gset:cn} +% \begin{syntax} +% \cs{muskip_gset:Nn} \meta{muskip} \Arg{muskip expression} +% \end{syntax} +% Sets \meta{muskip} to the value of \meta{muskip expression}, which +% must evaluate to a math length with units and may include a rubber +% component (for example |1 mu plus 0.5 mu|. This assignment is +% global and is not limited to the current \TeX{} group level. +% \end{function} +% +% \begin{function} +% { +% \muskip_set_eq:NN, \muskip_set_eq:cN, +% \muskip_set_eq:Nc, \muskip_set_eq:cc +% } +% \begin{syntax} +% \cs{muskip_set_eq:NN} \meta{muskip1} \meta{muskip2} +% \end{syntax} +% Sets the content of \meta{muskip1} equal to that of +% \meta{muskip2}. This assignment is restricted to the current +% \TeX{} group level. +% \end{function} +% +% \begin{function} +% { +% \muskip_gset_eq:NN, \muskip_gset_eq:cN, +% \muskip_gset_eq:Nc, \muskip_gset_eq:cc +% } +% \begin{syntax} +% \cs{muskip_gset_eq:NN} \meta{muskip1} \meta{muskip2} +% \end{syntax} +% Sets the content of \meta{muskip1} equal to that of \meta{muskip2}. +% This assignment is global and so is not limited by the current +% \TeX{} group level. +% \end{function} +% +% \begin{function}{\muskip_sub:Nn, \muskip_sub:cn} +% \begin{syntax} +% \cs{muskip_sub:Nn} \meta{muskip} \Arg{muskip expression} +% \end{syntax} +% Subtracts the result of the \meta{muskip expression} to the +% current content of the \meta{skip}. This assignment is local. +% \end{function} +% +% \begin{function}{\muskip_gsub:Nn, \muskip_gsub:cn} +% \begin{syntax} +% \cs{muskip_gsub:Nn} \meta{muskip} \Arg{muskip expression} +% \end{syntax} +% Subtracts the result of the \meta{muskip expression} to the +% current content of the \meta{muskip}. This assignment is global. +% \end{function} +% +% \section{Using \texttt{muskip} expressions and variables} +% +% \begin{function}[EXP]{\muskip_eval:n} +% \begin{syntax} +% \cs{muskip_eval:n} \Arg{muskip expression} +% \end{syntax} +% Evaluates the \meta{muskip expression}, expanding any skips +% and token list variables within the \meta{expression} +% to their content (without requiring \cs{muskip_use:N}/\cs{tl_use:N}) +% and applying the standard mathematical rules. The result of the +% calculation is left in the input stream as a \meta{muglue denotation} +% after two expansions. This will be expressed in \texttt{mu}, +% and will require suitable termination if used in a \TeX{}-style +% assignment as it is \emph{not} an \meta{internal muglue}. +% \end{function} +% +% \begin{function}[EXP]{\muskip_use:N, \muskip_use:c} +% \begin{syntax} +% \cs{muskip_use:N} \meta{muskip} +% \end{syntax} +% Recovers the content of a \meta{skip} and places it directly +% in the input stream. An error will be raised if the variable does +% not exist or if it is invalid. Can be omitted in places where a +% \meta{dimension} is required (such as in the argument of +% \cs{muskip_eval:n}). +% \begin{texnote} +% \cs{muskip_use:N} is the \TeX{} primitive \cs{the}: this is one of +% several \LaTeX3 names for this primitive. +% \end{texnote} +% \end{function} +% +% \section{Inserting skips into the output} +% +% \begin{function}{\skip_horizontal:N, \skip_horizontal:c, \skip_horizontal:n} +% \begin{syntax} +% \cs{skip_horizontal:N} \meta{skip} +% \cs{skip_horizontal:n} \Arg{skipexpr} +% \end{syntax} +% Inserts a horizontal \meta{skip} into the current list. +% \begin{texnote} +% \cs{skip_horizontal:N} is the \TeX{} primitive \cs{hskip} renamed. +% \end{texnote} +% \end{function} +% +% \begin{function}{\skip_vertical:N, \skip_vertical:c, \skip_vertical:n} +% \begin{syntax} +% \cs{skip_vertical:N} \meta{skip} +% \cs{skip_vertical:n} \Arg{skipexpr} +% \end{syntax} +% Inserts a vertical \meta{skip} into the current list. +% \begin{texnote} +% \cs{skip_vertical:N} is the \TeX{} primitive \cs{vskip} renamed. +% \end{texnote} +% \end{function} +% +% \section{Viewing \texttt{muskip} variables} +% +% \begin{function}{\muskip_show:N, \muskip_show:c} +% \begin{syntax} +% \cs{muskip_show:N} \meta{muskip} +% \end{syntax} +% Displays the value of the \meta{muskip} on the terminal. +% \end{function} +% +% \section{Internal functions} +% +% \begin{function}{\if_dim:w} +% \begin{syntax} +% \cs{if_dim:w} \meta{dimen1} \meta{relation} \meta{dimen1} +% ~~\meta{true code} +% \cs{else:} +% ~~\meta{false} +% \cs{fi:} +% \end{syntax} +% Compare two dimensions. The \meta{relation} is one of +% |<|, |=| or |>| with category code $12$. +% \begin{texnote} +% This is the \TeX{} primitive \cs{ifdim}. +% \end{texnote} +% \end{function} +% +% \begin{function}[EXP]{\dim_eval:w, \dim_eval_end:} +% \begin{syntax} +% \cs{dim_eval:w} \meta{dimexpr} \cs{dim_eval_end:} +% \end{syntax} +% Evaluates \meta{dimension expression} as described for \cs{dim_eval:n}. +% The evaluation stops when an unexpandable token which is not a valid +% part of a dimension is read or when \cs{dim_eval_end:} is +% reached. The latter is gobbled by the scanner mechanism: +% \cs{dim_eval_end:} itself is unexpandable but used correctly +% the entire construct is expandable. +% \begin{texnote} +% This is the \eTeX{} primitive \cs{dimexpr}. +% \end{texnote} +% \end{function} +% +% \section{Experimental skip functions} +% +% \begin{function}{\skip_split_finite_else_action:nnNN} +% \begin{syntax} +% \cs{skip_split_finite_else_action:nnNN} \Arg{skipexpr} \Arg{action} +% ~~\meta{dimen1} \meta{dimen2} +% \end{syntax} +% Checks if the \meta{skipexpr} contains finite glue. If it does then it +% assigns +% \meta{dimen1} the stretch component and \meta{dimen2} the shrink +% component. If +% it contains infinite glue set \meta{dimen1} and \meta{dimen2} to $0$\,pt +% and place |#2| into the input stream: this is usually an error or +% warning message of some sort. +% \end{function} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{l3skip} implementation} +% +% \begin{macrocode} +%<*initex|package> +% \end{macrocode} +% +% \begin{macrocode} +%<*package> +\ProvidesExplPackage + {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +\package_check_loaded_expl: +%</package> +% \end{macrocode} +% +% \subsection{Length primitives renamed} +% +% \begin{macro}{\if_dim:w} +% \begin{macro}{\dim_eval:w} +% \begin{macro}{\dim_eval_end:} +% Primitives renamed. +% \begin{macrocode} +\cs_new_eq:NN \if_dim:w \tex_ifdim:D +\cs_new_eq:NN \dim_eval:w \etex_dimexpr:D +\cs_new_eq:NN \dim_eval_end: \tex_relax:D +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Creating and initialising \texttt{dim} variables} +% +% \begin{macro}{\dim_new:N,\dim_new:c} +% Allocating \meta{dim} registers \ldots +% \begin{macrocode} +%<*initex> +\alloc_new:nnnN { dim } \c_zero \c_max_register_int \tex_dimendef:D +%</initex> +%<*package> +\cs_new_protected_nopar:Npn \dim_new:N #1 + { + \chk_if_free_cs:N #1 + \newdimen #1 + } +%</package> +\cs_generate_variant:Nn \dim_new:N { c } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\dim_zero:N, \dim_zero:c} +% \begin{macro}{\dim_gzero:N, \dim_gzero:c} +% Reset the register to zero. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \dim_zero:N #1 { #1 \c_zero_dim } +\cs_new_protected_nopar:Npn \dim_gzero:N { \pref_global:D \dim_zero:N } +\cs_generate_variant:Nn \dim_zero:N { c } +\cs_generate_variant:Nn \dim_gzero:N { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Setting \texttt{dim} variables} +% +% \begin{macro}{\dim_set:Nn, \dim_set:cn} +% \begin{macro}{\dim_gset:Nn, \dim_gset:cn} +% Setting dimensions is easy enough. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \dim_set:Nn #1#2 + { #1 ~ \dim_eval:w #2 \dim_eval_end: } +\cs_new_protected_nopar:Npn \dim_gset:Nn { \pref_global:D \dim_set:Nn } +\cs_generate_variant:Nn \dim_set:Nn { c } +\cs_generate_variant:Nn \dim_gset:Nn { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\dim_set_eq:NN,\dim_set_eq:cN, \dim_set_eq:Nc,\dim_set_eq:cc} +% \begin{macro} +% {\dim_gset_eq:NN,\dim_gset_eq:cN, \dim_gset_eq:Nc,\dim_gset_eq:cc} +% All straightforward. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \dim_set_eq:NN #1#2 { #1 = #2 } +\cs_generate_variant:Nn \dim_set_eq:NN { c } +\cs_generate_variant:Nn \dim_set_eq:NN { Nc , cc } +\cs_new_protected_nopar:Npn \dim_gset_eq:NN #1#2 { \pref_global:D #1 = #2 } +\cs_generate_variant:Nn \dim_gset_eq:NN { c } +\cs_generate_variant:Nn \dim_gset_eq:NN { Nc , cc } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\dim_set_max:Nn, \dim_set_max:cn} +% \begin{macro}{\dim_set_min:Nn, \dim_set_min:cn} +% \begin{macro}{\dim_gset_max:Nn, \dim_gset_max:cn} +% \begin{macro}{\dim_gset_min:Nn, \dim_gset_min:cn} +% Setting maximum and minimum values is simply a case of so build-in +% comparison. This only applies to dimensions as skips are not ordered. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \dim_set_max:Nn #1#2 + { \dim_compare:nNnT {#1} < {#2} { \dim_set:Nn #1 {#2} } } +\cs_new_protected_nopar:Npn \dim_gset_max:Nn #1#2 + { \dim_compare:nNnT {#1} < {#2} { \dim_gset:Nn #1 {#2} } } +\cs_new_protected_nopar:Npn \dim_set_min:Nn #1#2 + { \dim_compare:nNnT {#1} > {#2} { \dim_set:Nn #1 {#2} } } +\cs_new_protected_nopar:Npn \dim_gset_min:Nn #1#2 + { \dim_compare:nNnT {#1} > {#2} { \dim_gset:Nn #1 {#2} } } +\cs_generate_variant:Nn \dim_set_max:Nn { c } +\cs_generate_variant:Nn \dim_gset_max:Nn { c } +\cs_generate_variant:Nn \dim_set_min:Nn { c } +\cs_generate_variant:Nn \dim_gset_min:Nn { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\dim_add:Nn, \dim_add:cn} +% \begin{macro}{\dim_gadd:Nn, \dim_gadd:cn} +% \begin{macro}{\dim_sub:Nn, \dim_sub:cn} +% \begin{macro}{\dim_gsub:Nn, \dim_gsub:cn} +% Using |by| here deals with the (incorrect) case |\dimen123|. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \dim_add:Nn #1#2 + { \tex_advance:D #1 by \dim_eval:w #2 \dim_eval_end: } +\cs_new_protected_nopar:Npn \dim_gadd:Nn { \pref_global:D \dim_add:Nn } +\cs_generate_variant:Nn \dim_add:Nn { c } +\cs_generate_variant:Nn \dim_gadd:Nn { c } +\cs_new_protected_nopar:Npn \dim_sub:Nn #1#2 + { \tex_advance:D #1 by - \dim_eval:w #2 \dim_eval_end: } +\cs_new_protected_nopar:Npn \dim_gsub:Nn { \pref_global:D \dim_sub:Nn } +\cs_generate_variant:Nn \dim_sub:Nn { c } +\cs_generate_variant:Nn \dim_gsub:Nn { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Utilities for dimension calculations} +% +% \begin{macro}{\dim_ratio:nn} +% \begin{macro}[aux]{\dim_ratio_aux:n} +% With dimension expressions, something like |10 pt * ( 5 pt / 10 pt )| will +% not work. Instead, the ratio part needs to be converted to an integer +% expression. Using \cs{int_value:w} forces everything into |sp|, avoiding +% any decimal parts. +% \begin{macrocode} +\cs_new_nopar:Npn \dim_ratio:nn #1#2 + { \dim_ratio_aux:n {#1} / \dim_ratio_aux:n {#2} } +\cs_new_nopar:Npn \dim_ratio_aux:n #1 + { \exp_after:wN \int_value:w \dim_eval:w #1 \dim_eval_end: } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Dimension expression conditionals} +% +% \begin{macro}{\dim_compare_p:nNn} +% \begin{macro}[TF]{\dim_compare:nNn} +% \begin{macrocode} +\prg_new_conditional:Npnn \dim_compare:nNn #1#2#3 { p , T , F , TF } + { + \if_dim:w \dim_eval:w #1 #2 \dim_eval:w #3 \dim_eval_end: + \prg_return_true: \else: \prg_return_false: \fi: + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[pTF]{\dim_compare:n} +% \begin{macro}[aux]{\dim_compare_aux:wNN} +% \begin{macro}[aux]{\dim_compare_<:nw} +% \begin{macro}[aux]{\dim_compare_=:nw} +% \begin{macro}[aux]{\dim_compare_>:nw} +% \begin{macro}[aux]{\dim_compare_==:nw} +% \begin{macro}[aux]{\dim_compare_<=:nw} +% \begin{macro}[aux]{\dim_compare_!=:nw} +% \begin{macro}[aux]{\dim_compare_>=:nw} +% [This code plus comments are adapted from the \cs{int_compare:nTF} +% function.] +% Comparison tests using a simple syntax where only one set of braces +% is required and additional operators such as |!=| and |>=| are +% supported. First some notes on the idea behind this. We wish to +% support writing code like +% \begin{verbatim} +% \dim_compare_p:n { 5mm + \l_tmpa_dim >= 4pt - \l_tmpb_dim } +% \end{verbatim} +% In other words, we want to somehow add the missing |\dim_eval:w| +% where required. We can start evaluating from the left using +% |\dim_use:N \dim_eval:w|, and we know that since the relation +% symbols |<|, |>|, |=| and |!| are not allowed in such expressions, +% they will terminate the expression. Therefore, we first let \TeX{} +% evaluate this left hand side of the (in)equality. +% +% Eventually, we will convert the relation symbol to the appropriate +% version of \cs{if_dim:w}, and add \cs{dim_eval:w} after it. We +% optimize by placing the end-code already here: this avoids needless +% grabbing of arguments later. +% \begin{macrocode} +\prg_new_conditional:Npnn \dim_compare:n #1 { p , T , F , TF } + { + \exp_after:wN \dim_compare_aux:wNN \dim_use:N \dim_eval:w #1 + \dim_eval_end: + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +% \end{macrocode} +% +% Contrarily to the case of integers, where we have to remove the +% result in order to access the relation, \cs{dim_use:N} nicely +% produces a result which ends in |pt|. We can thus use a delimited +% argument to find the relation. \cs{tl_to_str:n} is needed to +% convert |pt| to \enquote{other} characters. +% +% The relation might be one character, |#2|, or two characters |#2#3|. +% We support the following forms: |=|, |<|, |>| and the extended |!=|, +% |==|, |<=| and |>=|. All the extended forms have an extra |=| so we +% check if that is present as well. Then use specific function to +% perform the (unbalanced) test. +% \begin{macrocode} +\exp_args:Nno \use:nn + { \cs_new:Npn \dim_compare_aux:wNN #1 } + { \tl_to_str:n { pt } } + #2 #3 + { + \use:c + { + dim_compare_ #2 + \if_meaning:w = #3 = \fi: + :nw + } + { #1 pt } #3 + } +% \end{macrocode} +% Here, \cs{dim_eval:w} will begin the right hand side of a dimension +% comparison (with \cs{if_dim:w}), closed cleanly by the trailing tokens +% we put in the definition of \cs{dim_compare:n}. +% +% The actual comparisons take as a first argument the left-hand side +% of the comparison (a length). In the case of normal comparisons, +% just place the relevant \cs{if_dim:w}, with a trailing \cs{dim_eval:w} +% to evaluate the right hand side. For extended comparisons, remove +% the trailing |=| that we left, before evaluating with \cs{dim_eval:w}. +% In both cases, the expansion of \cs{dim_eval:w} is stopped properly, +% and the conditional ended correctly by the tokens we put in the +% definition of \cs{dim_compare:n}. +% +% Equal, less than and greater than are straighforward. +% \begin{macrocode} +\cs_new:cpn { dim_compare_<:nw } #1 { \if_dim:w #1 < \dim_eval:w } +\cs_new:cpn { dim_compare_=:nw } #1 { \if_dim:w #1 = \dim_eval:w } +\cs_new:cpn { dim_compare_>:nw } #1 { \if_dim:w #1 > \dim_eval:w } +% \end{macrocode} +% For the extended syntax |==|, we remove |#2|, trailing |=| sign, +% and otherwise act as for |=|. +% \begin{macrocode} +\cs_new:cpn {dim_compare_==:nw} #1#2 { \if_dim:w #1 = \dim_eval:w } +% \end{macrocode} +% +% Not equal, greater than or equal, less than or equal follow the +% same scheme as the extended equality syntax, with an additional +% \cs{reverse_if:N} to get the opposite of their \enquote{simple} +% analog. +% \begin{macrocode} +\cs_new:cpn {dim_compare_<=:nw} #1#2 {\reverse_if:N \if_dim:w #1 > \dim_eval:w} +\cs_new:cpn {dim_compare_!=:nw} #1#2 {\reverse_if:N \if_dim:w #1 = \dim_eval:w} +\cs_new:cpn {dim_compare_>=:nw} #1#2 {\reverse_if:N \if_dim:w #1 < \dim_eval:w} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% +% \subsection{Dimension expression loops} +% +% \begin{macro}{\dim_while_do:nn} +% \begin{macro}{\dim_until_do:nn} +% \begin{macro}{\dim_do_while:nn} +% \begin{macro}{\dim_do_until:nn} +% |while_do| and |do_while| functions for dimensions. Same as for the +% |int| type only the names have changed. +% \begin{macrocode} +\cs_set:Npn \dim_while_do:nn #1#2 + { + \dim_compare:nT {#1} + { + #2 + \dim_while_do:nn {#1} {#2} + } + } +\cs_set:Npn \dim_until_do:nn #1#2 + { + \dim_compare:nF {#1} + { + #2 + \dim_until_do:nn {#1} {#2} + } + } +\cs_set:Npn \dim_do_while:nn #1#2 + { + #2 + \dim_compare:nT {#1} + { \dim_do_while:nNnn {#1} {#2} } + } +\cs_set:Npn \dim_do_until:nn #1#2 + { + #2 + \dim_compare:nF {#1} + { \dim_do_until:nn {#1} {#2} } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\dim_while_do:nNnn} +% \begin{macro}{\dim_until_do:nNnn} +% \begin{macro}{\dim_do_while:nNnn} +% \begin{macro}{\dim_do_until:nNnn} +% |while_do| and |do_while| functions for dimensions. Same as for the +% |int| type only the names have changed. +% \begin{macrocode} +\cs_set:Npn \dim_while_do:nNnn #1#2#3#4 + { + \dim_compare:nNnT {#1} #2 {#3} + { + #4 + \dim_while_do:nNnn {#1} #2 {#3} {#4} + } + } +\cs_set:Npn \dim_until_do:nNnn #1#2#3#4 + { + \dim_compare:nNnF {#1} #2 {#3} + { + #4 + \dim_until_do:nNnn {#1} #2 {#3} {#4} + } + } +\cs_set:Npn \dim_do_while:nNnn #1#2#3#4 + { + #4 + \dim_compare:nNnT {#1} #2 {#3} + { \dim_do_while:nNnn {#1} #2 {#3} {#4} } + } +\cs_set:Npn \dim_do_until:nNnn #1#2#3#4 + { + #4 + \dim_compare:nNnF {#1} #2 {#3} + { \dim_do_until:nNnn {#1} #2 {#3} {#4} } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Using \texttt{dim} expressions and variables} +% +% \begin{macro}{\dim_eval:n} +% Evaluating a dimension expression expandably. +% \begin{macrocode} +\cs_new_nopar:Npn \dim_eval:n #1 + { \dim_use:N \dim_eval:w #1 \dim_eval_end: } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\dim_use:N, \dim_use:c} +% Accessing a \meta{dim}. +% \begin{macrocode} +\cs_new_eq:NN \dim_use:N \tex_the:D +\cs_generate_variant:Nn \dim_use:N { c } +% \end{macrocode} +% \end{macro} +% +% \subsection{Viewing \texttt{dim} variables} +% +% \begin{macro}{\dim_show:N, \dim_show:c} +% Diagnostics. +% \begin{macrocode} +\cs_new_eq:NN \dim_show:N \kernel_register_show:N +\cs_generate_variant:Nn \dim_show:N { c } +% \end{macrocode} +% \end{macro} +% +% \subsection{Constant dimensions} +% +% \begin{variable}{\c_zero_dim} +% \begin{variable}{\c_max_dim} +% The source for these depends on whether we are in package mode. +% \begin{macrocode} +%<*initex> +\dim_new:N \c_zero_dim +\dim_new:N \c_max_dim +\dim_set:Nn \c_max_dim { 16383.99999 pt } +%</initex> +%<*package> +\cs_new_eq:NN \c_zero_dim \z@ +\cs_new_eq:NN \c_max_dim \maxdimen +%</package> +% \end{macrocode} +% \end{variable} +% \end{variable} +% +% \subsection{Scratch dimensions} +% +% \begin{variable}{\l_tmpa_dim, \l_tmpb_dim, \l_tmpc_dim} +% \begin{variable}{\g_tmpa_dim, \g_tmpb_dim} +% We provide three local and two global scratch registers, maybe we +% need more or less. +% \begin{macrocode} +\dim_new:N \l_tmpa_dim +\dim_new:N \l_tmpb_dim +\dim_new:N \l_tmpc_dim +\dim_new:N \g_tmpa_dim +\dim_new:N \g_tmpb_dim +% \end{macrocode} +% \end{variable} +% \end{variable} +% +% \subsection{Creating and initialising \texttt{skip} variables} +% +% \begin{macro}{\skip_new:N,\skip_new:c} +% Allocation of a new internal registers. +% \begin{macrocode} +%<*initex> +\alloc_new:nnnN { skip } \c_zero \c_max_register_int \tex_skipdef:D +%</initex> +%<*package> +\cs_new_protected_nopar:Npn \skip_new:N #1 + { + \chk_if_free_cs:N #1 + \newskip #1 + } +%</package> +\cs_generate_variant:Nn \skip_new:N { c } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\skip_zero:N, \skip_zero:c} +% \begin{macro}{\skip_gzero:N, \skip_gzero:c} +% Reset the register to zero. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \skip_zero:N #1 { #1 \c_zero_skip } +\cs_new_protected_nopar:Npn \skip_gzero:N { \pref_global:D \skip_zero:N } +\cs_generate_variant:Nn \skip_zero:N { c } +\cs_generate_variant:Nn \skip_gzero:N { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Setting \texttt{skip} variables} +% +% \begin{macro}{\skip_set:Nn, \skip_set:cn} +% \begin{macro}{\skip_gset:Nn, \skip_gset:cn} +% Much the same as for dimensions. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \skip_set:Nn #1#2 + { #1 ~ \etex_glueexpr:D #2 \scan_stop: } +\cs_new_protected_nopar:Npn \skip_gset:Nn { \pref_global:D \skip_set:Nn } +\cs_generate_variant:Nn \skip_set:Nn { c } +\cs_generate_variant:Nn \skip_gset:Nn { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro} +% {\skip_set_eq:NN,\skip_set_eq:cN, \skip_set_eq:Nc,\skip_set_eq:cc} +% \begin{macro} +% {\skip_gset_eq:NN,\skip_gset_eq:cN, \skip_gset_eq:Nc,\skip_gset_eq:cc} +% All straightforward. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \skip_set_eq:NN #1#2 { #1 = #2 } +\cs_generate_variant:Nn \skip_set_eq:NN { c } +\cs_generate_variant:Nn \skip_set_eq:NN { Nc , cc } +\cs_new_protected_nopar:Npn \skip_gset_eq:NN #1#2 { \pref_global:D #1 = #2 } +\cs_generate_variant:Nn \skip_gset_eq:NN { c } +\cs_generate_variant:Nn \skip_gset_eq:NN { Nc , cc } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\skip_add:Nn, \skip_add:cn} +% \begin{macro}{\skip_gadd:Nn, \skip_gadd:cn} +% \begin{macro}{\skip_sub:Nn, \skip_sub:cn} +% \begin{macro}{\skip_gsub:Nn, \skip_gsub:cn} +% Using |by| here deals with the (incorrect) case |\skip123|. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \skip_add:Nn #1#2 + { \tex_advance:D #1 by \etex_glueexpr:D #2 \scan_stop: } +\cs_new_protected_nopar:Npn \skip_gadd:Nn { \pref_global:D \skip_add:Nn } +\cs_generate_variant:Nn \skip_add:Nn { c } +\cs_generate_variant:Nn \skip_gadd:Nn { c } +\cs_new_protected_nopar:Npn \skip_sub:Nn #1#2 + { \tex_advance:D #1 by - \etex_glueexpr:D #2 \scan_stop: } +\cs_new_protected_nopar:Npn \skip_gsub:Nn { \pref_global:D \skip_sub:Nn } +\cs_generate_variant:Nn \skip_sub:Nn { c } +\cs_generate_variant:Nn \skip_gsub:Nn { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Skip expression conditionals} +% +% \begin{macro}[pTF]{\skip_if_eq:nn} +% Comparing skips means doing two expansions to make strings, and then +% testing them. As a result, only equality is tested. +% \begin{macrocode} +\prg_new_conditional:Npnn \skip_if_eq:nn #1#2 { p , T , F , TF } + { + \if_int_compare:w + \pdftex_strcmp:D { \skip_eval:n { #1 } } { \skip_eval:n { #2 } } + = \c_zero + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[pTF]{\skip_if_infinite_glue:n} +% 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. cs{skip_if_infinite_glue:nTF} tests it directly by +% looking at the stretch and shrink order. If either of the predicate +% functions return \meta{true}, |\bool_if:nTF| will return \meta{true} +% and the logic test will take the true branch. +% \begin{macrocode} +\prg_new_conditional:Npnn \skip_if_infinite_glue:n #1 { p , T , F , TF } + { + \bool_if:nTF + { + \int_compare_p:nNn { \etex_gluestretchorder:D #1 } > \c_zero || + \int_compare_p:nNn { \etex_glueshrinkorder:D #1 } > \c_zero + } + { \prg_return_true: } + { \prg_return_false: } + } +% \end{macrocode} +% \end{macro} +% +% \subsection{Using \texttt{skip} expressions and variables} +% +% \begin{macro}{\skip_eval:n} +% Evaluating a skip expression expandably. +% \begin{macrocode} +\cs_new_nopar:Npn \skip_eval:n #1 + { \skip_use:N \etex_glueexpr:D #1 \scan_stop: } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\skip_use:N, \skip_use:c} +% Accessing a \meta{skip}. +% \begin{macrocode} +\cs_new_eq:NN \skip_use:N \tex_the:D +\cs_generate_variant:Nn \skip_use:N { c } +% \end{macrocode} +% \end{macro} +% +% \subsection{Inserting skips into the output} +% +% \begin{macro}{\skip_horizontal:N, \skip_horizontal:c, \skip_horizontal:n} +% \begin{macro}{\skip_vertical:N, \skip_vertical:c, \skip_vertical:n} +% Inserting skips. +% \begin{macrocode} +\cs_new_eq:NN \skip_horizontal:N \tex_hskip:D +\cs_new_nopar:Npn \skip_horizontal:n #1 + { \skip_horizontal:N \etex_glueexpr:D #1 \scan_stop: } +\cs_new_eq:NN \skip_vertical:N \tex_vskip:D +\cs_new_nopar:Npn \skip_vertical:n #1 + { \skip_vertical:N \etex_glueexpr:D #1 \scan_stop: } +\cs_generate_variant:Nn \skip_horizontal:N { c } +\cs_generate_variant:Nn \skip_vertical:N { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Viewing \texttt{skip} variables} +% +% \begin{macro}{\skip_show:N, \skip_show:c} +% Diagnostics. +% \begin{macrocode} +\cs_new_eq:NN \skip_show:N \kernel_register_show:N +\cs_generate_variant:Nn \skip_show:N { c } +% \end{macrocode} +% \end{macro} +% +% \subsection{Constant skips} +% +% \begin{macro}{\c_zero_skip} +% \begin{macro}{\c_max_skip} +% Skips with no rubber component are just dimensions +% \begin{macrocode} +\cs_new_eq:NN \c_zero_skip \c_zero_dim +\cs_new_eq:NN \c_max_skip \c_max_dim +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Scratch skips} +% +% \begin{variable}{\l_tmpa_skip, \l_tmpb_skip, \l_tmpc_skip} +% \begin{variable}{\g_tmpa_skip, \g_tmpb_skip} +% We provide three local and two global scratch registers, maybe we +% need more or less. +% \begin{macrocode} +\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{variable} +% \end{variable} +% +% \subsection{Creating and initialising \texttt{muskip} variables} +% +% \begin{macro}{\muskip_new:N, \muskip_new:c} +% And then we add muskips. +% \begin{macrocode} +%<*initex> +\alloc_new:nnnN { muskip } \c_zero \c_max_register_int \tex_muskipdef:D +%</initex> +%<*package> +\cs_new_protected_nopar:Npn \muskip_new:N #1 + { + \chk_if_free_cs:N #1 + \newmuskip #1 + } +%</package> +\cs_generate_variant:Nn \muskip_new:N { c } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\muskip_zero:N, \muskip_zero:c} +% \begin{macro}{\muskip_gzero:N, \muskip_gzero:c} +% Reset the register to zero. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \muskip_zero:N #1 + { #1 \c_zero_muskip } +\cs_new_protected_nopar:Npn \muskip_gzero:N { \pref_global:D \muskip_zero:N } +\cs_generate_variant:Nn \muskip_zero:N { c } +\cs_generate_variant:Nn \muskip_gzero:N { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Setting \texttt{muskip} variables} +% +% \begin{macro}{\muskip_set:Nn, \muskip_set:cn} +% \begin{macro}{\muskip_gset:Nn, \muskip_gset:cn} +% This should be pretty familiar. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \muskip_set:Nn #1#2 + { #1 ~ \etex_muexpr:D #2 \scan_stop: } +\cs_new_protected_nopar:Npn \muskip_gset:Nn { \pref_global:D \muskip_set:Nn } +\cs_generate_variant:Nn \muskip_set:Nn { c } +\cs_generate_variant:Nn \muskip_gset:Nn { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro} +% { +% \muskip_set_eq:NN, \muskip_set_eq:cN, +% \muskip_set_eq:Nc, \muskip_set_eq:cc +% } +% \begin{macro} +% { +% \muskip_gset_eq:NN,\muskip_gset_eq:cN, +% \muskip_gset_eq:Nc,\muskip_gset_eq:cc +% } +% All straightforward. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \muskip_set_eq:NN #1#2 { #1 = #2 } +\cs_generate_variant:Nn \muskip_set_eq:NN { c } +\cs_generate_variant:Nn \muskip_set_eq:NN { Nc , cc } +\cs_new_protected_nopar:Npn \muskip_gset_eq:NN #1#2 { \pref_global:D #1 = #2 } +\cs_generate_variant:Nn \muskip_gset_eq:NN { c } +\cs_generate_variant:Nn \muskip_gset_eq:NN { Nc , cc } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\muskip_add:Nn, \muskip_add:cn} +% \begin{macro}{\muskip_gadd:Nn, \muskip_gadd:cn} +% \begin{macro}{\muskip_sub:Nn, \muskip_sub:cn} +% \begin{macro}{\muskip_gsub:Nn, \muskip_gsub:cn} +% Using |by| here deals with the (incorrect) case |\muskip123|. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \muskip_add:Nn #1#2 + { \tex_advance:D #1 by \etex_muexpr:D #2 \scan_stop: } +\cs_new_protected_nopar:Npn \muskip_gadd:Nn { \pref_global:D \muskip_add:Nn } +\cs_generate_variant:Nn \muskip_add:Nn { c } +\cs_generate_variant:Nn \muskip_gadd:Nn { c } +\cs_new_protected_nopar:Npn \muskip_sub:Nn #1#2 + { \tex_advance:D #1 by - \etex_muexpr:D #2 \scan_stop: } +\cs_new_protected_nopar:Npn \muskip_gsub:Nn { \pref_global:D \muskip_sub:Nn } +\cs_generate_variant:Nn \muskip_sub:Nn { c } +\cs_generate_variant:Nn \muskip_gsub:Nn { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Using \texttt{muskip} expressions and variables} +% +% \begin{macro}{\muskip_eval:n} +% Evaluating a muskip expression expandably. +% \begin{macrocode} +\cs_new_nopar:Npn \muskip_eval:n #1 + { \muskip_use:N \etex_muexpr:D #1 \scan_stop: } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\muskip_use:N, \muskip_use:c} +% Accessing a \meta{muskip}. +% \begin{macrocode} +\cs_new_eq:NN \muskip_use:N \tex_the:D +\cs_generate_variant:Nn \muskip_use:N { c } +% \end{macrocode} +% \end{macro} +% +% \subsection{Viewing \texttt{muskip} variables} +% +% \begin{macro}{\muskip_show:N, \muskip_show:c} +% Diagnostics. +% \begin{macrocode} +\cs_new_eq:NN \muskip_show:N \kernel_register_show:N +\cs_generate_variant:Nn \muskip_show:N { c } +% \end{macrocode} +% \end{macro} +% +% \subsection{Experimental skip functions} +% +% \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} +\cs_new_nopar:Npn \skip_split_finite_else_action:nnNN #1#2#3#4 + { + \skip_if_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} +% +% \begin{macrocode} +%</initex|package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintIndex diff --git a/Master/texmf-dist/source/latex/l3kernel/l3tl.dtx b/Master/texmf-dist/source/latex/l3kernel/l3tl.dtx new file mode 100644 index 00000000000..a7f292d14c7 --- /dev/null +++ b/Master/texmf-dist/source/latex/l3kernel/l3tl.dtx @@ -0,0 +1,2268 @@ +% \iffalse meta-comment +% +%% File: l3tl.dtx Copyright (C) 1990-2011 The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +% +%<*driver|package> +\RequirePackage{l3names} +\GetIdInfo$Id: l3tl.dtx 2498 2011-07-09 17:51:47Z joseph $ + {L3 Experimental token lists} +%</driver|package> +%<*driver> +\documentclass[full]{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{^^A +% The \pkg{l3tl} package\\ Token lists^^A +% \thanks{This file describes v\ExplFileVersion, +% last revised \ExplFileDate.}^^A +% } +% +% \author{^^A +% The \LaTeX3 Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% +% \date{Released \ExplFileDate} +% +% \maketitle +% +% \begin{documentation} +% +% \LaTeX3 stores lists of token in variables also called \enquote{token lists}. +% Variables of this type get the suffix |tl| and functions of this type +% have the prefix |tl|. To use a token list variable you simply call +% the corresponding variable. +% +% Often you find yourself with not a token list variable but an +% arbitrary token list which has to undergo certain tests. We will \emph{also} +% prefix these functions with |tl|. While token list variables are +% always single tokens, token lists are always surrounded by +% braces. Many of the functions for token lists and token list variables +% are very similar, and so are grouped together here. +% +% \section{Creating and initialising token list variables} +% +% \begin{function}{\tl_new:N, \tl_new:c} +% \begin{syntax} +% \cs{tl_new:N} \meta{tl~var} +% \end{syntax} +% Creates a new \meta{tl~var} or raises an error if the +% name is already taken. The declaration is global. The +% \meta{tl~var} will initially be empty. +% \end{function} +% +% \begin{function}{\tl_const:Nn, \tl_const:Nx, \tl_const:cn, \tl_const:cx} +% \begin{syntax} +% \cs{tl_const:Nn} \meta{tl~var} \Arg{token list} +% \end{syntax} +% Creates a new constant \meta{tl~var} or raises an error +% if the name is already taken. The value of the +% \meta{tl~var} will be set globally to the +% \meta{token list}. +% \end{function} +% +% \begin{function}{\tl_clear:N, \tl_clear:c} +% \begin{syntax} +% \cs{tl_clear:N} \meta{tl~var} +% \end{syntax} +% Clears all entries from the \meta{tl~var} within the scope of +% the current \TeX{} group. +% \end{function} +% +% \begin{function}{\tl_gclear:N, \tl_gclear:c} +% \begin{syntax} +% \cs{tl_gclear:N} \meta{tl~var} +% \end{syntax} +% Clears all entries from the \meta{tl~var} globally. +% \end{function} +% +% \begin{function}{\tl_clear_new:N, \tl_clear_new:c} +% \begin{syntax} +% \cs{tl_clear_new:N} \meta{tl~var} +% \end{syntax} +% If the \meta{tl~var} already exists, clears it within the scope +% of the current \TeX{} group. If the \meta{tl~var} is not defined, +% it will be created (using \cs{tl_new:N}). Thus the sequence is +% guaranteed to be available and clear within the current \TeX{} +% group. The \meta{tl~var} will exist globally, but the content +% outside of the current \TeX{} group is not specified. +% \end{function} +% +% \begin{function}{\tl_gclear_new:N, \tl_gclear_new:c} +% \begin{syntax} +% \cs{tl_gclear_new:N} \meta{tl~var} +% \end{syntax} +% If the \meta{tl~var} already exists, clears it globally. If the +% \meta{tl~var} is not defined, it will be created (using +% \cs{tl_new:N}). Thus the sequence is guaranteed to be available +% and globally clear. +% \end{function} +% +% \begin{function}{\tl_set_eq:NN, \tl_set_eq:cN, \tl_set_eq:Nc, \tl_set_eq:cc} +% \begin{syntax} +% \cs{tl_set_eq:NN} \meta{tl~var1} \meta{tl~var2} +% \end{syntax} +% Sets the content of \meta{tl~var1} equal to that of +% \meta{tl~var2}. This assignment is restricted to the current +% \TeX{} group level. +% \end{function} +% +% \begin{function} +% {\tl_gset_eq:NN, \tl_gset_eq:cN, \tl_gset_eq:Nc, \tl_gset_eq:cc} +% \begin{syntax} +% \cs{tl_gset_eq:NN} \meta{tl~var1} \meta{tl~var2} +% \end{syntax} +% Sets the content of \meta{tl~var1} equal to that of +% \meta{tl~var2}. This assignment is global and so is not +% limited by the current \TeX{} group level. +% \end{function} +% +% \section{Adding data to token list variables} +% +% \begin{function} +% { +% \tl_set:Nn, \tl_set:NV, \tl_set:Nv, \tl_set:No, \tl_set:Nf, \tl_set:Nx, +% \tl_set:cn, \tl_set:NV, \tl_set:Nv, \tl_set:co, \tl_set:cf, \tl_set:cx +% } +% \begin{syntax} +% \cs{tl_set:Nn} \meta{tl~var} \Arg{tokens} +% \end{syntax} +% Sets \meta{tl~var} to contain \meta{tokens}, +% removing any previous content from the variable. This assignment +% is restricted to the current \TeX{} group. +% \end{function} +% +% \begin{function} +% { +% \tl_gset:Nn, \tl_gset:NV, \tl_gset:Nv, +% \tl_gset:No, \tl_gset:Nf, \tl_gset:Nx, +% \tl_gset:cn, \tl_gset:cV, \tl_gset:cv, +% \tl_gset:co, \tl_gset:cf, \tl_gset:cx +% } +% \begin{syntax} +% \cs{tl_gset:Nn} \meta{tl~var} \Arg{tokens} +% \end{syntax} +% Sets \meta{tl~var} to contain \meta{tokens}, +% removing any previous content from the variable. This assignment +% is global and is not limited to the current \TeX{} group level. +% \end{function} +% +% \begin{function} +% { +% \tl_put_left:Nn, \tl_put_left:NV, \tl_put_left:No, \tl_put_left:Nx, +% \tl_put_left:cn, \tl_put_left:cV, \tl_put_left:co, \tl_put_left:cx +% } +% \begin{syntax} +% \cs{tl_put_left:Nn} \meta{tl~var} \Arg{tokens} +% \end{syntax} +% Appends \meta{tokens} to the left side of the current content of +% \meta{tl~var}. This modification is restricted to the +% current \TeX{} group level. +% \end{function} +% +% \begin{function} +% { +% \tl_gput_left:Nn, \tl_gput_left:NV, \tl_gput_left:No, \tl_gput_left:Nx, +% \tl_gput_left:cn, \tl_gput_left:cV, \tl_gput_left:co, \tl_gput_left:cx +% } +% \begin{syntax} +% \cs{tl_gput_left:Nn} \meta{tl~var} \Arg{tokens} +% \end{syntax} +% Globally appends \meta{tokens} to the left side of the current +% content of \meta{tl~var}. This modification is not +% limited by \TeX{} grouping. +% \end{function} +% +% \begin{function} +% { +% \tl_put_right:Nn, \tl_put_right:NV, \tl_put_right:No, \tl_put_right:Nx, +% \tl_put_right:cn, \tl_put_right:cV, \tl_put_right:co, \tl_put_right:cx +% } +% \begin{syntax} +% \cs{tl_put_right:Nn} \meta{tl~var} \Arg{tokens} +% \end{syntax} +% Appends \meta{tokens} to the right side of the current content of +% \meta{tl~var}. This modification is restricted to the +% current \TeX{} group level. +% \end{function} +% +% \begin{function} +% { +% \tl_gput_right:Nn, \tl_gput_right:NV, \tl_gput_right:No, +% \tl_gput_right:Nx, +% \tl_gput_right:cn, \tl_gput_right:cV, \tl_gput_right:co, +% \tl_gput_right:cx +% } +% \begin{syntax} +% \cs{tl_gput_right:Nn} \meta{tl~var} \Arg{tokens} +% \end{syntax} +% Globally appends \meta{tokens} to the right side of the current +% content of \meta{tl~var}. This modification is not +% limited by \TeX{} grouping. +% \end{function} +% +% \section{Modifying token list variables} +% +% \begin{function}{\tl_replace_once:Nnn, \tl_replace_once:cnn} +% \begin{syntax} +% \cs{tl_replace_once:Nnn} \meta{tl~var} \Arg{old tokens} +% ~~\Arg{new tokens} +% \end{syntax} +% Replaces the first (leftmost) occurrence of \meta{old tokens} in the +% \meta{tl~var} with \meta{new tokens}. \meta{Old tokens} +% cannot contain |{|, |}| or |#| +% (assuming normal \TeX{} category codes). The assignment is +% restricted to the current \TeX{} group. +% \end{function} +% +% \begin{function}{\tl_greplace_once:Nnn, \tl_greplace_once:cnn} +% \begin{syntax} +% \cs{tl_greplace_once:Nnn} \meta{tl~var} \Arg{old tokens} +% ~~\Arg{new tokens} +% \end{syntax} +% Replaces the first (leftmost) occurrence of \meta{old tokens} in the +% \meta{tl~var} with \meta{new tokens}. \meta{Old tokens} +% cannot contain |{|, |}| or |#| +% (assuming normal \TeX{} category codes). The assignment is +% applied globally. +% \end{function} +% +% \begin{function}{\tl_replace_all:Nnn, \tl_replace_all:cnn} +% \begin{syntax} +% \cs{tl_replace_all:Nnn} \meta{tl~var} \Arg{old tokens} +% ~~\Arg{new tokens} +% \end{syntax} +% Replaces all occurrences of \meta{old tokens} in the +% \meta{tl~var} with \meta{new tokens}. \meta{Old tokens} +% cannot contain |{|, |}| or |#| +% (assuming normal \TeX{} category codes). The assignment is +% restricted to the current \TeX{} group. +% \end{function} +% +% \begin{function}{\tl_greplace_all:Nnn, \tl_greplace_all:cnn} +% \begin{syntax} +% \cs{tl_greplace_all:Nnn} \meta{tl~var} \Arg{old tokens} +% ~~\Arg{new tokens} +% \end{syntax} +% Replaces all occurrences of \meta{old tokens} in the +% \meta{tl~var} with \meta{new tokens}. \meta{Old tokens} +% cannot contain |{|, |}| or |#| +% (assuming normal \TeX{} category codes). The assignment is +% applied globally. +% \end{function} +% +% \begin{function}{\tl_remove_once:Nn, \tl_remove_once:cn} +% \begin{syntax} +% \cs{tl_remove_once:Nn} \meta{tl~var} \Arg{tokens} +% \end{syntax} +% Removes the first (leftmost) occurrence of \meta{tokens} from the +% \meta{tl~var}. \meta{Tokens} cannot contain |{|, |}| or +% |#| (assuming normal \TeX{} category codes). The assignment is +% restricted to the current \TeX{} group. +% \end{function} +% +% \begin{function}{\tl_gremove_once:Nn, \tl_gremove_once:cn} +% \begin{syntax} +% \cs{tl_gremove_once:Nn} \meta{tl~var} \Arg{tokens} +% \end{syntax} +% Removes the first (leftmost) occurrence of \meta{tokens} from the +% \meta{tl~var}. \meta{Tokens} cannot contain |{|, |}| or +% |#| (assuming normal \TeX{} category codes). The assignment is +% applied globally. +% \end{function} +% +% \begin{function}{\tl_remove_all:Nn, \tl_remove_all:cn} +% \begin{syntax} +% \cs{tl_remove_all:Nn} \meta{tl~var} \Arg{tokens} +% \end{syntax} +% Removes all occurrences of \meta{tokens} from the +% \meta{tl~var}. \meta{Tokens} cannot contain |{|, |}| or +% |#| (assuming normal \TeX{} category codes). The assignment is +% restricted to the current \TeX{} group. +% \end{function} +% +% \begin{function}{\tl_gremove_all:Nn, \tl_gremove_all:cn} +% \begin{syntax} +% \cs{tl_gremove_all:Nn} \meta{tl~var} \Arg{tokens} +% \end{syntax} +% Removes all occurrences of \meta{tokens} from the +% \meta{tl~var}. \meta{Tokens} cannot contain |{|, |}| or +% |#| (assuming normal \TeX{} category codes). The assignment is +% applied globally. +% \end{function} +% +% \section{Reassigning token list category codes} +% +% \begin{function} +% { +% \tl_set_rescan:Nnn, \tl_set_rescan:Nno, \tl_set_rescan:Nnx, +% \tl_set_rescan:cnn, \tl_set_rescan:cno, \tl_set_rescan:cnx, +% } +% \begin{syntax} +% \cs{tl_set_rescan:Nnn} \meta{tl~var} \Arg{setup} +% ~~\Arg{tokens} +% \end{syntax} +% Sets \meta{tl~var} to contain \meta{tokens}, +% applying the category code regim{\'e} specified in the +% \meta{setup} before carrying out the assignment. This allows the +% \meta{tl~var} to contain material with category codes +% other than those that apply when \meta{tokens} are absorbed. The +% assignment is local to the current \TeX{} group. See also +% \cs{tl_rescan:nn}. +% \end{function} +% +% \begin{function} +% { +% \tl_gset_rescan:Nnn, \tl_gset_rescan:Nno, \tl_gset_rescan:Nnx, +% \tl_gset_rescan:cnn, \tl_gset_rescan:cno, \tl_gset_rescan:cnx, +% } +% \begin{syntax} +% \cs{tl_gset_rescan:Nnn} \meta{tl~var} \Arg{setup} +% ~~\Arg{tokens} +% \end{syntax} +% Sets \meta{tl~var} to contain \meta{tokens}, +% applying the category code regim{\'e} specified in the +% \meta{setup} before carrying out the assignment. This allows the +% \meta{tl~var} to contain material with category codes +% other than those that apply when \meta{tokens} are absorbed. The +% assignment is global. See also \cs{tl_rescan:nn}. +% \end{function} +% +% \begin{function}{\tl_rescan:nn} +% \begin{syntax} +% \cs{tl_rescan:nn} \Arg{setup} \Arg{tokens} +% \end{syntax} +% Rescans \meta{tokens} applying the category code regim{\'e} specified +% in the \meta{setup}, and leaves the resulting tokens in the input +% stream. See also \cs{tl_set_rescan:Nnn}. +% \end{function} +% +% \section{Reassigning token list character codes} +% +% \begin{function}{\tl_to_lowercase:n} +% \begin{syntax} +% \cs{tl_to_lowercase:n} \Arg{tokens} +% \end{syntax} +% Works through all of the \meta{tokens}, replacing each character +% with the lower case equivalent as defined by \cs{char_set_lccode:nn}. +% Characters with no defined lower case character code are left +% unchanged. This process does not alter the category code assigned +% to the \meta{tokens}. +% \begin{texnote} +% This is the \TeX{} primitive \cs{lowercase} renamed. +% As a result, this function takes place on execution and +% not on expansion. +% \end{texnote} +% \end{function} +% +% \begin{function}{\tl_to_uppercase:n} +% \begin{syntax} +% \cs{tl_to_uppercase:n} \Arg{tokens} +% \end{syntax} +% Works through all of the \meta{tokens}, replacing each character +% with the upper case equivalent as defined by \cs{char_set_uccode:nn}. +% Characters with no defined lower case character code are left +% unchanged. This process does not alter the category code assigned +% to the \meta{tokens}. +% \begin{texnote} +% This is the \TeX{} primitive \cs{uppercase} renamed.. +% As a result, this function takes place on execution and +% not on expansion. +% \end{texnote} +% \end{function} +% +% \section{Token list conditionals} +% +% \begin{function}[EXP,pTF]{\tl_if_blank:n, \tl_if_blank:V, \tl_if_blank:o} +% \begin{syntax} +% \cs{tl_if_blank_p:n} \Arg{token list} +% \cs{tl_if_blank:nTF} \Arg{token list} \Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the \meta{token list} consists only of blank spaces. The +% test is \texttt{true} if \meta{token list} is empty or consists +% entirely of explicit tokens of character code $32$ +% and category code $10$, and is \texttt{false} +% otherwise. The branching versions then leave either \meta{true code} +% or \meta{false code} in the input stream, as appropriate to the +% truth of the test and the variant of the function chosen. The logical +% truth of the test is left in the input stream by the predicate +% version. +% \end{function} +% +% \begin{function}[EXP,pTF]{\tl_if_empty:N, \tl_if_empty:c} +% \begin{syntax} +% \cs{tl_if_empty_p:N} \meta{tl var} +% \cs{tl_if_empty:NTF} \meta{tl var} \Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the \meta{token list variable} is entirely empty +% (\emph{i.e.}~contains no tokens at all). The branching versions then +% leave either \meta{true code} or \meta{false code} in the input +% stream, as appropriate to the truth of the test and the variant of +% the function chosen. The logical truth of the test is left in the +% input stream by the predicate version. +% \end{function} +% +% \begin{function}[EXP,pTF]{\tl_if_empty:n, \tl_if_empty:V, \tl_if_empty:o} +% \begin{syntax} +% \cs{tl_if_empty_p:n} \Arg{token list} +% \cs{tl_if_empty:nTF} \Arg{token list} \Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the \meta{token list} is entirely empty +% (\emph{i.e.}~contains no tokens at all). The branching versions then +% leave either \meta{true code} or \meta{false code} in the input +% stream, as appropriate to the truth of the test and the variant of +% the function chosen. The logical truth of the test is left in the +% input stream by the predicate version. +% \end{function} +% +% \begin{function}[EXP,pTF] +% {\tl_if_eq:NN, \tl_if_eq:Nc, \tl_if_eq:cN, \tl_if_eq:cc} +% \begin{syntax} +% \cs{tl_if_eq_p:NN} \Arg{tl var1} \Arg{tl var2} +% \cs{tl_if_eq:NNTF} \Arg{tl var1} \Arg{tl var2} \Arg{true code} +% ~~\Arg{false code} +% \end{syntax} +% Compares the content of two \meta{token list variables} and +% is logically \texttt{true} if the two contain the same list of +% tokens (\emph{i.e.}~identical in both the list of characters they +% contain and the category codes of those characters). Thus for example +% \begin{verbatim} +% \tl_set:Nn \l_tmpa_tl { abc } +% \tl_set:Nx \l_tmpb_tl { \tl_to_str:n { abc } } +% \tl_if_eq_p:NN \l_tmpa_tl \l_tmpb_tl +% \end{verbatim} +% is logically \texttt{false}. The branching versions then leave either +% \meta{true code} or \meta{false code} in the input stream, as +% appropriate to the truth of the test and the variant of the function +% chosen. The logical truth of the test is left in the input stream by +% the predicate version. +% \end{function} +% +% \begin{function}[TF]{\tl_if_eq:nn} +% \begin{syntax} +% \cs{tl_if_eq:nnTF} \meta{token list1} \Arg{token list2} \Arg{true code} +% ~~\Arg{false code} +% \end{syntax} +% Tests if \meta{token list1} and \meta{token list2} are equal, both in +% respect of character codes and category codes. Either the +% \meta{true code} or \meta{false code} in the input stream, as +% appropriate to the truth of the test and the variant of the function +% chosen. +% \end{function} +% +% \begin{function}[TF]{\tl_if_in:Nn, \tl_if_in:cn} +% \begin{syntax} +% \cs{tl_if_in:NnTF} \meta{tl~var} \Arg{token list} \Arg{true code} +% ~~\Arg{false code} +% \end{syntax} +% Tests if the \meta{token list} is found in the content of the +% \meta{token list variable}. The \meta{token list} cannot contain +% the tokens |{|, |}| or |#| (assuming the usual \TeX{} category +% codes apply). Either the \meta{true code} or \meta{false code} +% is left in the +% input stream, as appropriate to the truth of the test and the variant +% of the function chosen. +% \end{function} +% +% \begin{function}[TF] +% {\tl_if_in:nn, \tl_if_in:Vn, \tl_if_in:on, \tl_if_in:on} +% \begin{syntax} +% \cs{tl_if_in:nnTF} \meta{token list1} \Arg{token list2} \Arg{true code} +% ~~\Arg{false code} +% \end{syntax} +% Tests if the \meta{token list1} is found inside \meta{token list2}. +% The \meta{token list} cannot contain the tokens |{|, |}| or |#| +% (assuming the usual \TeX{} category codes apply). Either the +% \meta{true code} or \meta{false code} is left in the input stream, as +% appropriate to the truth of the test and the variant of the function +% chosen. +% \end{function} +% +% \begin{function}[EXP,pTF]{\tl_if_single:N, \tl_if_single:c} +% \begin{syntax} +% \cs{tl_if_single_p:N} \Arg{tl~var} +% \cs{tl_if_single:nTF} \Arg{tl~var} \Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the content of the \meta{tl~var} consists of a +% single token or token group. The test is \texttt{true} if +% \meta{token list} contains exactly one token, if it consists +% entirely of explicit tokens of character code $32$ and category +% code $10$, or if it contains one braced token group (optionally +% preceeded by spaces), and it is \texttt{false} otherwise. The branching +% versions then leave either \meta{true code} or \meta{false code} +% in the input stream, as appropriate to the truth of the test and the +% variant of the function chosen. The logical truth of the test is left +% in the input stream by the predicate version. +% \end{function} +% +% \begin{function}[EXP,pTF]{\tl_if_single:n} +% \begin{syntax} +% \cs{tl_if_single_p:n} \Arg{token list} +% \cs{tl_if_single:nTF} \Arg{token list} \Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the \meta{token list} consists of a single token +% or token group. The test is \texttt{true} if \meta{token list} +% contains exactly one token, or if it consists entirely of +% explicit tokens of character code $32$ and category code $10$, +% or if it contains a braced token group (optionally preceeded by blank +% spaces), and it is +% \texttt{false} otherwise. The branching versions then leave +% either \meta{true code} or \meta{false code} in the input stream, as +% appropriate to the truth of the test and the variant of the function +% chosen. The logical truth of the test is left in the input stream by +% the predicate version. +% \end{function} +% +% \section{Mapping to token lists} +% +% \begin{function}[EXP]{\tl_map_function:NN, \tl_map_function:cN} +% \begin{syntax} +% \cs{tl_map_function:NN} \meta{tl~var} \meta{function} +% \end{syntax} +% Applies \meta{function} to every \meta{token group} stored in the +% \meta{tl~var}. The \meta{function} +% will receive one argument for each iteration. This may be a number +% of tokens if the \meta{token group} was an item stored within +% braces. Hence the \meta{function} should anticipate receiving +% \texttt{n}-type arguments. See also \cs{tl_map_function:nN}. +% \end{function} +% +% \begin{function}[EXP]{\tl_map_function:nN} +% \begin{syntax} +% \cs{tl_map_function:nN} \meta{token list} \meta{function} +% \end{syntax} +% Applies \meta{function} to every \meta{token group} in the +% \meta{token list}. The \meta{function} +% will receive one argument for each iteration. This may be a number +% of tokens if the \meta{token group} was an item stored within +% braces. Hence the \meta{function} should anticipate receiving +% \texttt{n}-type arguments. See also \cs{tl_map_function:NN}. +% \end{function} +% +% \begin{function}{\tl_map_inline:Nn, \tl_map_inline:cn} +% \begin{syntax} +% \cs{tl_map_inline:Nn} \meta{tl~var} \Arg{inline function} +% \end{syntax} +% Applies the \meta{inline function} to every \meta{token group} stored +% within the \meta{tl~var}. The \meta{inline function} +% should consist of code which will receive the \meta{token group} as +% |#1|. One in line mapping can be nested inside another. See also +% \cs{tl_map_function:Nn}. +% \end{function} +% +% \begin{function}{\tl_map_inline:nn} +% \begin{syntax} +% \cs{tl_map_inline:nn} \meta{token list} \Arg{inline function} +% \end{syntax} +% Applies the \meta{inline function} to every \meta{token group} stored +% within the \meta{token list}. The \meta{inline function} should +% consist of code which will receive the \meta{token group} as +% |#1|. One in line mapping can be nested inside another. See also +% \cs{tl_map_function:nn}. +% \end{function} +% +% \begin{function}{\tl_map_variable:NNn, \tl_map_variable:cNn} +% \begin{syntax} +% \cs{tl_map_variable:NNn} \meta{tl~var} \meta{variable} \Arg{function} +% \end{syntax} +% Applies the \meta{function} to every \meta{token group} stored +% within the \meta{tl~var}. The \meta{function} should consist of code +% which will receive the \meta{token group} stored in the \meta{variable}. +% One variable mapping can be nested inside another. See also +% \cs{tl_map_inline:Nn}. +% \end{function} +% +% \begin{function}{\tl_map_variable:nNn} +% \begin{syntax} +% \cs{tl_map_variable:nNn} \meta{token list} \meta{variable} \Arg{function} +% \end{syntax} +% Applies the \meta{function} to every \meta{token group} stored +% within the \meta{token list}. The \meta{function} should consist of code +% which will receive the \meta{token group} stored in the \meta{variable}. +% One variable mapping can be nested inside another. See also +% \cs{tl_map_inline:nn}. +% \end{function} +% +% \begin{function}[EXP]{\tl_map_break:} +% \begin{syntax} +% \cs{tl_map_break:} +% \end{syntax} +% Used to terminate a \cs{tl_map_\ldots} function before all +% entries in the \meta{token list variable} have been processed. This +% will normally take place within a conditional statement, for example +% \begin{verbatim} +% \tl_map_inline:Nn \l_my_tl +% { +% \str_if_eq:nnTF { #1 } { bingo } +% { \tl_map_break: } +% { +% % Do something useful +% } +% } +% \end{verbatim} +% Use outside of a \cs{tl_map_\ldots} scenario will lead low +% level \TeX{} errors. +% \end{function} +% +% \section{Using token lists} +% +% \begin{function}[EXP]{\tl_to_str:N, \tl_to_str:c} +% \begin{syntax} +% \cs{tl_to_str:N} \meta{tl~var} +% \end{syntax} +% Converts the content of the \meta{tl~var} into a series of characters +% with category code $12$ (other) with the exception of spaces, which +% retain category code $10$ (space). This \meta{string} is then left +% in the input stream. +% \end{function} +% +% \begin{function}[EXP]{\tl_to_str:n} +% \begin{syntax} +% \cs{tl_to_str:n} \Arg{tokens} +% \end{syntax} +% Converts the given \meta{tokens} into a series of characters with +% category code $12$ (other) with the exception of spaces, which +% retain category code $10$ (space). This \meta{string} is then left +% in the input stream. Note that this function requires only a single +% expansion. +% \begin{texnote} +% This is the \eTeX{} primitive \cs{detokenize}. +% \end{texnote} +% \end{function} +% +% \begin{function}[EXP]{\tl_use:N, \tl_use:c} +% \begin{syntax} +% \cs{tl_use:N} \meta{tl~var} +% \end{syntax} +% Recovers the content of a \meta{tl~var} and places it +% directly in the input stream. An error will be raised if the variable +% does not exist or if it is invalid. Note that it is possible to use +% a \meta{tl~var} directly without an accessor function. +% \end{function} +% +% \section{Working with the content of token lists} +% +% \begin{function}[EXP]{\tl_length:n, \tl_length:V, \tl_length:o} +% \begin{syntax} +% \cs{tl_length:n} \Arg{tokens} +% \end{syntax} +% Counts the number of token groups in \meta{tokens} and leaves this +% information in the input stream. Unbraced tokens count as one +% element as do each token group (|{|\ldots|}|). This process will +% ignore any unprotected spaces within \meta{tokens}. See also +% \cs{tl_length:N}. This function requires three expansions, +% giving an \meta{integer denotation}. +% \end{function} +% +% \begin{function}[EXP]{\tl_length:N, \tl_length:c} +% \begin{syntax} +% \cs{tl_length:N} \Arg{tl~var} +% \end{syntax} +% Counts the number of token groups in the \meta{tl~var} +% and leaves this information in the input stream. Unbraced tokens +% count as one element as do each token group (|{|\ldots|}|). This +% process will ignore any unprotected spaces within \meta{tokens}. +% See also \cs{tl_length:n}. This function requires three expansions, +% giving an \meta{integer denotation}. +% \end{function} +% +% \begin{function}[EXP]{\tl_reverse:n, \tl_reverse:V, \tl_reverse:o} +% \begin{syntax} +% \cs{tl_reverse:n} \Arg{tokens} +% \end{syntax} +% Reverses the order of the \meta{tokens}, so that +% \meta{token1}\meta{token2}\meta{token3} \ldots \meta{token$_n$} +% becomes \meta{token$_n$}\ldots +% \meta{token3}\meta{token2}\meta{token1}. This process will remove +% any unprotected space within the \meta{tokens}. Tokens are not reversed +% within braced token groups, which lose their outer set of braces. +% See also \cs{tl_reverse:N}. +% \end{function} +% +% \begin{function}{\tl_reverse:N, \tl_reverse:c} +% \begin{syntax} +% \cs{tl_reverse:N} \Arg{tl~var} +% \end{syntax} +% Reverses the order of the \meta{tokens} stored in +% \meta{tl~var}, so that +% \meta{token1}\meta{token2}\meta{token3} \ldots \meta{token$_n$} +% becomes \meta{token$_n$}\ldots +% \meta{token3}\meta{token2}\meta{token1}. This process will +% remove any unprotected spaces within the +% \meta{token list variable}. Braced token groups are copied without +% reversing the order of tokens, and the outer set of braces is removed. +% The reversal is local to the current +% \TeX{} group. See also \cs{tl_reverse:n}. +% \end{function} +% +% \begin{function}[EXP]{\tl_trim_spaces:n} +% \begin{syntax} +% \cs{tl_trim_spaces:n} \meta{token list} +% \end{syntax} +% Removes any leading and trailing spaces from the \meta{token list} +% and leaves the result in the input stream. This process requires +% two expansions. +% \end{function} +% +% \begin{function}{\tl_trim_spaces:N, \tl_trim_spaces:c} +% \begin{syntax} +% \cs{tl_trim_spaces:N} \meta{tl~var} +% \end{syntax} +% Removes any leading and trailing spaces from the content of the +% \meta{tl~var} within the current \TeX{} group. +% \end{function} +% +% \begin{function}{\tl_gtrim_spaces:N, \tl_gtrim_spaces:c} +% \begin{syntax} +% \cs{tl_gtrim_spaces:N} \meta{tl~var} +% \end{syntax} +% Removes any leading and trailing spaces from the content of the +% \meta{tl~var} globally. +% \end{function} +% +% \section{The first token from a token list} +% +% Functions which deal with either onlt the very first token of a +% token list or everything except the first token. +% +% \begin{function}[EXP]{\tl_head:n, \tl_head:V, \tl_head:v, \tl_head:f} +% \begin{syntax} +% \cs{tl_head:n} \Arg{tokens} +% \end{syntax} +% Leaves only the first \meta{token} in \meta{tokens} in the input +% stream, discarding the remainder. +% \end{function} +% +% \begin{function}[EXP]{\tl_head:w} +% \begin{syntax} +% \cs{tl_head:w} \Arg{tokens} \cs{q_stop} +% \end{syntax} +% Leaves only the first \meta{token} in \meta{tokens} in the input +% stream, discarding the remainder. This function requires only a +% single expansion, and so is suitable for use inside an +% \texttt{o}-type expansion. In general \cs{tl_head:n} should be +% preferred. +% \end{function} +% +% \begin{function}[EXP]{\tl_tail:n, \tl_tail:V, \tl_tail:v, \tl_tail:f} +% \begin{syntax} +% \cs{tl_tail:n} \Arg{tokens} +% \end{syntax} +% Discards the first \meta{token} of the \meta{tokens} and leaves the +% remainder in the input stream. +% \end{function} +% +% \begin{function}[EXP]{\tl_tail:w} +% \begin{syntax} +% \cs{tl_tail:w} \Arg{tokens} \cs{q_stop} +% \end{syntax} +% Discards the first \meta{token} of the \meta{tokens} and leaves the +% remainder in the input stream. This function requires only a +% single expansion, and so is suitable for use inside an +% \texttt{o}-type expansion. In general \cs{tl_tail:n} should be +% preferred. +% \end{function} +% +% \begin{function}[EXP,pTF]{\tl_if_head_eq_catcode:nN} +% \begin{syntax} +% \cs{tl_if_head_eq_catcode_p:n} \Arg{token list} \meta{test token} +% \cs{tl_if_head_eq_catcode:nTF} \Arg{token list} \meta{test token} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the first \meta{token} in the \meta{token list} has the same +% category code as the \meta{test token}. The branching versions then +% leave either \meta{true code} or \meta{false code} in the input +% stream, as appropriate to the truth of the test and the variant of +% the function chosen. The logical truth of the test is left in the +% input stream by the predicate +% version. +% \end{function} +% +% \begin{function}[EXP,pTF] +% {\tl_if_head_eq_charcode:nN, \tl_if_head_eq_charcode:fN} +% \begin{syntax} +% \cs{tl_if_head_eq_charcode_p:n} \Arg{token list} \meta{test token} +% \cs{tl_if_head_eq_charcode:nTF} \Arg{token list} \meta{test token} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the first \meta{token} in the \meta{token list} has the same +% character code as the \meta{test token}. The branching versions then +% leave either \meta{true code} or \meta{false code} in the input +% stream, as appropriate to the truth of the test and the variant of +% the function chosen. The logical truth of the test is left in the +% input stream by the predicate +% version. +% \end{function} +% +% \begin{function}[EXP,pTF]{\tl_if_head_eq_meaning:nN} +% \begin{syntax} +% \cs{tl_if_head_eq_meaning_p:n} \Arg{token list} \meta{test token} +% \cs{tl_if_head_eq_meaning:nTF} \Arg{token list} \meta{test token} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the first \meta{token} in the \meta{token list} has the same +% meaning as the \meta{test token}. The branching versions then +% leave either \meta{true code} or \meta{false code} in the input +% stream, as appropriate to the truth of the test and the variant of +% the function chosen. The logical truth of the test is left in the +% input stream by the predicate +% version. +% \end{function} +% +% \section{Viewing token lists} +% +% \begin{function}{\tl_show:N, \tl_show:c} +% \begin{syntax} +% \cs{tl_show:N} \meta{tl~var} +% \end{syntax} +% Displays the content of the \meta{tl~var} on the terminal. +% \begin{texnote} +% \cs{tl_show:N} is the \TeX{} primitive \cs{show}. +% \end{texnote} +% \end{function} +% +% \begin{function}{\tl_show:n} +% \begin{syntax} +% \cs{tl_show:n} \meta{token list} +% \end{syntax} +% Displays the \meta{token list} on the terminal. +% \begin{texnote} +% \cs{tl_show:n} is the \eTeX{} primitive \cs{showtokens}. +% \end{texnote} +% \end{function} +% +% \section{Constant token lists} +% +% \begin{variable}{\c_job_name_tl} +% Constant that gets the \enquote{job name} assigned when \TeX{} starts. +% \begin{texnote} +% This is the new name for the primitive \cs{jobname}. It is a constant +% that is set by \TeX{} and should not be overwritten by the package. +% \end{texnote} +% \end{variable} +% +% \begin{variable}{\c_empty_tl} +% Constant that is always empty. +% \end{variable} +% +% \begin{variable}{\c_space_tl} +% A space token contained in a token list (compare this with +% \cs{c_space_token}). For use where an explicit space is required. +% \end{variable} +% +% \section{Scratch token lists} +% +% \begin{variable}{\l_tmpa_tl, \l_tmpb_tl} +% Scratch token lists for local assignment. These are never used by +% the kernel code, and so are safe for use with any \LaTeX3-defined +% function. However, they may be overwritten by other non-kernel +% code and so should only be used for short-term storage. +% \end{variable} +% +% \begin{variable}{\g_tmpa_tl, \g_tmpb_tl} +% Scratch token lists for global assignment. These are never used by +% the kernel code, and so are safe for use with any \LaTeX3-defined +% function. However, they may be overwritten by other non-kernel +% code and so should only be used for short-term storage. +% \end{variable} +% +% \section{Experimental token list functions} +% +% \begin{function}[EXP,pTF]{\tl_if_single_item:n} +% \begin{syntax} +% \cs{tl_if_single_item_p:n} \Arg{token list} +% \cs{tl_if_single_item:nTF} \Arg{token list} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the token list has exactly one item, i.e., is either +% a single normal token or a single brace group, surrounded by +% optional spaces on both sides. In other words, such a token list +% has length $1$ according to \cs{tl_length:n}. The branching +% versions then leave either \meta{true code} or \meta{false code} +% in the input stream, as appropriate to the truth of the test and +% the variant of the function chosen. The logical truth of the test +% is left in the input stream by the predicate. +% \end{function} +% +% \begin{function}[EXP,pTF]{\tl_if_head_begin_group:n} +% \begin{syntax} +% \cs{tl_if_head_begin_group_p:n} \Arg{token list} +% \cs{tl_if_head_begin_group:nTF} \Arg{token list} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the first \meta{token} in the \meta{token list} +% has catcode~1, i.e., is a begin-group character. This conditional +% is mainly intended to be used in combination with +% \cs{tl_if_head_eq_space:n} to check if grabbing an undelimited +% argument from the token list is safe. The branching +% versions leave either \meta{true code} or \meta{false code} +% in the input stream, as appropriate to the truth of the test and +% the variant of the function chosen. The logical truth of the test +% is left in the input stream by the predicate. +% \end{function} +% +% \begin{function}[EXP,pTF]{\tl_if_head_eq_space:n} +% \begin{syntax} +% \cs{tl_if_head_eq_space_p:n} \Arg{token list} +% \cs{tl_if_head_eq_space:nTF} \Arg{token list} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +%^^A Needs rewriting. We need to add a discussion of +%^^A explicit vs implicit tokens somewhere in the doc. +% Tests if the first token of the token list is an explicit space, +% i.e., a token which matches \verb*+ + both in character code and +% in category code. In the case of an implicit space token, such as +% \cs{c_space_token}, the test will return \meta{false}. +% This conditional is mainly intended to be used in combination with +% \cs{tl_if_head_begin_group:n} to test if grabbing an undelimited +% argument is safe (see \cs{tl_if_single_token:n} for an example. +% The branching versions leave either \meta{true code} or +% \meta{false code} in the input stream, as appropriate to the truth +% of the test and the variant of the function chosen. The logical +% truth of the test is left in the input stream by the predicate. +% \begin{texnote} +% When \TeX{}'s reads a character of category code $10$ for the +% first time, it is converted to an explicit space token, with +% character code $32$, regardless of the initial character code. +% ``Funny'' spaces with a different category code, can be produced +% using \cs{tex_lowercase:D}. Explicit spaces are also produced +% as a result of \cs{token_to_str:N}, \cs{tl_to_str:n}, etc. +% \end{texnote} +% \end{function} +% +% \begin{function}[EXP,pTF]{\tl_if_single_token:n} +% \begin{syntax} +% \cs{tl_if_single_token_p:n} \Arg{token list} +% \cs{tl_if_single_token:nTF} \Arg{token list} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the token list consists of exactly one token, i.e., +% is either a single space character or a single ``normal'' token. +% Token groups are not single tokens. The branching +% versions leaves either \meta{true code} or \meta{false code} +% in the input stream, as appropriate to the truth of the test and +% the variant of the function chosen. The logical truth of the test +% is left in the input stream by the predicate. +% \end{function} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{l3tl} implementation} +% +% \begin{macrocode} +%<*initex|package> +% \end{macrocode} +% +% \begin{macrocode} +%<*package> +\ProvidesExplPackage + {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +\package_check_loaded_expl: +%</package> +% \end{macrocode} +% +% A token list variable is a \TeX{} macro that holds tokens. By using the +% \eTeX{} primitive \cs{unexpanded} inside a \TeX{} \cs{edef} it is +% possible to store any tokens, including |#|, in this way. +% +% \subsection{Functions} +% +% \begin{macro}{\tl_new:N, \tl_new:c} +% Creating new token list variables is a case of checking for an +% existing definition and if free doing the definition. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \tl_new:N #1 + { + \chk_if_free_cs:N #1 + \cs_gset_eq:NN #1 \c_empty_tl + } +\cs_generate_variant:Nn \tl_new:N { c } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\tl_const:Nn, \tl_const:Nx, \tl_const:cn, \tl_const:cx} +% Constants are also easy to generate. +% \begin{macrocode} +\cs_new_protected:Npn \tl_const:Nn #1#2 + { + \chk_if_free_cs:N #1 + \cs_gset_nopar:Npx #1 { \exp_not:n {#2} } + } +\cs_new_protected:Npn \tl_const:Nx #1#2 + { + \chk_if_free_cs:N #1 + \cs_gset_nopar:Npx #1 {#2} + } +\cs_generate_variant:Nn \tl_const:Nn { c } +\cs_generate_variant:Nn \tl_const:Nx { c } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\tl_clear:N, \tl_clear:c} +% \begin{macro}{\tl_gclear:N, \tl_gclear:c} +% Clearing a token list variable means setting it to an empty value. +% Error checking will be sorted out by the parent function. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \tl_clear:N #1 + { \tl_set_eq:NN #1 \c_empty_tl } +\cs_new_protected_nopar:Npn \tl_gclear:N #1 + { \tl_gset_eq:NN #1 \c_empty_tl } +\cs_generate_variant:Nn \tl_clear:N { c } +\cs_generate_variant:Nn \tl_gclear:N { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\tl_clear_new:N, \tl_clear_new:c} +% \begin{macro}{\tl_gclear_new:N, \tl_gclear_new:c} +% Clearing a token list variable means setting it to an empty value. +% Error checking will be sorted out by the parent function. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \tl_clear_new:N #1 + { \cs_if_exist:NTF #1 { \tl_clear:N #1 } { \tl_new:N #1 } } +\cs_new_protected_nopar:Npn \tl_gclear_new:N #1 + { \cs_if_exist:NTF #1 { \tl_gclear:N #1 } { \tl_new:N #1 } } +\cs_generate_variant:Nn \tl_clear_new:N { c } +\cs_generate_variant:Nn \tl_gclear_new:N { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\tl_set_eq:NN, \tl_set_eq:Nc, \tl_set_eq:cN, \tl_set_eq:cc} +% \begin{macro}{\tl_gset_eq:NN, \tl_gset_eq:Nc, \tl_gset_eq:cN, \tl_gset_eq:cc} +% For setting token list variables equal to each other. +% \begin{macrocode} +\cs_new_eq:NN \tl_set_eq:NN \cs_set_eq:NN +\cs_new_eq:NN \tl_set_eq:cN \cs_set_eq:cN +\cs_new_eq:NN \tl_set_eq:Nc \cs_set_eq:Nc +\cs_new_eq:NN \tl_set_eq:cc \cs_set_eq:cc +\cs_new_eq:NN \tl_gset_eq:NN \cs_gset_eq:NN +\cs_new_eq:NN \tl_gset_eq:cN \cs_gset_eq:cN +\cs_new_eq:NN \tl_gset_eq:Nc \cs_gset_eq:Nc +\cs_new_eq:NN \tl_gset_eq:cc \cs_gset_eq:cc +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Adding to token list variables} +% +% \begin{macro} +% { +% \tl_set:Nn, \tl_set:NV, \tl_set:Nv, \tl_set:No, \tl_set:Nf, \tl_set:Nx, +% \tl_set:cn, \tl_set:NV, \tl_set:Nv, \tl_set:co, \tl_set:cf, \tl_set:cx +% } +% \begin{macro} +% { +% \tl_gset:Nn, \tl_gset:NV, \tl_gset:Nv, +% \tl_gset:No, \tl_gset:Nf, \tl_gset:Nx, +% \tl_gset:cn, \tl_gset:NV, \tl_gset:Nv, +% \tl_gset:co, \tl_gset:cf, \tl_gset:cx +% } +% By using \cs{exp_not:n} token list variables can contain |#| tokens, +% which makes the token list registers provided by \TeX{} +% more or less redundant. The \cs{tl_set:No} version is done +% \enquote{by hand} as it is used quite a lot. +% \begin{macrocode} +\cs_new_protected:Npn \tl_set:Nn #1#2 + { \cs_set_nopar:Npx #1 { \exp_not:n {#2} } } +\cs_new_protected:Npn \tl_set:No #1#2 + { \cs_set_nopar:Npx #1 { \exp_not:o {#2} } } +\cs_new_protected:Npn \tl_set:Nx #1#2 + { \cs_set_nopar:Npx #1 {#2} } +\cs_new_protected:Npn \tl_gset:Nn #1#2 + { \cs_gset_nopar:Npx #1 { \exp_not:n {#2} } } +\cs_new_protected:Npn \tl_gset:No #1#2 + { \cs_gset_nopar:Npx #1 { \exp_not:o {#2} } } +\cs_new_protected:Npn \tl_gset:Nx #1#2 + { \cs_gset_nopar:Npx #1 {#2} } +\cs_generate_variant:Nn \tl_set:Nn { NV , Nv , Nf } +\cs_generate_variant:Nn \tl_set:Nx { c } +\cs_generate_variant:Nn \tl_set:Nn { c, co , cV , cv , cf } +\cs_generate_variant:Nn \tl_gset:Nn { NV , Nv , Nf } +\cs_generate_variant:Nn \tl_gset:Nx { c } +\cs_generate_variant:Nn \tl_gset:Nn { c, co , cV , cv , cf } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro} +% { +% \tl_put_left:Nn, \tl_put_left:NV, \tl_put_left:No, \tl_put_left:Nx, +% \tl_put_left:cn, \tl_put_left:cV, \tl_put_left:co, \tl_put_left:cx +% } +% \begin{macro} +% { +% \tl_gput_left:Nn, \tl_gput_left:NV, \tl_gput_left:No, \tl_gput_left:Nx, +% \tl_gput_left:cn, \tl_gput_left:cV, \tl_gput_left:co, \tl_gput_left:cx +% } +% Adding to the left is done directly to gain a little performance. +% \begin{macrocode} +\cs_new_protected:Npn \tl_put_left:Nn #1#2 + { \cs_set_nopar:Npx #1 { \exp_not:n {#2} \exp_not:o #1 } } +\cs_new_protected:Npn \tl_put_left:NV #1#2 + { \cs_set_nopar:Npx #1 { \exp_not:V #2 \exp_not:o #1 } } +\cs_new_protected:Npn \tl_put_left:No #1#2 + { \cs_set_nopar:Npx #1 { \exp_not:o {#2} \exp_not:o #1 } } +\cs_new_protected:Npn \tl_put_left:Nx #1#2 + { \cs_set_nopar:Npx #1 { #2 \exp_not:o #1 } } +\cs_new_protected:Npn \tl_gput_left:Nn #1#2 + { \cs_gset_nopar:Npx #1 { \exp_not:n {#2} \exp_not:o #1 } } +\cs_new_protected:Npn \tl_gput_left:NV #1#2 + { \cs_gset_nopar:Npx #1 { \exp_not:V #2 \exp_not:o #1 } } +\cs_new_protected:Npn \tl_gput_left:No #1#2 + { \cs_gset_nopar:Npx #1 { \exp_not:o {#2} \exp_not:o #1 } } +\cs_new_protected:Npn \tl_gput_left:Nx #1#2 + { \cs_gset_nopar:Npx #1 { #2 \exp_not:o {#1} } } +\cs_generate_variant:Nn \tl_put_left:Nn { c } +\cs_generate_variant:Nn \tl_put_left:NV { c } +\cs_generate_variant:Nn \tl_put_left:No { c } +\cs_generate_variant:Nn \tl_put_left:Nx { c } +\cs_generate_variant:Nn \tl_gput_left:Nn { c } +\cs_generate_variant:Nn \tl_gput_left:NV { c } +\cs_generate_variant:Nn \tl_gput_left:No { c } +\cs_generate_variant:Nn \tl_gput_left:Nx { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro} +% { +% \tl_put_right:Nn, \tl_put_right:NV, \tl_put_right:No, \tl_put_right:Nx, +% \tl_put_right:cn, \tl_put_right:cV, \tl_put_right:co, \tl_put_right:cx +% } +% \begin{macro} +% { +% \tl_gput_right:Nn, \tl_gput_right:NV, \tl_gput_right:No, +% \tl_gput_right:Nx, +% \tl_gput_right:cn, \tl_gput_right:cV, \tl_gput_right:co, +% \tl_gput_right:cx +% } +% The same on the right. +% \begin{macrocode} +\cs_new_protected:Npn \tl_put_right:Nn #1#2 + { \cs_set_nopar:Npx #1 { \exp_not:o #1 \exp_not:n {#2} } } +\cs_new_protected:Npn \tl_put_right:NV #1#2 + { \cs_set_nopar:Npx #1 { \exp_not:o #1 \exp_not:V #2 } } +\cs_new_protected:Npn \tl_put_right:No #1#2 + { \cs_set_nopar:Npx #1 { \exp_not:o #1 \exp_not:o {#2} } } +\cs_new_protected:Npn \tl_put_right:Nx #1#2 + { \cs_set_nopar:Npx #1 { \exp_not:o #1 #2 } } +\cs_new_protected:Npn \tl_gput_right:Nn #1#2 + { \cs_gset_nopar:Npx #1 { \exp_not:o #1 \exp_not:n {#2} } } +\cs_new_protected:Npn \tl_gput_right:NV #1#2 + { \cs_gset_nopar:Npx #1 { \exp_not:o #1 \exp_not:V #2 } } +\cs_new_protected:Npn \tl_gput_right:No #1#2 + { \cs_gset_nopar:Npx #1 { \exp_not:o #1 \exp_not:o {#2} } } +\cs_new_protected:Npn \tl_gput_right:Nx #1#2 + { \cs_gset_nopar:Npx #1 { \exp_not:o {#1} #2 } } +\cs_generate_variant:Nn \tl_put_right:Nn { c } +\cs_generate_variant:Nn \tl_put_right:NV { c } +\cs_generate_variant:Nn \tl_put_right:No { c } +\cs_generate_variant:Nn \tl_put_right:Nx { c } +\cs_generate_variant:Nn \tl_gput_right:Nn { c } +\cs_generate_variant:Nn \tl_gput_right:NV { c } +\cs_generate_variant:Nn \tl_gput_right:No { c } +\cs_generate_variant:Nn \tl_gput_right:Nx { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Reassigning token list category codes} +% +% \begin{variable}{\c_tl_rescan_marker_tl} +% The rescanning code needs a special token list containing the same +% character with two different category codes. This is set up here, +% while the detail is described below. +% \begin{macrocode} +\group_begin: + \tex_lccode:D `\A = `\@ \scan_stop: + \tex_lccode:D `\B = `\@ \scan_stop: + \tex_catcode:D `\A = 8 \scan_stop: + \tex_catcode:D `\B = 3 \scan_stop: +\tex_lowercase:D + { + \group_end: + \tl_const:Nn \c_tl_rescan_marker_tl { A B } + } +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_tl_rescan_tl} +% A token list variable to actually store the material being processed. +% \begin{macrocode} +\tl_new:N \l_tl_rescan_tl +% \end{macrocode} +% \end{variable} +% +% \begin{macro} +% { +% \tl_set_rescan:Nnn, \tl_set_rescan:Nno, +% \tl_set_rescan:cnn, \tl_set_rescan:cno +% } +% \begin{macro} +% { +% \tl_gset_rescan:Nnn, \tl_gset_rescan:Nno, +% \tl_gset_rescan:cnn, \tl_gset_rescan:cno +% } +% \begin{macro}[aux]{\tl_set_rescan_aux:NNnn} +% \begin{macro}[aux]{\tl_rescan_aux:w} +% The idea here is to deal cleanly with the problem that +% \cs{tex_scantokens:D} treats the argument as a file, and without +% the correct settings a \TeX{} error occurs: +% \begin{verbatim} +% ! File ended while scanning definition of ... +% \end{verbatim} +% When expanding a token list this can be handled using \cs{exp_not:N} +% but this fails if the token list is not being expanded. So instead +% a delimited argument is used with an end marker which cannot appear +% within the token list which is scanned: two |@| symbols with different +% category codes. The rescanned token list cannot contain the end marker, +% because all |@| present in the token list are read with the same category +% code. The setting of \cs{tex_endlinechar:D} +% is needed to avoid introducing an extraneous space in the result. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \tl_set_rescan:Nnn + { \tl_set_rescan_aux:NNnn \tl_set:Nn } +\cs_new_protected_nopar:Npn \tl_gset_rescan:Nnn + { \tl_set_rescan_aux:NNnn \tl_gset:Nn } +\cs_new_protected:Npn \tl_set_rescan_aux:NNnn #1#2#3#4 + { + \group_begin: + \exp_args:No \etex_everyeof:D { \c_tl_rescan_marker_tl } + \tex_endlinechar:D \c_minus_one + #3 + \tl_clear:N \l_tl_rescan_tl + \exp_after:wN \tl_rescan_aux:w \etex_scantokens:D {#4} + \exp_args:NNNo \group_end: + #1 #2 \l_tl_rescan_tl + } +\cs_new_nopar:Npx \tl_rescan_aux:w + { + \cs_set_protected:Npn \exp_not:N \tl_rescan_aux:w ##1 + \c_tl_rescan_marker_tl + { \tl_set:Nn \exp_not:N \l_tl_rescan_tl {##1} } + } +\tl_rescan_aux:w +\cs_generate_variant:Nn \tl_set_rescan:Nnn { Nno } +\cs_generate_variant:Nn \tl_set_rescan:Nnn { c , cno } +\cs_generate_variant:Nn \tl_gset_rescan:Nnn { Nno } +\cs_generate_variant:Nn \tl_gset_rescan:Nnn { c , cno } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\tl_set_rescan:Nnx, \tl_set_rescan:cnx} +% \begin{macro}{\tl_gset_rescan:Nnx, \tl_gset_rescan:cnx} +% \begin{macro}[aux]{\tl_set_rescan_aux:NNnx} +% With \texttt{x}-type expansion the \cs{tex_everyoef:D} method +% does apply and the code is simple. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \tl_set_rescan:Nnx + { \tl_set_rescan_aux:NNnx \tl_set:Nn } +\cs_new_protected_nopar:Npn \tl_gset_rescan:Nnx + { \tl_set_rescan_aux:NNnx \tl_gset:Nn } +\cs_new_protected_nopar:Npn \tl_set_rescan_aux:NNnx #1#2#3#4 + { + \group_begin: + \etex_everyeof:D { \exp_not:N } + \tex_endlinechar:D \c_minus_one + #3 + \tl_set:Nx \l_tl_rescan_tl { \etex_scantokens:D {#4} } + \exp_args:NNNo \group_end: + #1 #2 \l_tl_rescan_tl + } +\cs_generate_variant:Nn \tl_set_rescan:Nnx { c } +\cs_generate_variant:Nn \tl_gset_rescan:Nnx { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\tl_rescan:nn} +% The same idea is also applied to in line token lists. +% \begin{macrocode} +\cs_new_protected:Npn \tl_rescan:nn #1#2 + { + \group_begin: + \exp_args:No \etex_everyeof:D { \c_tl_rescan_marker_tl } + \tex_endlinechar:D \c_minus_one + #1 + \exp_after:wN \tl_rescan_aux:w \etex_scantokens:D {#2} + \exp_args:No \group_end: + \l_tl_rescan_tl + } +% \end{macrocode} +% \end{macro} +% +% \subsection{Reassigning token list character codes} +% +% \begin{macro}{\tl_to_lowercase:n} +% \begin{macro}{\tl_to_uppercase:n} +% Just some names for a few primitives. +% \begin{macrocode} +\cs_new_eq:NN \tl_to_lowercase:n \tex_lowercase:D +\cs_new_eq:NN \tl_to_uppercase:n \tex_uppercase:D +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Modifying token list variables} +% +% \begin{variable}{\l_tl_replace_tl} +% A scratch variable for doing token replacement. +% \begin{macrocode} +\tl_new:N \l_tl_replace_tl +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\tl_replace_once:Nnn, \tl_replace_once:cnn} +% \begin{macro}{\tl_greplace_once:Nnn, \tl_greplace_once:cnn} +% \begin{macro}[aux]{\tl_replace_once_aux:NNnn} +% The concept here is that only the first occurrence should be +% replaced. The first step is to define an auxiliary which will +% match the appropriate item, with a trailing marker. If the last token +% is the marker there is nothing to do, otherwise replace the token +% and clean up (hence the second use of \cs{tl_tmp:w}). To prevent +% loosing braces or spaces there are a couple of empty groups and +% the strange-looking \cs{use:n}. There is a \cs{q_nil} between the +% original and the search input, to prevent cases where +% the end of the original and the start of the search run together +% to give an erroneous test result. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \tl_replace_once:Nnn + { \tl_replace_once_aux:NNnn \tl_set_eq:NN } +\cs_new_protected_nopar:Npn \tl_greplace_once:Nnn + { \tl_replace_once_aux:NNnn \tl_gset_eq:NN } +\cs_new_protected:Npn \tl_replace_once_aux:NNnn #1#2#3#4 + { + \cs_set_protected:Npx \tl_tmp:w ##1 #3 ##2 \q_stop + { + \exp_not:N \quark_if_no_value:nF {##2} + { + \tl_set:No \exp_not:N \l_tl_replace_tl { ##1 \exp_not:n{#4} } + \exp_not:n + { + \cs_set_protected:Npn \tl_tmp:w ##1 \q_nil #3 \q_no_value + { \tl_put_right:No \l_tl_replace_tl {##1} } + } + \exp_not:n { \tl_tmp:w \prg_do_nothing: } ##2 + \exp_not:n { #1 #2 \l_tl_replace_tl } + } + } + \exp_after:wN \tl_tmp:w \exp_after:wN \prg_do_nothing: + #2 \q_nil #3 \q_no_value \q_stop + } +\cs_generate_variant:Nn \tl_replace_once:Nnn { c } +\cs_generate_variant:Nn \tl_greplace_once:Nnn { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\tl_replace_all:Nnn, \tl_replace_all:cnn} +% \begin{macro}{\tl_greplace_all:Nnn, \tl_greplace_all:cnn} +% \begin{macro}[aux]{\tl_replace_all_aux:NNnn} +% A similar approach here but with a loop built in. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \tl_replace_all:Nnn + { \tl_replace_all_aux:NNnn \tl_set_eq:NN } +\cs_new_protected_nopar:Npn \tl_greplace_all:Nnn + { \tl_replace_all_aux:NNnn \tl_gset_eq:NN } +\cs_new_protected:Npn \tl_replace_all_aux:NNnn #1#2#3#4 + { + \tl_clear:N \l_tl_replace_tl + \cs_set_protected:Npx \tl_tmp:w ##1 #3 ##2 \q_stop + { + \exp_not:N \quark_if_no_value:nTF {##2} + { + \exp_not:n + { + \cs_set_protected:Npn \tl_tmp:w ##1 \q_nil ##2 \q_stop + { \tl_put_right:No \l_tl_replace_tl {##1} } + } + \exp_not:N \tl_tmp:w ##1 \exp_not:N \q_stop + } + { + \exp_not:n { \tl_put_right:No \l_tl_replace_tl } + { ##1 \exp_not:n{#4} } + \exp_not:n { \tl_tmp:w \prg_do_nothing: } ##2 \exp_not:N \q_stop + } + } + \exp_after:wN \tl_tmp:w \exp_after:wN \prg_do_nothing: + #2 \q_nil #3 \q_no_value \q_stop + #1 #2 \l_tl_replace_tl + } +\cs_generate_variant:Nn \tl_replace_all:Nnn { c } +\cs_generate_variant:Nn \tl_greplace_all:Nnn { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\tl_remove_once:Nn, \tl_remove_once:cn} +% \begin{macro}{\tl_gremove_once:Nn, \tl_gremove_once:cn} +% Removal is just a special case of replacement. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \tl_remove_once:Nn #1#2 + { \tl_replace_once:Nnn #1 {#2} { } } +\cs_new_protected_nopar:Npn \tl_gremove_once:Nn #1#2 + { \tl_greplace_once:Nnn #1 {#2} { } } +\cs_generate_variant:Nn \tl_remove_once:Nn { c } +\cs_generate_variant:Nn \tl_gremove_once:Nn { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\tl_remove_all:Nn, \tl_remove_all:cn} +% \begin{macro}{\tl_gremove_all:Nn, \tl_gremove_all:cn} +% Removal is just a special case of replacement. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \tl_remove_all:Nn #1#2 + { \tl_replace_all:Nnn #1 {#2} { } } +\cs_new_protected_nopar:Npn \tl_gremove_all:Nn #1#2 + { \tl_greplace_all:Nnn #1 {#2} { } } +\cs_generate_variant:Nn \tl_remove_all:Nn { c } +\cs_generate_variant:Nn \tl_gremove_all:Nn { c } +% \end{macrocode} +% \end{macro} +% +% \subsection{Token list conditionals} +% +% \begin{macro}[pTF]{\tl_if_blank:n,\tl_if_blank:V,\tl_if_blank:o} +% \begin{macro}[aux]{\tl_if_blank_p_aux:NNw} +% \TeX{} skips spaces when reading a non-delimited arguments. Thus, +% a \meta{token list} is blank if and only if \cs{use_none:n} +% \meta{token list} |?| is empty. For performance reasons, we hard-code +% the emptyness test done in \cs{tl_if_empty:n(TF)}: convert to harmless +% characters with \cs{tl_to_str:n}, and then use +% \cs{if_meaning:w} \cs{q_nil} |...| \cs{q_nil}. +% Note that converting to a string is done after reading the delimited +% argument for \cs{use_none:n}. The similar construction +% \cs{exp_after:wN} \cs{use_none:n} \cs{tl_to_str:n} \Arg{token list} |?| +% would fail if the token list contains the control sequence \cs{ }, +% while \cs{tex_escapechar:D} is a space or is unprintable. +% \begin{macrocode} +\prg_new_conditional:Npnn \tl_if_blank:n #1 { p , T , F , TF } + { \tl_if_empty_return:o { \use_none:n #1 ? } } +\cs_generate_variant:Nn \tl_if_blank_p:n { V } +\cs_generate_variant:Nn \tl_if_blank:nT { V } +\cs_generate_variant:Nn \tl_if_blank:nF { V } +\cs_generate_variant:Nn \tl_if_blank:nTF { V } +\cs_generate_variant:Nn \tl_if_blank_p:n { o } +\cs_generate_variant:Nn \tl_if_blank:nT { o } +\cs_generate_variant:Nn \tl_if_blank:nF { o } +\cs_generate_variant:Nn \tl_if_blank:nTF { o } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}[pTF]{\tl_if_empty:N,\tl_if_empty:c} +% These functions check whether the token list in the argument is +% empty and execute the proper code from their argument(s). +% \begin{macrocode} +\prg_set_conditional:Npnn \tl_if_empty:N #1 { p , T , F , TF } + { + \if_meaning:w #1 \c_empty_tl + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +\cs_generate_variant:Nn \tl_if_empty_p:N { c } +\cs_generate_variant:Nn \tl_if_empty:NT { c } +\cs_generate_variant:Nn \tl_if_empty:NF { c } +\cs_generate_variant:Nn \tl_if_empty:NTF { c } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[pTF]{\tl_if_empty:n,\tl_if_empty:V} +% It would be tempting to just use |\if_meaning:w \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:w|, 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} +\prg_new_conditional:Npnn \tl_if_empty:n #1 { p,TF,T,F} { + \exp_after:wN \if_meaning:w \exp_after:wN \q_nil \tl_to_str:n {#1} \q_nil + \prg_return_true: + \else: + \prg_return_false: + \fi: +} +\cs_generate_variant:Nn \tl_if_empty_p:n { V } +\cs_generate_variant:Nn \tl_if_empty:nTF { V } +\cs_generate_variant:Nn \tl_if_empty:nT { V } +\cs_generate_variant:Nn \tl_if_empty:nF { V } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[pTF]{\tl_if_empty:o} +% \begin{macro}[EXP,aux]{\tl_if_empty_return:o} +% The auxiliary function \cs{tl_if_empty_return:o} is for use +% in conditionals on token lists, which mostly reduce to testing +% if a given token list is empty after applying a simple function +% to it. +% The test for emptyness is based on \cs{tl_if_empty:n(TF)}, but +% the expansion is hard-coded for efficiency, as this auxiliary +% function is used in many places. +% Note that this works because \cs{tl_to_str:n} expands tokens +% that follow until reading a catcode $1$ (begin-group) token. +% \begin{macrocode} +\cs_new:Npn \tl_if_empty_return:o #1 { + \exp_after:wN \if_meaning:w \exp_after:wN \q_nil + \tl_to_str:n \exp_after:wN {#1} \q_nil + \prg_return_true: + \else: + \prg_return_false: + \fi: +} +\prg_new_conditional:Npnn \tl_if_empty:o #1 { p,TF,T,F} + { \tl_if_empty_return:o {#1} } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[pTF]{\tl_if_eq:NN,\tl_if_eq:Nc,\tl_if_eq:cN,\tl_if_eq:cc} +% Returns \cs{c_true_bool} if and only if the two token list variables are +% equal. +% \begin{macrocode} +\prg_new_conditional:Npnn \tl_if_eq:NN #1#2 { p , T , F , TF } + { + \if_meaning:w #1 #2 + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +\cs_generate_variant:Nn \tl_if_eq_p:NN { Nc , c , cc } +\cs_generate_variant:Nn \tl_if_eq:NNTF { Nc , c , cc } +\cs_generate_variant:Nn \tl_if_eq:NNT { Nc , c , cc } +\cs_generate_variant:Nn \tl_if_eq:NNF { Nc , c , cc } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[TF]{\tl_if_eq:nn} +% \begin{variable}{\l_tl_tmpa_tl, \l_tl_tmpb_tl} +% A simple store and compare routine. +% \begin{macrocode} +\prg_new_protected_conditional:Npnn \tl_if_eq:nn #1#2 { T , F , TF } + { + \group_begin: + \tl_set:Nn \l_tl_tmpa_tl {#1} + \tl_set:Nn \l_tl_tmpb_tl {#2} + \if_meaning:w \l_tl_tmpa_tl \l_tl_tmpb_tl + \group_end: + \prg_return_true: + \else: + \group_end: + \prg_return_false: + \fi: + } +\tl_new:N \l_tl_tmpa_tl +\tl_new:N \l_tl_tmpb_tl +% \end{macrocode} +% \end{variable} +% \end{macro} +% +% \begin{macro}[TF]{\tl_if_in:Nn, \tl_if_in:cn} +% See \cs{tl_if_in:nn(TF)} for further comments. Here we simply +% expand the token list variable and pass it to \cs{tl_if_in:nn(TF)}. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \tl_if_in:NnT { \exp_args:No \tl_if_in:nnT } +\cs_new_protected_nopar:Npn \tl_if_in:NnF { \exp_args:No \tl_if_in:nnF } +\cs_new_protected_nopar:Npn \tl_if_in:NnTF { \exp_args:No \tl_if_in:nnTF } +\cs_generate_variant:Nn \tl_if_in:NnT { c } +\cs_generate_variant:Nn \tl_if_in:NnF { c } +\cs_generate_variant:Nn \tl_if_in:NnTF { c } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[TF]{\tl_if_in:nn, \tl_if_in:Vn, \tl_if_in:on, \tl_if_in:no} +% Once more, the test relies on \cs{tl_to_str:n} for robustness. +% The function \cs{tl_tmp:w} removes tokens until the first occurrence +% of |#2|. If this does not appear in |#1|, then the final |#2| is removed, +% leaving an empty token list. Otherwise some tokens remain, and the +% test is false. See \cs{tl_if_empty:n(TF)} for details on +% the emptyness test. +% +% Special care is needed to treat correctly cases like +% |\tl_if_in:nnTF {a state}{states}|, where |#1#2| contains |#2| before +% the end. To cater for this case, we insert |{}{}| between the two token +% lists. This marker may not appear in |#2| because of \TeX{} limitations +% on what can delimit a parameter, hence we are safe. Using two brace +% groups makes the test work also for empty arguments. +% \begin{macrocode} +\prg_new_protected_conditional:Npnn \tl_if_in:nn #1#2 { T , F , TF } + { + \cs_set:Npn \tl_tmp:w ##1 #2 { } + \tl_if_empty:oTF { \tl_tmp:w #1 {} {} #2 } + { \prg_return_false: } { \prg_return_true: } + } +\cs_generate_variant:Nn \tl_if_in:nnT { V } +\cs_generate_variant:Nn \tl_if_in:nnF { V } +\cs_generate_variant:Nn \tl_if_in:nnTF { V } +\cs_generate_variant:Nn \tl_if_in:nnT { o } +\cs_generate_variant:Nn \tl_if_in:nnF { o } +\cs_generate_variant:Nn \tl_if_in:nnTF { o } +\cs_generate_variant:Nn \tl_if_in:nnT { no } +\cs_generate_variant:Nn \tl_if_in:nnF { no } +\cs_generate_variant:Nn \tl_if_in:nnTF { no } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[pTF]{\tl_if_single:n} +% \begin{macro}[aux]{\tl_if_single_aux:n} +% If the argument is a single token, or a single brace group +% preceeded by optional (explicit) spaces, or a non-zero number +% of spaces. +% \begin{macrocode} +\prg_new_conditional:Npnn \tl_if_single:n #1 { p , T , F , TF } + { + \tl_if_blank:nTF {#1} + { \tl_if_empty:nTF {#1} { \prg_return_false: } { \prg_return_true: } } + { \tl_if_single_aux:n {#1} } + } +\prg_new_conditional:Npnn \tl_if_single:N #1 { p , T , F , TF } + { + \tl_if_blank:oTF #1 + { \tl_if_empty:NTF #1 { \prg_return_false: } { \prg_return_true: } } + { \exp_args:No \tl_if_single_aux:n {#1} } + } +\cs_new:Npn \tl_if_single_aux:n #1 + { \tl_if_empty_return:o { \use_none:n #1 } } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Mapping to token lists} +% +% \begin{macro}{\tl_map_function:nN} +% \begin{macro}{\tl_map_function:NN, \tl_map_function:cN} +% \begin{macro}[aux]{\tl_map_function_aux:NN} +% Expandable loop macro for token lists. 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} +\cs_new:Npn \tl_map_function:nN #1#2 + { \tl_map_function_aux:Nn #2 #1 \q_recursion_tail \q_recursion_stop } +\cs_new_nopar:Npn \tl_map_function:NN #1#2 + { + \exp_after:wN \tl_map_function_aux:Nn + \exp_after:wN #2 #1 \q_recursion_tail \q_recursion_stop + } +\cs_new:Npn \tl_map_function_aux:Nn #1#2 + { + \quark_if_recursion_tail_stop:n {#2} + #1 {#2} \tl_map_function_aux:Nn #1 + } +\cs_generate_variant:Nn \tl_map_function:NN { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\tl_map_inline:nn} +% \begin{macro}{\tl_map_inline:Nn, \tl_map_inline:cn} +% \begin{macro}[aux]{\tl_map_inline_aux:n} +% \begin{variable}{\g_tl_inline_level_int} +% The inline functions are straight forward by now. We use a little +% trick with the counter \cs{g_tl_inline_level_int} to make +% them nestable. We can also make use of \cs{tl_map_function:Nn} +% from before. (\cs{g_tl_inline_level_int} is defined in \pkg{l3int} +% for order-of-loading reasons.) +% \begin{macrocode} +\cs_new_protected:Npn \tl_map_inline:nn #1#2 + { + \int_gincr:N \g_tl_inline_level_int + \cs_gset:cpn { tl_map_inline_ \int_use:N \g_tl_inline_level_int :n } + ##1 {#2} + \exp_args:Nc \tl_map_function_aux:Nn + { tl_map_inline_ \int_use:N \g_tl_inline_level_int :n } + #1 \q_recursion_tail \q_recursion_stop + \int_gdecr:N \g_tl_inline_level_int + } +\cs_new_protected:Npn \tl_map_inline:Nn #1#2 + { + \int_gincr:N \g_tl_inline_level_int + \cs_gset:cpn { tl_map_inline_ \int_use:N \g_tl_inline_level_int :n } + ##1 {#2} + \exp_last_unbraced:NcV \tl_map_function_aux:Nn + { tl_map_inline_ \int_use:N \g_tl_inline_level_int :n } + #1 \q_recursion_tail\q_recursion_stop + \int_gdecr:N \g_tl_inline_level_int + } +\cs_generate_variant:Nn \tl_map_inline:Nn { c } +% \end{macrocode} +% \end{variable} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\tl_map_variable:nNn} +% \begin{macro}{\tl_map_variable:NNn, \tl_map_variable:cNn} +% \begin{macro}[aux]{\tl_map_variable_aux:NnN} +% \cs{tl_map_variable:nNn} \meta{token list} \meta{temp} \meta{action} +% assigns +% \meta{temp} to each element and executes \meta{action}. +% \begin{macrocode} +\cs_new_protected:Npn \tl_map_variable:nNn #1#2#3 + { \tl_map_variable_aux:Nnn #2 {#3} #1 \q_recursion_tail \q_recursion_stop } +\cs_new_protected_nopar:Npn \tl_map_variable:NNn + { \exp_args:No \tl_map_variable:nNn } +\cs_new_protected:Npn \tl_map_variable_aux:Nnn #1#2#3 + { + \tl_set:Nn #1 {#3} + \quark_if_recursion_tail_stop:N #1 + #2 \tl_map_variable_aux:Nnn #1 {#2} + } +\cs_generate_variant:Nn \tl_map_variable:NNn { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\tl_map_break:} +% The break statement. +% \begin{macrocode} +\cs_new_eq:NN \tl_map_break: \use_none_delimit_by_q_recursion_stop:w +% \end{macrocode} +% \end{macro} +% +% \subsection{Using token lists} +% +% \begin{macro}{\tl_to_str:n} +% Another name for a primitive. +% \begin{macrocode} +\cs_new_eq:NN \tl_to_str:n \etex_detokenize:D +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\tl_to_str:N, \tl_to_str:c} +% These functions return the replacement text of a token list as a +% string. +% \begin{macrocode} +\cs_new_nopar:Npn \tl_to_str:N #1 { \etex_detokenize:D \exp_after:wN {#1} } +\cs_generate_variant:Nn \tl_to_str:N { c } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\tl_use:N, \tl_use:c} +% \begin{macro}[aux]{\tl_error_message:} +% Token lists which are simply not defined will give a clear \TeX{} +% error here. No such luck for ones equal to \cs{scan_stop:} so +% instead a test is made and if there is an issue an error is forced. +% \begin{macrocode} +\cs_new_eq:NN \tl_use:N \prg_do_nothing: +\cs_new_nopar:Npn \tl_use:c #1 + { + \if_cs_exist:w #1 \cs_end: + \cs:w #1 \exp_after:wN \cs_end: + \else: + \exp_after:wN \tl_error_message: + \fi: + } +\group_begin: +\tex_catcode:D `\! = 11 \scan_stop: +\tex_catcode:D `\ = 11\scan_stop:% +\cs_gset_nopar:Npn\tl_error_message:{\undefined variable name!}% +\group_end:% +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Working with the contents of token lists} +% +% \begin{macro}{\tl_length:n, \tl_length:V, \tl_length:o} +% \begin{macro}{\tl_length:N, \tl_length:c} +% \begin{macro}[aux]{\tl_length_aux:n} +% Count number of elements within a token list or token list +% variable. Brace groups within the list are read as a single +% element. Spaces are ignored. +% \cs{tl_length_aux:n} grabs the element and replaces it by |+1|. +% The |0| to ensure it works on an empty list. +% \begin{macrocode} +\cs_new:Npn \tl_length:n #1 + { + \int_eval:n + { 0 \tl_map_function:nN {#1} \tl_length_aux:n } + } +\cs_new_nopar:Npn \tl_length:N #1 + { + \int_eval:n + { 0 \tl_map_function:NN #1 \tl_length_aux:n } + } +\cs_new:Npn \tl_length_aux:n #1 { + 1 } +\cs_generate_variant:Nn \tl_length:n { V , o } +\cs_generate_variant:Nn \tl_length:N { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\tl_reverse:n, \tl_reverse:V, \tl_reverse:o} +% \begin{macro}[aux]{\tl_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} +\cs_new:Npn \tl_reverse:n #1 + { \tl_reverse_aux:nN { } #1 \q_recursion_tail \q_recursion_stop } +\cs_new:Npn \tl_reverse_aux:nN #1#2 + { + \quark_if_recursion_tail_stop_do:nn {#2} {#1} + \tl_reverse_aux:nN { #2 #1 } + } +\cs_generate_variant:Nn \tl_reverse:n {V,o} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\tl_reverse:N, \tl_reverse:c} +% This reverses the list, leaving |\exp_stop_f:| in front, which in turn +% is removed by the |f| expansion which comes to a halt. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \tl_reverse:N #1 + { \tl_set:Nf #1 { \tl_reverse:o { #1 \exp_stop_f: } } } +\cs_generate_variant:Nn \tl_reverse:N { c } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\tl_trim_spaces:n} +% \begin{macro} +% { +% \tl_trim_spaces:N, \tl_trim_spaces:c, +% \tl_gtrim_spaces:N, \tl_gtrim_spaces:c +% } +% \begin{macro}[aux]{\tl_trim_spaces_exp:n} +% \begin{macro}[aux]{\tl_trim_spaces_aux_i:w} +% \begin{macro}[aux]{\tl_trim_spaces_aux_ii:w} +% Trimming spaces from around the input uses the idea of a sufficiently +% odd token to allow for a delimited argument to do this. Here, the +% standard approach [a |Q| with category code 3 (math toggle)] is used. +% The \cs{etex_unexpanded:D} here is used so that space trimming will +% behave correctly within an \texttt{x}-type expansion. +% \begin{macrocode} +\cs_new:Npn \tl_trim_spaces:n #1 + { + \etex_unexpanded:D \exp_after:wN \exp_after:wN \exp_after:wN + { \tl_trim_spaces_exp:n {#1} } + } +\cs_new_protected:Npn \tl_trim_spaces:N #1 + { \tl_set:Nx #1 { \exp_after:wN \tl_trim_spaces:n \exp_after:wN {#1} } } +\cs_new_protected:Npn \tl_gtrim_spaces:N #1 + { \tl_gset:Nx #1 { \exp_after:wN \tl_trim_spaces:n \exp_after:wN {#1} } } +\group_begin: + \tex_catcode:D `\Q = 3 \scan_stop: + \cs_new:Npn \tl_trim_spaces_exp:n #1 + { \tex_romannumeral:D - `0 \tl_trim_spaces_aux_i:w \exp_not:N #1 Q ~ Q } + \cs_new:Npn \tl_trim_spaces_aux_i:w #1 ~ Q { \tl_trim_spaces_aux_ii:w #1 Q } + \cs_new:Npn \tl_trim_spaces_aux_ii:w #1 Q #2 {#1} +\group_end: +\cs_generate_variant:Nn \tl_trim_spaces:N { c } +\cs_generate_variant:Nn \tl_gtrim_spaces:N { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{The first token from a token list} +% +% \begin{macro}{\tl_head:n, \tl_head:V, \tl_head:v, \tl_head:f} +% \begin{macro}{\tl_head:w} +% \begin{macro}{\tl_tail:n, \tl_tail:V, \tl_tail:v, \tl_tail:f} +% \begin{macro}{\tl_tail:w} +% These functions pick up either the head or the tail of a list. +% \begin{macrocode} +\cs_new:Npn \tl_head:n #1 { \tl_head:w #1 \q_stop } +\cs_new:Npn \tl_tail:n #1 { \tl_tail:w #1 \q_stop } +\cs_new:Npn \tl_head:w #1#2 \q_stop {#1} +\cs_new:Npn \tl_tail:w #1#2 \q_stop {#2} +\cs_generate_variant:Nn \tl_head:n { V , v , f } +\cs_generate_variant:Nn \tl_tail:n { V , v , f } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}[pTF]{\tl_if_head_eq_meaning:nN} +% \begin{macro}[pTF]{\tl_if_head_eq_charcode:nN} +% \begin{macro}[pTF]{\tl_if_head_eq_charcode:fN} +% \begin{macro}[pTF]{\tl_if_head_eq_catcode:nN} +% 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. +% \cs{tl_if_head_meaning_eq:nNTF} uses \cs{if_meaning:w} and will +% consider the tokens |b|$\sb{11}$ and |b|$\sb{12}$ different. +% \cs{tl_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} +\prg_new_conditional:Npnn \tl_if_head_eq_meaning:nN #1#2 { p , T , F , TF } + { + \exp_after:wN \if_meaning:w \tl_head:w #1 \q_stop #2 + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +% \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} +\prg_new_conditional:Npnn \tl_if_head_eq_charcode:nN #1#2 { p , T , F , TF } + { + \exp_after:wN \if:w + \exp_after:wN \exp_not:N \tl_head:w #1 \q_stop \exp_not:N #2 + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +\cs_generate_variant:Nn \tl_if_head_eq_charcode_p:nN { f } +\cs_generate_variant:Nn \tl_if_head_eq_charcode:nNTF { f } +\cs_generate_variant:Nn \tl_if_head_eq_charcode:nNT { f } +\cs_generate_variant:Nn \tl_if_head_eq_charcode:nNF { f } +% \end{macrocode} +% And now catcodes: +% \begin{macrocode} +\prg_new_conditional:Npnn \tl_if_head_eq_catcode:nN #1#2 { p , T , F , TF } + { + \exp_after:wN \if_catcode:w \exp_after:wN \exp_not:N + \tl_head:w #1 \q_stop \exp_not:N #2 + \prg_return_true: \else: \prg_return_false: \fi: + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Viewing token lists} +% +% \begin{macro}{\tl_show:N, \tl_show:c} +% Showing token list variables is done directly: at the moment do not +% worry if they are defined. +% \begin{macrocode} +\cs_new_protected:Npn \tl_show:N #1 { \cs_show:N #1 } +\cs_generate_variant:Nn \tl_show:N { c } +% \end{macrocode} +%\end{macro} +% +% \begin{macro}{\tl_show:n} +% For literal token lists, life is easy. +% \begin{macrocode} +\cs_new_eq:NN \tl_show:n \etex_showtokens:D +% \end{macrocode} +%\end{macro} +% +% \subsection{Constant token lists} +% +% \begin{variable}{\c_job_name_tl} +% Inherited from the \LaTeX3 name for the primitive: this needs to +% actually contain the text of the job name rather than the name of +% the primitive, of course. +% \begin{macrocode} +%<*package> +\tl_const:Nx \c_job_name_tl { \tex_jobname:D } +%</package> +%<*initex> +\tex_everyjob:D \exp_after:wN + { + \tex_the:D \tex_everyjob:D + \luatex_if_engine:TF + { + \tl_if_in:onTF { \tex_jobname:D } { ~ } + { \tl_const:Nx \c_job_name_tl { " \tex_jobname:D " } } + { \tl_const:Nx \c_job_name_tl { \tex_jobname:D } } + } + { \tl_const:Nx \c_job_name_tl { \tex_jobname:D } } + } +%</initex> +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\c_empty_tl} +% Never full. +% \begin{macrocode} +\tl_const:Nn \c_empty_tl { } +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\c_space_tl} +% A space as a token list (as opposed to as a character). +% \begin{macrocode} +\tl_const:Nn \c_space_tl { ~ } +% \end{macrocode} +% \end{variable} +% +% \subsection{Scratch token lists} +% +% \begin{variable}{\g_tmpa_tl, \g_tmpb_tl} +% Global temporary token list variables. +% 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. +% \begin{macrocode} +\tl_new:N \g_tmpa_tl +\tl_new:N \g_tmpb_tl +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_tmpa_tl, \l_tmpb_tl} +% These are local temporary token list variables. Be sure not to assume +% that the value you put into them will survive for +% long---see discussion above. +% \begin{macrocode} +\tl_new:N \l_tmpa_tl +\tl_new:N \l_tmpb_tl +% \end{macrocode} +% \end{variable} +% +% \subsection{Experimental functions} +% +% \begin{macro}[EXP,pTF]{\tl_if_single_item:n} +% A token list has exactly one item if it is either a single +% token surrounded by optional explicit spaces, or a single brace +% group surrounded by optional explicit spaces. The naive +% version of this test would do \cs{use_none:n} |#1|, and +% test if the result is empty. However, this will fail when +% the token list is empty. Furthermore, it does not allow optional +% trailing spaces. +% \begin{macrocode} +\cs_new:Npn \tl_if_single_item:nTF #1 + { \str_if_eq:onTF { \use_ii:nn #1 {?} ? } {??} } +\cs_new:Npn \tl_if_single_item:nT #1 + { \str_if_eq:onT { \use_ii:nn #1 {?} ? } {??} } +\cs_new:Npn \tl_if_single_item:nF #1 + { \str_if_eq:onF { \use_ii:nn #1 {?} ? } {??} } +\cs_new:Npn \tl_if_single_item_p:n #1 + { \str_if_eq_p:on { \use_ii:nn #1 {?} ? } {??} } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[EXP,pTF]{\tl_if_head_begin_group:n} +% \begin{macrocode} +\prg_new_conditional:Npnn \tl_if_head_begin_group:n #1 { p , T , F , TF } + { + \exp_after:wN \use_none:n + \exp_after:wN { + \exp_after:wN { + \token_to_str:N #1 . + } + \prg_return_true: \exp_after:wN \use_none:nn \token_to_str:N + } + \prg_return_false: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[EXP,pTF]{\tl_if_head_eq_space:n} +% \begin{macro}[EXP,aux]{\tl_if_head_eq_space_aux:w} +% If the first token of the token list is an explicit space, i.e., +% a character token with character code $32$ and category code $10$, +% then this test will be \meta{true}. It is \meta{false} if the token +% list is empty, if the first token is an implicit space token, +% such as \cs{c_space_token}, or any token other than an explicit space. +% \begin{macrocode} +\prg_new_conditional:Npnn \tl_if_head_eq_space:n #1 { p , T , F , TF } + { + \if_false: { \fi: + \tl_if_head_eq_space_aux:w \prg_do_nothing: #1 ? ~ } + } +\cs_new:Npn \tl_if_head_eq_space_aux:w #1 ~ % + { + \tl_if_empty_return:o { #1 } + \exp_after:wN \use_none:n \exp_after:wN { \if_false: } \fi: + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[EXP,pTF]{\tl_if_single_token:n} +% If the token list starts with a space, then it is +% a single token if and only if its string representation +% is exactly one space character. Otherwise, we check if removing +% the first token group makes the token list empty. If it doesn't, +% the token list is not a single token. If it does, then the token +% list is either a single token or a single brace group. This is +% tested for using \cs{tl_if_head_begin_group:n}. +% \begin{macrocode} +\prg_new_conditional:Npnn \tl_if_single_token:n #1 { p , T , F , TF } + { + \tl_if_head_eq_space:nTF {#1} + { + \str_if_eq:nnTF {#1} {~} + \prg_return_true: \prg_return_false: + } + { + \str_if_eq:onTF { \use_none:n #1 ? } {?} + { + \tl_if_head_begin_group:nTF {#1} + \prg_return_false: \prg_return_true: + } + \prg_return_false: + } + } +% \end{macrocode} +% \end{macro} +% +% \subsection{Deprecated functions} +% +% \begin{macro}{\tl_new:Nn, \tl_new:cn, \tl_new:Nx} +% Use either \cs{tl_const:Nn} or \cs{tl_new:N}. +% \begin{macrocode} +\cs_new_protected:Npn \tl_new:Nn #1#2 + { + \tl_new:N #1 + \tl_gset:Nn #1 {#2} + } +\cs_generate_variant:Nn \tl_new:Nn { c } +\cs_generate_variant:Nn \tl_new:Nn { Nx } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\tl_gset:Nc} +% \begin{macro}{\tl_set:Nc} +% This was useful once, but nowadays does not make much sense. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \tl_gset:Nc + { \pref_global:D \tl_set:Nc } +\cs_new_protected_nopar:Npn \tl_set:Nc #1#2 + { \tl_set:No #1 { \cs:w #2 \cs_end: } } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\tl_replace_in:Nnn, \tl_replace_in:cnn} +% \begin{macro}{\tl_greplace_in:Nnn, \tl_greplace_in:cnn} +% \begin{macro}{\tl_replace_all_in:Nnn, \tl_replace_all_in:cnn} +% \begin{macro}{\tl_greplace_all_in:Nnn, \tl_greplace_all_in:cnn} +% These are renamed. +% \begin{macrocode} +\cs_new_eq:NN \tl_replace_in:Nnn \tl_replace_once:Nnn +\cs_new_eq:NN \tl_replace_in:cnn \tl_replace_once:cnn +\cs_new_eq:NN \tl_greplace_in:Nnn \tl_greplace_once:Nnn +\cs_new_eq:NN \tl_greplace_in:cnn \tl_greplace_once:cnn +\cs_new_eq:NN \tl_replace_all_in:Nnn \tl_replace_all:Nnn +\cs_new_eq:NN \tl_replace_all_in:cnn \tl_replace_all:cnn +\cs_new_eq:NN \tl_greplace_all_in:Nnn \tl_greplace_all:Nnn +\cs_new_eq:NN \tl_greplace_all_in:cnn \tl_greplace_all:cnn +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\tl_remove_in:Nn, \tl_remove_in:cn} +% \begin{macro}{\tl_gremove_in:Nn, \tl_gremove_in:cn} +% \begin{macro}{\tl_remove_all_in:Nn, \tl_remove_all_in:cn} +% \begin{macro}{\tl_gremove_all_in:Nn, \tl_gremove_all_in:cn} +% Also renamed. +% \begin{macrocode} +\cs_new_eq:NN \tl_remove_in:Nn \tl_remove_once:Nn +\cs_new_eq:NN \tl_remove_in:cn \tl_remove_once:cn +\cs_new_eq:NN \tl_gremove_in:Nn \tl_gremove_once:Nn +\cs_new_eq:NN \tl_gremove_in:cn \tl_gremove_once:cn +\cs_new_eq:NN \tl_remove_all_in:Nn \tl_remove_all:Nn +\cs_new_eq:NN \tl_remove_all_in:cn \tl_remove_all:cn +\cs_new_eq:NN \tl_gremove_all_in:Nn \tl_gremove_all:Nn +\cs_new_eq:NN \tl_gremove_all_in:cn \tl_gremove_all:cn +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\tl_elt_count:n, \tl_elt_count:V, \tl_elt_count:o} +% \begin{macro}{\tl_elt_count:N, \tl_elt_count:c} +% Another renaming job. +% \begin{macrocode} +\cs_new_eq:NN \tl_elt_count:n \tl_length:n +\cs_new_eq:NN \tl_elt_count:V \tl_length:V +\cs_new_eq:NN \tl_elt_count:o \tl_length:o +\cs_new_eq:NN \tl_elt_count:N \tl_length:N +\cs_new_eq:NN \tl_elt_count:c \tl_length:c +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\tl_head_i:n} +% \begin{macro}{\tl_head_i:w} +% \begin{macro}{\tl_head_iii:n} +% \begin{macro}{\tl_head_iii:f} +% \begin{macro}{\tl_head_iii:w} +% Two renames, and a few that are rather too specialised. +% \begin{macrocode} +\cs_new_eq:NN \tl_head_i:n \tl_head:n +\cs_new_eq:NN \tl_head_i:w \tl_head:w +\cs_new:Npn \tl_head_iii:n #1 { \tl_head_iii:w #1 \q_stop } +\cs_generate_variant:Nn \tl_head_iii:n { f } +\cs_new:Npn \tl_head_iii:w #1#2#3#4 \q_stop {#1#2#3} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macrocode} +%</initex|package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintIndex diff --git a/Master/texmf-dist/source/latex/l3kernel/l3token.dtx b/Master/texmf-dist/source/latex/l3kernel/l3token.dtx new file mode 100644 index 00000000000..153ca92f7e0 --- /dev/null +++ b/Master/texmf-dist/source/latex/l3kernel/l3token.dtx @@ -0,0 +1,2495 @@ +% \iffalse meta-comment +% +%% File: l3token.dtx Copyright (C) 2005-2011 The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +% +%<*driver|package> +\RequirePackage{l3names} +\GetIdInfo$Id: l3token.dtx 2491 2011-07-02 11:49:37Z joseph $ + {L3 Experimental token manipulation} +%</driver|package> +%<*driver> +\documentclass[full]{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{^^A +% The \pkg{l3token} package\\ Token manipulation^^A +% \thanks{This file describes v\ExplFileVersion, +% last revised \ExplFileDate.}^^A +% } +% +% \author{^^A +% The \LaTeX3 Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% +% \date{Released \ExplFileDate} +% +% \maketitle +% +% \begin{documentation} +% +% 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 \enquote{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 by a single control sequence is a \enquote{token list variable} +% |tl var|. Functions for these two types are found in the \textsf{l3tl} +% module. +% +% \section{All possible tokens} +% +% Let us start by reviewing every case that a given token can fall into. +% It is very important to distinguish two aspects of a token: its meaning, +% and what it looks like. +% +% For instance, \cs{if:w}, \cs{if_charcode:w}, and \cs{tex_if:D} are +% three for the same internal operation of \TeX{}, namely the primitive +% testing the next two characters for equality of their character code. +% They behave identically in many situations. However, \TeX{} +% distinguishes them when searching for a delimited argument. Namely, the +% example function \cs{show_until_if:w} defined below will take everything +% until \cs{if:w} as an argument, despite the presence of other copies of +% \cs{if:w} under different names. +% \begin{verbatim} +% \cs_new:Npn \show_until_if:w #1 \if:w { \tl_show:n {#1} } +% \show_until_if:w \tex_if:D \if_charcode:w \if:w +% \end{verbatim} +% +% It is easier to start by considering the possibilities for what a +% token looks like, in other words, how \TeX{} sees it from the point +% of view of delimited arguments. Two cases: the token is either a +% control sequence or a single character. +% \begin{center} +% \begin{tabular}{p{4cm}p{4cm}} +% \toprule +% Control sequence & Character \\ +% \midrule +% Control word: an escape character followed by some letters. & +% \end{tabular} +% \end{center} +% The token can be a control sequence, +% in other words, an escape character followed by some letters, or by +% a single non-letter character. Examples of this include \cs{begin}, +% \cs{;}, \cs{emph}\ldots{} The other case +% There are two cases. either the token +% is a single character, in which case it is associated with a category +% code: +% +% +% \section{Character tokens} +% +% \begin{function} +% { +% \char_set_catcode_escape:N , +% \char_set_catcode_group_begin:N , +% \char_set_catcode_group_end:N , +% \char_set_catcode_math_toggle:N , +% \char_set_catcode_alignment:N , +% \char_set_catcode_end_line:N , +% \char_set_catcode_parameter:N , +% \char_set_catcode_math_superscript:N , +% \char_set_catcode_math_subscript:N , +% \char_set_catcode_ignore:N , +% \char_set_catcode_space:N , +% \char_set_catcode_letter:N , +% \char_set_catcode_other:N , +% \char_set_catcode_active:N , +% \char_set_catcode_comment:N , +% \char_set_catcode_invalid:N +% } +% \begin{syntax} +% \cs{char_make_letter:N} \meta{character} +% \end{syntax} +% Sets the category code of the \meta{character} to that indicated in +% the function name. Depending on the current category code of the +% \meta{token} the escape token may also be needed: +% \begin{verbatim} +% \char_set_catcode_other:N \% +% \end{verbatim} +% The assignment is local. +% \end{function} +% +% \begin{function} +% { +% \char_set_catcode_escape:n , +% \char_set_catcode_group_begin:n , +% \char_set_catcode_group_end:n , +% \char_set_catcode_math_toggle:n , +% \char_set_catcode_alignment:n , +% \char_set_catcode_end_line:n , +% \char_set_catcode_parameter:n , +% \char_set_catcode_math_superscript:n , +% \char_set_catcode_math_subscript:n , +% \char_set_catcode_ignore:n , +% \char_set_catcode_space:n , +% \char_set_catcode_letter:n , +% \char_set_catcode_other:n , +% \char_set_catcode_active:n , +% \char_set_catcode_comment:n , +% \char_set_catcode_invalid:n +% } +% \begin{syntax} +% \cs{char_make_letter:n} \Arg{integer expression} +% \end{syntax} +% Sets the category code of the \meta{character} which has character +% code as given by the \meta{integer expression}. This version can be +% used to set up characters which cannot otherwise be given +% (\emph{cf.}~the \texttt{N}-type variants). The assignment is local. +% \end{function} +% +% \begin{function}{\char_set_catcode:nn} +% \begin{syntax} +% \cs{char_set_catcode:nn} \Arg{intexpr1} \Arg{intexpr2} +% \end{syntax} +% These functions set the category code of the \meta{character} which +% has character code as given by the \meta{integer expression}. +% The first \meta{integer expression} +% is the character code and the second is the category code to apply. +% The setting applies within the current \TeX{} group. In general, the +% symbolic functions \cs{char_make_\meta{type}} should be preferred, +% but there are cases where these lower-level functions may be useful. +% \end{function} +% +% \begin{function}[EXP]{\char_value_catcode:n} +% \begin{syntax} +% \cs{char_value_catcode:n} \Arg{integer expression} +% \end{syntax} +% Expands to the current category code of the \meta{character} with +% character code given by the +% \meta{integer expression}. +% \end{function} +% +% \begin{function}{\char_show_value_catcode:n} +% \begin{syntax} +% \cs{char_show_value_catcode:n} \Arg{integer expression} +% \end{syntax} +% Displays the current category code of the \meta{character} with +% character code given by the \meta{integer expression} on the +% terminal. +% \end{function} +% +% \begin{function}{\char_set_lccode:nn} +% \begin{syntax} +% \cs{char_set_lcode:nn} \Arg{intexpr1} \Arg{intexpr2} +% \end{syntax} +% This function set up the behaviour of \meta{character} when +% found inside \cs{tl_to_lowercase:n}, such that \meta{character1} +% will be converted into \meta{character2}. The two \meta{characters} +% may be specified using an \meta{integer expression} for the character code +% concerned. This may include the \TeX{} |`|\meta{character} +% method for converting a single character into its character +% code: +% \begin{verbatim} +% \char_set_lccode:nn { `\A } { `\a } % Standard behaviour +% \char_set_lccode:nn { `\A } { `\A + 32 } +% \char_set_lccode:nn { 50 } { 60 } +% \end{verbatim} +% The setting applies within the current \TeX{} group. +% \end{function} +% +% \begin{function}[EXP]{\char_value_lccode:n} +% \begin{syntax} +% \cs{char_value_lccode:n} \Arg{integer expression} +% \end{syntax} +% Expands to the current lower case code of the \meta{character} with +% character code given by the +% \meta{integer expression}. +% \end{function} +% +% \begin{function}{\char_show_value_lccode:n} +% \begin{syntax} +% \cs{char_show_value_lccode:n} \Arg{integer expression} +% \end{syntax} +% Displays the current lower case code of the \meta{character} with +% character code given by the \meta{integer expression} on the +% terminal. +% \end{function} +% +% \begin{function}{\char_set_uccode:nn} +% \begin{syntax} +% \cs{char_set_uccode:nn} \Arg{intexpr1} \Arg{intexpr2} +% \end{syntax} +% This function set up the behaviour of \meta{character} when +% found inside \cs{tl_to_uppeercase:n}, such that \meta{character1} +% will be converted into \meta{character2}. The two \meta{characters} +% may be specified using an \meta{integer expression} for the character code +% concerned. This may include the \TeX{} |`|\meta{character} +% method for converting a single character into its character +% code: +% \begin{verbatim} +% \char_set_uccode:nn { `\a } { `\A } % Standard behaviour +% \char_set_uccode:nn { `\A } { `\A - 32 } +% \char_set_uccode:nn { 60 } { 50 } +% \end{verbatim} +% The setting applies within the current \TeX{} group. +% \end{function} +% +% \begin{function}[EXP]{\char_value_uccode:n} +% \begin{syntax} +% \cs{char_value_uccode:n} \Arg{integer expression} +% \end{syntax} +% Expands to the current upper case code of the \meta{character} with +% character code given by the +% \meta{integer expression}. +% \end{function} +% +% \begin{function}{\char_show_value_uccode:n} +% \begin{syntax} +% \cs{char_show_value_uccode:n} \Arg{integer expression} +% \end{syntax} +% Displays the current upper case code of the \meta{character} with +% character code given by the \meta{integer expression} on the +% terminal. +% \end{function} +% +% \begin{function}{\char_set_mathcode:nn} +% \begin{syntax} +% \cs{char_set_mathcode:nn} \Arg{intexpr1} \Arg{intexpr2} +% \end{syntax} +% This function sets up the math code of \meta{character}. +% The \meta{character} is specified as +% an \meta{integer expression} which will be used as the character +% code of the relevant character. The setting applies within the +% current \TeX{} group. +% \end{function} +% +% \begin{function}[EXP]{\char_value_mathcode:n} +% \begin{syntax} +% \cs{char_value_mathcode:n} \Arg{integer expression} +% \end{syntax} +% Expands to the current math code of the \meta{character} with +% character code given by the +% \meta{integer expression}. +% \end{function} +% +% \begin{function}{\char_show_value_mathcode:n} +% \begin{syntax} +% \cs{char_show_value_mathcode:n} \Arg{integer expression} +% \end{syntax} +% Displays the current math code of the \meta{character} with +% character code given by the \meta{integer expression} on the +% terminal. +% \end{function} +% +% \begin{function}{\char_set_sfcode:nn} +% \begin{syntax} +% \cs{char_set_sfcode:nn} \Arg{intexpr1} \Arg{intexpr2} +% \end{syntax} +% This function sets up the space factor for the \meta{character}. +% The \meta{character} is specified as +% an \meta{integer expression} which will be used as the character +% code of the relevant character. The setting applies within the +% current \TeX{} group. +% \end{function} +% +% \begin{function}[EXP]{\char_value_sfcode:n} +% \begin{syntax} +% \cs{char_value_sfcode:n} \Arg{integer expression} +% \end{syntax} +% Expands to the current space factor for the \meta{character} with +% character code given by the +% \meta{integer expression}. +% \end{function} +% +% \begin{function}{\char_show_value_sfcode:n} +% \begin{syntax} +% \cs{char_show_value_sfcode:n} \Arg{integer expression} +% \end{syntax} +% Displays the current space factor for the \meta{character} with +% character code given by the \meta{integer expression} on the +% terminal. +% \end{function} +% +% \section{Generic tokens} +% +% \begin{function}{\token_new:Nn} +% \begin{syntax} +% \cs{token_new:Nn} \meta{token1} \Arg{token2} +% \end{syntax} +% Defines \meta{token1} to globally be a snapshot of \meta{token2}. +% This will be an implicit representation of \meta{token2}. +% \end{function} +% +% \begin{variable} +% { +% \c_group_begin_token, +% \c_group_end_token, +% \c_math_toggle_token, +% \c_alignment_token, +% \c_parameter_token, +% \c_math_superscript_token, +% \c_math_subscript_token, +% \c_space_token +% } +% These are implicit tokens which have the category code described +% by their name. They are used internally for test purposes but +% are also available to the programmer for other uses. +% \end{variable} +% +% \begin{variable} +% { +% \c_catcode_letter_token, +% \c_catcode_other_token +% } +% These are implicit tokens which have the category code described +% by their name. They are used internally for test purposes and should +% not be used other than for category code tests. +% \end{variable} +% +% \begin{variable}{\c_catcode_active_tl} +% A token list containing an active token. This is used internally +% for test purposes and should not be used other than in +% appropriately-constructed category code tests. +% \end{variable} +% +% \section{Converting tokens} +% +% \begin{function}[EXP]{\token_to_meaning:N} +% \begin{syntax} +% \cs{token_to_meaning:N} \meta{token} +% \end{syntax} +% Inserts the current meaning of the \meta{token} into the input +% stream as a series of characters of category code $12$ (other). +% This will be the primitive \TeX{} description of the \meta{token}, +% thus for example both functions defined by \cs{cs_set_nopar:Npn} +% and token list variables defined using \cs{tl_new:N} will be described +% as |macro|s. +% \begin{texnote} +% This is the \TeX{} primitive \tn{meaning}. +% \end{texnote} +% \end{function} +% +% \begin{function}[EXP]{\token_to_str:N, \token_to_str:c} +% \begin{syntax} +% \cs{token_to_str:N} \meta{token} +% \end{syntax} +% Converts the given \meta{token} into a series of characters with +% category code $12$ (other). The current escape character will be +% the first character in the sequence, although this will also have +% category code $12$ (the escape character is part of the +% \meta{token}). This function requires only a single expansion. +% \begin{texnote} +% \cs{token_to_str:N} is the \TeX{} primitive \cs{string} renamed. +% \end{texnote} +% \end{function} +% +% \section{Token conditionals} +% +% \begin{function}[EXP,pTF]{\token_if_group_begin:N} +% \begin{syntax} +% \cs{token_if_group_begin_p:N} \meta{token} +% \cs{token_if_group_begin:NTF} \meta{token} \Arg{true code} +% ~~\Arg{false code} +% \end{syntax} +% Tests if \meta{token} has the category code of a begin group token +% (|{| when normal \TeX{} category codes are in ^^A } +% force). The branching versions then leave either \meta{true code} or +% \meta{false code} in the input stream, as appropriate to the truth of +% the test and the variant of the function chosen. The logical truth of +% the test is left in the input stream by the predicate version. +% Note that an explicit begin group token cannot be tested in this way, +% as it is not a valid \texttt{N}-type argument. +% \end{function} +% +% \begin{function}[EXP,pTF]{\token_if_group_end:N} +% \begin{syntax} +% \cs{token_if_group_end_p:N} \meta{token} +% \cs{token_if_group_end:NTF} \meta{token} \Arg{true code} +% ~~\Arg{false code} +% \end{syntax} +% Tests if \meta{token} has the category code of an end group token +% (^^A { +% |}| when normal \TeX{} category codes are in force). The branching +% versions then leave either \meta{true code} or \meta{false code} in the +% input stream, as appropriate to the truth of the test and the variant +% of the function chosen. The logical truth of the test is left in the +% input stream by the predicate version. +% Note that an explicit end group token cannot be tested in this way, +% as it is not a valid \texttt{N}-type argument. +% \end{function} +% +% \begin{function}[EXP,pTF]{\token_if_math_toggle:N} +% \begin{syntax} +% \cs{token_if_math_toggle_p:N} \meta{token} +% \cs{token_if_math_toggle:NTF} \meta{token} \Arg{true code} +% ~~\Arg{false code} +% \end{syntax} +% Tests if \meta{token} has the category code of a math shift token +% (|$| when normal \TeX{} category codes are in force). The +% branching versions then leave either \meta{true code} or +% \meta{false code} in the input stream, as appropriate to the truth of +% the test and the variant of the function chosen. The logical truth of +% the test is left in the input stream by the predicate version. +% \end{function} +% +% \begin{function}[EXP,pTF]{\token_if_alignment:N} +% \begin{syntax} +% \cs{token_if_alignment_p:N} \meta{token} +% \cs{token_if_alignment:NTF} \meta{token} \Arg{true code} +% ~~\Arg{false code} +% \end{syntax} +% Tests if \meta{token} has the category code of an alignment token +% (|&| when normal \TeX{} category codes are in force). The +% branching versions then leave either \meta{true code} or +% \meta{false code} in the input stream, as appropriate to the truth of +% the test and the variant of the function chosen. The logical truth of +% the test is left in the input stream by the predicate version. +% \end{function} +% +% \begin{function}[EXP,pTF]{\token_if_parameter:N} +% \begin{syntax} +% \cs{token_if_parameter_p:N} \meta{token} +% \cs{token_if_alignment:NTF} \meta{token} \Arg{true code} +% ~~\Arg{false code} +% \end{syntax} +% Tests if \meta{token} has the category code of a macro parameter token +% (|#| when normal \TeX{} category codes are in force). The +% branching versions then leave either \meta{true code} or +% \meta{false code} in the input stream, as appropriate to the truth of +% the test and the variant of the function chosen. The logical truth of +% the test is left in the input stream by the predicate version. +% \end{function} +% +% \begin{function}[EXP,pTF]{\token_if_math_superscript:N} +% \begin{syntax} +% \cs{token_if_math_superscript_p:N} \meta{token} +% \cs{token_if_math_superscript:NTF} \meta{token} \Arg{true code} +% ~~\Arg{false code} +% \end{syntax} +% Tests if \meta{token} has the category code of a superscript token +% (|^| when normal \TeX{} category codes are in force). The +% branching versions then leave either \meta{true code} or +% \meta{false code} in the input stream, as appropriate to the truth of +% the test and the variant of the function chosen. The logical truth of +% the test is left in the input stream by the predicate version. +% \end{function} +% +% \begin{function}[EXP,pTF]{\token_if_math_subscript:N} +% \begin{syntax} +% \cs{token_if_math_subscript_p:N} \meta{token} +% \cs{token_if_math_subscript:NTF} \meta{token} \Arg{true code} +% ~~\Arg{false code} +% \end{syntax} +% Tests if \meta{token} has the category code of a subscript token +% (|_| when normal \TeX{} category codes are in force). The +% branching versions then leave either \meta{true code} or +% \meta{false code} in the input stream, as appropriate to the truth of +% the test and the variant of the function chosen. The logical truth of +% the test is left in the input stream by the predicate version. +% \end{function} +% +% \begin{function}[EXP,pTF]{\token_if_space:N} +% \begin{syntax} +% \cs{token_if_space_p:N} \meta{token} +% \cs{token_if_space:NTF} \meta{token} \Arg{true code} +% ~~\Arg{false code} +% \end{syntax} +% Tests if \meta{token} has the category code of a space token. The +% branching versions then leave either \meta{true code} or +% \meta{false code} in the input stream, as appropriate to the truth of +% the test and the variant of the function chosen. The logical truth of +% the test is left in the input stream by the predicate version. +% Note that an explicit space token with character code $32$ cannot +% be tested in this way, as it is not a valid \texttt{N}-type argument. +% \end{function} +% +% \begin{function}[EXP,pTF]{\token_if_letter:N} +% \begin{syntax} +% \cs{token_if_letter_p:N} \meta{token} +% \cs{token_if_letter:NTF} \meta{token} \Arg{true code} +% ~~\Arg{false code} +% \end{syntax} +% Tests if \meta{token} has the category code of a letter token. The +% branching versions then leave either \meta{true code} or +% \meta{false code} in the input stream, as appropriate to the truth of +% the test and the variant of the function chosen. The logical truth of +% the test is left in the input stream by the predicate version. +% \end{function} +% +% \begin{function}[EXP,pTF]{\token_if_other:N} +% \begin{syntax} +% \cs{token_if_other_p:N} \meta{token} +% \cs{token_if_other:NTF} \meta{token} \Arg{true code} +% ~~\Arg{false code} +% \end{syntax} +% Tests if \meta{token} has the category code of an \enquote{other} +% token. The branching versions then leave either \meta{true code} or +% \meta{false code} in the input stream, as appropriate to the truth of +% the test and the variant of the function chosen. The logical truth of +% the test is left in the input stream by the predicate version. +% \end{function} +% +% \begin{function}[EXP,pTF]{\token_if_active:N} +% \begin{syntax} +% \cs{token_if_active_p:N} \meta{token} +% \cs{token_if_active:NTF} \meta{token} \Arg{true code} +% ~~\Arg{false code} +% \end{syntax} +% Tests if \meta{token} has the category code of an active character. +% The branching versions then leave either \meta{true code} or +% \meta{false code} in the input stream, as appropriate to the truth of +% the test and the variant of the function chosen. The logical truth of +% the test is left in the input stream by the predicate version. +% \end{function} +% +% \begin{function}[EXP,pTF]{\token_if_eq_catcode:NN} +% \begin{syntax} +% \cs{token_if_eq_catcode_p:NN} \meta{token1} \meta{token2} +% \cs{token_if_eq_catcode:NNTF} \meta{token1} \meta{token2} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the two \meta{tokens} have the same category code. The +% branching versions then leave either \meta{true code} or +% \meta{false code} in the input stream, as appropriate to the truth of +% the test and the variant of the function chosen. The logical truth of +% the test is left in the input stream by the predicate version. +% \end{function} +% +% \begin{function}[EXP,pTF]{\token_if_eq_charcode:NN} +% \begin{syntax} +% \cs{token_if_eq_charcode_p:NN} \meta{token1} \meta{token2} +% \cs{token_if_eq_charcode:NNTF} \meta{token1} \meta{token2} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the two \meta{tokens} have the same character code. The +% branching versions then leave either \meta{true code} or +% \meta{false code} in the input stream, as appropriate to the truth of +% the test and the variant of the function chosen. The logical truth of +% the test is left in the input stream by the predicate version. +% \end{function} +% +% \begin{function}[EXP,pTF]{\token_if_eq_meaning:NN} +% \begin{syntax} +% \cs{token_if_eq_meaning_p:NN} \meta{token1} \meta{token2} +% \cs{token_if_eq_meaning:NNTF} \meta{token1} \meta{token2} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the two \meta{tokens} have the same meaning when expanded. +% The branching versions then leave either \meta{true code} or +% \meta{false code} in the input stream, as appropriate to the truth of +% the test and the variant of the function chosen. The logical truth of +% the test is left in the input stream by the predicate version. +% \end{function} +% +% \begin{function}[EXP,pTF]{\token_if_macro:N} +% \begin{syntax} +% \cs{token_if_macro_p:N} \meta{token} +% \cs{token_if_macro:NTF} \meta{token} \Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the \meta{token} is a \TeX{} macro. +% The branching versions then leave either \meta{true code} or +% \meta{false code} in the input stream, as appropriate to the truth of +% the test and the variant of the function chosen. The logical truth of +% the test is left in the input stream by the predicate version. +% \end{function} +% +% \begin{function}[EXP,pTF]{\token_if_cs:N} +% \begin{syntax} +% \cs{token_if_cs_p:N} \meta{token} +% \cs{token_if_cs:NTF} \meta{token} \Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the \meta{token} is a control sequence. +% The branching versions then leave either \meta{true code} or +% \meta{false code} in the input stream, as appropriate to the truth of +% the test and the variant of the function chosen. The logical truth of +% the test is left in the input stream by the predicate version. +% \end{function} +% +% \begin{function}[EXP,pTF]{\token_if_expandable:N} +% \begin{syntax} +% \cs{token_if_expandable_p:N} \meta{token} +% \cs{token_if_expandable:NTF} \meta{token} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the \meta{token} is expandable. This test returns \meta{false} +% for an undefined token. +% The branching versions then leave either \meta{true code} or +% \meta{false code} in the input stream, as appropriate to the truth of +% the test and the variant of the function chosen. The logical truth of +% the test is left in the input stream by the predicate version. +% \end{function} +% +% \begin{function}[EXP,pTF]{\token_if_long_macro:N} +% \begin{syntax} +% \cs{token_if_long_macro_p:N} \meta{token} +% \cs{token_if_long_macro:NTF} \meta{token} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the \meta{token} is a long macro. +% The branching versions then leave either \meta{true code} or +% \meta{false code} in the input stream, as appropriate to the truth of +% the test and the variant of the function chosen. The logical truth of +% the test is left in the input stream by the predicate version. +% \end{function} +% +% \begin{function}[EXP,pTF]{\token_if_protected_macro:N} +% \begin{syntax} +% \cs{token_if_protected_macro_p:N} \meta{token} +% \cs{token_if_protected_macro:NTF} \meta{token} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the \meta{token} is a protected macro: a macro which +% is both protected and long will return logical false. +% The branching versions then leave either \meta{true code} or +% \meta{false code} in the input stream, as appropriate to the truth of +% the test and the variant of the function chosen. The logical truth of +% the test is left in the input stream by the predicate version. +% \end{function} +% +%% \begin{function}[EXP,pTF]{\token_if_protected_long_macro:N} +% \begin{syntax} +% \cs{token_if_protected_long_macro_p:N} \meta{token} +% \cs{token_if_protected_long_macro:NTF} \meta{token} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the \meta{token} is a protected long macro. +% The branching versions then leave either \meta{true code} or +% \meta{false code} in the input stream, as appropriate to the truth of +% the test and the variant of the function chosen. The logical truth of +% the test is left in the input stream by the predicate version. +% \end{function} +% +% \begin{function}[EXP,pTF]{\token_if_chardef:N} +% \begin{syntax} +% \cs{token_if_chardef_p:N} \meta{token} +% \cs{token_if_chardef:NTF} \meta{token} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the \meta{token} is defined to be a chardef. +% The branching versions then leave either \meta{true code} or +% \meta{false code} in the input stream, as appropriate to the truth of +% the test and the variant of the function chosen. The logical truth of +% the test is left in the input stream by the predicate version. +% \end{function} +% +% \begin{function}[EXP,pTF]{\token_if_mathchardef:N} +% \begin{syntax} +% \cs{token_if_mathchardef_p:N} \meta{token} +% \cs{token_if_mathchardef:NTF} \meta{token} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the \meta{token} is defined to be a mathchardef. +% The branching versions then leave either \meta{true code} or +% \meta{false code} in the input stream, as appropriate to the truth of +% the test and the variant of the function chosen. The logical truth of +% the test is left in the input stream by the predicate version. +% \end{function} +% +% \begin{function}[EXP,pTF]{\token_if_dim_register:N} +% \begin{syntax} +% \cs{token_if_dim_register_p:N} \meta{token} +% \cs{token_if_dim_register:NTF} \meta{token} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the \meta{token} is defined to be a dimension register. +% The branching versions then leave either \meta{true code} or +% \meta{false code} in the input stream, as appropriate to the truth of +% the test and the variant of the function chosen. The logical truth of +% the test is left in the input stream by the predicate version. +% \end{function} +% +% \begin{function}[EXP,pTF]{\token_if_int_register:N} +% \begin{syntax} +% \cs{token_if_int_register_p:N} \meta{token} +% \cs{token_if_int_register:NTF} \meta{token} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the \meta{token} is defined to be a integer register. +% The branching versions then leave either \meta{true code} or +% \meta{false code} in the input stream, as appropriate to the truth of +% the test and the variant of the function chosen. The logical truth of +% the test is left in the input stream by the predicate version. +% \end{function} +% +% \begin{function}[EXP,pTF]{\token_if_skip_register:N} +% \begin{syntax} +% \cs{token_if_skip_register_p:N} \meta{token} +% \cs{token_if_skip_register:NTF} \meta{token} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the \meta{token} is defined to be a skip register. +% The branching versions then leave either \meta{true code} or +% \meta{false code} in the input stream, as appropriate to the truth of +% the test and the variant of the function chosen. The logical truth of +% the test is left in the input stream by the predicate version. +% \end{function} +% +% \begin{function}[EXP,pTF]{\token_if_toks_register:N} +% \begin{syntax} +% \cs{token_if_toks_register_p:N} \meta{token} +% \cs{token_if_toks_register:NTF} \meta{token} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the \meta{token} is defined to be a toks register +% (not used by\LaTeX3). +% The branching versions then leave either \meta{true code} or +% \meta{false code} in the input stream, as appropriate to the truth of +% the test and the variant of the function chosen. The logical truth of +% the test is left in the input stream by the predicate version. +% \end{function} +% +% \begin{function}[EXP,pTF]{\token_if_primitive:N} +% \begin{syntax} +% \cs{token_if_primitive_p:N} \meta{token} +% \cs{token_if_primitive:NTF} \meta{token} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the \meta{token} is an engine primitive. +% The branching versions then leave either \meta{true code} or +% \meta{false code} in the input stream, as appropriate to the truth of +% the test and the variant of the function chosen. The logical truth of +% the test is left in the input stream by the predicate version. +% \end{function} +% +% \section{Peeking ahead at the next token} +% +% There is often a need to look ahead at the next token in the input +% stream while leaving it in place. This is handled using the +% \enquote{peek} functions. The generic \cs{peek_after:Nw} is +% provided along with a family of predefined tests for common cases. +% As peeking ahead does \emph{not} skip spaces the predefined tests +% include both a space-respecting and space-skipping version. +% +% \begin{function}{\peek_after:Nw} +% \begin{syntax} +% \cs{peek_after:Nw} \meta{function} \meta{token} +% \end{syntax} +% Locally sets the test variable \cs{l_peek_token} equal to \meta{token} +% (as an implicit token, \emph{not} as a token list), and then +% expands the \meta{function}. The \meta{token} will remain in +% the input stream as the next item after the \meta{function}. +% The \meta{token} here may be \verb*| |, |{| or |}| (assuming +% normal \TeX{} category codes), \emph{i.e.}~it is not necessarily the +% next argument which would be grabbed by a normal function. +% \end{function} +% +% \begin{function}{\peek_gafter:Nw} +% \begin{syntax} +% \cs{peek_gafter:Nw} \meta{function} \meta{token} +% \end{syntax} +% Globally sets the test variable \cs{g_peek_token} equal to \meta{token} +% (as an implicit token, \emph{not} as a token list), and then +% expands the \meta{function}. The \meta{token} will remain in +% the input stream as the next item after the \meta{function}. +% The \meta{token} here may be \verb*| |, |{| or |}| (assuming +% normal \TeX{} category codes), \emph{i.e.}~it is not necessarily the +% next argument which would be grabbed by a normal function. +% \end{function} +% +% \begin{variable}{\l_peek_token} +% Token set by \cs{peek_after:Nw} and available for testing +% as described above. +% \end{variable} +% +% \begin{variable}{\g_peek_token} +% Token set by \cs{peek_gafter:Nw} and available for testing +% as described above. +% \end{variable} +% +% \begin{function}[TF]{\peek_catcode:N} +% \begin{syntax} +% \cs{peek_catcode:NTF} \meta{test token} \Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the next \meta{token} in the input stream has the same +% category code as the \meta{test token} (as defined by the test +% \cs{token_if_eq_catcode:NNTF}). Spaces are respected by the test +% and the \meta{token} will be left in the input stream after +% the \meta{true code} or \meta{false code} (as appropriate to the +% result of the test). +% \end{function} +% +% \begin{function}[TF]{\peek_catcode_ignore_spaces:N} +% \begin{syntax} +% \cs{peek_catcode_ignore_spaces:NTF} \meta{test token} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the next \meta{token} in the input stream has the same +% category code as the \meta{test token} (as defined by the test +% \cs{token_if_eq_catcode:NNTF}). Spaces are ignored by the test +% and the \meta{token} will be left in the input stream after +% the \meta{true code} or \meta{false code} (as appropriate to the +% result of the test). +% \end{function} +% +% \begin{function}[TF]{\peek_catcode_remove:N} +% \begin{syntax} +% \cs{peek_catcode_remove:NTF} \meta{test token} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the next \meta{token} in the input stream has the same +% category code as the \meta{test token} (as defined by the test +% \cs{token_if_eq_catcode:NNTF}). Spaces are respected by the test +% and the \meta{token} will be removed from the input stream if the +% test is true. The function will then place either the +% \meta{true code} or \meta{false code} in the input stream (as +% appropriate to the result of the test). +% \end{function} +% +% \begin{function}[TF]{\peek_catcode_remove_ignore_spaces:N} +% \begin{syntax} +% \cs{peek_catcode_remove_ignore_spaces:NTF} \meta{test token} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the next \meta{token} in the input stream has the same +% category code as the \meta{test token} (as defined by the test +% \cs{token_if_eq_catcode:NNTF}). Spaces are ignored by the test +% and the \meta{token} will be removed from the input stream if the +% test is true. The function will then place either the +% \meta{true code} or \meta{false code} in the input stream (as +% appropriate to the result of the test). +% \end{function} +% +% \begin{function}[TF]{\peek_charcode:N} +% \begin{syntax} +% \cs{peek_charcode:NTF} \meta{test token} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the next \meta{token} in the input stream has the same +% character code as the \meta{test token} (as defined by the test +% \cs{token_if_eq_charcode:NNTF}). Spaces are respected by the test +% and the \meta{token} will be left in the input stream after +% the \meta{true code} or \meta{false code} (as appropriate to the +% result of the test). +% \end{function} +% +% \begin{function}[TF]{\peek_charcode_ignore_spaces:N} +% \begin{syntax} +% \cs{peek_charcode_ignore_spaces:NTF} \meta{test token} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the next \meta{token} in the input stream has the same +% character code as the \meta{test token} (as defined by the test +% \cs{token_if_eq_charcode:NNTF}). Spaces are ignored by the test +% and the \meta{token} will be left in the input stream after +% the \meta{true code} or \meta{false code} (as appropriate to the +% result of the test). +% \end{function} +% +% \begin{function}[TF]{\peek_charcode_remove:N} +% \begin{syntax} +% \cs{peek_charcode_remove:NTF} \meta{test token} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the next \meta{token} in the input stream has the same +% character code as the \meta{test token} (as defined by the test +% \cs{token_if_eq_charcode:NNTF}). Spaces are respected by the test +% and the \meta{token} will be removed from the input stream if the +% test is true. The function will then place either the +% \meta{true code} or \meta{false code} in the input stream (as +% appropriate to the result of the test). +% \end{function} +% +% \begin{function}[TF]{\peek_charcode_remove_ignore_spaces:N} +% \begin{syntax} +% \cs{peek_charcode_remove_ignore_spaces:NTF} \meta{test token} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the next \meta{token} in the input stream has the same +% character code as the \meta{test token} (as defined by the test +% \cs{token_if_eq_charcode:NNTF}). Spaces are ignored by the test +% and the \meta{token} will be removed from the input stream if the +% test is true. The function will then place either the +% \meta{true code} or \meta{false code} in the input stream (as +% appropriate to the result of the test). +% \end{function} +% +% \begin{function}[TF]{\peek_meaning:N} +% \begin{syntax} +% \cs{peek_meaning:NTF} \meta{test token} \Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the next \meta{token} in the input stream has the same +% meaning as the \meta{test token} (as defined by the test +% \cs{token_if_eq_meaning:NNTF}). Spaces are respected by the test +% and the \meta{token} will be left in the input stream after +% the \meta{true code} or \meta{false code} (as appropriate to the +% result of the test). +% \end{function} +% +% \begin{function}[TF]{\peek_meaning_ignore_spaces:N} +% \begin{syntax} +% \cs{peek_meaning_ignore_spaces:NTF} \meta{test token} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the next \meta{token} in the input stream has the same +% meaning as the \meta{test token} (as defined by the test +% \cs{token_if_eq_meaning:NNTF}). Spaces are ignored by the test +% and the \meta{token} will be left in the input stream after +% the \meta{true code} or \meta{false code} (as appropriate to the +% result of the test). +% \end{function} +% +% \begin{function}[TF]{\peek_meaning_remove:N} +% \begin{syntax} +% \cs{peek_meaning_remove:NTF} \meta{test token} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the next \meta{token} in the input stream has the same +% meaning as the \meta{test token} (as defined by the test +% \cs{token_if_eq_meaning:NNTF}). Spaces are respected by the test +% and the \meta{token} will be removed from the input stream if the +% test is true. The function will then place either the +% \meta{true code} or \meta{false code} in the input stream (as +% appropriate to the result of the test). +% \end{function} +% +% \begin{function}[TF]{\peek_meaning_remove_ignore_spaces:N} +% \begin{syntax} +% \cs{peek_meaning_remove_ignore_spaces:NTF} \meta{test token} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the next \meta{token} in the input stream has the same +% meaning as the \meta{test token} (as defined by the test +% \cs{token_if_eq_meaning:NNTF}). Spaces are ignored by the test +% and the \meta{token} will be removed from the input stream if the +% test is true. The function will then place either the +% \meta{true code} or \meta{false code} in the input stream (as +% appropriate to the result of the test). +% \end{function} +% +% \section{Decomposing a macro definition} +% +% These functions decompose \TeX{} macros into their constituent +% parts: if the \meta{token} passed is not a macro then no decomposition +% can occur. In the later case, all three functions leave \cs{scan_stop:} +% in the input stream. +% +% \begin{function}[EXP]{\token_get_arg_spec:N} +% \begin{syntax} +% \cs{token_get_arg_spec:N} \meta{token} +% \end{syntax} +% If the \meta{token} is a macro, this function will leave +% the primitive \TeX{} argument specification in input stream as +% a string of tokens of category code $12$ (with spaces having category +% code $10$). Thus for example for a token \cs{next} defined by +% \begin{verbatim} +% \cs_set:Npn \next #1#2 { x #1 y #2 } +% \end{verbatim} +% will leave |#1#2| in the input stream. If the \meta{token} is +% not a macro then \cs{scan_stop:} will be left in the input stream +% \begin{texnote} +% If the arg~spec. contains the string |->|, then the |spec| function +% will produce incorrect results. +% \end{texnote} +% \end{function} +% +% \begin{function}[EXP]{\token_get_replacement_text:N} +% \begin{syntax} +% \cs{token_get_replacement_text:N} \meta{token} +% \end{syntax} +% If the \meta{token} is a macro, this function will leave +% the replacement text in input stream as +% a string of tokens of category code $12$ (with spaces having category +% code $10$). Thus for example for a token \cs{next} defined by +% \begin{verbatim} +% \cs_set:Npn \next #1#2 { x #1~y #2 } +% \end{verbatim} +% will leave \verb|x#1 y#2| in the input stream. If the \meta{token} is +% not a macro then \cs{scan_stop:} will be left in the input stream +% \end{function} +% +% \begin{function}[EXP]{\token_get_prefix_spec:N} +% \begin{syntax} +% \cs{token_get_prefix_spec:N} \meta{token} +% \end{syntax} +% If the \meta{token} is a macro, this function will leave +% the \TeX{} prefixes applicable in input stream as +% a string of tokens of category code $12$ (with spaces having category +% code $10$). Thus for example for a token \cs{next} defined by +% \begin{verbatim} +% \cs_set:Npn \next #1#2 { x #1~y #2 } +% \end{verbatim} +% will leave |\long| in the input stream. If the \meta{token} is +% not a macro then \cs{scan_stop:} will be left in the input stream +% \end{function} +% +% \section{Experimental token functions} +% +% \begin{function}{\char_active_set:Npn, \char_active_set:Npx} +% \begin{syntax} +% \cs{char_active_set:Npn} \meta{char} \meta{parameters} \Arg{code} +% \end{syntax} +% Makes \meta{char} an active character to expand to \meta{code} as +% replacement text. +% Within the \meta{code}, the \meta{parameters} (|#1|, |#2|, +% \emph{etc.}) will be replaced by those absorbed +% This definition is local to the current \TeX{} group. +% \end{function} +% +% \begin{function}{\char_active_gset:Npn, \char_active_gset:Npx} +% \begin{syntax} +% \cs{char_active_gset:Npn} \meta{char} \meta{parameters} \Arg{code} +% \end{syntax} +% Makes \meta{char} an active character to expand to \meta{code} as +% replacement text. +% Within the \meta{code}, the \meta{parameters} (|#1|, |#2|, +% \emph{etc.}) will be replaced by those absorbed +% This definition is global. +% \end{function} +% +% \begin{function}{\char_active_set_eq:NN} +% \begin{syntax} +% \cs{char_active_set_eq:NN} \meta{char} \meta{function} +% \end{syntax} +% Makes \meta{char} an active character equivalent in meaning to the +% \meta{fiucntion} (which may itself be an active character). This +% definition is local to the current \TeX{} group. +% \end{function} +% +% \begin{function}{\char_active_gset_eq:NN} +% \begin{syntax} +% \cs{char_active_gset_eq:NN} \meta{char} \meta{function} +% \end{syntax} +% Makes \meta{char} an active character equivalent in meaning to the +% \meta{fiucntion} (which may itself be an active character). This +% definition is global. +% \end{function} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{l3token} implementation} +% +% \begin{macrocode} +%<*initex|package> +% \end{macrocode} +% +% \begin{macrocode} +%<*package> +\ProvidesExplPackage + {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +\package_check_loaded_expl: +%</package> +% \end{macrocode} +% +% \subsection{Character tokens} +% +% \begin{macro}{\char_set_catcode:nn} +% \begin{macro}{\char_value_catcode:n} +% \begin{macro}{\char_show_value_catcode:n} +% Category code changes. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \char_set_catcode:nn #1#2 + { \tex_catcode:D #1 = \int_eval:w #2 \int_eval_end: } +\cs_new_nopar:Npn \char_value_catcode:n #1 + { \tex_the:D \tex_catcode:D \int_eval:w #1\int_eval_end: } +\cs_new_nopar:Npn \char_show_value_catcode:n #1 + { \tex_showthe:D \tex_catcode:D \int_eval:w #1 \int_eval_end: } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro} +% { +% \char_set_catcode_escape:N , +% \char_set_catcode_group_begin:N , +% \char_set_catcode_group_end:N , +% \char_set_catcode_math_toggle:N , +% \char_set_catcode_alignment:N , +% \char_set_catcode_end_line:N , +% \char_set_catcode_parameter:N , +% \char_set_catcode_math_superscript:N , +% \char_set_catcode_math_subscript:N , +% \char_set_catcode_ignore:N , +% \char_set_catcode_space:N , +% \char_set_catcode_letter:N , +% \char_set_catcode_other:N , +% \char_set_catcode_active:N , +% \char_set_catcode_comment:N , +% \char_set_catcode_invalid:N +% } +% \begin{macrocode} +\cs_new_protected_nopar:Npn \char_set_catcode_escape:N #1 + { \char_set_catcode:nn { `#1 } \c_zero } +\cs_new_protected_nopar:Npn \char_set_catcode_group_begin:N #1 + { \char_set_catcode:nn { `#1 } \c_one } +\cs_new_protected_nopar:Npn \char_set_catcode_group_end:N #1 + { \char_set_catcode:nn { `#1 } \c_two } +\cs_new_protected_nopar:Npn \char_set_catcode_math_toggle:N #1 + { \char_set_catcode:nn { `#1 } \c_three } +\cs_new_protected_nopar:Npn \char_set_catcode_alignment:N #1 + { \char_set_catcode:nn { `#1 } \c_four } +\cs_new_protected_nopar:Npn \char_set_catcode_end_line:N #1 + { \char_set_catcode:nn { `#1 } \c_five } +\cs_new_protected_nopar:Npn \char_set_catcode_parameter:N #1 + { \char_set_catcode:nn { `#1 } \c_six } +\cs_new_protected_nopar:Npn \char_set_catcode_math_superscript:N #1 + { \char_set_catcode:nn { `#1 } \c_seven } +\cs_new_protected_nopar:Npn \char_set_catcode_math_subscript:N #1 + { \char_set_catcode:nn { `#1 } \c_eight } +\cs_new_protected_nopar:Npn \char_set_catcode_ignore:N #1 + { \char_set_catcode:nn { `#1 } \c_nine } +\cs_new_protected_nopar:Npn \char_set_catcode_space:N #1 + { \char_set_catcode:nn { `#1 } \c_ten } +\cs_new_protected_nopar:Npn \char_set_catcode_letter:N #1 + { \char_set_catcode:nn { `#1 } \c_eleven } +\cs_new_protected_nopar:Npn \char_set_catcode_other:N #1 + { \char_set_catcode:nn { `#1 } \c_twelve } +\cs_new_protected_nopar:Npn \char_set_catcode_active:N #1 + { \char_set_catcode:nn { `#1 } \c_thirteen } +\cs_new_protected_nopar:Npn \char_set_catcode_comment:N #1 + { \char_set_catcode:nn { `#1 } \c_fourteen } +\cs_new_protected_nopar:Npn \char_set_catcode_invalid:N #1 + { \char_set_catcode:nn { `#1 } \c_fifteen } +% \end{macrocode} +% \end{macro} +% +% \begin{macro} +% { +% \char_set_catcode_escape:n , +% \char_set_catcode_group_begin:n , +% \char_set_catcode_group_end:n , +% \char_set_catcode_math_toggle:n , +% \char_set_catcode_alignment:n , +% \char_set_catcode_end_line:n , +% \char_set_catcode_parameter:n , +% \char_set_catcode_math_superscript:n , +% \char_set_catcode_math_subscript:n , +% \char_set_catcode_ignore:n , +% \char_set_catcode_space:n , +% \char_set_catcode_letter:n , +% \char_set_catcode_other:n , +% \char_set_catcode_active:n , +% \char_set_catcode_comment:n , +% \char_set_catcode_invalid:n +% } +% \begin{macrocode} +\cs_new_protected_nopar:Npn \char_set_catcode_escape:n #1 + { \char_set_catcode:nn {#1} \c_zero } +\cs_new_protected_nopar:Npn \char_set_catcode_group_begin:n #1 + { \char_set_catcode:nn {#1} \c_one } +\cs_new_protected_nopar:Npn \char_set_catcode_group_end:n #1 + { \char_set_catcode:nn {#1} \c_two } +\cs_new_protected_nopar:Npn \char_set_catcode_math_toggle:n #1 + { \char_set_catcode:nn {#1} \c_three } +\cs_new_protected_nopar:Npn \char_set_catcode_alignment:n #1 + { \char_set_catcode:nn {#1} \c_four } +\cs_new_protected_nopar:Npn \char_set_catcode_end_line:n #1 + { \char_set_catcode:nn {#1} \c_five } +\cs_new_protected_nopar:Npn \char_set_catcode_parameter:n #1 + { \char_set_catcode:nn {#1} \c_six } +\cs_new_protected_nopar:Npn \char_set_catcode_math_superscript:n #1 + { \char_set_catcode:nn {#1} \c_seven } +\cs_new_protected_nopar:Npn \char_set_catcode_math_subscript:n #1 + { \char_set_catcode:nn {#1} \c_eight } +\cs_new_protected_nopar:Npn \char_set_catcode_ignore:n #1 + { \char_set_catcode:nn {#1} \c_nine } +\cs_new_protected_nopar:Npn \char_set_catcode_space:n #1 + { \char_set_catcode:nn {#1} \c_ten } +\cs_new_protected_nopar:Npn \char_set_catcode_letter:n #1 + { \char_set_catcode:nn {#1} \c_eleven } +\cs_new_protected_nopar:Npn \char_set_catcode_other:n #1 + { \char_set_catcode:nn {#1} \c_twelve } +\cs_new_protected_nopar:Npn \char_set_catcode_active:n #1 + { \char_set_catcode:nn {#1} \c_thirteen } +\cs_new_protected_nopar:Npn \char_set_catcode_comment:n #1 + { \char_set_catcode:nn {#1} \c_fourteen } +\cs_new_protected_nopar:Npn \char_set_catcode_invalid:n #1 + { \char_set_catcode:nn {#1} \c_fifteen } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\char_set_mathcode:nn} +% \begin{macro}{\char_value_mathcode:n} +% \begin{macro}{\char_show_value_mathcode:n} +% \begin{macro}{\char_set_lccode:nn} +% \begin{macro}{\char_value_lccode:n} +% \begin{macro}{\char_show_value_lccode:n} +% \begin{macro}{\char_set_uccode:nn} +% \begin{macro}{\char_value_uccode:n} +% \begin{macro}{\char_show_value_uccode:n} +% \begin{macro}{\char_set_sfcode:nn} +% \begin{macro}{\char_value_sfcode:n} +% \begin{macro}{\char_show_value_sfcode:n} +% Pretty repetitive, but necessary! +% \begin{macrocode} +\cs_new_protected_nopar:Npn \char_set_mathcode:nn #1#2 + { \tex_mathcode:D #1 = \int_eval:w #2 \int_eval_end: } +\cs_new_nopar:Npn \char_value_mathcode:n #1 + { \tex_the:D \tex_mathcode:D \int_eval:w #1\int_eval_end: } +\cs_new_nopar:Npn \char_show_value_mathcode:n #1 + { \tex_showthe:D \tex_mathcode:D \int_eval:w #1 \int_eval_end: } +\cs_new_protected_nopar:Npn \char_set_lccode:nn #1#2 + { \tex_lccode:D #1 = \int_eval:w #2 \int_eval_end: } +\cs_new_nopar:Npn \char_value_lccode:n #1 + { \tex_the:D \tex_lccode:D \int_eval:w #1\int_eval_end: } +\cs_new_nopar:Npn \char_show_value_lccode:n #1 + { \tex_showthe:D \tex_lccode:D \int_eval:w #1 \int_eval_end: } +\cs_new_protected_nopar:Npn \char_set_uccode:nn #1#2 + { \tex_uccode:D #1 = \int_eval:w #2 \int_eval_end: } +\cs_new_nopar:Npn \char_value_uccode:n #1 + { \tex_the:D \tex_uccode:D \int_eval:w #1\int_eval_end: } +\cs_new_nopar:Npn \char_show_value_uccode:n #1 + { \tex_showthe:D \tex_uccode:D \int_eval:w #1 \int_eval_end: } +\cs_new_protected_nopar:Npn \char_set_sfcode:nn #1#2 + { \tex_sfcode:D #1 = \int_eval:w #2 \int_eval_end: } +\cs_new_nopar:Npn \char_value_sfcode:n #1 + { \tex_the:D \tex_sfcode:D \int_eval:w #1\int_eval_end: } +\cs_new_nopar:Npn \char_show_value_sfcode:n #1 + { \tex_showthe:D \tex_sfcode:D \int_eval:w #1 \int_eval_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} +% \end{macro} +% +% \subsection{Generic tokens} +% +% \begin{macro}{\token_new:Nn} +% Creates a new token. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \token_new:Nn #1#2 { \cs_new_eq:NN #1 #2 } +% \end{macrocode} +% \end{macro} +% +% \begin{macro} +% { +% \c_group_begin_token, +% \c_group_end_token, +% \c_math_toggle_token, +% \c_alignment_token, +% \c_parameter_token, +% \c_math_superscript_token, +% \c_math_subscript_token, +% \c_space_token, +% \c_catcode_letter_token, +% \c_catcode_other_token +% } +% We define these useful tokens. We have to do it by hand with the +% brace tokens for obvious reasons. +% \begin{macrocode} +\cs_new_eq:NN \c_group_begin_token { +\cs_new_eq:NN \c_group_end_token } +\group_begin: + \char_set_catcode_math_toggle:N \* + \token_new:Nn \c_math_toggle_token { * } + \char_set_catcode_alignment:N \* + \token_new:Nn \c_alignment_token { * } + \token_new:Nn \c_parameter_token { # } + \token_new:Nn \c_math_superscript_token { ^ } + \char_set_catcode_math_subscript:N \* + \token_new:Nn \c_math_subscript_token { * } + \token_new:Nn \c_space_token { ~ } + \token_new:Nn \c_catcode_letter_token { a } + \token_new:Nn \c_catcode_other_token { 1 } +\group_end: +% \end{macrocode} +% \end{macro} +% +% \begin{variable}{\c_catcode_active_tl} +% Not an implicit token! +% \begin{macrocode} +\group_begin: + \char_set_catcode_active:N \* + \cs_new_nopar:Npn \c_catcode_active_tl { \exp_not:N * } +\group_end: +% \end{macrocode} +% \end{variable} +% +% \subsection{Token conditionals} +% +% \begin{macro}[pTF]{\token_if_group_begin:N} +% Check if token is a begin group token. We use the constant +% |\c_group_begin_token| for this. +% \begin{macrocode} +\prg_new_conditional:Npnn \token_if_group_begin:N #1 { p , T , F , TF } + { + \if_catcode:w \exp_not:N #1 \c_group_begin_token + \prg_return_true: \else: \prg_return_false: \fi: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[pTF]{\token_if_group_end:N} +% Check if token is a end group token. We use the constant +% |\c_group_end_token| for this. +% \begin{macrocode} +\prg_new_conditional:Npnn \token_if_group_end:N #1 { p , T , F , TF } + { + \if_catcode:w \exp_not:N #1 \c_group_end_token + \prg_return_true: \else: \prg_return_false: \fi: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[pTF]{\token_if_math_toggle:N} +% Check if token is a math shift token. We use the constant +% |\c_math_toggle_token| for this. +% \begin{macrocode} +\prg_new_conditional:Npnn \token_if_math_toggle:N #1 { p , T , F , TF } + { + \if_catcode:w \exp_not:N #1 \c_math_toggle_token + \prg_return_true: \else: \prg_return_false: \fi: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[pTF]{\token_if_alignment:N} +% Check if token is an alignment tab token. We use the constant +% |\c_alignment_tab_token| for this. +% \begin{macrocode} +\prg_new_conditional:Npnn \token_if_alignment:N #1 { p , T , F , TF } + { + \if_catcode:w \exp_not:N #1 \c_alignment_token + \prg_return_true: \else: \prg_return_false: \fi: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[pTF]{\token_if_parameter:N} +% 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: within a group we prevent +% \cs{c_parameter_token} from behaving like a macro parameter character. +% The definitions of \cs{prg_new_conditional:Npnn} are global, so they +% will remain after the group. +% \begin{macrocode} +\group_begin: +\cs_set_eq:NN \c_parameter_token \scan_stop: +\prg_new_conditional:Npnn \token_if_parameter:N #1 { p , T , F , TF } + { + \if_catcode:w \exp_not:N #1 \c_parameter_token + \prg_return_true: \else: \prg_return_false: \fi: + } +\group_end: +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[pTF]{\token_if_math_superscript:N} +% Check if token is a math superscript token. We use the constant +% |\c_superscript_token| for this. +% \begin{macrocode} +\prg_new_conditional:Npnn \token_if_math_superscript:N #1 { p , T , F , TF } + { + \if_catcode:w \exp_not:N #1 \c_math_superscript_token + \prg_return_true: \else: \prg_return_false: \fi: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[pTF]{\token_if_math_subscript:N} +% Check if token is a math subscript token. We use the constant +% |\c_subscript_token| for this. +% \begin{macrocode} +\prg_new_conditional:Npnn \token_if_math_subscript:N #1 { p , T , F , TF } + { + \if_catcode:w \exp_not:N #1 \c_math_subscript_token + \prg_return_true: \else: \prg_return_false: \fi: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[pTF]{\token_if_space:N} +% Check if token is a space token. We use the constant +% |\c_space_token| for this. +% \begin{macrocode} +\prg_new_conditional:Npnn \token_if_space:N #1 { p , T , F , TF } + { + \if_catcode:w \exp_not:N #1 \c_space_token + \prg_return_true: \else: \prg_return_false: \fi: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[pTF]{\token_if_letter:N} +% Check if token is a letter token. We use the constant +% |\c_letter_token| for this. +% \begin{macrocode} +\prg_new_conditional:Npnn \token_if_letter:N #1 { p , T , F , TF } + { + \if_catcode:w \exp_not:N #1 \c_catcode_letter_token + \prg_return_true: \else: \prg_return_false: \fi: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[pTF]{\token_if_other:N} +% Check if token is an other char token. We use the constant +% |\c_other_char_token| for this. +% \begin{macrocode} +\prg_new_conditional:Npnn \token_if_other:N #1 { p , T , F , TF } + { + \if_catcode:w \exp_not:N #1 \c_catcode_other_token + \prg_return_true: \else: \prg_return_false: \fi: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[pTF]{\token_if_active:N} +% Check if token is an active char token. We use the constant +% |\c_active_char_tl| for this. A technical point is that +% \cs{c_active_char_tl} is in fact a macro expanding to +% |\exp_not:N *|, where |*| is active. +% \begin{macrocode} +\prg_new_conditional:Npnn \token_if_active:N #1 { p , T , F , TF } + { + \if_catcode:w \exp_not:N #1 \c_catcode_active_tl + \prg_return_true: \else: \prg_return_false: \fi: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[pTF]{\token_if_eq_meaning:NN} +% Check if the tokens |#1| and |#2| have same meaning. +% \begin{macrocode} +\prg_new_conditional:Npnn \token_if_eq_meaning:NN #1#2 { p , T , F , TF } + { + \if_meaning:w #1 #2 + \prg_return_true: \else: \prg_return_false: \fi: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[pTF]{\token_if_eq_catcode:NN} +% Check if the tokens |#1| and |#2| have same category code. +% \begin{macrocode} +\prg_new_conditional:Npnn \token_if_eq_catcode:NN #1#2 { p , T , F , TF } + { + \if_catcode:w \exp_not:N #1 \exp_not:N #2 + \prg_return_true: \else: \prg_return_false: \fi: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[pTF]{\token_if_eq_charcode:NN} +% Check if the tokens |#1| and |#2| have same character code. +% \begin{macrocode} +\prg_new_conditional:Npnn \token_if_eq_charcode:NN #1#2 { p , T , F , TF } + { + \if_charcode:w \exp_not:N #1 \exp_not:N #2 + \prg_return_true: \else: \prg_return_false: \fi: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[pTF]{\token_if_macro:N} +% \begin{macro}[aux]{\token_if_macro_p_aux:w} +% When a token is a macro, |\token_to_meaning:N| will always output +% something like |\long macro:#1->#1| so we could naively check to +% see if the meaning contains |->|. However, this can fail the five +% \cs{tex_...mark:D} primitives, whose meaning has the form +% |...mark:|\meta{user material}. The problem is that the +% \meta{user material} can contain |->|. +% +% However, only characters, macros, and marks can contain the colon +% character. The idea is thus to grab until the first |:|, and analyse +% what is left. However, macros can have any combination of |\long|, +% |\protected| or |\outer| (not used in \LaTeX3) before the string +% |macro:|. We thus only select the part of the meaning between +% the first |ma| and the first following |:|. If this string is +% |cro|, then we have a macro. If the string is |rk|, then we have +% a mark. The string can also be |cro parameter character | for a +% colon with a weird category code (namely the usual category code +% of |#|). Otherwise, it is empty. +% +% This relies on the fact that |\long|, |\protected|, |\outer| +% cannot contain |ma|, regardless of the escape character, even if +% the escape character is |m|\ldots{} +% +% Both |ma| and |:| must be of category code $12$ (other), and we +% achieve using the standard lowercasing technique. +% +% \begin{macrocode} +\group_begin: +\char_set_catcode_other:N \M +\char_set_catcode_other:N \A +\char_set_lccode:nn { `\; } { `\: } +\char_set_lccode:nn { `\T } { `\T } +\char_set_lccode:nn { `\F } { `\F } +\tl_to_lowercase:n + { + \group_end: + \prg_new_conditional:Npnn \token_if_macro:N #1 { p , T , F , TF } + { + \exp_after:wN \token_if_macro_p_aux:w + \token_to_meaning:N #1 MA; \q_stop + } + \cs_new_nopar:Npn \token_if_macro_p_aux:w #1 MA #2 ; #3 \q_stop + { + \if_int_compare:w \pdftex_strcmp:D { #2 } { cro } = \c_zero + \prg_return_true: + \else: + \prg_return_false: + \fi: + } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[pTF]{\token_if_cs:N} +% Check if token has same catcode as a control sequence. This +% follows the same pattern as for \cs{token_if_letter:N} \emph{etc.} +% We use |\scan_stop:| for this. +% \begin{macrocode} +\prg_new_conditional:Npnn \token_if_cs:N #1 { p , T , F , TF } + { + \if_catcode:w \exp_not:N #1 \scan_stop: + \prg_return_true: \else: \prg_return_false: \fi: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[pTF]{\token_if_expandable:N} +% Check if token is expandable. We use the fact that \TeX{} will +% temporarily convert |\exp_not:N| \meta{token} into |\scan_stop:| if +% \meta{token} is expandable. +% \begin{macrocode} +\prg_new_conditional:Npnn \token_if_expandable:N #1 { p , T , F , TF } + { + \cs_if_exist:NTF #1 + { + \exp_after:wN \if_meaning:w \exp_not:N #1 #1 + \prg_return_false: \else: \prg_return_true: \fi: + } + { \prg_return_false: } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[pTF]{\token_if_chardef:N,\token_if_mathchardef:N, +% \token_if_long_macro:N, \token_if_protected_macro:N, +% \token_if_protected_long_macro:N, \token_if_dim_register:N, +% \token_if_skip_register:N, \token_if_int_register:N, +% \token_if_toks_register:N} +% \begin{macro}[aux]{ +% \token_if_chardef_p_aux:w, +% \token_if_mathchardef_p_aux:w, +% \token_if_int_register_p_aux:w, +% \token_if_skip_register_p_aux:w, +% \token_if_dim_register_p_aux:w, +% \token_if_toks_register_p_aux:w, +% \token_if_protected_macro_p_aux:w, +% \token_if_long_macro_p_aux:w, +% \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 { `\T } { `\T } + \char_set_lccode:nn { `\F } { `\F } + \char_set_lccode:nn { `\X } { `\n } + \char_set_lccode:nn { `\Y } { `\t } + \char_set_lccode:nn { `\Z } { `\d } + \char_set_lccode:nn { `\? } { `\\ } + \tl_map_inline:nn { \X \Y \Z \M \C \H \A \R \O \U \S \K \I \P \L \G \P \E } + { \char_set_catcode:nn { `#1 } \c_twelve } +% \end{macrocode} +% We convert the token list to lower case and restore the catcode and +% lowercase code changes. +% \begin{macrocode} +\tl_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} + \prg_new_conditional:Npnn \token_if_chardef:N #1 { p , T , F , TF } + { + \exp_after:wN \token_if_chardef_aux:w + \token_to_meaning:N #1 ?CHAR" \q_stop + } + \cs_new_nopar:Npn \token_if_chardef_aux:w #1 ?CHAR" #2 \q_stop + { \tl_if_empty:nTF {#1} { \prg_return_true: } { \prg_return_false: } } +% \end{macrocode} +% +% \begin{macrocode} + \prg_new_conditional:Npnn \token_if_mathchardef:N #1 { p , T , F , TF } + { + \exp_after:wN \token_if_mathchardef_aux:w + \token_to_meaning:N #1 ?MAYHCHAR" \q_stop + } + \cs_new_nopar:Npn \token_if_mathchardef_aux:w #1 ?MAYHCHAR" #2 \q_stop + { \tl_if_empty:nTF {#1} { \prg_return_true: } { \prg_return_false: } } +% \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} + \prg_new_conditional:Npnn \token_if_int_register:N #1 { p , T , F , TF } + { + \if_meaning:w \tex_countdef:D #1 + \prg_return_false: + \else: + \exp_after:wN \token_if_int_register_aux:w + \token_to_meaning:N #1 ?COUXY \q_stop + \fi: + } + \cs_new_nopar:Npn \token_if_int_register_aux:w #1 ?COUXY #2 \q_stop + { \tl_if_empty:nTF {#1} { \prg_return_true: } { \prg_return_false: } } +% \end{macrocode} +% Skip registers are done the same way as the integer registers. +% \begin{macrocode} + \prg_new_conditional:Npnn \token_if_skip_register:N #1 { p , T , F , TF } + { + \if_meaning:w \tex_skipdef:D #1 + \prg_return_false: + \else: + \exp_after:wN \token_if_skip_register_aux:w + \token_to_meaning:N #1?SKIP\q_stop + \fi: + } + \cs_new_nopar:Npn \token_if_skip_register_aux:w #1 ?SKIP #2 \q_stop + { \tl_if_empty:nTF {#1} { \prg_return_true: } { \prg_return_false: } } +% \end{macrocode} +% Dim registers. No news here +% \begin{macrocode} + \prg_new_conditional:Npnn \token_if_dim_register:N #1 { p , T , F , TF } + { + \if_meaning:w \tex_dimendef:D #1 + \c_false_bool + \else: + \exp_after:wN \token_if_dim_register_aux:w + \token_to_meaning:N #1 ?ZIMEX \q_stop + \fi: + } + \cs_new_nopar:Npn \token_if_dim_register_aux:w #1 ?ZIMEX #2 \q_stop + { \tl_if_empty:nTF {#1} { \prg_return_true: } { \prg_return_false: } } +% \end{macrocode} +% Toks registers. +% \begin{macrocode} + \prg_new_conditional:Npnn \token_if_toks_register:N #1 { p , T , F , TF } + { + \if_meaning:w \tex_toksdef:D #1 + \prg_return_false: + \else: + \exp_after:wN \token_if_toks_register_aux:w + \token_to_meaning:N #1 ?YOKS \q_stop + \fi: + } + \cs_new_nopar:Npn \token_if_toks_register_aux:w #1 ?YOKS #2 \q_stop + { \tl_if_empty:nTF {#1} { \prg_return_true: } { \prg_return_false: } } +% \end{macrocode} +% Protected macros. +% \begin{macrocode} + \prg_new_conditional:Npnn \token_if_protected_macro:N #1 + { p , T , F , TF } + { + \exp_after:wN \token_if_protected_macro_aux:w + \token_to_meaning:N #1 ?PROYECYEZ~MACRO \q_stop + } + \cs_new_nopar:Npn \token_if_protected_macro_aux:w + #1 ?PROYECYEZ~MACRO #2 \q_stop + { \tl_if_empty:nTF {#1} { \prg_return_true: } { \prg_return_false: } } +% \end{macrocode} +% Long macros. +% \begin{macrocode} + \prg_new_conditional:Npnn \token_if_long_macro:N #1 { p , T , F , TF } + { + \exp_after:wN \token_if_long_macro_aux:w + \token_to_meaning:N #1 ?LOXG~MACRO \q_stop + } + \cs_new_nopar:Npn \token_if_long_macro_aux:w #1 ?LOXG~MACRO #2 \q_stop + { \tl_if_empty:nTF {#1} { \prg_return_true: } { \prg_return_false: } } +% \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} + \prg_new_conditional:Npnn \token_if_protected_long_macro:N #1 + { p , T , F , TF } + { + \exp_after:wN \token_if_protected_long_macro_aux:w + \token_to_meaning:N #1 ?PROYECYEZ?LOXG~MACRO \q_stop + } + \cs_new_nopar:Npn \token_if_protected_long_macro_aux:w + #1 ?PROYECYEZ?LOXG~MACRO #2 \q_stop + { \tl_if_empty:nTF {#1} { \prg_return_true: } { \prg_return_false: } } +% \end{macrocode} +% Finally the |\tl_to_lowercase:n| ends! +% \begin{macrocode} + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[pTF]{\token_if_primitive:N} +% \begin{macro}[aux]{\token_if_primitive_aux:NNw, +% \token_if_primitive_aux_space:w, +% \token_if_primitive_aux_nullfont:N, +% \token_if_primitive_aux_loop:N, +% \token_if_primitive_auxii:Nw, +% \token_if_primitive_aux_undefined:N} +%^^A See http://groups.google.com/group/comp.text.tex/browse_thread/thread/0a72666873f8753d# +% +% We filter out macros first, because they cause endless trouble later +% otherwise. +% +% Primitives are almost distinguished by the fact that the result +% of \cs{token_to_meaning:N} is formed from letters only. Every other +% token has either a space (e.g., |the letter A|), a digit +% (e.g., |\count123|) or a double quote (e.g., |\char"A|). +% +% Ten exceptions: on the one hand, \cs{c_undefined:D} is not a +% primitive, but its meaning is |undefined|, only letters; +% on the other hand, \cs{tex_space:D}, \cs{tex_italiccorr:D}, +% \cs{tex_hyphen:D}, \cs{tex_firstmark:D}, \cs{tex_topmark:D}, +% \cs{tex_botmark:D}, \cs{tex_splitfirstmark:D}, \cs{tex_splitbotmark:D}, +% and \cs{tex_nullfont:D} are primitives, but have non-letters +% in their meaning. +% +% We start by removing the two first (non-space) characters from +% the meaning. This removes the escape character (which may be +% inexistent depending on \cs{tex_endlinechar:D}), and takes care +% of three of the exceptions: \cs{tex_space:D}, \cs{tex_italiccorr:D} +% and \cs{tex_hyphen:D}, whose meaning is at most two characters. +% This leaves a string terminated by some |:|, and \cs{q_stop}. +% +% The meaning of each one of the five \cs{tex_...mark:D} primitives +% has the form \meta{letters}|:|\meta{user material}. In other words, +% the first non-letter is a colon. We remove everything after the first +% colon. +% +% We are now left with a string, which we must analyze. For primitives, +% it contains only letters. For non-primitives, it contains either +% |"|, or a space, or a digit. Two exceptions remain: \cs{c_undefined:D}, +% which is not a primitive, and \cs{tex_nullfont:D}, which is a primitive. +% +% Spaces cannot be grabbed in an undelimited way, so we check them +% separately. If there is a space, we test for \cs{tex_nullfont:D}. +% Otherwise, we go through characters one by one, and stop at the +% first character less than |`A| (this is not quite a test for +% \enquote{only letters}, but is close enough to work in this context). +% If this first character is |:| then we have a primitive, or +% \cs{c_undefined:D}, and if it is |"| or a digit, then the token +% is not a primitive. +% +% \begin{macrocode} +\tex_chardef:D \c_token_A_int = `A ~ % +\group_begin: +\char_set_catcode_other:N \; +\char_set_lccode:nn { `\; } { `\: } +\char_set_lccode:nn { `\T } { `\T } +\char_set_lccode:nn { `\F } { `\F } +\tl_to_lowercase:n { + \group_end: + \prg_new_conditional:Npnn \token_if_primitive:N #1 { p , T , F , TF } + { + \token_if_macro:NTF #1 + \prg_return_false: + { + \exp_after:wN \token_if_primitive_aux:NNw + \token_to_meaning:N #1 ; ; ; \q_stop #1 + } + } + \cs_new_nopar:Npn \token_if_primitive_aux:NNw #1#2 #3 ; #4 \q_stop + { + \tl_if_empty:oTF { \token_if_primitive_aux_space:w #3 ~ } + { \token_if_primitive_aux_loop:N #3 ; \q_stop } + { \token_if_primitive_aux_nullfont:N } + } +} +\cs_new_nopar:Npn \token_if_primitive_aux_space:w #1 ~ { } +\cs_new:Npn \token_if_primitive_aux_nullfont:N #1 + { + \if_meaning:w \tex_nullfont:D #1 + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +\cs_new_nopar:Npn \token_if_primitive_aux_loop:N #1 + { + \if_num:w `#1 < \c_token_A_int % + \exp_after:wN \token_if_primitive_auxii:Nw + \exp_after:wN #1 + \else: + \exp_after:wN \token_if_primitive_aux_loop:N + \fi: + } +\cs_new_nopar:Npn \token_if_primitive_auxii:Nw #1 #2 \q_stop + { + \if:w : #1 + \exp_after:wN \token_if_primitive_aux_undefined:N + \else: + \prg_return_false: + \exp_after:wN \use_none:n + \fi: + } +\cs_new:Npn \token_if_primitive_aux_undefined:N #1 + { + \if_cs_exist:N #1 + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Peeking ahead at the next token} +% +% Peeking ahead is implemented using a two part mechanism. The +% outer level provides a defined interface to the lower level material. +% This allows a large amount of code to be shared. There are four +% 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} +% +% \begin{variable}{\l_peek_token} +% \begin{variable}{\g_peek_token} +% Storage tokens which are publicly documented: the token peeked. +% \begin{macrocode} +\cs_new_eq:NN \l_peek_token ? +\cs_new_eq:NN \g_peek_token ? +% \end{macrocode} +% \end{variable} +% \end{variable} +% +% \begin{variable}{\l_peek_search_token} +% The token to search for as an implicit token: +% \emph{cf.}~\cs{l_peek_search_tl}. +% \begin{macrocode} +\cs_new_eq:NN \l_peek_search_token ? +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_peek_search_tl} +% The token to search for as an explicit token: +% \emph{cf.}~\cs{l_peek_search_token}. +% \begin{macrocode} +\cs_new_nopar:Npn \l_peek_search_tl { } +% \end{macrocode} +% \end{variable} +% +% \begin{macro}[aux] +% {\peek_true:w, \peek_true_aux:w, \peek_false:w, \peek_tmp:w} +% Functions used by the branching and space-stripping code. +% \begin{macrocode} +\cs_new_nopar:Npn \peek_true:w { } +\cs_new_nopar:Npn \peek_true_aux:w { } +\cs_new_nopar:Npn \peek_false:w { } +\cs_new:Npn \peek_tmp:w { } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\peek_after:Nw} +% \begin{macro}{\peek_after:Nw} +% Simple wrappers for \cs{tex_futurelet:D}: no arguments absorbed +% here. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \peek_after:Nw + { \tex_futurelet:D \l_peek_token } +\cs_new_protected_nopar:Npn \peek_gafter:Nw + { \pref_global:D \tex_futurelet:D \g_peek_token } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[aux]{\peek_true_remove:w} +% A function to remove the next token and then regain control. +% \begin{macrocode} +\cs_new_protected:Npn \peek_true_remove:w + { + \group_align_safe_end: + \tex_afterassignment:D \peek_true_aux:w + \cs_set_eq:NN \peek_tmp:w + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[TF]{\peek_token_generic:NN} +% The generic function stores the test token in both implicit and +% explicit modes, and the \texttt{true} and \texttt{false} code as +% token lists, more or less. The two branches have to be absorbed here +% as the input stream needs to be cleared for the peek function itself. +% \begin{macrocode} +\cs_new_protected:Npn \peek_token_generic:NNTF #1#2#3#4 + { + \cs_set_eq:NN \l_peek_search_token #2 + \tl_set:Nn \l_peek_search_tl {#2} + \cs_set_nopar:Npx \peek_true:w + { + \exp_not:N \group_align_safe_end: + \exp_not:n {#3} + } + \cs_set_nopar:Npx \peek_false:w + { + \exp_not:N \group_align_safe_end: + \exp_not:n {#4} + } + \group_align_safe_begin: + \peek_after:Nw #1 + } +\cs_new_protected:Npn \peek_token_generic:NNT #1#2#3 + { \peek_token_generic:NNTF #1 #2 {#3} { } } +\cs_new_protected:Npn \peek_token_generic:NNF #1#2#3 + { \peek_token_generic:NNTF #1 #2 { } {#3} } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[TF]{\peek_token_remove_generic:NN} +% For token removal there needs to be a call to the auxiliary +% function which does the work. +% \begin{macrocode} +\cs_new_protected:Npn \peek_token_remove_generic:NNTF #1#2#3#4 + { + \cs_set_eq:NN \l_peek_search_token #2 + \tl_set:Nn \l_peek_search_tl {#2} + \cs_set_eq:NN \peek_true:w \peek_true_remove:w + \cs_set_nopar:Npx \peek_true_aux:w { \exp_not:n {#3} } + \cs_set_nopar:Npx \peek_false:w + { + \exp_not:N \group_align_safe_end: + \exp_not:n {#4} + } + \group_align_safe_begin: + \peek_after:Nw #1 + } +\cs_new_protected:Npn \peek_token_remove_generic:NNT #1#2#3 + { \peek_token_remove_generic:NNTF #1 #2 {#3} { } } +\cs_new_protected:Npn \peek_token_remove_generic:NNF #1#2#3 + { \peek_token_remove_generic:NNTF #1 #2 { } {#3} } +% \end{macrocode} +% \end{macro} +% +% \begin{macro} +% {\peek_execute_branches_catcode:, \peek_execute_branches_meaning:} +% The category code and meaning tests are straight forward. +% \begin{macrocode} +\cs_new_nopar:Npn \peek_execute_branches_catcode: + { + \if_catcode:w + \exp_not:N \l_peek_token \exp_not:N \l_peek_search_token + \exp_after:wN \peek_true:w + \else: + \exp_after:wN \peek_false:w + \fi: + } +\cs_new_nopar:Npn \peek_execute_branches_meaning: + { + \if_meaning:w \l_peek_token \l_peek_search_token + \exp_after:wN \peek_true:w + \else: + \exp_after:wN \peek_false:w + \fi: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\peek_execute_branches_charcode:} +% \begin{macro}[aux]{\peek_execute_branches_charcode:NN} +% First the character code test there is a need to worry about \TeX{} +% grabbing brace group or skipping spaces. These are all tested for +% using a category code check before grabbing what must be a real +% single token and doing the comparison. +% \begin{macrocode} +\cs_new_nopar:Npn \peek_execute_branches_charcode: + { + \bool_if:nTF + { + \token_if_eq_catcode_p:NN \l_peek_token \c_group_begin_token + || \token_if_eq_catcode_p:NN \l_peek_token \c_group_end_token + || \token_if_eq_meaning_p:NN \l_peek_token \c_space_token + } + { \peek_false:w } + { + \exp_after:wN \peek_execute_branches_charcode_aux:NN + \l_peek_search_tl + } + } +\cs_new:Npn \peek_execute_branches_charcode_aux:NN #1#2 + { + \if:w \exp_not:N #1 \exp_not:N #2 + \exp_after:wN \peek_true:w + \else: + \exp_after:wN \peek_false:w + \fi: + #2 + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\peek_ignore_spaces_execute_branches:} +% \begin{macro}[aux]{\peek_ignore_spaces_execute_branches_aux:} +% This function removes one token at a time with a mechanism that can +% be applied to things other than spaces. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \peek_ignore_spaces_execute_branches: + { + \token_if_eq_meaning:NNTF \l_peek_token \c_space_token + { + \tex_afterassignment:D \peek_ignore_spaces_execute_branches_aux: + \cs_set_eq:NN \peek_tmp:w + } + { \peek_execute_branches: } + } +\cs_new_protected_nopar:Npn \peek_ignore_spaces_execute_branches_aux: + { \peek_after:Nw \peek_ignore_spaces_execute_branches: } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[aux]{\peek_def:nnnn} +% \begin{macro}[aux]{\peek_def_aux:nnnnn} +% The public functions themselves cannot be defined using +% \cs{prg_set_conditional:Npnn} and so a couple of auxiliary functions +% are used. As a result, everything is done inside a group. As a result +% things are a bit complicated. +% \begin{macrocode} +\group_begin: + \cs_set_nopar:Npn \peek_def:nnnn #1#2#3#4 + { + \peek_def_aux:nnnnn {#1} {#2} {#3} {#4} { TF } + \peek_def_aux:nnnnn {#1} {#2} {#3} {#4} { T } + \peek_def_aux:nnnnn {#1} {#2} {#3} {#4} { F } + } + \cs_set_nopar:Npn \peek_def_aux:nnnnn #1#2#3#4#5 + { + \cs_gset_nopar:cpx { #1 #5 } + { + \tl_if_empty:nF {#2} + { \exp_not:n { \cs_set_eq:NN \peek_execute_branches: #2 } } + \exp_not:c { #3 #5 } + \exp_not:n {#4} + } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \begin{macro}[TF] +% { +% \peek_catcode:N, \peek_catcode_ignore_spaces:N, +% \peek_catcode_remove:N, \peek_catcode_remove_ignore_spaces:N +% } +% With everything in place the definitions can take place. First for +% category codes. +% \begin{macrocode} + \peek_def:nnnn { peek_catcode:N } + { } + { peek_token_generic:NN } + { \peek_execute_branches_catcode: } + \peek_def:nnnn { peek_catcode_ignore_spaces:N } + { \peek_execute_branches_catcode: } + { peek_token_generic:NN } + { \peek_ignore_spaces_execute_branches: } + \peek_def:nnnn { peek_catcode_remove:N } + { } + { peek_token_remove_generic:NN } + { \peek_execute_branches_catcode: } + \peek_def:nnnn { peek_catcode_remove_ignore_spaces:N } + { \peek_execute_branches_catcode: } + { peek_token_remove_generic:NN } + { \peek_ignore_spaces_execute_branches: } +% \end{macrocode} +% \end{macro} +% \begin{macro}[TF] +% { +% \peek_charcode:N, \peek_charcode_ignore_spaces:N, +% \peek_charcode_remove:N, \peek_charcode_remove_ignore_spaces:N +% } +% Then for character codes. +% \begin{macrocode} + \peek_def:nnnn { peek_charcode:N } + { } + { peek_token_generic:NN } + { \peek_execute_branches_charcode: } + \peek_def:nnnn { peek_charcode_ignore_spaces:N } + { \peek_execute_branches_charcode: } + { peek_token_generic:NN } + { \peek_ignore_spaces_execute_branches: } + \peek_def:nnnn { peek_charcode_remove:N } + { } + { peek_token_remove_generic:NN } + { \peek_execute_branches_charcode: } + \peek_def:nnnn { peek_charcode_remove_ignore_spaces:N } + { \peek_execute_branches_charcode: } + { peek_token_remove_generic:NN } + { \peek_ignore_spaces_execute_branches: } +% \end{macrocode} +% \end{macro} +% \begin{macro}[TF] +% { +% \peek_meaning:N, \peek_meaning_ignore_spaces:N, +% \peek_meaning_remove:N, \peek_meaning_remove_ignore_spaces:N +% } +% Finally for meaning, with the group closed to remove the temporary +% definition functions. +% \begin{macrocode} + \peek_def:nnnn { peek_meaning:N } + { } + { peek_token_generic:NN } + { \peek_execute_branches_meaning: } + \peek_def:nnnn { peek_meaning_ignore_spaces:N } + { \peek_execute_branches_meaning: } + { peek_token_generic:NN } + { \peek_ignore_spaces_execute_branches: } + \peek_def:nnnn { peek_meaning_remove:N } + { } + { peek_token_remove_generic:NN } + { \peek_execute_branches_meaning: } + \peek_def:nnnn { peek_meaning_remove_ignore_spaces:N } + { \peek_execute_branches_meaning: } + { peek_token_remove_generic:NN } + { \peek_ignore_spaces_execute_branches: } +\group_end: +% \end{macrocode} +% \end{macro} +% +% \subsection{Decomposing a macro definition} +% +% \begin{macro}{\token_get_prefix_spec:N} +% \begin{macro}{\token_get_arg_spec:N} +% \begin{macro}{\token_get_replacement_spec:N} +% \begin{macro}[aux]{\token_get_prefix_arg_replacement_aux:wN} +% 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} +\exp_args:Nno \use:nn + { \cs_new_nopar:Npn \token_get_prefix_arg_replacement_aux:wN #1 } + { \tl_to_str:n { macro : } #2 -> #3 \q_stop #4 } + { #4 {#1} {#2} {#3} } +\cs_new:Npn \token_get_prefix_spec:N #1 + { + \token_if_macro:NTF #1 + { + \exp_after:wN \token_get_prefix_arg_replacement_aux:wN + \token_to_meaning:N #1 \q_stop \use_i:nnn + } + { \scan_stop: } + } +\cs_new:Npn \token_get_arg_spec:N #1 + { + \token_if_macro:NTF #1 + { + \exp_after:wN \token_get_prefix_arg_replacement_aux:wN + \token_to_meaning:N #1 \q_stop \use_ii:nnn + } + { \scan_stop: } + } +\cs_new:Npn \token_get_replacement_spec:N #1 + { + \token_if_macro:NTF #1 + { + \exp_after:wN \token_get_prefix_arg_replacement_aux:wN + \token_to_meaning:N #1 \q_stop \use_iii:nnn + } + { \scan_stop: } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Experimental token functions} +% +% \begin{macro}{\char_active_set:Npn,\char_active_set:Npx} +% \begin{macro}{\char_active_set:Npn,\char_active_set:Npx} +% \begin{macro}{\char_active_set_eq:NN,\char_active_gset_eq:NN} +% \begin{macrocode} +\group_begin: + \char_set_catcode_active:N \^^@ + \cs_set:Npn \char_tmp:NN #1#2 + { + \cs_new:Npn #1 ##1 + { + \char_set_catcode_active:n { `##1 } + \group_begin: + \char_set_lccode:nn { `\^^@ } { `##1 } + \tl_to_lowercase:n { \group_end: #2 ^^@ } + } + } + \char_tmp:NN \char_active_set:Npn \cs_set:Npn + \char_tmp:NN \char_active_set:Npx \cs_set:Npx + \char_tmp:NN \char_active_gset:Npn \cs_gset:Npn + \char_tmp:NN \char_active_gset:Npx \cs_gset:Npx + \char_tmp:NN \char_active_set_eq:NN \cs_set_eq:NN + \char_tmp:NN \char_active_gset_eq:NN \cs_gset_eq:NN +\group_end: +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Deprecated functions} +% +% Deprecated on 2011-05-27, for removal by 2011-08-31. +% +% \begin{macro}{\char_set_catcode:w} +% \begin{macro}{\char_set_mathcode:w} +% \begin{macro}{\char_set_lccode:w} +% \begin{macro}{\char_set_uccode:w} +% \begin{macro}{\char_set_sfcode:w} +% Primitives renamed. +% \begin{macrocode} +\cs_new_eq:NN \char_set_catcode:w \tex_catcode:D +\cs_new_eq:NN \char_set_mathcode:w \tex_mathcode:D +\cs_new_eq:NN \char_set_lccode:w \tex_lccode:D +\cs_new_eq:NN \char_set_uccode:w \tex_uccode:D +\cs_new_eq:NN \char_set_sfcode:w \tex_sfcode:D +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\char_value_catcode:w} +% \begin{macro}{\char_show_value_catcode:w} +% \begin{macro}{\char_value_mathcode:w} +% \begin{macro}{\char_show_value_mathcode:w} +% \begin{macro}{\char_value_lccode:w} +% \begin{macro}{\char_show_value_lccode:w} +% \begin{macro}{\char_value_uccode:w} +% \begin{macro}{\char_show_value_uccode:w} +% \begin{macro}{\char_value_sfcode:w} +% \begin{macro}{\char_show_value_sfcode:w} +% More |w| functions we should not have. +% \begin{macrocode} +\cs_new_nopar:Npn \char_value_catcode:w { \tex_the:D \char_set_catcode:w } +\cs_new_nopar:Npn \char_show_value_catcode:w + { \tex_showthe:D \char_set_catcode:w } +\cs_new_nopar:Npn \char_value_mathcode:w { \tex_the:D \char_set_mathcode:w } +\cs_new_nopar:Npn \char_show_value_mathcode:w + { \tex_showthe:D \char_set_mathcode:w } +\cs_new_nopar:Npn \char_value_lccode:w { \tex_the:D \char_set_lccode:w } +\cs_new_nopar:Npn \char_show_value_lccode:w + { \tex_showthe:D \char_set_lccode:w } +\cs_new_nopar:Npn \char_value_uccode:w { \tex_the:D \char_set_uccode:w } +\cs_new_nopar:Npn \char_show_value_uccode:w + { \tex_showthe:D \char_set_uccode:w } +\cs_new_nopar:Npn \char_value_sfcode:w { \tex_the:D \char_set_sfcode:w } +\cs_new_nopar:Npn \char_show_value_sfcode:w + { \tex_showthe:D \char_set_sfcode:w } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\peek_after:NN} +% \begin{macro}{\peek_gafter:NN} +% The second argument here must be |w|. +% \begin{macrocode} +\cs_new_eq:NN \peek_after:NN \peek_after:Nw +\cs_new_eq:NN \peek_gafter:NN \peek_gafter:Nw +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% Functions deprecated 2011-05-28 for removal by 2011-08-31. +% +% \begin{macro}{\c_alignment_tab_token} +% \begin{macro}{\c_math_shift_token} +% \begin{macro}{\c_letter_token} +% \begin{macro}{\c_other_char_token} +% \begin{macrocode} +\cs_new_eq:NN \c_alignment_tab_token \c_alignment_token +\cs_new_eq:NN \c_math_shift_token \c_math_toggle_token +\cs_new_eq:NN \c_letter_token \c_catcode_letter_token +\cs_new_eq:NN \c_other_char_token \c_catcode_other_token +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\c_active_char_token} +% An odd one: this was never a |token|! +% \begin{macrocode} +\cs_new_eq:NN \c_active_char_token \c_catcode_active_tl +% \end{macrocode} +% \end{macro} +% +% \begin{macro} +% { +% \char_make_escape:N , +% \char_make_group_begin:N , +% \char_make_group_end:N , +% \char_make_math_toggle:N , +% \char_make_alignment:N , +% \char_make_end_line:N , +% \char_make_parameter:N , +% \char_make_math_superscript:N , +% \char_make_math_subscript:N , +% \char_make_ignore:N , +% \char_make_space:N , +% \char_make_letter:N , +% \char_make_other:N , +% \char_make_active:N , +% \char_make_comment:N , +% \char_make_invalid:N +% } +% \begin{macro} +% { +% \char_make_escape:n , +% \char_make_group_begin:n , +% \char_make_group_end:n , +% \char_make_math_toggle:n , +% \char_make_alignment:n , +% \char_make_end_line:n , +% \char_make_parameter:n , +% \char_make_math_superscript:n , +% \char_make_math_subscript:n , +% \char_make_ignore:n , +% \char_make_space:n , +% \char_make_letter:n , +% \char_make_other:n , +% \char_make_active:n , +% \char_make_comment:n , +% \char_make_invalid:n +% } +% Two renames in one block! +% \begin{macrocode} +\cs_new_eq:NN \char_make_escape:N \char_set_catcode_escape:N +\cs_new_eq:NN \char_make_begin_group:N \char_set_catcode_group_begin:N +\cs_new_eq:NN \char_make_end_group:N \char_set_catcode_group_end:N +\cs_new_eq:NN \char_make_math_shift:N \char_set_catcode_math_toggle:N +\cs_new_eq:NN \char_make_alignment_tab:N \char_set_catcode_alignment:N +\cs_new_eq:NN \char_make_end_line:N \char_set_catcode_end_line:N +\cs_new_eq:NN \char_make_parameter:N \char_set_catcode_parameter:N +\cs_new_eq:NN \char_make_math_superscript:N + \char_set_catcode_math_superscript:N +\cs_new_eq:NN \char_make_math_subscript:N + \char_set_catcode_math_subscript:N +\cs_new_eq:NN \char_make_ignore:N \char_set_catcode_ignore:N +\cs_new_eq:NN \char_make_space:N \char_set_catcode_space:N +\cs_new_eq:NN \char_make_letter:N \char_set_catcode_letter:N +\cs_new_eq:NN \char_make_other:N \char_set_catcode_other:N +\cs_new_eq:NN \char_make_active:N \char_set_catcode_active:N +\cs_new_eq:NN \char_make_comment:N \char_set_catcode_comment:N +\cs_new_eq:NN \char_make_invalid:N \char_set_catcode_invalid:N +\cs_new_eq:NN \char_make_escape:n \char_set_catcode_escape:n +\cs_new_eq:NN \char_make_begin_group:n \char_set_catcode_group_begin:n +\cs_new_eq:NN \char_make_end_group:n \char_set_catcode_group_end:n +\cs_new_eq:NN \char_make_math_shift:n \char_set_catcode_math_toggle:n +\cs_new_eq:NN \char_make_alignment_tab:n \char_set_catcode_alignment:n +\cs_new_eq:NN \char_make_end_line:n \char_set_catcode_end_line:n +\cs_new_eq:NN \char_make_parameter:n \char_set_catcode_parameter:n +\cs_new_eq:NN \char_make_math_superscript:n + \char_set_catcode_math_superscript:n +\cs_new_eq:NN \char_make_math_subscript:n + \char_set_catcode_math_subscript:n +\cs_new_eq:NN \char_make_ignore:n \char_set_catcode_ignore:n +\cs_new_eq:NN \char_make_space:n \char_set_catcode_space:n +\cs_new_eq:NN \char_make_letter:n \char_set_catcode_letter:n +\cs_new_eq:NN \char_make_other:n \char_set_catcode_other:n +\cs_new_eq:NN \char_make_active:n \char_set_catcode_active:n +\cs_new_eq:NN \char_make_comment:n \char_set_catcode_comment:n +\cs_new_eq:NN \char_make_invalid:n \char_set_catcode_invalid:n +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[pTF]{\token_if_alignment_tab:N} +% \begin{macro}[pTF]{\token_if_math_shift:N} +% \begin{macro}[pTF]{\token_if_other_char:N} +% \begin{macro}[pTF]{\token_if_active_char:N} +% \begin{macrocode} +\cs_new_eq:NN \token_if_alignment_tab_p:N \token_if_alignment_p:N +\cs_new_eq:NN \token_if_alignment_tab:NT \token_if_alignment:NT +\cs_new_eq:NN \token_if_alignment_tab:NF \token_if_alignment:NF +\cs_new_eq:NN \token_if_alignment_tab:NTF \token_if_alignment:NTF +\cs_new_eq:NN \token_if_math_shift_p:N \token_if_math_toggle_p:N +\cs_new_eq:NN \token_if_math_shift:NT \token_if_math_toggle:NT +\cs_new_eq:NN \token_if_math_shift:NF \token_if_math_toggle:NF +\cs_new_eq:NN \token_if_math_shift:NTF \token_if_math_toggle:NTF +\cs_new_eq:NN \token_if_other_char_p:N \token_if_other_p:N +\cs_new_eq:NN \token_if_other_char:NT \token_if_other:NT +\cs_new_eq:NN \token_if_other_char:NF \token_if_other:NF +\cs_new_eq:NN \token_if_other_char:NTF \token_if_other:NTF +\cs_new_eq:NN \token_if_active_char_p:N \token_if_active_p:N +\cs_new_eq:NN \token_if_active_char:NT \token_if_active:NT +\cs_new_eq:NN \token_if_active_char:NF \token_if_active:NF +\cs_new_eq:NN \token_if_active_char:NTF \token_if_active:NTF +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macrocode} +%</initex|package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintIndex diff --git a/Master/texmf-dist/source/latex/l3kernel/l3toks.dtx b/Master/texmf-dist/source/latex/l3kernel/l3toks.dtx new file mode 100644 index 00000000000..62824848afc --- /dev/null +++ b/Master/texmf-dist/source/latex/l3kernel/l3toks.dtx @@ -0,0 +1,548 @@ +% \iffalse meta-comment +% +%% File: l3toks.dtx Copyright (C) 1990-2011 The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +% +%<*driver|package> +\RequirePackage{l3names} +\GetIdInfo$Id: l3toks.dtx 2478 2011-06-19 21:34:23Z joseph $ + {L3 Experimental token registers} +%</driver|package> +%<*driver> +\documentclass[full]{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{^^A +% The \pkg{l3toks} package\\ Token registers^^A +% \thanks{This file describes v\ExplFileVersion, +% last revised \ExplFileDate.}^^A +% } +% +% \author{^^A +% The \LaTeX3 Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% +% \date{Released \ExplFileDate} +% +% \maketitle +% +% \begin{documentation} +% +% \textbf{THIS ENTIRE MODULE IS DEPRECIATED: DO NOT USE \cs{TOKS_\ldots} +% FUNCTIONS} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{l3toks} implementation} +% +% We start by ensuring that the required packages are loaded. +% \begin{macrocode} +%<*package> +\ProvidesExplPackage + {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +\package_check_loaded_expl: +%</package> +%<*initex|package> +% \end{macrocode} +% +% \subsection{Allocation and use} +% +% \begin{macro}{\toks_new:N,\toks_new:c} +% Allocates a new token register. +% \begin{macrocode} +%<*initex> +\alloc_new:nnnN {toks} \c_zero \c_max_register_int \tex_toksdef:D +%</initex> +% \end{macrocode} +% +% \begin{macrocode} +%<*package> +\cs_new_protected_nopar:Npn \toks_new:N #1 { + \chk_if_free_cs:N #1 + \newtoks #1 +} +%</package> +% \end{macrocode} +% +% \begin{macrocode} +\cs_generate_variant:Nn \toks_new:N {c} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\toks_use:N} +% \begin{macro}{\toks_use:c} +% This function returns the contents of a token register. +% \begin{macrocode} +\cs_new_eq:NN \toks_use:N \tex_the:D +\cs_generate_variant:Nn \toks_use:N {c} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\toks_set:Nn} +% \begin{macro}{\toks_set:NV} +% \begin{macro}{\toks_set:Nv} +% \begin{macro}{\toks_set:No} +% \begin{macro}{\toks_set:Nx} +% \begin{macro}{\toks_set:Nf} +% \begin{macro}{\toks_set:cn} +% \begin{macro}{\toks_set:co} +% \begin{macro}{\toks_set:cV} +% \begin{macro}{\toks_set:cv} +% \begin{macro}{\toks_set:cx} +% \begin{macro}{\toks_set:cf} +% |\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. +% \begin{macrocode} +%<*check> +\cs_new_protected_nopar:Npn \toks_set:Nn #1 { \chk_local:N #1 #1 } +\cs_generate_variant:Nn \toks_set:Nn {No,Nf} +%</check> +% \end{macrocode} +% If we don't check if \m{toks} is a local register then the +% |\toks_set:Nn| function has nothing to do. +% We implement |\toks_set:No|/|d|/|f| by hand when not checking because this +% is going to be used \emph{extensively} in keyval processing! +% TODO: (Will) Can we get some numbers published on how necessary this is? +% On the other hand I'm happy to believe Morten |:)| +% \begin{macrocode} +%<*!check> +\cs_new_eq:NN \toks_set:Nn \prg_do_nothing: +\cs_new_protected:Npn \toks_set:NV #1#2 { + #1 \exp_after:wN { \int_to_roman:w -`0 \exp_eval_register:N #2 } +} +\cs_new_protected:Npn \toks_set:Nv #1#2 { + #1 \exp_after:wN { \int_to_roman:w -`0 \exp_eval_register:c {#2} } +} +\cs_new_protected:Npn \toks_set:No #1#2 { #1 \exp_after:wN {#2} } +\cs_new_protected:Npn \toks_set:Nf #1#2 { + #1 \exp_after:wN { \int_to_roman:w -`0#2 } +} +%</!check> +% \end{macrocode} +% +% \begin{macrocode} +\cs_generate_variant:Nn \toks_set:Nn {Nx,cn,cV,cv,co,cx,cf} +% \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}{\toks_gset:Nn} +% \begin{macro}{\toks_gset:NV} +% \begin{macro}{\toks_gset:No} +% \begin{macro}{\toks_gset:Nx} +% \begin{macro}{\toks_gset:cn} +% \begin{macro}{\toks_gset:cV} +% \begin{macro}{\toks_gset:co} +% \begin{macro}{\toks_gset:cx} +% These functions are the global variants of the above. +% \begin{macrocode} +%<check>\cs_new_protected_nopar:Npn \toks_gset:Nn #1 { \chk_global:N #1 \pref_global:D #1 } +%<!check>\cs_new_eq:NN \toks_gset:Nn \pref_global:D +\cs_generate_variant:Nn \toks_gset:Nn {NV,No,Nx,cn,cV,co,cx} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \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} +%<*check> +\cs_new_protected_nopar:Npn\toks_set_eq:NN #1#2 { + \chk_local:N #1 + \chk_var_or_const:N #2 + #1 #2 +} +\cs_new_protected_nopar:Npn\toks_gset_eq:NN #1#2 { + \chk_global:N #1 + \chk_var_or_const:N #2 + \pref_global:D #1 #2 +} +%</check> +%<*!check> +\cs_new_eq:NN \toks_set_eq:NN \prg_do_nothing: +\cs_new_eq:NN \toks_gset_eq:NN \pref_global:D +%</!check> +\cs_generate_variant:Nn \toks_set_eq:NN {Nc,cN,cc} +\cs_generate_variant:Nn \toks_gset_eq:NN {Nc,cN,cc} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\toks_clear:N,\toks_gclear:N,\toks_clear:c,\toks_gclear:c} +% These functions clear a token register, either locally or globally. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \toks_clear:N #1 { + #1\c_empty_toks +%<check>\chk_local_or_pref_global:N #1 +} +% \end{macrocode} +% +% \begin{macrocode} +\cs_new_protected_nopar:Npn \toks_gclear:N { +%<check> \pref_global_chk: +%<!check> \pref_global:D + \toks_clear:N +} +% \end{macrocode} +% +% \begin{macrocode} +\cs_generate_variant:Nn \toks_clear:N {c} +\cs_generate_variant:Nn \toks_gclear:N {c} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\toks_use_clear:N} +% \begin{macro}{\toks_use_clear:c} +% \begin{macro}{\toks_use_gclear:N} +% \begin{macro}{\toks_use_gclear:c} +% These functions clear a token register (locally or globally) after +% returning the contents. +% +% They make sure that clearing the register does not +% interfere with following tokens. In other words, the contents of +% the register might operate on what follows in the input stream. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \toks_use_clear:N #1 { + \exp_last_unbraced:NNV \toks_clear:N #1 #1 +} +% \end{macrocode} +% +% \begin{macrocode} +\cs_new_protected_nopar:Npn \toks_use_gclear:N { +%<check> \pref_global_chk: +%<!check> \pref_global:D + \toks_use_clear:N +} +% \end{macrocode} +% +% \begin{macrocode} +\cs_generate_variant:Nn \toks_use_clear:N {c} +\cs_generate_variant:Nn \toks_use_gclear:N {c} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\toks_show:N} +% \begin{macro}{\toks_show:c} +% This function shows the contents of a token register on the terminal. +% \begin{macrocode} +\cs_new_eq:NN \toks_show:N \kernel_register_show:N +\cs_generate_variant:Nn \toks_show:N {c} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Adding to token registers' contents} +% +% \begin{macro}{\toks_put_left:Nn} +% \begin{macro}{\toks_put_left:NV} +% \begin{macro}{\toks_put_left:No} +% \begin{macro}{\toks_put_left:Nx} +% \begin{macro}{\toks_put_left:cn} +% \begin{macro}{\toks_put_left:cV} +% \begin{macro}{\toks_put_left:co} +% \begin{macro}{\toks_gput_left:Nn} +% \begin{macro}{\toks_gput_left:NV} +% \begin{macro}{\toks_gput_left:No} +% \begin{macro}{\toks_gput_left:Nx} +% \begin{macro}{\toks_gput_left:cn} +% \begin{macro}{\toks_gput_left:cV} +% \begin{macro}{\toks_gput_left:co} +% \begin{macro}[aux]{\toks_put_left_aux:w} +% |\toks_put_left:Nn |\meta{toks}\meta{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} +\cs_new_protected_nopar:Npn \toks_put_left:Nn #1 { + \exp_after:wN \toks_put_left_aux:w \exp_after:wN \q_nil + \toks_use:N #1 \q_stop #1 +} +% \end{macrocode} +% +% \begin{macrocode} +\cs_generate_variant:Nn \toks_put_left:Nn {NV,No,Nx,cn,co,cV} +% \end{macrocode} +% +% \begin{macrocode} +\cs_new_protected_nopar:Npn \toks_gput_left:Nn { +%<check> \pref_global_chk: +%<!check> \pref_global:D + \toks_put_left:Nn +} +% \end{macrocode} +% +% \begin{macrocode} +\cs_generate_variant:Nn \toks_gput_left:Nn {NV,No,Nx,cn,cV,co} +% \end{macrocode} +% A helper function for |\toks_put_left:Nn|. Its arguments are +% subsequently the tokens of \meta{stuff\/}, the token register +% \meta{toks} and the current contents of \meta{toks}. We make sure to +% remove the token we inserted earlier. +% \begin{macrocode} +\cs_new:Npn \toks_put_left_aux:w #1\q_stop #2#3 { + #2 \exp_after:wN { \use_i:nn {#3} #1 } +%<check> \chk_local_or_pref_global:N #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} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\toks_put_right:Nn} +% \begin{macro}{\toks_put_right:NV} +% \begin{macro}{\toks_put_right:No} +% \begin{macro}{\toks_put_right:Nx} +% \begin{macro}{\toks_put_right:cn} +% \begin{macro}{\toks_put_right:cV} +% \begin{macro}{\toks_put_right:co} +% \begin{macro}{\toks_gput_right:Nn} +% \begin{macro}{\toks_gput_right:NV} +% \begin{macro}{\toks_gput_right:No} +% \begin{macro}{\toks_gput_right:Nx} +% \begin{macro}{\toks_gput_right:cn} +% \begin{macro}{\toks_gput_right:cV} +% \begin{macro}{\toks_gput_right:co} +% These macros add a list of tokens to the right of a token register. +% \begin{macrocode} +\cs_new_protected:Npn \toks_put_right:Nn #1#2 { + #1 \exp_after:wN { \toks_use:N #1 #2 } +%<check> \chk_local_or_pref_global:N #1 +} +% \end{macrocode} +% +% \begin{macrocode} +\cs_new_protected_nopar:Npn \toks_gput_right:Nn { +%<check> \pref_global_chk: +%<!check> \pref_global:D + \toks_put_right:Nn +} +% \end{macrocode} +% A couple done by hand for speed. +% \begin{macrocode} +%<check>\cs_generate_variant:Nn \toks_put_right:Nn {No} +%<*!check> +\cs_new_protected:Npn \toks_put_right:NV #1#2 { + #1 \exp_after:wN \exp_after:wN \exp_after:wN { + \exp_after:wN \toks_use:N \exp_after:wN #1 + \int_to_roman:w -`0 \exp_eval_register:N #2 + } +} +\cs_new_protected:Npn \toks_put_right:No #1#2 { + #1 \exp_after:wN \exp_after:wN \exp_after:wN { + \exp_after:wN \toks_use:N \exp_after:wN #1 #2 + } +} +%</!check> +\cs_generate_variant:Nn \toks_put_right:Nn {Nx,cn,cV,co} +\cs_generate_variant:Nn \toks_gput_right:Nn {NV,No,Nx,cn,cV,co} +% \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} +% +% \begin{macro}{\toks_put_right:Nf} +% 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>\cs_generate_variant:Nn \toks_put_right:Nn {Nf} +%<*!check> +\cs_new_protected:Npn \toks_put_right:Nf #1#2 { + #1 \exp_after:wN \exp_after:wN \exp_after:wN { + \exp_after:wN \toks_use:N \exp_after:wN #1 \int_to_roman:w -`0#2 + } +} +%</!check> +% \end{macrocode} +% \end{macro} +% +% \subsection{Predicates and conditionals} +% +% \begin{macro}{\toks_if_empty_p:N,\toks_if_empty_p:c} +% \begin{macro}[TF]{\toks_if_empty:N,\toks_if_empty:c} +% |\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} +\prg_new_conditional:Nnn \toks_if_empty:N {p,TF,T,F} { + \tl_if_empty:VTF #1 {\prg_return_true:} {\prg_return_false:} +} +% \end{macrocode} +% \begin{macrocode} +\cs_generate_variant:Nn \toks_if_empty_p:N {c} +\cs_generate_variant:Nn \toks_if_empty:NTF {c} +\cs_generate_variant:Nn \toks_if_empty:NT {c} +\cs_generate_variant:Nn \toks_if_empty:NF {c} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\toks_if_eq_p:NN,\toks_if_eq_p:cN,\toks_if_eq_p:Nc,\toks_if_eq_p:cc} +% \begin{macro}[TF]{\toks_if_eq:NN,\toks_if_eq:Nc,\toks_if_eq:cN,\toks_if_eq:cc} +% This function test whether two token registers have the same contents. +% \begin{macrocode} +\prg_new_conditional:Nnn \toks_if_eq:NN {p,TF,T,F} { + \str_if_eq:xxTF {\toks_use:N #1} {\toks_use:N #2} + {\prg_return_true:} {\prg_return_false:} +} +\cs_generate_variant:Nn \toks_if_eq_p:NN {Nc,c,cc} +\cs_generate_variant:Nn \toks_if_eq:NNTF {Nc,c,cc} +\cs_generate_variant:Nn \toks_if_eq:NNT {Nc,c,cc} +\cs_generate_variant:Nn \toks_if_eq:NNF {Nc,c,cc} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Variables and constants} +% +% \begin{macro}{\l_tmpa_toks} +% \begin{macro}{\l_tmpb_toks} +% \begin{macro}{\l_tmpc_toks} +% \begin{macro}{\g_tmpa_toks} +% \begin{macro}{\g_tmpb_toks} +% \begin{macro}{\g_tmpc_toks} +% Some scratch registers \ldots +% \begin{macrocode} +\tex_toksdef:D \l_tmpa_toks = 255\scan_stop: +%<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 +\toks_new:N \g_tmpb_toks +\toks_new:N \g_tmpc_toks +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\c_empty_toks} +% And here is a constant, which is a (permanently) empty token register. +% \begin{macrocode} +\toks_new:N \c_empty_toks +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\l_tl_replace_toks} +% And here is one for tl vars. Can't define it there as the allocation +% isn't set up at that point. +% \begin{macrocode} +\toks_new:N \l_tl_replace_toks +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +%</initex|package> +% \end{macrocode} +% +% +% \end{implementation} +% \PrintIndex +% +% \endinput + diff --git a/Master/texmf-dist/tex/latex/l3kernel/expl3.sty b/Master/texmf-dist/tex/latex/l3kernel/expl3.sty new file mode 100644 index 00000000000..d0ac38f18e1 --- /dev/null +++ b/Master/texmf-dist/tex/latex/l3kernel/expl3.sty @@ -0,0 +1,179 @@ +%% +%% This is file `expl3.sty', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% expl3.dtx (with options: `package') +%% +%% EXPERIMENTAL CODE +%% +%% Do not distribute this file without also distributing the +%% source files specified above. +%% +%% Do not distribute a modified version of this file. +%% +%% File: expl3.dtx Copyright (C) 1990-2011 The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +\RequirePackage{l3names} +\GetIdInfo$Id: expl3.dtx 2478 2011-06-19 21:34:23Z joseph $ + {L3 Experimental code bundle wrapper} + %\subsubsection{Variables: scope and type} +\RequirePackage{etex} +\reserveinserts{32} +\RequirePackage{calc} +\ProvidesExplPackage + {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +\newcommand* \@l@expl@check@declarations@bool { 0 } +\newcommand*\@l@expl@log@functions@bool { 0 } +\DeclareOption { check-declarations } + { \def \@l@expl@check@declarations@bool { 1 } } +\DeclareOption { log-functions } + {\def \@l@expl@log@functions@bool { 1 } } +\ProcessOptions \relax +\RequirePackage{ l3basics, l3expan, l3tl } +\ifodd \@l@expl@check@declarations@bool \relax + \cs_new_protected:Npn \tl_check_exists:N #1 + { + \cs_if_exist:NF #1 + { + \msg_kernel_error:nnx { check } { non-declared-variable } + { \token_to_str:N #1 } + } + } + \cs_set_protected:Npn \tl_set:Nn #1#2 + { + \tl_check_exists:N #1 + \cs_set_nopar:Npx #1 { \exp_not:n {#2} } + } + \cs_set_protected:Npn \tl_set:Nx #1#2 + { + \tl_check_exists:N #1 + \cs_set_nopar:Npx #1 {#2} + } + \cs_set_protected:Npn \tl_gset:Nn #1#2 + { + \tl_check_exists:N #1 + \cs_gset_nopar:Npx #1 { \exp_not:n {#2} } + } + \cs_set_protected:Npn \tl_gset:Nx #1#2 + { + \tl_check_exists:N #1 + \cs_gset_nopar:Npx #1 {#2} + } + \cs_set_protected:Npn \tl_set_eq:NN #1#2 + { + \tl_check_exists:N #1 + \tl_check_exists:N #2 + \cs_set_eq:NN #1 #2 + } + \cs_set_protected:Npn \tl_gset_eq:NN #1#2 + { + \tl_check_exists:N #1 + \tl_check_exists:N #2 + \cs_gset_eq:NN #1 #2 + } +\fi +\RequirePackage{ + l3seq, + l3int, + l3quark, + l3prg, + l3clist, + l3token, + l3prop, + l3msg, + l3io, + l3file, + l3skip, + l3box, + l3keyval, + l3keys, + l3fp, + l3luatex +} +\RequirePackage{l3toks} +\bool_if:nT { \@l@expl@check@declarations@bool } + { + \msg_kernel_new:nnnn { check } { non-declared-variable } + { The~variable~#1~has~not~been~declared~\msg_line_context:. } + { + Checking~is~active,~and~you~have~tried~do~so~something~like: \\ + \ \ \tl_set:Nn #1 ~ + \iow_char:N \{ ~ ... ~ \iow_char:N \} \\ + without~first~having: \\ + \ \ \tl_new:N #1 \\ + \\ + LaTeX~will~create~the~variable~and~continue. + } + } +\cs_set_protected_nopar:Npn \ExplSyntaxOn + { + \bool_if:NF \l_expl_status_bool + { + \cs_set_protected_nopar:Npx \ExplSyntaxOff + { + \char_set_catcode:nn { 9 } { \char_value_catcode:n { 9 } } + \char_set_catcode:nn { 32 } { \char_value_catcode:n { 32 } } + \char_set_catcode:nn { 34 } { \char_value_catcode:n { 34 } } + \char_set_catcode:nn { 38 } { \char_value_catcode:n { 38 } } + \char_set_catcode:nn { 58 } { \char_value_catcode:n { 58 } } + \char_set_catcode:nn { 94 } { \char_value_catcode:n { 94 } } + \char_set_catcode:nn { 95 } { \char_value_catcode:n { 95 } } + \char_set_catcode:nn { 124 } { \char_value_catcode:n { 124 } } + \char_set_catcode:nn { 126 } { \char_value_catcode:n { 126 } } + \tex_endlinechar:D = \tex_the:D \tex_endlinechar:D \scan_stop: + \bool_set_false:N \l_expl_status_bool + \cs_set_protected_nopar:Npn \ExplSyntaxOff { } + } + } + \char_set_catcode_ignore:n { 9 } % tab + \char_set_catcode_ignore:n { 32 } % space + \char_set_catcode_other:n { 34 } % double quote + \char_set_catcode_alignment:n { 38 } % ampersand + \char_set_catcode_letter:n { 58 } % colon + \char_set_catcode_math_superscript:n { 94 } % circumflex + \char_set_catcode_letter:n { 95 } % underscore + \char_set_catcode_other:n { 124 } % pipe + \char_set_catcode_space:n { 126 } % tilde + \tex_endlinechar:D = 32 \scan_stop: + \bool_set_true:N \l_expl_status_bool + } +\cs_set_protected_nopar:Npx \ExplSyntaxOff + { + \exp_not:o \ExplSyntaxOff + \cs_set_protected_nopar:Npn \ExplSyntaxOff { } + } +%% +%% +%% End of file `expl3.sty'. diff --git a/Master/texmf-dist/tex/latex/l3kernel/l3basics.sty b/Master/texmf-dist/tex/latex/l3kernel/l3basics.sty new file mode 100644 index 00000000000..edecb52c1c7 --- /dev/null +++ b/Master/texmf-dist/tex/latex/l3kernel/l3basics.sty @@ -0,0 +1,784 @@ +%% +%% This is file `l3basics.sty', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% l3basics.dtx (with options: `package') +%% +%% EXPERIMENTAL CODE +%% +%% Do not distribute this file without also distributing the +%% source files specified above. +%% +%% Do not distribute a modified version of this file. +%% +%% File: l3basics.dtx Copyright (C) 1990-2011 The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +\RequirePackage{l3names} +\GetIdInfo$Id: l3basics.dtx 2493 2011-07-04 09:50:22Z bruno $ + {L3 Experimental basic definitions} + +\ProvidesExplPackage + {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +\package_check_loaded_expl: +\tex_let:D \cs_set_eq:NwN \tex_let:D +\cs_set_eq:NwN \if_true: \tex_iftrue:D +\cs_set_eq:NwN \if_false: \tex_iffalse:D +\cs_set_eq:NwN \or: \tex_or:D +\cs_set_eq:NwN \else: \tex_else:D +\cs_set_eq:NwN \fi: \tex_fi:D +\cs_set_eq:NwN \reverse_if:N \etex_unless:D +\cs_set_eq:NwN \if:w \tex_if:D +\cs_set_eq:NwN \if_bool:N \tex_ifodd:D +\cs_set_eq:NwN \if_predicate:w \tex_ifodd:D +\cs_set_eq:NwN \if_charcode:w \tex_if:D +\cs_set_eq:NwN \if_catcode:w \tex_ifcat:D +\cs_set_eq:NwN \if_meaning:w \tex_ifx:D +\cs_set_eq:NwN \if_mode_math: \tex_ifmmode:D +\cs_set_eq:NwN \if_mode_horizontal: \tex_ifhmode:D +\cs_set_eq:NwN \if_mode_vertical: \tex_ifvmode:D +\cs_set_eq:NwN \if_mode_inner: \tex_ifinner:D +\cs_set_eq:NwN \if_cs_exist:N \etex_ifdefined:D +\cs_set_eq:NwN \if_cs_exist:w \etex_ifcsname:D +\cs_set_eq:NwN \exp_after:wN \tex_expandafter:D +\cs_set_eq:NwN \exp_not:N \tex_noexpand:D +\cs_set_eq:NwN \exp_not:n \etex_unexpanded:D +\cs_set_eq:NwN \token_to_meaning:N \tex_meaning:D +\cs_set_eq:NwN \token_to_str:N \tex_string:D +\cs_set_eq:NwN \cs:w \tex_csname:D +\cs_set_eq:NwN \cs_end: \tex_endcsname:D +\cs_set_eq:NwN \cs_meaning:N \tex_meaning:D +\cs_set_eq:NwN \cs_show:N \tex_show:D +\cs_set_eq:NwN \scan_stop: \tex_relax:D +\cs_set_eq:NwN \group_begin: \tex_begingroup:D +\cs_set_eq:NwN \group_end: \tex_endgroup:D +\cs_set_eq:NwN \if_int_compare:w \tex_ifnum:D +\cs_set_eq:NwN \int_to_roman:w \tex_romannumeral:D +\cs_set_eq:NwN \group_insert_after:N \tex_aftergroup:D +\cs_set_eq:NwN \pref_global:D \tex_global:D +\cs_set_eq:NwN \pref_long:D \tex_long:D +\cs_set_eq:NwN \pref_protected:D \etex_protected:D +\tex_long:D \tex_def:D \exp_args:Nc #1#2 { \exp_after:wN #1 \cs:w #2 \cs_end: } +%% A small number of variants by hand. +\tex_def:D \cs_meaning:c { \exp_args:Nc \cs_meaning:N } +\tex_def:D \token_to_str:c { \exp_args:Nc \token_to_str:N } +\tex_def:D \cs_show:c { \exp_args:Nc \cs_show:N } +\cs_set_eq:NwN \cs_set_nopar:Npn \tex_def:D +\cs_set_eq:NwN \cs_set_nopar:Npx \tex_edef:D +\pref_protected:D \cs_set_nopar:Npn \cs_set:Npn + { \pref_long:D \cs_set_nopar:Npn } +\pref_protected:D \cs_set_nopar:Npn \cs_set:Npx + { \pref_long:D \cs_set_nopar:Npx } +\pref_protected:D \cs_set_nopar:Npn \cs_set_protected_nopar:Npn + { \pref_protected:D \cs_set_nopar:Npn } +\pref_protected:D \cs_set_nopar:Npn \cs_set_protected_nopar:Npx + { \pref_protected:D \cs_set_nopar:Npx } +\cs_set_protected_nopar:Npn \cs_set_protected:Npn + { \pref_protected:D \pref_long:D \cs_set_nopar:Npn } +\cs_set_protected_nopar:Npn \cs_set_protected:Npx + { \pref_protected:D \pref_long:D \cs_set_nopar:Npx } +\cs_set_eq:NwN \cs_gset_nopar:Npn \tex_gdef:D +\cs_set_eq:NwN \cs_gset_nopar:Npx \tex_xdef:D +\cs_set_protected_nopar:Npn \cs_gset:Npn + { \pref_long:D \cs_gset_nopar:Npn } +\cs_set_protected_nopar:Npn \cs_gset:Npx + { \pref_long:D \cs_gset_nopar:Npx } +\cs_set_protected_nopar:Npn \cs_gset_protected_nopar:Npn + { \pref_protected:D \cs_gset_nopar:Npn } +\cs_set_protected_nopar:Npn \cs_gset_protected_nopar:Npx + { \pref_protected:D \cs_gset_nopar:Npx } +\cs_set_protected_nopar:Npn \cs_gset_protected:Npn + { \pref_protected:D \pref_long:D \cs_gset_nopar:Npn } +\cs_set_protected_nopar:Npn \cs_gset_protected:Npx + { \pref_protected:D \pref_long:D \cs_gset_nopar:Npx } +\cs_set:Npn \use:c #1 { \cs:w #1 \cs_end: } +\cs_set_protected:Npn \use:x #1 + { + \group_begin: + \cs_set:Npx \cs_tmp:w {#1} + \exp_after:wN + \group_end: + \cs_tmp:w + } +\cs_set:Npn \cs_tmp:w { } +\cs_set:Npn \use:n #1 {#1} +\cs_set:Npn \use:nn #1#2 {#1#2} +\cs_set:Npn \use:nnn #1#2#3 {#1#2#3} +\cs_set:Npn \use:nnnn #1#2#3#4 {#1#2#3#4} +\cs_set:Npn \use_i:nn #1#2 {#1} +\cs_set:Npn \use_ii:nn #1#2 {#2} +\cs_set:Npn \use_i:nnn #1#2#3 {#1} +\cs_set:Npn \use_ii:nnn #1#2#3 {#2} +\cs_set:Npn \use_iii:nnn #1#2#3 {#3} +\cs_set:Npn \use_i_ii:nnn #1#2#3 {#1#2} +\cs_set:Npn \use_i:nnnn #1#2#3#4 {#1} +\cs_set:Npn \use_ii:nnnn #1#2#3#4 {#2} +\cs_set:Npn \use_iii:nnnn #1#2#3#4 {#3} +\cs_set:Npn \use_iv:nnnn #1#2#3#4 {#4} +\cs_set:Npn \use_none_delimit_by_q_nil:w #1 \q_nil { } +\cs_set:Npn \use_none_delimit_by_q_stop:w #1 \q_stop { } +\cs_set:Npn \use_none_delimit_by_q_recursion_stop:w #1 \q_recursion_stop { } +\cs_set:Npn \use_i_delimit_by_q_nil:nw #1#2 \q_nil {#1} +\cs_set:Npn \use_i_delimit_by_q_stop:nw #1#2 \q_stop {#1} +\cs_set:Npn \use_i_delimit_by_q_recursion_stop:nw #1#2 \q_recursion_stop {#1} +\cs_set:Npn \use_i_after_fi:nw #1 \fi: { \fi: #1 } +\cs_set:Npn \use_i_after_else:nw #1 \else: #2 \fi: { \fi: #1 } +\cs_set:Npn \use_i_after_or:nw #1 \or: #2 \fi: { \fi: #1 } +\cs_set:Npn \use_i_after_orelse:nw #1#2#3 \fi: { \fi: #1 } +\cs_set:Npn \use_none:n #1 { } +\cs_set:Npn \use_none:nn #1#2 { } +\cs_set:Npn \use_none:nnn #1#2#3 { } +\cs_set:Npn \use_none:nnnn #1#2#3#4 { } +\cs_set:Npn \use_none:nnnnn #1#2#3#4#5 { } +\cs_set:Npn \use_none:nnnnnn #1#2#3#4#5#6 { } +\cs_set:Npn \use_none:nnnnnnn #1#2#3#4#5#6#7 { } +\cs_set:Npn \use_none:nnnnnnnn #1#2#3#4#5#6#7#8 { } +\cs_set:Npn \use_none:nnnnnnnnn #1#2#3#4#5#6#7#8#9 { } +\cs_set_nopar:Npn \prg_return_true: + { \exp_after:wN \use_i:nn \int_to_roman:w } +\cs_set_nopar:Npn \prg_return_false: + { \exp_after:wN \use_ii:nn \int_to_roman:w} +\cs_set_protected:Npn \prg_set_conditional:Npnn #1 + { + \prg_get_parm_aux:nw + { + \cs_split_function:NN #1 \prg_generate_conditional_aux:nnNNnnnn + \cs_set:Npn { parm } + } + } +\cs_set_protected:Npn \prg_new_conditional:Npnn #1 + { + \prg_get_parm_aux:nw + { + \cs_split_function:NN #1 \prg_generate_conditional_aux:nnNNnnnn + \cs_new:Npn { parm } + } + } +\cs_set_protected:Npn \prg_set_protected_conditional:Npnn #1 + { + \prg_get_parm_aux:nw{ + \cs_split_function:NN #1 \prg_generate_conditional_aux:nnNNnnnn + \cs_set_protected:Npn { parm } + } + } +\cs_set_protected:Npn \prg_new_protected_conditional:Npnn #1 + { + \prg_get_parm_aux:nw + { + \cs_split_function:NN #1 \prg_generate_conditional_aux:nnNNnnnn + \cs_new_protected:Npn { parm } + } + } +\cs_set_protected:Npn \prg_set_conditional:Nnn #1 + { + \exp_args:Nnf \prg_get_count_aux:nn + { + \cs_split_function:NN #1 \prg_generate_conditional_aux:nnNNnnnn + \cs_set:Npn { count } + } + { \cs_get_arg_count_from_signature:N #1 } + } +\cs_set_protected:Npn \prg_new_conditional:Nnn #1 + { + \exp_args:Nnf \prg_get_count_aux:nn + { + \cs_split_function:NN #1 \prg_generate_conditional_aux:nnNNnnnn + \cs_new:Npn { count} + } + { \cs_get_arg_count_from_signature:N #1 } + } + +\cs_set_protected:Npn \prg_set_protected_conditional:Nnn #1{ + \exp_args:Nnf \prg_get_count_aux:nn{ + \cs_split_function:NN #1 \prg_generate_conditional_aux:nnNNnnnn + \cs_set_protected:Npn {count} + }{\cs_get_arg_count_from_signature:N #1} +} + +\cs_set_protected:Npn \prg_new_protected_conditional:Nnn #1 + { + \exp_args:Nnf \prg_get_count_aux:nn + { + \cs_split_function:NN #1 \prg_generate_conditional_aux:nnNNnnnn + \cs_new_protected:Npn {count} + } + { \cs_get_arg_count_from_signature:N #1 } + } +\cs_set_protected:Npn \prg_set_eq_conditional:NNn #1#2#3 + { \prg_set_eq_conditional_aux:NNNn \cs_set_eq:cc #1#2 {#3} } +\cs_set_protected:Npn \prg_new_eq_conditional:NNn #1#2#3 + { \prg_set_eq_conditional_aux:NNNn \cs_new_eq:cc #1#2 {#3} } +\cs_set:Npn \prg_get_count_aux:nn #1#2 { #1 {#2} } +\cs_set:Npn \prg_get_parm_aux:nw #1#2# { #1 {#2} } +\cs_set_protected:Npn \prg_generate_conditional_aux:nnNNnnnn #1#2#3#4#5#6#7#8 + { + \prg_generate_conditional_aux:nnw {#5} + { + #4 {#1} {#2} {#6} {#8} + } + #7 , ? , \q_recursion_stop + } +\cs_set_protected:Npn \prg_generate_conditional_aux:nnw #1#2#3 , + { + \if:w ?#3 + \exp_after:wN \use_none_delimit_by_q_recursion_stop:w + \fi: + \use:c { prg_generate_#3_form_#1:Nnnnn } #2 + \prg_generate_conditional_aux:nnw {#1} {#2} + } +\cs_set_protected:Npn \prg_generate_p_form_parm:Nnnnn #1#2#3#4#5 + { + \exp_args:Nc #1 { #2 _p: #3 } #4 + { + #5 \c_zero + \c_true_bool \c_false_bool + } + } +\cs_set_protected:Npn \prg_generate_T_form_parm:Nnnnn #1#2#3#4#5 + { + \exp_args:Nc #1 { #2 : #3 T } #4 + { + #5 \c_zero + \use:n \use_none:n + } + } +\cs_set_protected:Npn \prg_generate_F_form_parm:Nnnnn #1#2#3#4#5 + { + \exp_args:Nc #1 { #2 : #3 F } #4 + { + #5 \c_zero + { } + } + } +\cs_set_protected:Npn \prg_generate_TF_form_parm:Nnnnn #1#2#3#4#5 + { + \exp_args:Nc #1 { #2 : #3 TF } #4 + { #5 \c_zero } + } +\cs_set_protected:Npn \prg_generate_p_form_count:Nnnnn #1#2#3#4#5 + { + \cs_generate_from_arg_count:cNnn { #2 _p: #3 } #1 {#4} + { + #5 \c_zero + \c_true_bool \c_false_bool + } + } +\cs_set_protected:Npn \prg_generate_T_form_count:Nnnnn #1#2#3#4#5 + { + \cs_generate_from_arg_count:cNnn { #2 : #3 T } #1 {#4} + { + #5 \c_zero + \use:n \use_none:n + } + } +\cs_set_protected:Npn \prg_generate_F_form_count:Nnnnn #1#2#3#4#5 + { + \cs_generate_from_arg_count:cNnn { #2 : #3 F } #1 {#4} + { + #5 \c_zero + { } + } + } +\cs_set_protected:Npn \prg_generate_TF_form_count:Nnnnn #1#2#3#4#5 + { + \cs_generate_from_arg_count:cNnn { #2 : #3 TF } #1 {#4} + { #5 \c_zero } + } +\cs_set_protected:Npn \prg_set_eq_conditional_aux:NNNn #1#2#3#4 + { \prg_set_eq_conditional_aux:NNNw #1#2#3#4 , ? , \q_recursion_stop } +\cs_set_protected:Npn \prg_set_eq_conditional_aux:NNNw #1#2#3#4 , + { + \if:w ? #4 \scan_stop: + \exp_after:wN \use_none_delimit_by_q_recursion_stop:w + \fi: + #1 + { \exp_args:NNc \cs_split_function:NN #2 { prg_conditional_form_#4:nnn } } + { \exp_args:NNc \cs_split_function:NN #3 { prg_conditional_form_#4:nnn } } + \prg_set_eq_conditional_aux:NNNw #1 {#2} {#3} + } +\cs_set:Npn \prg_conditional_form_p:nnn #1#2#3 { #1 _p : #2 } +\cs_set:Npn \prg_conditional_form_TF:nnn #1#2#3 { #1 : #2 TF } +\cs_set:Npn \prg_conditional_form_T:nnn #1#2#3 { #1 : #2 T } +\cs_set:Npn \prg_conditional_form_F:nnn #1#2#3 { #1 : #2 F } +\tex_chardef:D \c_true_bool = 1~ +\tex_chardef:D \c_false_bool = 0~ +\cs_set_nopar:Npn \cs_to_str:N + { + \if:w \int_to_roman:w - `0 \token_to_str:N \ % + \cs_to_str_aux:w + \fi: + \exp_after:wN \use_none:n \token_to_str:N + } +\cs_set_nopar:Npn \cs_to_str_aux:w #1 \use_none:n + { ~ \int_to_roman:w - `0 \fi: } +\group_begin: + \tex_lccode:D `\@ = `\: \scan_stop: + \tex_catcode:D `\@ = 12~ +\tex_lowercase:D + { + \group_end: + \cs_set:Npn \cs_split_function:NN #1#2 + { + \exp_after:wN \cs_split_function_aux:w + \int_to_roman:w - `\q \cs_to_str:N #1 @ a \q_stop #2 + } + \cs_set:Npn \cs_split_function_aux:w #1 @ #2#3 \q_stop #4 + { + \if_meaning:w a #2 + \exp_after:wN \use_i:nn + \else: + \exp_after:wN\use_ii:nn + \fi: + { #4 {#1} { } \c_false_bool } + { \cs_split_function_auxii:w #2#3 \q_stop #4 {#1} } + } + \cs_set:Npn \cs_split_function_auxii:w #1 @a \q_stop #2#3 + { #2{#3}{#1}\c_true_bool } + } +\cs_set:Npn \cs_get_function_name:N #1 + { \cs_split_function:NN #1 \use_i:nnn } +\cs_set:Npn \cs_get_function_signature:N #1 + { \cs_split_function:NN #1 \use_ii:nnn } +\prg_set_conditional:Npnn \cs_if_exist:N #1 { p , T , F , TF } + { + \if_meaning:w #1 \scan_stop: + \prg_return_false: + \else: + \if_cs_exist:N #1 + \prg_return_true: + \else: + \prg_return_false: + \fi: + \fi: + } +\prg_set_conditional:Npnn \cs_if_exist:c #1 { p , T , F , TF } + { + \if_cs_exist:w #1 \cs_end: + \exp_after:wN \use_i:nn + \else: + \exp_after:wN \use_ii:nn + \fi: + { + \exp_after:wN \if_meaning:w \cs:w #1 \cs_end: \scan_stop: + \prg_return_false: + \else: + \prg_return_true: + \fi: + } + \prg_return_false: + } +\prg_set_conditional:Npnn \cs_if_free:N #1 { p , T , F , TF } + { + \if_meaning:w #1 \scan_stop: + \prg_return_true: + \else: + \if_cs_exist:N #1 + \prg_return_false: + \else: + \prg_return_true: + \fi: + \fi: + } +\prg_set_conditional:Npnn \cs_if_free:c #1 { p , T , F , TF } + { + \if_cs_exist:w #1 \cs_end: + \exp_after:wN \use_i:nn + \else: + \exp_after:wN \use_ii:nn + \fi: + { + \exp_after:wN \if_meaning:w \cs:w #1 \cs_end: \scan_stop: + \prg_return_true: + \else: + \prg_return_false: + \fi: + } + { \prg_return_true: } + } +\cs_set_eq:NwN \c_minus_one \m@ne +\tex_chardef:D \c_sixteen = 16~ +\tex_chardef:D \c_zero = 0~ +\tex_chardef:D \c_six = 6~ +\tex_chardef:D \c_seven = 7~ +\tex_chardef:D \c_twelve = 12~ +\tex_mathchardef:D \c_max_register_int = 32 767 \scan_stop: +\cs_set_protected_nopar:Npn \iow_log:x + { \tex_immediate:D \tex_write:D \c_minus_one } +\cs_set_protected_nopar:Npn \iow_term:x + { \tex_immediate:D \tex_write:D \c_sixteen } +\cs_set_protected_nopar:Npn \msg_kernel_error:nnxx #1#2#3#4 + { + \tex_errmessage:D + { + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!~! ^^J + Argh,~internal~LaTeX3~error! ^^J ^^J + Module ~ #1 , ~ message~name~"#2": ^^J + Arguments~'#3'~and~'#4' ^^J ^^J + This~is~one~for~The~LaTeX3~Project:~bailing~out + } + \tex_end:D + } +\cs_set_protected_nopar:Npn \msg_kernel_error:nnx #1#2#3 + { \msg_kernel_error:nnxx {#1} {#2} {#3} { } } +\cs_set_protected_nopar:Npn \msg_kernel_error:nn #1#2 + { \msg_kernel_error:nnxx {#1} {#2} { } { } } +\cs_set_nopar:Npn \msg_line_context: + { on~line~\tex_the:D \tex_inputlineno:D } +\cs_set:Npn \cs_record_meaning:N #1 { } +\cs_set_protected_nopar:Npn \chk_if_free_cs:N #1 + { + \cs_if_free:NF #1 + { + \msg_kernel_error:nnxx { kernel } { command-already-defined } + { \token_to_str:N #1 } { \token_to_meaning:N #1 } + } +} +\tex_ifodd:D \@l@expl@log@functions@bool + \cs_set_protected_nopar:Npn \chk_if_free_cs:N #1 + { + \cs_if_free:NF #1 + { + \msg_kernel_error:nnxx { kernel } { command-already-defined } + { \token_to_str:N #1 } { \token_to_meaning:N #1 } + } + \iow_log:x { Defining~\token_to_str:N #1~ \msg_line_context: } + } +\fi: +\cs_set_protected_nopar:Npn \chk_if_free_cs:c + { \exp_args:Nc \chk_if_free_cs:N } +\cs_set_protected_nopar:Npn \chk_if_exist_cs:N #1 + { + \cs_if_exist:NF #1 + { + \msg_kernel_error:nnxx { kernel } { command-not-defined } + { \token_to_str:N #1 } { \token_to_meaning:N #1 } + } + } +\cs_set_protected_nopar:Npn \chk_if_exist_cs:c + { \exp_args:Nc \chk_if_exist_cs:N } +\cs_set:Npn \cs_tmp:w #1#2 + { + \cs_set_protected_nopar:Npn #1 ##1 + { + \chk_if_free_cs:N ##1 + #2 ##1 + } + } +\cs_tmp:w \cs_new_nopar:Npn \cs_gset_nopar:Npn +\cs_tmp:w \cs_new_nopar:Npx \cs_gset_nopar:Npx +\cs_tmp:w \cs_new:Npn \cs_gset:Npn +\cs_tmp:w \cs_new:Npx \cs_gset:Npx +\cs_tmp:w \cs_new_protected_nopar:Npn \cs_gset_protected_nopar:Npn +\cs_tmp:w \cs_new_protected_nopar:Npx \cs_gset_protected_nopar:Npx +\cs_tmp:w \cs_new_protected:Npn \cs_gset_protected:Npn +\cs_tmp:w \cs_new_protected:Npx \cs_gset_protected:Npx +\cs_set:Npn \cs_tmp:w #1#2 + { \cs_new_protected_nopar:Npn #1 { \exp_args:Nc #2 } } +\cs_tmp:w \cs_set_nopar:cpn \cs_set_nopar:Npn +\cs_tmp:w \cs_set_nopar:cpx \cs_set_nopar:Npx +\cs_tmp:w \cs_gset_nopar:cpn \cs_gset_nopar:Npn +\cs_tmp:w \cs_gset_nopar:cpx \cs_gset_nopar:Npx +\cs_tmp:w \cs_new_nopar:cpn \cs_new_nopar:Npn +\cs_tmp:w \cs_new_nopar:cpx \cs_new_nopar:Npx +\cs_tmp:w \cs_set:cpn \cs_set:Npn +\cs_tmp:w \cs_set:cpx \cs_set:Npx +\cs_tmp:w \cs_gset:cpn \cs_gset:Npn +\cs_tmp:w \cs_gset:cpx \cs_gset:Npx +\cs_tmp:w \cs_new:cpn \cs_new:Npn +\cs_tmp:w \cs_new:cpx \cs_new:Npx +\cs_tmp:w \cs_set_protected_nopar:cpn \cs_set_protected_nopar:Npn +\cs_tmp:w \cs_set_protected_nopar:cpx \cs_set_protected_nopar:Npx +\cs_tmp:w \cs_gset_protected_nopar:cpn \cs_gset_protected_nopar:Npn +\cs_tmp:w \cs_gset_protected_nopar:cpx \cs_gset_protected_nopar:Npx +\cs_tmp:w \cs_new_protected_nopar:cpn \cs_new_protected_nopar:Npn +\cs_tmp:w \cs_new_protected_nopar:cpx \cs_new_protected_nopar:Npx +\cs_tmp:w \cs_set_protected:cpn \cs_set_protected:Npn +\cs_tmp:w \cs_set_protected:cpx \cs_set_protected:Npx +\cs_tmp:w \cs_gset_protected:cpn \cs_gset_protected:Npn +\cs_tmp:w \cs_gset_protected:cpx \cs_gset_protected:Npx +\cs_tmp:w \cs_new_protected:cpn \cs_new_protected:Npn +\cs_tmp:w \cs_new_protected:cpx \cs_new_protected:Npx +\cs_new_nopar:cpn { use_0_parameter: } { } +\cs_new_nopar:cpn { use_1_parameter: } { {##1} } +\cs_new_nopar:cpn { use_2_parameter: } { {##1} {##2} } +\cs_new_nopar:cpn { use_3_parameter: } { {##1} {##2} {##3} } +\cs_new_nopar:cpn { use_4_parameter: } { {##1} {##2} {##3} {##4} } +\cs_new_nopar:cpn { use_5_parameter: } { {##1} {##2} {##3} {##4} {##5} } +\cs_new_nopar:cpn { use_6_parameter: } { {##1} {##2} {##3} {##4} {##5} {##6} } +\cs_new_nopar:cpn { use_7_parameter: } + { {##1} {##2} {##3} {##4} {##5}{##6} {##7} } +\cs_new_nopar:cpn { use_8_parameter: } + { {##1} {##2} {##3} {##4} {##5} {##6} {##7} {##8} } +\cs_new_nopar:cpn{ use_9_parameter: } + { {##1} {##2} {##3} {##4} {##5} {##6} {##7} {##8} {##9} } +\cs_new_protected:Npn \cs_set_eq:NN #1 { \cs_set_eq:NwN #1 =~ } +\cs_new_protected_nopar:Npn \cs_set_eq:cN { \exp_args:Nc \cs_set_eq:NN } +\cs_new_protected_nopar:Npn \cs_set_eq:Nc { \exp_args:NNc \cs_set_eq:NN } +\cs_new_protected_nopar:Npn \cs_set_eq:cc { \exp_args:Ncc \cs_set_eq:NN } +\cs_new_protected:Npn \cs_new_eq:NN #1 + { + \chk_if_free_cs:N #1 + \pref_global:D \cs_set_eq:NN #1 + } +\cs_new_protected_nopar:Npn \cs_new_eq:cN { \exp_args:Nc \cs_new_eq:NN } +\cs_new_protected_nopar:Npn \cs_new_eq:Nc { \exp_args:NNc \cs_new_eq:NN } +\cs_new_protected_nopar:Npn \cs_new_eq:cc { \exp_args:Ncc \cs_new_eq:NN } +\cs_new_protected_nopar:Npn \cs_gset_eq:NN { \pref_global:D \cs_set_eq:NN } +\cs_new_protected_nopar:Npn \cs_gset_eq:Nc { \exp_args:NNc \cs_gset_eq:NN } +\cs_new_protected_nopar:Npn \cs_gset_eq:cN { \exp_args:Nc \cs_gset_eq:NN } +\cs_new_protected_nopar:Npn \cs_gset_eq:cc { \exp_args:Ncc \cs_gset_eq:NN } +\cs_new_protected_nopar:Npn \cs_undefine:N #1 + { \cs_gset_eq:NN #1 \c_undefined:D } +\cs_new_protected_nopar:Npn \cs_undefine:c #1 + { \cs_gset_eq:cN {#1} \c_undefined:D } +\cs_new:Npn \cs_get_arg_count_from_signature:N #1 + { \cs_split_function:NN #1 \cs_get_arg_count_from_signature_aux:nnN } +\cs_new:Npn \cs_get_arg_count_from_signature_aux:nnN #1#2#3 + { + \if_predicate:w #3 + \exp_after:wN \use_i:nn + \else: + \exp_after:wN\use_ii:nn + \fi: + { + \exp_after:wN \cs_get_arg_count_from_signature_auxii:w + \use_none:nnnnnnnnn #2 9876543210 \q_stop + } + { -1 } +} +\cs_new:Npn \cs_get_arg_count_from_signature_auxii:w #1#2 \q_stop {#1} +\cs_new_nopar:Npn \cs_get_arg_count_from_signature:c + { \exp_args:Nc \cs_get_arg_count_from_signature:N } +\cs_new_protected:Npn \cs_generate_from_arg_count:NNnn #1#2#3#4 + { + \if_case:w \int_eval:w #3 \int_eval_end: + \use_i_after_orelse:nw {#2#1} + \or: + \use_i_after_orelse:nw {#2#1 ##1} + \or: + \use_i_after_orelse:nw {#2#1 ##1##2} + \or: + \use_i_after_orelse:nw {#2#1 ##1##2##3} + \or: + \use_i_after_orelse:nw {#2#1 ##1##2##3##4} + \or: + \use_i_after_orelse:nw {#2#1 ##1##2##3##4##5} + \or: + \use_i_after_orelse:nw {#2#1 ##1##2##3##4##5##6} + \or: + \use_i_after_orelse:nw {#2#1 ##1##2##3##4##5##6##7} + \or: + \use_i_after_orelse:nw {#2#1 ##1##2##3##4##5##6##7##8} + \or: + \use_i_after_orelse:nw {#2#1 ##1##2##3##4##5##6##7##8##9} + \else: + \use_i_after_fi:nw + { + \cs_generate_from_arg_count_error_msg:Nn #1 {#3} + \use_none:n + } + \fi: + {#4} + } +\cs_new_nopar:Npn \cs_generate_from_arg_count:cNnn + { \exp_args:Nc \cs_generate_from_arg_count:NNnn } +\cs_new:Npn \cs_generate_from_arg_count_error_msg:Nn #1#2 + { + \msg_kernel_error:nnxx { kernel } { bad-number-of-arguments } + { \token_to_str:N #1 } { \int_eval:n {#2} } + } +\cs_set:Npn \cs_tmp:w #1#2#3 + { + \cs_set_protected:cpx { cs_ #1 : #2 } ##1##2 + { + \exp_not:N \cs_generate_from_arg_count:NNnn ##1 + \exp_after:wN \exp_not:N \cs:w cs_#1 : #3 \cs_end: + { \exp_not:N\cs_get_arg_count_from_signature:N ##1 }{##2} + } + } +\cs_tmp:w { set } { Nn } { Npn } +\cs_tmp:w { set } { Nx } { Npx } +\cs_tmp:w { set_nopar } { Nn } { Npn } +\cs_tmp:w { set_nopar } { Nx } { Npx } +\cs_tmp:w { set_protected } { Nn } { Npn } +\cs_tmp:w { set_protected } { Nx } { Npx } +\cs_tmp:w { set_protected_nopar } { Nn } { Npn } +\cs_tmp:w { set_protected_nopar } { Nx } { Npx } +\cs_tmp:w { gset } { Nn } { Npn } +\cs_tmp:w { gset } { Nx } { Npx } +\cs_tmp:w { gset_nopar } { Nn } { Npn } +\cs_tmp:w { gset_nopar } { Nx } { Npx } +\cs_tmp:w { gset_protected } { Nn } { Npn } +\cs_tmp:w { gset_protected } { Nx } { Npx } +\cs_tmp:w { gset_protected_nopar } { Nn } { Npn } +\cs_tmp:w { gset_protected_nopar } { Nx } { Npx } +\cs_tmp:w { new } { Nn } { Npn } +\cs_tmp:w { new } { Nx } { Npx } +\cs_tmp:w { new_nopar } { Nn } { Npn } +\cs_tmp:w { new_nopar } { Nx } { Npx } +\cs_tmp:w { new_protected } { Nn } { Npn } +\cs_tmp:w { new_protected } { Nx } { Npx } +\cs_tmp:w { new_protected_nopar } { Nn } { Npn } +\cs_tmp:w { new_protected_nopar } { Nx } { Npx } +\cs_set:Npn \cs_tmp:w #1#2#3 + { + \cs_set_protected:cpx {cs_#1:#2}##1##2{ + \exp_not:N\cs_generate_from_arg_count:cNnn {##1} + \exp_after:wN \exp_not:N \cs:w cs_#1:#3 \cs_end: + { \exp_not:N \cs_get_arg_count_from_signature:c {##1} } {##2} + } + } +\cs_tmp:w { set } { cn } { Npn } +\cs_tmp:w { set } { cx } { Npx } +\cs_tmp:w { set_nopar } { cn } { Npn } +\cs_tmp:w { set_nopar } { cx } { Npx } +\cs_tmp:w { set_protected } { cn } { Npn } +\cs_tmp:w { set_protected } { cx } { Npx } +\cs_tmp:w { set_protected_nopar } { cn } { Npn } +\cs_tmp:w { set_protected_nopar } { cx } { Npx } +\cs_tmp:w { gset } { cn } { Npn } +\cs_tmp:w { gset } { cx } { Npx } +\cs_tmp:w { gset_nopar } { cn } { Npn } +\cs_tmp:w { gset_nopar } { cx } { Npx } +\cs_tmp:w { gset_protected } { cn } { Npn } +\cs_tmp:w { gset_protected } { cx } { Npx } +\cs_tmp:w { gset_protected_nopar } { cn } { Npn } +\cs_tmp:w { gset_protected_nopar } { cx } { Npx } +\cs_tmp:w { new } { cn } { Npn } +\cs_tmp:w { new } { cx } { Npx } +\cs_tmp:w { new_nopar } { cn } { Npn } +\cs_tmp:w { new_nopar } { cx } { Npx } +\cs_tmp:w { new_protected } { cn } { Npn } +\cs_tmp:w { new_protected } { cx } { Npx } +\cs_tmp:w { new_protected_nopar } { cn } { Npn } +\cs_tmp:w { new_protected_nopar } { cx } { Npx } +\prg_new_conditional:Npnn \cs_if_eq:NN #1#2 { p , T , F , TF } + { + \if_meaning:w #1#2 + \prg_return_true: \else: \prg_return_false: \fi: + } +\cs_new_nopar:Npn \cs_if_eq_p:cN { \exp_args:Nc \cs_if_eq_p:NN } +\cs_new_nopar:Npn \cs_if_eq:cNTF { \exp_args:Nc \cs_if_eq:NNTF } +\cs_new_nopar:Npn \cs_if_eq:cNT { \exp_args:Nc \cs_if_eq:NNT } +\cs_new_nopar:Npn \cs_if_eq:cNF { \exp_args:Nc \cs_if_eq:NNF } +\cs_new_nopar:Npn \cs_if_eq_p:Nc { \exp_args:NNc \cs_if_eq_p:NN } +\cs_new_nopar:Npn \cs_if_eq:NcTF { \exp_args:NNc \cs_if_eq:NNTF } +\cs_new_nopar:Npn \cs_if_eq:NcT { \exp_args:NNc \cs_if_eq:NNT } +\cs_new_nopar:Npn \cs_if_eq:NcF { \exp_args:NNc \cs_if_eq:NNF } +\cs_new_nopar:Npn \cs_if_eq_p:cc { \exp_args:Ncc \cs_if_eq_p:NN } +\cs_new_nopar:Npn \cs_if_eq:ccTF { \exp_args:Ncc \cs_if_eq:NNTF } +\cs_new_nopar:Npn \cs_if_eq:ccT { \exp_args:Ncc \cs_if_eq:NNT } +\cs_new_nopar:Npn \cs_if_eq:ccF { \exp_args:Ncc \cs_if_eq:NNF } +\cs_new_nopar:Npn \kernel_register_show:N #1 + { + \cs_if_exist:NTF #1 + { \tex_showthe:D #1 } + { + \msg_kernel_error:nnx { kernel } { variable-not-defined } + { \token_to_str:N #1 } + } + } +\cs_new_nopar:Npn \kernel_register_show:c { \exp_args:Nc \int_show:N } +\cs_new_eq:NN \luatex_if_engine:T \use_none:n +\cs_new_eq:NN \luatex_if_engine:F \use:n +\cs_new_eq:NN \luatex_if_engine:TF \use_ii:nn +\cs_new_eq:NN \pdftex_if_engine:T \use:n +\cs_new_eq:NN \pdftex_if_engine:F \use_none:n +\cs_new_eq:NN \pdftex_if_engine:TF \use_i:nn +\cs_new_eq:NN \xetex_if_engine:T \use_none:n +\cs_new_eq:NN \xetex_if_engine:F \use:n +\cs_new_eq:NN \xetex_if_engine:TF \use_ii:nn +\cs_new_eq:NN \c_luatex_is_engine_bool \c_false_bool +\cs_new_eq:NN \c_pdftex_is_engine_bool \c_true_bool +\cs_new_eq:NN \c_xetex_is_engine_bool \c_false_bool +\cs_if_exist:NT \xetex_XeTeXversion:D + { + \cs_set_eq:NN \pdftex_if_engine:T \use_none:n + \cs_set_eq:NN \pdftex_if_engine:F \use:n + \cs_set_eq:NN \pdftex_if_engine:TF \use_ii:nn + \cs_set_eq:NN \xetex_if_engine:T \use:n + \cs_set_eq:NN \xetex_if_engine:F \use_none:n + \cs_set_eq:NN \xetex_if_engine:TF \use_i:nn + \cs_set_eq:NN \c_pdftex_is_engine_bool \c_false_bool + \cs_set_eq:NN \c_xetex_is_engine_bool \c_true_bool + } +\cs_if_exist:NT \luatex_directlua:D + { + \cs_set_eq:NN \luatex_if_engine:T \use:n + \cs_set_eq:NN \luatex_if_engine:F \use_none:n + \cs_set_eq:NN \luatex_if_engine:TF \use_i:nn + \cs_set_eq:NN \pdftex_if_engine:T \use_none:n + \cs_set_eq:NN \pdftex_if_engine:F \use:n + \cs_set_eq:NN \pdftex_if_engine:TF \use_ii:nn + \cs_set_eq:NN \c_luatex_is_engine_bool \c_true_bool + \cs_set_eq:NN \c_pdftex_is_engine_bool \c_false_bool + } +\cs_new_nopar:Npn \prg_do_nothing: { } +\prg_new_conditional:Npnn \str_if_eq:nn #1#2 { p , T , F , TF } + { + \if_int_compare:w \pdftex_strcmp:D { \exp_not:n {#1} } { \exp_not:n {#2} } + = \c_zero + \prg_return_true: \else: \prg_return_false: \fi: + } +\prg_new_conditional:Npnn \str_if_eq:xx #1#2 { p , T , F , TF } + { + \if_int_compare:w \pdftex_strcmp:D {#1} {#2} = \c_zero + \prg_return_true: \else: \prg_return_false: \fi: + } +\cs_new_eq:NN \cs_gnew_nopar:Npn \cs_new_nopar:Npn +\cs_new_eq:NN \cs_gnew:Npn \cs_new:Npn +\cs_new_eq:NN \cs_gnew_protected_nopar:Npn \cs_new_protected_nopar:Npn +\cs_new_eq:NN \cs_gnew_protected:Npn \cs_new_protected:Npn +\cs_new_eq:NN \cs_gnew_nopar:Npx \cs_new_nopar:Npx +\cs_new_eq:NN \cs_gnew:Npx \cs_new:Npx +\cs_new_eq:NN \cs_gnew_protected_nopar:Npx \cs_new_protected_nopar:Npx +\cs_new_eq:NN \cs_gnew_protected:Npx \cs_new_protected:Npx +\cs_new_eq:NN \cs_gnew_nopar:cpn \cs_new_nopar:cpn +\cs_new_eq:NN \cs_gnew:cpn \cs_new:cpn +\cs_new_eq:NN \cs_gnew_protected_nopar:cpn \cs_new_protected_nopar:cpn +\cs_new_eq:NN \cs_gnew_protected:cpn \cs_new_protected:cpn +\cs_new_eq:NN \cs_gnew_nopar:cpx \cs_new_nopar:cpx +\cs_new_eq:NN \cs_gnew:cpx \cs_new:cpx +\cs_new_eq:NN \cs_gnew_protected_nopar:cpx \cs_new_protected_nopar:cpx +\cs_new_eq:NN \cs_gnew_protected:cpx \cs_new_protected:cpx +\cs_new_eq:NN \cs_gnew_eq:NN \cs_new_eq:NN +\cs_new_eq:NN \cs_gnew_eq:cN \cs_new_eq:cN +\cs_new_eq:NN \cs_gnew_eq:Nc \cs_new_eq:Nc +\cs_new_eq:NN \cs_gnew_eq:cc \cs_new_eq:cc +\cs_new_eq:NN \cs_gundefine:N \cs_undefine:N +\cs_new_eq:NN \cs_gundefine:c \cs_undefine:c +\cs_new_eq:NN \group_execute_after:N \group_insert_after:N +%% +%% +%% End of file `l3basics.sty'. diff --git a/Master/texmf-dist/tex/latex/l3kernel/l3bootstrap.sty b/Master/texmf-dist/tex/latex/l3kernel/l3bootstrap.sty new file mode 100644 index 00000000000..54b4a0cf7c4 --- /dev/null +++ b/Master/texmf-dist/tex/latex/l3kernel/l3bootstrap.sty @@ -0,0 +1,256 @@ +%% +%% This is file `l3bootstrap.sty', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% l3bootstrap.dtx (with options: `package') +%% +%% EXPERIMENTAL CODE +%% +%% Do not distribute this file without also distributing the +%% source files specified above. +%% +%% Do not distribute a modified version of this file. +%% +%% File: l3bootstrap.dtx Copyright (C) 2011 The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +\def\GetIdInfo$% + Id: #1 #2 #3-#4-#5 #6 #7 $#8% + {% + \def\ExplFileDate{#3/#4/#5}% + \def\ExplFileVersion{#2}% + } +\GetIdInfo$Id: l3bootstrap.dtx 2478 2011-06-19 21:34:23Z joseph $ + {L3 experimental bootstrap code} +\ProvidesPackage{l3bootstrap} + [% + \ExplFileDate\space v\ExplFileVersion\space + L3 Experimental bootstrap code% + ] +\def\@tempa% + {% + \def\@tempa{}% + \RequirePackage{luatex}% + \RequirePackage{pdftexcmds}% + \let\pdfstrcmp\pdf@strcmp + } +\begingroup\expandafter\expandafter\expandafter\endgroup +\expandafter\ifx\csname directlua\endcsname\relax +\else + \expandafter\@tempa +\fi +\protected\edef\ExplSyntaxOff + {% + \catcode 9 = \the\catcode 9\relax + \catcode 32 = \the\catcode 32\relax + \catcode 34 = \the\catcode 34\relax + \catcode 38 = \the\catcode 38\relax + \catcode 58 = \the\catcode 58\relax + \catcode 94 = \the\catcode 94\relax + \catcode 95 = \the\catcode 95\relax + \catcode 124 = \the\catcode 124\relax + \catcode 126 = \the\catcode 126\relax + \endlinechar = \the\endlinechar\relax + \chardef\csname\detokenize{l_expl_status_bool}\endcsname = 0 \relax + } +\protected\edef\ExplSyntaxOn + { + \catcode 9 = 9 \relax + \catcode 32 = 9 \relax + \catcode 34 = 12 \relax + \catcode 58 = 11 \relax + \catcode 94 = 7 \relax + \catcode 95 = 11 \relax + \catcode 124 = 12 \relax + \catcode 126 = 10 \relax + \endlinechar = 32 \relax + \chardef\csname\detokenize{l_expl_status_bool}\endcsname = 1 \relax + } +\expandafter\chardef\csname\detokenize{l_expl_status_bool}\endcsname = 0 \relax +\protected\def\GetIdInfo + { + \begingroup + \catcode 32 = 10 \relax + \GetIdInfoAuxI + } +\protected\def\GetIdInfoAuxI$#1$#2% + { + \def\tempa{#1}% + \def\tempb{Id}% + \ifx\tempa\tempb + \def\tempa + {% + \endgroup + \def\ExplFileDate{0000/00/00}% + \def\ExplFileDescription{#2}% + \def\ExplFileName{[unknown~name]}% + \def\ExplFileVersion{000}% + }% + \else + \def\tempa + {% + \endgroup + \GetIdInfoAuxII$#1${#2}% + }% + \fi + \tempa + } +\protected\def\GetIdInfoAuxII$#1 #2.#3 #4 #5 #6 #7 #8$#9% + {% + \def\ExplFileName{#2}% + \def\ExplFileVersion{#4}% + \def\ExplFileDescription{#9}% + \GetIdInfoAuxIII#5\relax#3\relax#5\relax#6\relax + } +\protected\def\GetIdInfoAuxIII#1#2#3#4#5#6\relax + {% + \ifx#5/% + \expandafter\GetIdInfoAuxCVS + \else + \expandafter\GetIdInfoAuxSVN + \fi + } +\protected\def\GetIdInfoAuxCVS#1,v\relax#2\relax#3\relax + {\def\ExplFileDate{#2}} +\protected\def\GetIdInfoAuxSVN#1\relax#2-#3-#4\relax#5Z\relax + {\def\ExplFileDate{#2/#3/#4}} +\protected\def\ProvidesExplPackage#1#2#3#4% + {% + \ProvidesPackage{#1}[#2 v#3 #4]% + \ExplSyntaxOn + } +\protected\def\ProvidesExplClass#1#2#3#4% + {% + \ProvidesClass{#1}[#2 v#3 #4]% + \ExplSyntaxOn + } +\protected\def\ProvidesExplFile#1#2#3#4% + {% + \ProvidesFile{#1}[#2 v#3 #4]% + \ExplSyntaxOn + } +\edef\@pushfilename + {% + \edef\expandafter\noexpand + \csname\detokenize{l_expl_status_stack_tl}\endcsname + {% + \noexpand\ifodd\expandafter\noexpand + \csname\detokenize{l_expl_status_bool}\endcsname + 1% + \noexpand\else + 0% + \noexpand\fi + \expandafter\noexpand + \csname\detokenize{l_expl_status_stack_tl}\endcsname + }% + \ExplSyntaxOff + \unexpanded\expandafter{\@pushfilename}% + } +\edef\@popfilename + {% + \unexpanded\expandafter{\@popfilename}% + \noexpand\if a\expandafter\noexpand\csname + \detokenize{l_expl_status_stack_tl}\endcsname a% + \ExplSyntaxOff + \noexpand\else + \noexpand\expandafter + \expandafter\noexpand\csname + \detokenize{expl_status_pop:w}\endcsname + \expandafter\noexpand\csname + \detokenize{l_expl_status_stack_tl}\endcsname + \noexpand\@nil + \noexpand\fi + } +\@namedef{\detokenize{l_expl_status_stack_tl}}{0} +\expandafter\edef\csname\detokenize{expl_status_pop:w}\endcsname#1#2\@nil + {% + \def\expandafter\noexpand + \csname\detokenize{l_expl_status_stack_tl}\endcsname{#2}% + \noexpand\ifodd#1\space + \noexpand\expandafter\noexpand\ExplSyntaxOn + \noexpand\else + \noexpand\expandafter\ExplSyntaxOff + \noexpand\fi + } +\expandafter\protected\expandafter\def + \csname\detokenize{package_check_loaded_expl:}\endcsname + {% + \@ifpackageloaded{expl3} + {} + {% + \PackageError{expl3} + {Cannot load the expl3 modules separately} + {% + The expl3 modules cannot be loaded separately;\MessageBreak + please \string\usepackage\string{expl3\string} instead. + }% + }% + } +\begingroup\expandafter\expandafter\expandafter\endgroup + \expandafter\ifx\csname pdfstrcmp\endcsname\relax + \let\pdfstrcmp\strcmp +\fi +\begingroup\expandafter\expandafter\expandafter\endgroup +\expandafter\ifx\csname pdfstrcmp\endcsname\relax + \PackageError{l3names}{Required primitive not found: \protect\pdfstrcmp} + {% + LaTeX3 requires the e-TeX primitives and + \string\pdfstrcmp.\MessageBreak + These are available in engine versions: \MessageBreak + - pdfTeX 1.30 \MessageBreak + - XeTeX 0.9994 \MessageBreak + - LuaTeX 0.60 \MessageBreak + or later. \MessageBreak + \MessageBreak + Loading of expl3 will abort! + } + \expandafter\endinput +\fi +\protected\edef\ExplSyntaxNamesOn + {% + \expandafter\noexpand + \csname\detokenize{char_set_catcode_letter:n}\endcsname{58}% + \expandafter\noexpand + \csname\detokenize{char_set_catcode_letter:n}\endcsname{95}% + } +\protected\edef\ExplSyntaxNamesOff + {% + \expandafter\noexpand + \csname\detokenize{char_set_catcode_math_subscript:n}\endcsname{58}% + \expandafter\noexpand + \csname\detokenize{char_set_catcode_other:n}\endcsname{95}% + } +%% +%% +%% End of file `l3bootstrap.sty'. diff --git a/Master/texmf-dist/tex/latex/l3kernel/l3box.sty b/Master/texmf-dist/tex/latex/l3kernel/l3box.sty new file mode 100644 index 00000000000..68db799fdf3 --- /dev/null +++ b/Master/texmf-dist/tex/latex/l3kernel/l3box.sty @@ -0,0 +1,219 @@ +%% +%% This is file `l3box.sty', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% l3box.dtx (with options: `package') +%% +%% EXPERIMENTAL CODE +%% +%% Do not distribute this file without also distributing the +%% source files specified above. +%% +%% Do not distribute a modified version of this file. +%% +%% File: l3box.dtx Copyright (C) 2005-2011 The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +\RequirePackage{l3names} +\GetIdInfo$Id: l3box.dtx 2478 2011-06-19 21:34:23Z joseph $ + {L3 Experimental boxes} +\ProvidesExplPackage + {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +\package_check_loaded_expl: +\cs_new_protected:Npn \box_new:N #1 + { + \chk_if_free_cs:N #1 + \newbox #1 + } +\cs_generate_variant:Nn \box_new:N { c } +\cs_new_protected_nopar:Npn \box_clear:N #1 + { \box_set_eq:NN #1 \c_empty_box } +\cs_new_protected_nopar:Npn \box_gclear:N #1 + { \box_gset_eq:NN #1 \c_empty_box } +\cs_generate_variant:Nn \box_clear:N { c } +\cs_generate_variant:Nn \box_gclear:N { c } +\cs_new_protected_nopar:Npn \box_clear_new:N #1 + { + \cs_if_exist:NTF #1 + { \box_set_eq:NN #1 \c_empty_box } + { \box_new:N #1 } + } +\cs_new_protected_nopar:Npn \box_gclear_new:N #1 + { + \cs_if_exist:NTF #1 + { \box_gset_eq:NN #1 \c_empty_box } + { \box_new:N #1 } + } +\cs_generate_variant:Nn \box_clear_new:N { c } +\cs_generate_variant:Nn \box_gclear_new:N { c } +\cs_new_protected_nopar:Npn \box_set_eq:NN #1#2 + { \tex_setbox:D #1 \tex_copy:D #2 } +\cs_new_protected_nopar:Npn \box_gset_eq:NN + { \pref_global:D \box_set_eq:NN } +\cs_generate_variant:Nn \box_set_eq:NN { cN , Nc , cc } +\cs_generate_variant:Nn \box_gset_eq:NN { cN , Nc , cc } +\cs_new_protected_nopar:Npn \box_set_eq_clear:NN #1#2 + { \tex_setbox:D #1 \tex_box:D #2 } +\cs_new_protected_nopar:Npn \box_gset_eq_clear:NN + { \pref_global:D \box_set_eq_clear:NN } +\cs_generate_variant:Nn \box_set_eq_clear:NN { cN , Nc , cc } +\cs_generate_variant:Nn \box_gset_eq_clear:NN { cN , Nc , cc } +\cs_new_eq:NN \box_ht:N \tex_ht:D +\cs_new_eq:NN \box_dp:N \tex_dp:D +\cs_new_eq:NN \box_wd:N \tex_wd:D +\cs_generate_variant:Nn \box_ht:N { c } +\cs_generate_variant:Nn \box_dp:N { c } +\cs_generate_variant:Nn \box_wd:N { c } +\cs_new_protected_nopar:Npn \box_set_dp:Nn #1#2 + { \box_dp:N #1 \dim_eval:w #2 \dim_eval_end: } +\cs_new_protected_nopar:Npn \box_set_ht:Nn #1#2 + { \box_ht:N #1 \dim_eval:w #2 \dim_eval_end: } +\cs_new_protected_nopar:Npn \box_set_wd:Nn #1#2 + { \box_wd:N #1 \dim_eval:w #2 \dim_eval_end: } +\cs_generate_variant:Nn \box_set_ht:Nn { c } +\cs_generate_variant:Nn \box_set_dp:Nn { c } +\cs_generate_variant:Nn \box_set_wd:Nn { c } +\cs_new_eq:NN \box_use_clear:N \tex_box:D +\cs_new_eq:NN \box_use:N \tex_copy:D +\cs_generate_variant:Nn \box_use_clear:N { c } +\cs_generate_variant:Nn \box_use:N { c } +\cs_new_protected:Npn \box_move_left:nn #1#2 + { \tex_moveleft:D \dim_eval:w #1 \dim_eval_end: #2 } +\cs_new_protected:Npn \box_move_right:nn #1#2 + { \tex_moveright:D \dim_eval:w #1 \dim_eval_end: #2 } +\cs_new_protected:Npn \box_move_up:nn #1#2 + { \tex_raise:D \dim_eval:w #1 \dim_eval_end: #2 } +\cs_new_protected:Npn \box_move_down:nn #1#2 + { \tex_lower:D \dim_eval:w #1 \dim_eval_end: #2 } +\cs_new_eq:NN \if_hbox:N \tex_ifhbox:D +\cs_new_eq:NN \if_vbox:N \tex_ifvbox:D +\cs_new_eq:NN \if_box_empty:N \tex_ifvoid:D +\prg_new_conditional:Npnn \box_if_horizontal:N #1 { p , T , F , TF } + { \if_hbox:N #1 \prg_return_true: \else: \prg_return_false: \fi: } +\prg_new_conditional:Npnn \box_if_vertical:N #1 { p , T , F , TF } + { \if_vbox:N #1 \prg_return_true: \else: \prg_return_false: \fi: } +\cs_generate_variant:Nn \box_if_horizontal_p:N { c } +\cs_generate_variant:Nn \box_if_horizontal:NT { c } +\cs_generate_variant:Nn \box_if_horizontal:NF { c } +\cs_generate_variant:Nn \box_if_horizontal:NTF { c } +\cs_generate_variant:Nn \box_if_vertical_p:N { c } +\cs_generate_variant:Nn \box_if_vertical:NT { c } +\cs_generate_variant:Nn \box_if_vertical:NF { c } +\cs_generate_variant:Nn \box_if_vertical:NTF { c } +\prg_new_conditional:Npnn \box_if_empty:N #1 { p , T , F , TF } + { \if_box_empty:N #1 \prg_return_true: \else: \prg_return_false: \fi: } +\cs_generate_variant:Nn \box_if_empty_p:N { c } +\cs_generate_variant:Nn \box_if_empty:NT { c } +\cs_generate_variant:Nn \box_if_empty:NF { c } +\cs_generate_variant:Nn \box_if_empty:NTF { c } +\cs_new_eq:NN \l_last_box \tex_lastbox:D +\cs_new_protected_nopar:Npn \box_set_to_last:N #1 + { \tex_setbox:D #1 \l_last_box } +\cs_new_protected_nopar:Npn \box_gset_to_last:N + { \pref_global:D \box_set_to_last:N } +\cs_generate_variant:Nn \box_set_to_last:N { c } +\cs_generate_variant:Nn \box_gset_to_last:N { c } +\cs_new_eq:NN \c_empty_box \voidb@x +\cs_new_eq:NN \l_tmpa_box \@tempboxa +\box_new:N \l_tmpb_box +\cs_new_eq:NN \box_show:N \tex_showbox:D +\cs_generate_variant:Nn \box_show:N { c } +\cs_new_protected_nopar:Npn \hbox:n { \tex_hbox:D \scan_stop: } +\cs_new_protected:Npn \hbox_set:Nn #1#2 { \tex_setbox:D #1 \tex_hbox:D {#2} } +\cs_new_protected_nopar:Npn \hbox_gset:Nn { \pref_global:D \hbox_set:Nn } +\cs_generate_variant:Nn \hbox_set:Nn { c } +\cs_generate_variant:Nn \hbox_gset:Nn { c } +\cs_new_protected:Npn \hbox_set_to_wd:Nnn #1#2#3 + { \tex_setbox:D #1 \tex_hbox:D to \dim_eval:w #2 \dim_eval_end: {#3} } +\cs_new_protected_nopar:Npn \hbox_gset_to_wd:Nnn + { \pref_global:D \hbox_set_to_wd:Nnn } +\cs_generate_variant:Nn \hbox_set_to_wd:Nnn { c } +\cs_generate_variant:Nn \hbox_gset_to_wd:Nnn {cnn} +\cs_new_protected_nopar:Npn \hbox_set_inline_begin:N #1 + { \tex_setbox:D #1 \tex_hbox:D \c_group_begin_token } +\cs_new_protected_nopar:Npn \hbox_gset_inline_begin:N + { \pref_global:D \hbox_set_inline_begin:N } +\cs_generate_variant:Nn \hbox_set_inline_begin:N { c } +\cs_generate_variant:Nn \hbox_gset_inline_begin:N { c } +\cs_new_eq:NN \hbox_set_inline_end: \c_group_end_token +\cs_new_eq:NN \hbox_gset_inline_end: \c_group_end_token +\cs_new_protected:Npn \hbox_to_wd:nn #1#2 + { \tex_hbox:D to \dim_eval:w #1 \dim_eval_end: {#2} } +\cs_new_protected:Npn \hbox_to_zero:n #1 { \tex_hbox:D to \c_zero_skip {#1} } +\cs_new_protected:Npn \hbox_overlap_left:n #1 + { \hbox_to_zero:n { \tex_hss:D #1 } } +\cs_new_protected:Npn \hbox_overlap_right:n #1 + { \hbox_to_zero:n { #1 \tex_hss:D } } +\cs_new_eq:NN \hbox_unpack:N \tex_unhcopy:D +\cs_new_eq:NN \hbox_unpack_clear:N \tex_unhbox:D +\cs_generate_variant:Nn \hbox_unpack:N { c } +\cs_generate_variant:Nn \hbox_unpack_clear:N { c } +\cs_new_protected_nopar:Npn \vbox:n { \tex_vbox:D \scan_stop: } +\cs_new_protected_nopar:Npn \vbox_top:n { \tex_vtop:D \scan_stop: } +\cs_new_protected:Npn \vbox_to_ht:nn #1#2 + { \tex_vbox:D to \dim_eval:w #1 \dim_eval_end: {#2} } +\cs_new_protected:Npn \vbox_to_zero:n #1 { \tex_vbox:D to \c_zero_dim {#1} } +\cs_new_protected:Npn \vbox_set:Nn #1#2 { \tex_setbox:D #1 \tex_vbox:D {#2} } +\cs_new_protected_nopar:Npn \vbox_gset:Nn { \pref_global:D \vbox_set:Nn } +\cs_generate_variant:Nn \vbox_set:Nn { c } +\cs_generate_variant:Nn \vbox_gset:Nn { c } +\cs_new_protected:Npn \vbox_set_top:Nn #1#2 + { \tex_setbox:D #1 \tex_vtop:D {#2} } +\cs_new_protected_nopar:Npn \vbox_gset_top:Nn + { \pref_global:D \vbox_set_top:Nn } +\cs_generate_variant:Nn \vbox_set_top:Nn { c } +\cs_generate_variant:Nn \vbox_gset_top:Nn { c } +\cs_new_protected:Npn \vbox_set_to_ht:Nnn #1#2#3 + { \tex_setbox:D #1 \tex_vbox:D to \dim_eval:w #2 \dim_eval_end: {#3} } +\cs_new_protected_nopar:Npn \vbox_gset_to_ht:Nnn + { \pref_global:D \vbox_set_to_ht:Nnn } +\cs_generate_variant:Nn \vbox_set_to_ht:Nnn { c } +\cs_generate_variant:Nn \vbox_gset_to_ht:Nnn { c } +\cs_new_nopar:Npn \vbox_set_inline_begin:N #1 + { \tex_setbox:D #1 \tex_vbox:D \c_group_begin_token } +\cs_new_protected_nopar:Npn \vbox_gset_inline_begin:N + { \pref_global:D \vbox_set_inline_begin:N } +\cs_generate_variant:Nn \vbox_set_inline_begin:N { c } +\cs_generate_variant:Nn \vbox_gset_inline_begin:N { c } +\cs_new_eq:NN \vbox_set_inline_end: \c_group_end_token +\cs_new_eq:NN \vbox_gset_inline_end: \c_group_end_token +\cs_new_eq:NN \vbox_unpack:N \tex_unvcopy:D +\cs_new_eq:NN \vbox_unpack_clear:N \tex_unvbox:D +\cs_generate_variant:Nn \vbox_unpack:N { c } +\cs_generate_variant:Nn \vbox_unpack_clear:N { c } +\cs_new_protected_nopar:Npn \vbox_set_split_to_ht:NNn #1#2#3 + { \tex_setbox:D #1 \tex_vsplit:D #2 to \dim_eval:w #3 \dim_eval_end: } +%% +%% +%% End of file `l3box.sty'. diff --git a/Master/texmf-dist/tex/latex/l3kernel/l3clist.sty b/Master/texmf-dist/tex/latex/l3kernel/l3clist.sty new file mode 100644 index 00000000000..ab92e649563 --- /dev/null +++ b/Master/texmf-dist/tex/latex/l3kernel/l3clist.sty @@ -0,0 +1,426 @@ +%% +%% This is file `l3clist.sty', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% l3clist.dtx (with options: `package') +%% +%% EXPERIMENTAL CODE +%% +%% Do not distribute this file without also distributing the +%% source files specified above. +%% +%% Do not distribute a modified version of this file. +%% +%% File: l3clist.dtx Copyright (C) 2004-2011 Frank Mittelbach, +%% The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +\RequirePackage{l3names} +\GetIdInfo$Id: l3clist.dtx 2498 2011-07-09 17:51:47Z joseph $ + {L3 Experimental comma separated lists} +\ProvidesExplPackage + {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +\package_check_loaded_expl: +\tl_new:N \l_clist_tmpa_tl +\tl_new:N \l_clist_tmpb_tl +\cs_new_eq:NN \clist_new:N \tl_new:N +\cs_new_eq:NN \clist_new:c \tl_new:c +\cs_new_eq:NN \clist_clear:N \tl_clear:N +\cs_new_eq:NN \clist_clear:c \tl_clear:c +\cs_new_eq:NN \clist_gclear:N \tl_gclear:N +\cs_new_eq:NN \clist_gclear:c \tl_gclear:c +\cs_new_eq:NN \clist_clear_new:N \tl_clear_new:N +\cs_new_eq:NN \clist_clear_new:c \tl_clear_new:c +\cs_new_eq:NN \clist_gclear_new:N \tl_gclear_new:N +\cs_new_eq:NN \clist_gclear_new:c \tl_gclear_new:c +\cs_new_eq:NN \clist_set_eq:NN \tl_set_eq:NN +\cs_new_eq:NN \clist_set_eq:Nc \tl_set_eq:Nc +\cs_new_eq:NN \clist_set_eq:cN \tl_set_eq:cN +\cs_new_eq:NN \clist_set_eq:cc \tl_set_eq:cc +\cs_new_eq:NN \clist_gset_eq:NN \tl_gset_eq:NN +\cs_new_eq:NN \clist_gset_eq:Nc \tl_gset_eq:Nc +\cs_new_eq:NN \clist_gset_eq:cN \tl_gset_eq:cN +\cs_new_eq:NN \clist_gset_eq:cc \tl_gset_eq:cc +\cs_new_protected_nopar:Npn \clist_concat:NNN + { \clist_concat_aux:NNNN \tl_set:Nx } +\cs_new_protected_nopar:Npn \clist_gconcat:NNN + { \clist_concat_aux:NNNN \tl_gset:Nx } +\cs_new_protected_nopar:Npn \clist_concat_aux:NNNN #1#2#3#4 + { + #1 #2 + { + \clist_if_empty:NTF #3 + { \exp_not:o #4 } + { + \exp_not:o #3 + \clist_if_empty:NF #4 + { + , + \exp_not:o #4 + } + } + } + } +\cs_generate_variant:Nn \clist_concat:NNN { ccc } +\cs_generate_variant:Nn \clist_gconcat:NNN { ccc } +\cs_new_protected_nopar:Npn \clist_put_left:Nn + { \clist_put_aux:NNnnNn \tl_set:Nn \tl_put_left:Nn { } , } +\cs_new_protected_nopar:Npn \clist_gput_left:Nn + { \clist_put_aux:NNnnNn \tl_gset:Nn \tl_gput_left:Nn { } , } +\cs_new_protected:Npn \clist_put_aux:NNnnNn #1#2#3#4#5#6 + { + \clist_if_empty:NTF #5 + { #1 #5 {#6} } + { \tl_if_empty:nF {#6} { #2 #5 { #3 #6 #4 } } } + } +\cs_generate_variant:Nn \clist_put_left:Nn { NV , No , Nx } +\cs_generate_variant:Nn \clist_put_left:Nn { c , cV , co , cx } +\cs_generate_variant:Nn \clist_gput_left:Nn { NV , No , Nx } +\cs_generate_variant:Nn \clist_gput_left:Nn { c , cV , co , cx } +\cs_new_protected:Npn \clist_put_right:Nn + { \clist_put_aux:NNnnNn \tl_set:Nn \tl_put_right:Nn , { } } +\cs_new_protected_nopar:Npn \clist_gput_right:Nn + { \clist_put_aux:NNnnNn \tl_gset:Nn \tl_gput_right:Nn , { } } +\cs_generate_variant:Nn \clist_put_right:Nn { NV , No , Nx } +\cs_generate_variant:Nn \clist_put_right:Nn { c , cV , co , cx } +\cs_generate_variant:Nn \clist_gput_right:Nn { NV , No , Nx } +\cs_generate_variant:Nn \clist_gput_right:Nn { c , cV , co , cx } +\cs_new_protected_nopar:Npn \clist_get:NN #1#2 + { \exp_after:wN \clist_get_aux:wN #1 , \q_stop #2 } +\cs_new_protected:Npn \clist_get_aux:wN #1 , #2 \q_stop #3 + { \tl_set:Nn #3 {#1} } +\cs_generate_variant:Nn \clist_get:NN { c } +\cs_new_protected_nopar:Npn \clist_pop:NN + { \clist_pop_aux:NNN \tl_set:Nn } +\cs_new_protected_nopar:Npn \clist_gpop:NN + { \clist_pop_aux:NNN \tl_gset:Nn } +\cs_new_protected_nopar:Npn \clist_pop_aux:NNN #1#2#3 + { \exp_after:wN \clist_pop_aux:wNNN #2 , \q_nil , \q_nil , \q_stop #1#2#3 } +\cs_new_protected:Npn \clist_pop_aux:wNNN #1 , #2 , \q_nil , #3 \q_stop #4#5#6 + { + \quark_if_nil:nTF {#2} + { #4 #5 { } } + { #4 #5 {#2} } + \tl_set:Nn #6 {#1} + } +\cs_generate_variant:Nn \clist_pop:NN { c } +\cs_generate_variant:Nn \clist_gpop:NN { c } +\cs_new_eq:NN \clist_push:Nn \clist_put_left:Nn +\cs_new_eq:NN \clist_push:NV \clist_put_left:NV +\cs_new_eq:NN \clist_push:No \clist_put_left:No +\cs_new_eq:NN \clist_push:Nx \clist_put_left:Nx +\cs_new_eq:NN \clist_push:cn \clist_put_left:cn +\cs_new_eq:NN \clist_push:cV \clist_put_left:cV +\cs_new_eq:NN \clist_push:co \clist_put_left:co +\cs_new_eq:NN \clist_push:cx \clist_put_left:cx +\cs_new_eq:NN \clist_gpush:Nn \clist_gput_left:Nn +\cs_new_eq:NN \clist_gpush:NV \clist_gput_left:NV +\cs_new_eq:NN \clist_gpush:No \clist_gput_left:No +\cs_new_eq:NN \clist_gpush:Nx \clist_gput_left:Nx +\cs_new_eq:NN \clist_gpush:cn \clist_gput_left:cn +\cs_new_eq:NN \clist_gpush:cV \clist_gput_left:cV +\cs_new_eq:NN \clist_gpush:co \clist_gput_left:co +\cs_new_eq:NN \clist_gpush:cx \clist_gput_left:cx +\cs_new_eq:NN \clist_use:N \tl_use:N +\cs_new_eq:NN \clist_use:c \tl_use:c +\clist_new:N \l_clist_remove_clist +\cs_new_protected:Npn \clist_remove_duplicates:N + { \clist_remove_duplicates_aux:NN \clist_set_eq:NN } +\cs_new_protected:Npn \clist_gremove_duplicates:N + { \clist_remove_duplicates_aux:NN \clist_gset_eq:NN } +\cs_new_protected:Npn \clist_remove_duplicates_aux:NN #1#2 + { + \clist_clear:N \l_clist_remove_clist + \clist_map_inline:Nn #2 + { + \clist_if_in:NnF \l_clist_remove_clist {##1} + { \clist_put_right:Nn \l_clist_remove_clist {##1} } + } + #1 #2 \l_clist_remove_clist + } +\cs_generate_variant:Nn \clist_remove_duplicates:N { c } +\cs_generate_variant:Nn \clist_gremove_duplicates:N { c } +\cs_new_protected:Npn \clist_remove_all:Nn + { \clist_remove_all_aux:NNn \clist_set_eq:NN } +\cs_new_protected:Npn \clist_gremove_all:Nn + { \clist_remove_all_aux:NNn \clist_gset_eq:NN } +\cs_new_protected:Npn \clist_remove_all_aux:NNn #1#2#3 + { + \clist_if_empty:NF #2 + { + \clist_clear:N \l_clist_remove_clist + \cs_set_protected:Npn \clist_remove_all_aux:w + ##1 , #3 , ##2 \q_stop + { + \tl_put_right:Nn \l_clist_remove_clist {##1} + \quark_if_no_value:nF {##2} + { \clist_remove_all_aux:w , ##2 \q_stop } + } + \exp_after:wN \clist_remove_all_aux:w + \exp_after:wN , #2 , #3 , \q_no_value \q_stop + \tl_if_empty:NF \l_clist_remove_clist + { + \exp_after:wN \tl_set:No \exp_after:wN + \l_clist_remove_clist \exp_after:wN + { \exp_after:wN \use_none:n \l_clist_remove_clist } + } + #1 #2 \l_clist_remove_clist + } + } +\cs_new_protected:Npn \clist_remove_all_aux:w { } +\cs_generate_variant:Nn \clist_remove_all:Nn { c } +\cs_generate_variant:Nn \clist_gremove_all:Nn { c } +\cs_new:Npn \clist_trim_spaces:n #1 + { + \exp_args:Nf \clist_trim_spaces_aux_i:n + { \clist_map_function:nN {#1} \clist_trim_spaces_aux_ii:n } + } +\cs_new:Npn \clist_trim_spaces_aux_i:n #1 { \use_ii:nn #1 } +\cs_new:Npn \clist_trim_spaces_aux_ii:n #1 + { , \tl_trim_spaces:n {#1} } +\cs_new_protected:Npn \clist_trim_spaces:N #1 + { \tl_set:Nf #1 { \exp_args:No \clist_trim_spaces:n #1 } } +\cs_new_protected:Npn \clist_gtrim_spaces:N #1 + { \tl_gset:Nf #1 { \exp_args:No \clist_trim_spaces:n #1 } } +\cs_generate_variant:Nn \clist_trim_spaces:N { c } +\cs_generate_variant:Nn \clist_gtrim_spaces:N { c } +\cs_new_protected:Npn \clist_tmp:w { } +\prg_new_eq_conditional:NNn \clist_if_empty:N \tl_if_empty:N { p , T , F , TF } +\prg_new_eq_conditional:NNn \clist_if_empty:c \tl_if_empty:c { p , T , F , TF } +\prg_new_eq_conditional:NNn \clist_if_eq:NN \tl_if_eq:NN { p , T , F , TF } +\prg_new_eq_conditional:NNn \clist_if_eq:Nc \tl_if_eq:Nc { p , T , F , TF } +\prg_new_eq_conditional:NNn \clist_if_eq:cN \tl_if_eq:cN { p , T , F , TF } +\prg_new_eq_conditional:NNn \clist_if_eq:cc \tl_if_eq:cc { p , T , F , TF } +\prg_new_protected_conditional:Npnn \clist_if_in:Nn #1#2 + { T , F , TF } + { + \cs_set_protected:Npn \clist_tmp:w ##1 , #2 , ##2##3 \q_stop + { + \if_meaning:w \q_no_value ##2 + \prg_return_false: + \else: + \prg_return_true: + \fi: + } + \exp_last_unbraced:NNo \clist_tmp:w , #1 , #2 , \q_no_value \q_stop + } +\prg_new_protected_conditional:Npnn \clist_if_in:nn #1#2 + { T , F , TF } + { + \cs_set_protected:Npn \clist_tmp:w ##1 , #2 , ##2##3 \q_stop + { + \if_meaning:w \q_no_value ##2 + \prg_return_false: + \else: + \prg_return_true: + \fi: + } + \clist_tmp:w , #1 , #2 , \q_no_value \q_stop + } +\cs_generate_variant:Nn \clist_if_in:NnT { NV , No } +\cs_generate_variant:Nn \clist_if_in:NnT { c , cV , co } +\cs_generate_variant:Nn \clist_if_in:NnF { NV , No } +\cs_generate_variant:Nn \clist_if_in:NnF { c , cV , co } +\cs_generate_variant:Nn \clist_if_in:NnTF { NV , No } +\cs_generate_variant:Nn \clist_if_in:NnTF { c , cV , co } +\cs_generate_variant:Nn \clist_if_in:nnT { nV , no } +\cs_generate_variant:Nn \clist_if_in:nnF { nV , no } +\cs_generate_variant:Nn \clist_if_in:nnTF { nV , no } +\cs_new_nopar:Npn \clist_map_function:NN #1#2 + { + \clist_if_empty:NF #1 + { + \exp_last_unbraced:NNo \clist_map_function_aux:Nw #2 #1 + , \q_recursion_tail , \q_recursion_stop + } + } +\cs_new:Npn \clist_map_function:nN #1#2 + { + \tl_if_empty:nF {#1} + { + \clist_map_function_aux:Nw #2 #1 + , \q_recursion_tail , \q_recursion_stop + } + } +\cs_new:Npn \clist_map_function_aux:Nw #1#2 , + { + \quark_if_recursion_tail_stop:n {#2} + #1 {#2} + \clist_map_function_aux:Nw #1 + } +\cs_generate_variant:Nn \clist_map_function:NN { c } +\int_new:N \g_clist_map_inline_int +\cs_new_protected:Npn \clist_map_inline:Nn #1#2 + { + \int_gincr:N \g_clist_map_inline_int + \cs_gset:cpn { clist_map_inline_ \int_use:N \g_clist_map_inline_int :n } + ##1 + {#2} + \exp_args:NNc \clist_map_function:NN #1 + { clist_map_inline_ \int_use:N \g_clist_map_inline_int :n } + \int_gdecr:N \g_clist_map_inline_int + } +\cs_new_protected:Npn \clist_map_inline:nn #1#2 + { + \int_gincr:N \g_clist_map_inline_int + \cs_gset:cpn { clist_map_inline_ \int_use:N \g_clist_map_inline_int :n } + ##1 + {#2} + \exp_args:Nnc \clist_map_function:nN {#1} + { clist_map_inline_ \int_use:N \g_clist_map_inline_int :n } + \int_gdecr:N \g_clist_map_inline_int + } +\cs_generate_variant:Nn \clist_map_inline:Nn { c } +\cs_new_protected:Npn \clist_map_variable:NNn #1#2#3 + { + \clist_map_inline:Nn #1 + { + \tl_set:Nn #2 {##1} + #3 + } + } +\cs_new_protected:Npn \clist_map_variable:nNn #1#2#3 + { + \clist_map_inline:nn {#1} + { + \tl_set:Nn #2 {##1} + #3 + } + } +\cs_generate_variant:Nn \clist_map_variable:NNn { c } +\cs_new_eq:NN \clist_map_break: \use_none_delimit_by_q_recursion_stop:w +\cs_new_eq:NN \clist_map_break:n \use_i_delimit_by_q_recursion_stop:nw +\cs_new_protected_nopar:Npn \clist_show:N #1 + { + \clist_if_empty:NTF #1 + { + \iow_term:x { Comma~list~\token_to_str:N #1 \c_space_tl is~empty } + \tl_show:n { } + } + { + \iow_term:x + { + Comma~list~\token_to_str:N #1 \c_space_tl + contains~the~items~(without~outer~braces): + } + \tl_set:Nx \l_clist_show_tl + { \clist_map_function:NN #1 \clist_show_aux:n } + \etex_showtokens:D \exp_after:wN \exp_after:wN \exp_after:wN + { \exp_after:wN \clist_show_aux:w \l_clist_show_tl } + } + } +\cs_new:Npn \clist_show_aux:n #1 + { + \iow_newline: > \c_space_tl \c_space_tl + \iow_char:N \{ \exp_not:n {#1} \iow_char:N \} + } +\cs_new:Npn \clist_show_aux:w #1 > ~ { } +\cs_generate_variant:Nn \clist_show:N { c } +\cs_new:Npn \clist_length:N #1 + { + \int_eval:n + { + 0 + \clist_map_function:NN #1 \clist_length_aux:n + } + } +\cs_new:Npn \clist_length:n #1 + { + \int_eval:n + { + 0 + \clist_map_function:nN {#1} \clist_length_aux:n + } + } +\cs_new:Npn \clist_length_aux:n #1 { +1 } +\cs_generate_variant:Nn \clist_length:N { c } +\cs_set_nopar:Npn \clist_item:Nn #1#2 + { \exp_args:No \clist_item:nn #1 {#2} } +\cs_set:Npn \clist_item:nn #1#2 + { + \int_compare:nNnTF {#2} < \c_zero + { + \exp_args:Nf \clist_item_aux:nw + { \int_eval:n { \clist_length:n {#1} + #2 } } + #1 , \q_recursion_tail \q_recursion_stop + } + { \clist_item_aux:nw {#2} #1 , \q_recursion_tail \q_recursion_stop } + } +\cs_set:Npn \clist_item_aux:nw #1#2 , #3 + { + \int_compare:nNnTF {#1} = \c_zero + { \use_i_delimit_by_q_recursion_stop:nw {#2} } + { + \quark_if_recursion_tail_stop:n {#3} + \exp_args:Nf \clist_item_aux:nw + { \int_eval:n { #1 - 1 } } + #3 + } + } +\cs_generate_variant:Nn \clist_item:Nn { c } +\cs_new_protected:Npn \clist_set_from_seq:NN #1#2 + { + \seq_if_empty:NTF #2 + { \clist_clear:N #1 } + { + \seq_push_item_def:n { , \exp_not:n {{##1}} } + \tl_set:Nx #1 + { \exp_after:wN \use_none:n \tex_romannumeral:D -`\0 #2 } + \seq_pop_item_def: + } + } +\cs_new_protected:Npn \clist_gset_from_seq:NN #1#2 + { + \seq_if_empty:NTF #2 + { \clist_gclear:N #1 } + { + \seq_push_item_def:n { , \exp_not:n {##1} } + \tl_gset:Nx #1 + { \exp_after:wN \use_none:n \tex_romannumeral:D -`\0 #2 } + \seq_pop_item_def: + } + } +\cs_generate_variant:Nn \clist_set_from_seq:NN { Nc } +\cs_generate_variant:Nn \clist_set_from_seq:NN { c , cc } +\cs_generate_variant:Nn \clist_gset_from_seq:NN { Nc } +\cs_generate_variant:Nn \clist_gset_from_seq:NN { c , cc } +\cs_new_eq:NN \clist_top:NN \clist_get:NN +\cs_new_eq:NN \clist_top:cN \clist_get:cN +\cs_new_eq:NN \clist_remove_element:Nn \clist_remove_all:Nn +\cs_new_eq:NN \clist_gremove_element:Nn \clist_gremove_all:Nn +\cs_new_eq:NN \clist_display:N \clist_show:N +\cs_new_eq:NN \clist_display:c \clist_show:c +%% +%% +%% End of file `l3clist.sty'. diff --git a/Master/texmf-dist/tex/latex/l3kernel/l3doc.cls b/Master/texmf-dist/tex/latex/l3kernel/l3doc.cls new file mode 100644 index 00000000000..258a8475eb9 --- /dev/null +++ b/Master/texmf-dist/tex/latex/l3kernel/l3doc.cls @@ -0,0 +1,1001 @@ +%% +%% This is file `l3doc.cls', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% l3doc.dtx (with options: `class') +%% +%% +%% EXPERIMENTAL CODE +%% +%% Do not distribute this file without also distributing the +%% source files specified above. +%% +%% Do not distribute a modified version of this file. +%% +%% +%% File: l3doc.dtx Copyright (C) 1990-2011 The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +\RequirePackage{l3names} +\let \filenameOld \ExplFileName +\let \filedateOld \ExplFileDate +\let \fileversionOld \ExplFileVersion +\let \filedescriptionOld \ExplFileDescription +\GetIdInfo$Id: l3doc.dtx 2478 2011-06-19 21:34:23Z joseph $ + {L3 Experimental documentation class} +\ProvidesExplClass + {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +\RequirePackage{expl3,xparse} +\let \ExplFileName \filenameOld +\let \ExplFileDate \filedateOld +\let \ExplFileVersion \fileversionOld +\let \ExplFileDescription \filedescriptionOld +\cs_new_nopar:Npn\Team{% + The~\LaTeX3~Project\thanks{% + Frank~Mittelbach,~Denys~Duchier,~Chris~Rowley,~ + Rainer~Sch\"opf,~Johannes~Braams,~Michael~Downes,~ + David~Carlisle,~Alan~Jeffrey,~Morten~H\o{}gholm,~Thomas~Lotze,~ + Javier~Bezos,~Will~Robertson,~Joseph~Wright}} +\DeclareOption{a5paper}{\@latexerr{Option not supported}{}} +\bool_new:N \g_doc_full_bool +\bool_new:N \g_doc_lmodern_bool +\bool_new:N \g_doc_checkfunc_bool +\bool_new:N \g_doc_checktest_bool +\DeclareOption{full}{ \bool_set_true:N \g_doc_full_bool } +\DeclareOption{onlydoc}{ \bool_set_false:N \g_doc_full_bool } +\DeclareOption{check}{ \bool_set_true:N \g_doc_checkfunc_bool } +\DeclareOption{nocheck}{ \bool_set_false:N \g_doc_checkfunc_bool } +\DeclareOption{checktest}{ \bool_set_true:N \g_doc_checktest_bool } +\DeclareOption{nochecktest}{ \bool_set_false:N \g_doc_checktest_bool } +\DeclareOption{cm-default}{ \bool_set_false:N \g_doc_lmodern_bool } +\DeclareOption{lm-default}{ \bool_set_true:N \g_doc_lmodern_bool } +\DeclareOption*{\PassOptionsToClass{\CurrentOption}{article}} +\ExecuteOptions{full,a4paper,nocheck,nochecktest,lm-default} +\InputIfFileExists{l3doc.cfg} + { + \typeout{*************************************^^J + *~Local~config~file~l3doc.cfg~used ^^J + *************************************} + } + { \@input{l3doc.ltx} } +\ProcessOptions +\LoadClass{article} +\RequirePackage{doc} +\RequirePackage{array,alphalph,booktabs,color,fixltx2e,enumitem,textcomp,trace,underscore,csquotes} +\bool_if:NT \g_doc_lmodern_bool { + \RequirePackage[T1]{fontenc} + \RequirePackage{lmodern} +} +\RequirePackage{hypdoc} +\let\doc@verbatim\verbatim +\let\enddoc@verbatim\endverbatim +\let\doc@@verbatim\@verbatim +\expandafter\let\csname doc@verbatim*\expandafter\endcsname + \csname verbatim*\endcsname +\expandafter\let\csname enddoc@verbatim*\expandafter\endcsname + \csname endverbatim*\endcsname +\expandafter\let\csname doc@@verbatim*\expandafter\endcsname + \csname @verbatim*\endcsname +\RequirePackage{verbatim} +\AtBeginDocument{% + \let\verbatim\doc@verbatim + \let\endverbatim\enddoc@verbatim + \let\@verbatim\doc@@verbatim + \expandafter\let\csname verbatim*\expandafter\endcsname + \csname doc@verbatim*\endcsname + \expandafter\let\csname endverbatim*\expandafter\endcsname + \csname enddoc@verbatim*\endcsname + \expandafter\let\csname @verbatim*\expandafter\endcsname + \csname doc@@verbatim*\endcsname +} +\cs_set_nopar:Npn \MakePrivateLetters { + \char_set_catcode_letter:N \@ + \char_set_catcode_letter:N \_ + \char_set_catcode_letter:N \: +} +\setcounter{StandardModuleDepth}{1} +\@addtoreset{CodelineNo}{part} +\cs_set_nopar:Npn \theCodelineNo { + \textcolor[gray]{0.5}{ \sffamily\tiny\arabic{CodelineNo} } +} +\setlength \textwidth { 385pt } +\addtolength \marginparwidth { 30pt } +\addtolength \oddsidemargin { 20pt } +\addtolength \evensidemargin { 20pt } +\cs_set_eq:NN \@@oldlist\list +\cs_set_nopar:Npn \list#1#2{\@@oldlist{#1}{#2\listparindent\z@}} +\setlength \parindent { 0pt } +\setlength \itemindent { 0pt } +\setlength \parskip { \medskipamount } +\AtBeginDocument { + \MakeShortVerb \" + \MakeShortVerb \| +} +\providecommand*\eTeX{ + \if b\expandafter\@car\f@series\@nil\boldmath\fi + $\m@th\varepsilon$-\TeX +} +\providecommand*\IniTeX{Ini\TeX} +\providecommand*\Lua{Lua} +\providecommand*\LuaTeX{\Lua\TeX} +\providecommand*\pdfTeX{pdf\TeX} +\RequirePackage{graphicx} +\cs_if_free:NT \XeTeX { + \cs_new_protected_nopar:Npn \XeTeX + {X\kern-.125em\lower.5ex\hbox{\reflectbox{E}}\kern-.1667em\TeX} +} +\cs_set_nopar:Npn \cmd #1 { \cs{\expandafter\cmd@to@cs\string#1} } +\cs_set_nopar:Npn \cmd@to@cs #1#2 { \char\number`#2\relax } +\DeclareRobustCommand \cs [1] { \texttt { \char`\\ #1 } } +\providecommand\marg[1]{ \texttt{\char`\{} \meta{#1} \texttt{\char`\}} } +\providecommand\oarg[1]{ \texttt[ \meta{#1} \texttt] } +\providecommand\parg[1]{ \texttt( \meta{#1} \texttt) } +\cs_set_eq:NN \m \meta +\cs_set_eq:NN \file \nolinkurl +\DeclareRobustCommand \env {\texttt} +\DeclareRobustCommand \pkg {\textsf} +\DeclareRobustCommand \cls {\textsf} +\newenvironment{texnote}{ + \endgraf + \vspace{3mm} + \small\textbf{\TeX~hackers~note:} +}{ + \vspace{3mm} +} +\newcommand\tn[1]{ + \texttt{\bslash #1} + \index{TeX~and~LaTeX2e~commands\actualchar + \string\TeX{}~and~\string\LaTeXe{}~commands:\levelchar + #1\actualchar{\string\ttfamily\string\bslash{}#1}}} +\cs_new:Npn \doc_implementation: { + \cs_set:Npn \variable {\macro[var]} +} +\cs_new:Npn \doc_docu: { + \cs_set_eq:NN \variable \variabledoc +} +\AtEndOfPackage{\doc_docu:} +\newenvironment{documentation}{\doc_docu:}{} +\newenvironment{implementation}{\doc_implementation:}{} +\newcommand\EnableDocumentation{% + \renewenvironment{documentation}{\doc_docu:}{}% +} +\newcommand\EnableImplementation{% + \renewenvironment{implementation}{\doc_implementation:}{}% +} +\newcommand\DisableDocumentation{% + \cs_set_eq:NN \documentation \comment + \cs_set_eq:NN \enddocumentation \endcomment +} +\newcommand\DisableImplementation{% + \cs_set_eq:NN \implementation \comment + \cs_set_eq:NN \endimplementation \endcomment +} +\newenvironment{arguments}{ + \enumerate[ + nolistsep, + label=\texttt{\#\arabic*}~:, + labelsep=*, + ] +}{ + \endenumerate +} +\char_set_catcode_active:N \< +\DeclareDocumentCommand \function { O{} } { + + \phantomsection + + \bool_gset_false:N \l_doc_meta_TF_bool + \bool_gset_false:N \l_doc_meta_pTF_bool + \bool_gset_false:N \l_doc_meta_EXP_bool + + \cs_set_nopar:Npn \KV_key_no_value_elt:n ##1 { \use:c {doc_meta_opt_##1:} } + \keyval_parse:NNn \KV_key_no_value_elt:n \use_none:nn {#1} + + \char_set_catcode_active:N \< + \cs_set_eq:NN < \doc_open_meta:n + + \group_begin: + \MakePrivateLetters + \char_set_catcode_other:N \| + \char_set_catcode_other:N \\ + \char_set_catcode_space:N \~ + \char_set_catcode_ignore:N \ % space + \char_set_catcode_ignore:N \^^M + \char_set_catcode_ignore:N \^^I + \function_aux:n +} +\char_set_catcode_other:N \< +\cs_set_eq:NN \variabledoc \function +\cs_set:Nn \doc_meta_opt_TF: { + \bool_gset_true:N \l_doc_meta_TF_bool +} +\cs_set:Nn \doc_meta_opt_EXP: { + \bool_gset_true:N \l_doc_meta_EXP_bool +} +\cs_set:Nn \doc_meta_opt_pTF: { + \bool_gset_true:N \l_doc_meta_pTF_bool + \bool_gset_true:N \l_doc_meta_TF_bool + \bool_gset_true:N \l_doc_meta_EXP_bool +} +\group_begin: +\char_set_catcode_other:N \| +\cs_gset_nopar:Npn \function_aux:n #1 { + \cs_set_nopar:Npn \nextnewline{\cs_gset_nopar:Npn\nextnewline{\\}} + \tl_gset_eq:NN \g_doc_macro_tl \c_empty_tl + \bigskip\endgraf\noindent\ttfamily + \tabular[b]{ | l @{} c | } + \hline + \clist_map_inline:nn {#1} {\doc_showmacro:w ##1 | \q_stop} \\ + \hline + \endtabular + \group_end: +} +\group_end: +\group_begin: +\char_set_catcode_other:N \| +\cs_gset_nopar:Npn \doc_showmacro:w #1 | { + \tl_if_blank:nTF {#1} { + \use_none:n + }{ + \doc_showmacro_aux:w #1 / \q_stop + \peek_meaning:NTF \q_stop { \use_none:n } { \doc_showmacro:w } + } +} +\group_end: +\bool_new:N \l_doc_meta_TF_bool +\bool_new:N \l_doc_meta_pTF_bool +\bool_new:N \l_doc_meta_EXP_bool +\cs_new_nopar:Npn \doc_showmacro_aux:w #1 / #2 \q_stop { + + \tl_if_in:nnT {#2} { (TF) } { + \bool_gset_true:N \l_doc_meta_TF_bool + } + + \tl_if_in:nnT {#2} { (EXP) } { + \bool_gset_true:N \l_doc_meta_EXP_bool + } + + \tl_if_in:nnT {#2} { (pTF) } { + \bool_gset_true:N \l_doc_meta_TF_bool + \bool_gset_true:N \l_doc_meta_pTF_bool + \bool_gset_true:N \l_doc_meta_EXP_bool + } + + \bool_if:NT \l_doc_meta_pTF_bool { + \tl_set:Nx \l_doc_pTF_name_tl { \doc_predicate_from_base:w #1 \q_nil } + \doc_special_main_index:o { \l_doc_pTF_name_tl } + \seq_gput_right:Nx \g_doc_functions_seq { \tl_to_str:N \l_doc_pTF_name_tl } + } + + \bool_if:NTF \l_doc_meta_TF_bool { + \doc_special_main_index:o { #1 TF } + \seq_gput_right:Nx \g_doc_functions_seq { \tl_to_str:n { #1 TF } } + \seq_gput_right:Nx \g_doc_functions_seq { \tl_to_str:n { #1 T } } + \seq_gput_right:Nx \g_doc_functions_seq { \tl_to_str:n { #1 F } } + }{ + \doc_special_main_index:o { #1 } + \seq_gput_right:Nx \g_doc_functions_seq { \tl_to_str:n { #1 } } + } + + \bool_if:NTF \l_doc_meta_pTF_bool { + \bool_gset_false:N \l_doc_meta_TF_bool + \exp_after:wN \doc_showmacro_aux_ii:w \l_doc_pTF_name_tl ::\q_stop + \bool_gset_true:N \l_doc_meta_TF_bool + \doc_showmacro_aux_ii:w #1::\q_stop + }{ + \doc_showmacro_aux_ii:w #1::\q_stop + } +} +\cs_set_nopar:Npn \doc_showmacro_aux_ii:w #1:#2:#3 \q_stop { + \nextnewline + \str_if_eq:xxTF {#1} {\g_doc_macro_tl} { + \doc_typeset_aux:n + }{ + \tl_gset:Nn \g_doc_macro_tl {#1} + \use:n + } + { \g_doc_macro_tl } + #3 + #2 + \bool_if:NT \l_doc_meta_TF_bool { \doc_typeset_TF: } + & + \bool_if:NT \l_doc_meta_EXP_bool { + \hspace{\tabcolsep} + $\star$ + } + \tl_set:Nx \g_doc_macro_tl { \tl_to_str:N \g_doc_macro_tl } + \exp_args:NNf \tl_replace_all_in:Nnn \g_doc_macro_tl {\token_to_str:N _} {/} + \exp_args:NNf \tl_replace_all_in:Nnn \g_doc_macro_tl {\@backslashchar} {} + \bool_if:NT \g_doc_full_bool { + \exp_args:Nf\label{doc/function/\g_doc_macro_tl#3#2} + } +} +\dim_new:N \g_doc_syntax_dim +\dim_set:Nn \g_doc_syntax_dim {0.7\textwidth} +\newenvironment{syntax}{ + \minipage[b]{\g_doc_syntax_dim} + \cs_set_nopar:Npn \meta@font@select{\rmfamily\itshape} % (Will: I HATE italic cmtt!) + \small\ttfamily\raggedright + \obeyspaces\obeylines +}{ + \endminipage + \hfil\break + \global\@ignoretrue +} +\tl_map_inline:nn {0123456789} { \cs_gset_eq:cN {char_other_#1} #1 } +\group_begin: + \tl_map_inline:nn {0123456789} { \char_set_catcode_active:N #1 } + \cs_new:Npn \doc_open_meta:n { + \group_begin: + \tl_map_function:nN {0123456789} \doc_assign_num:n + \doc_close_meta:w + } + \cs_new:Npn \Arg { + \texttt{ \char`\{ } + \group_begin: + \tl_map_function:nN {0123456789} \doc_assign_num:n + \doc_close_Arg:n + } +\group_end: +\cs_new_nopar:Npn \doc_close_meta:w #1> { \meta {#1} \group_end: } +\cs_new_nopar:Npn \doc_close_Arg:n #1 { + \meta {#1} + \group_end: + \texttt{ \char`\} } +} +\cs_new_nopar:Npn \doc_assign_num:n #1 { + \cs_set_eq:cc { \string #1 } { char_other_\string #1 } + \char_set_catcode_active:N #1 + \cs_set_nopar:Npn #1 { \unskip \, $ {} \sb { \use:c { char_other_\string #1 } } $ } +} +\renewcommand \macro [1][] { + + \int_compare:nNnTF \currentgrouplevel=2 + { \int_gzero:N \g_doc_nested_macro_int } + { \int_incr:N \g_doc_nested_macro_int } + + \bool_set_false:N \l_doc_macro_aux_bool + \bool_set_false:N \l_doc_macro_internal_bool + \bool_set_false:N \l_doc_macro_TF_bool + \bool_set_false:N \l_doc_macro_pTF_bool + \bool_set_false:N \l_doc_macro_var_bool + \bool_set_false:N \l_doc_tested_bool + + \cs_set_eq:NN \doc_macroname_prefix:n \use:n + \cs_set_eq:NN \doc_macroname_suffix: \c_empty_tl + + \cs_set_nopar:Npn \KV_key_no_value_elt:n ##1 { \use:c {doc_macro_opt_##1:} } + \keyval_parse:NNn \KV_key_no_value_elt:n \use_none:nn {#1} + + \cs_set_eq:NN \testfile \doc_print_testfile:n + + \group_begin: + \MakePrivateLetters + \char_set_catcode_letter:N \\ + \char_set_catcode_ignore:N \ % space + \char_set_catcode_ignore:N \^^M + \char_set_catcode_ignore:N \^^I + \doc_macro_aux:n +} +\cs_new_nopar:Npn \doc_macro_aux:n #1 { + \group_end: + \cs_set:Npn \l_doc_macro_input_clist {#1} + \bool_if:NTF \l_doc_macro_pTF_bool + { + \clist_map_inline:nn {#1} + { + \tl_if_blank:nF {##1} + { + \exp_args:Nf \doc_macro_single + { \doc_predicate_from_base:w ##1 \q_nil } + } + } + \bool_set_true:N \l_doc_macro_TF_bool + \clist_map_inline:nn {#1} + { \tl_if_blank:nF {##1} { \doc_macro_single {##1} } } + \bool_set_false:N \l_doc_macro_TF_bool + } + { + \clist_map_inline:nn {#1} + { \tl_if_blank:nF {##1} { \doc_macro_single {##1} } } + } +} +\bool_new:N \l_doc_macro_internal_bool +\bool_new:N \l_doc_macro_aux_bool +\bool_new:N \l_doc_macro_TF_bool +\bool_new:N \l_doc_macro_pTF_bool +\bool_new:N \l_doc_macro_var_bool +\cs_set_nopar:Npn \doc_macro_opt_aux: { \bool_set_true:N \l_doc_macro_aux_bool } +\cs_set_nopar:Npn \doc_macro_opt_internal: { \bool_set_true:N \l_doc_macro_internal_bool } +\cs_set_nopar:Npn \doc_macro_opt_TF: { \bool_set_true:N \l_doc_macro_TF_bool } +\cs_set_nopar:Npn \doc_macro_opt_pTF: { \bool_set_true:N \l_doc_macro_pTF_bool } +\cs_set_nopar:Npn \doc_macro_opt_var: { \bool_set_true:N \l_doc_macro_var_bool } +\cs_set:Npn \doc_predicate_from_base:w #1:#2 \q_nil {#1_p:#2} +\int_new:N \l_doc_macro_int +\cs_set_nopar:Npn \doc_macro_single #1 { + \int_incr:N \l_doc_macro_int + \tl_set:Nx \saved@macroname { \token_to_str:N #1 } + \topsep\MacroTopsep + \trivlist + \cs_set_nopar:Npn \makelabel ##1 { \llap{##1} } + \if@inlabel + \cs_set_eq:NN \@tempa \@empty + \count@ \macro@cnt + \loop \ifnum\count@>\z@ + \cs_set_nopar:Npx \@tempa{\@tempa\hbox{\strut}} + \advance\count@\m@ne + \repeat + \cs_set_nopar:Npx \makelabel ##1 { + \llap{\vtop to\baselineskip {\@tempa\hbox{##1}\vss}} + } + \advance \macro@cnt \@ne + \else + \macro@cnt \@ne + \fi + + \bool_if:NT \l_doc_macro_aux_bool { + \cs_set_eq:NN \doc_macroname_prefix:n \doc_typeset_aux:n + } + \bool_if:NT \l_doc_macro_TF_bool { + \cs_set_eq:NN \doc_macroname_suffix: \doc_typeset_TF: + } + + \bool_if:NF \l_doc_macro_aux_bool { + \tl_gset:Nx \l_doc_macro_tl { \tl_to_str:n {#1} } + \exp_args:NNf \tl_greplace_all_in:Nnn \l_doc_macro_tl {\token_to_str:N _} {/} + \exp_args:NNf \tl_greplace_all_in:Nnn \l_doc_macro_tl {\@backslashchar} {} + } + + \use:x { + \exp_not:N \item [ \exp_not:N \doc_print_macroname:n { + \tl_to_str:n {#1} + }] + } + \global\advance \c@CodelineNo \@ne + + \bool_if:NF \l_doc_macro_aux_bool { + \bool_if:NTF \l_doc_macro_TF_bool { + \seq_gput_right:Nx \g_doc_macros_seq { \tl_to_str:n { #1 TF } } + \seq_gput_right:Nx \g_doc_macros_seq { \tl_to_str:n { #1 T } } + \seq_gput_right:Nx \g_doc_macros_seq { \tl_to_str:n { #1 F } } + }{ + \seq_gput_right:Nx \g_doc_macros_seq { \tl_to_str:n {#1} } + } + } + \bool_if:NTF \l_doc_macro_TF_bool { + \SpecialMainIndex{#1 TF}\nobreak + \DoNotIndex{#1 TF} + }{ + \SpecialMainIndex{#1}\nobreak + \DoNotIndex{#1} + } + + \global\advance \c@CodelineNo \m@ne + \ignorespaces +} +\tl_clear:N \l_doc_macro_tl +\cs_set_nopar:Npn \doc_print_macroname:n #1 { + \strut + \int_compare:nTF { \tl_elt_count:n {#1} <= 28 } + { \MacroFont } { \MacroLongFont } + + % INEFFICIENT: (!) + \exp_args:NNx \seq_if_in:NnTF \g_doc_functions_seq + { #1 \bool_if:NT \l_doc_macro_TF_bool { \tl_to_str:n {TF} } } + { + \hyperref [doc/function/\l_doc_macro_tl] + } + { \use:n } + { + \doc_macroname_prefix:n {#1} \doc_macroname_suffix: \ % space! + } +} +\providecommand \MacroLongFont { + \fontfamily{lmtt}\fontseries{lc}\small +} +\cs_set_nopar:Npn \doc_typeset_TF: { + \itshape TF% + \makebox[0pt][r]{% + \color[gray]{0.5} + \underline { \phantom{\itshape TF} \kern-0.1em } + } +} +\cs_set_nopar:Npn \doc_typeset_aux:n #1 { + {\color[gray]{0.5} #1} +} +\DeclareDocumentCommand \doc_print_testfile:n {m} { + \bool_set_true:N \l_doc_tested_bool + \tl_if_eq:nnF {#1} {*} { + \seq_if_in:NnF \g_doc_testfiles_seq {#1} + { + \par{\footnotesize(\textit{ + The~ test~ suite~ for~ this~ command,~ and~ others~ in~ this~ file,~ is~ \textsf{#1}}. + )\par} + \seq_gput_right:Nn \g_doc_testfiles_seq {#1} + } + } +} +\seq_new:N \g_doc_testfiles_seq +\DeclareDocumentCommand \TestFiles {m} { + \par + {\itshape + The~ following~ test~ files~ are~ used~ for~ this~ code:~ \textsf{#1}. + } + \par\ignorespaces +} +\DeclareDocumentCommand \UnitTested {} { + \testfile* +} +\cs_generate_variant:Nn \prop_gput:Nnn {NVx} +\prop_new:N \g_doc_missing_tests_prop +\DeclareDocumentCommand \TestMissing {m} { + \prop_if_in:NVTF \g_doc_missing_tests_prop \l_doc_macro_input_clist + { + \prop_get:NVN \g_doc_missing_tests_prop \l_doc_macro_input_clist \l_tmpa_tl + \prop_gput:NVx \g_doc_missing_tests_prop \l_doc_macro_input_clist + { + *~ \l_tmpa_tl + ^^J \exp_not:n {\space\space\space\space\space\space} + *~ #1 + } + } + { \prop_gput:NVn \g_doc_missing_tests_prop \l_doc_macro_input_clist {#1} } +} +\int_new:N \g_doc_nested_macro_int +\cs_set:Nn \doc_texttt_comma:n {\,,~\texttt{#1}} +\cs_set:Npn \endmacro { + \int_compare:nT {\g_doc_nested_macro_int<1} + { + \par\nobreak{\footnotesize(\emph{ + End~ definition~ for~ + \prg_case_int:nnn { \clist_length:N \l_doc_macro_input_clist } + { + {1} { \texttt{ \clist_use:N \l_doc_macro_input_clist }. } + {2} + { + \tl_set:Nx \l_clist_first_tl { \clist_item:Nn \l_doc_macro_input_clist {0} } + \tl_set:Nx \l_clist_last_tl { \clist_item:Nn \l_doc_macro_input_clist {1} } + \texttt{\l_clist_first_tl}\,~ and~ \texttt{\l_clist_last_tl}\,. + } + {3} + { + \tl_set:Nx \l_clist_first_tl { \clist_item:Nn \l_doc_macro_input_clist {0} } + \tl_set:Nx \l_clist_mid_tl { \clist_item:Nn \l_doc_macro_input_clist {1} } + \tl_set:Nx \l_clist_last_tl { \clist_item:Nn \l_doc_macro_input_clist {2} } + \texttt{\l_clist_first_tl}\,,~ + \texttt{\l_clist_mid_tl}\,,~ + and~ \texttt{\l_clist_last_tl}\,. + } + } + { + \tl_set:Nx \l_clist_first_tl { \clist_item:Nn \l_doc_macro_input_clist {0} } + \texttt{\l_clist_first_tl}\,~and~others. + } + \bool_if:nT { + !\l_doc_macro_aux_bool && + !\l_doc_macro_internal_bool && + \int_compare_p:n {\g_doc_nested_macro_int<1} + } + { + \int_compare:nNnTF \l_doc_macro_int=1 {~This~} {~These~} + \bool_if:NTF \l_doc_macro_var_bool{variable}{function} + \int_compare:nNnTF \l_doc_macro_int=1 {~is~}{s~are~} + documented~on~page~ + \exp_args:Nx\pageref{doc/function/\l_doc_macro_tl}. + } + })\par} + } + \bool_if:nT + { \g_doc_checktest_bool && + !( \l_doc_macro_aux_bool || \l_doc_macro_var_bool ) && + !\l_doc_tested_bool + } + { + \seq_gput_right:Nx \g_doc_not_tested_seq + { + \l_doc_macro_input_clist + \bool_if:NT \l_doc_macro_pTF_bool {~(pTF)} + \bool_if:NT \l_doc_macro_TF_bool {~(TF)} + } + } +} +\newcommand*{\DescribeOption}{ + \leavevmode + \@bsphack + \begingroup + \MakePrivateLetters + \Describe@Option +} +\newcommand*{\Describe@Option}[1]{ + \endgroup + \marginpar{ + \raggedleft + \PrintDescribeEnv{#1} + } + \SpecialOptionIndex{#1} + \@esphack + \ignorespaces +} +\newcommand*{\SpecialOptionIndex}[1]{ + \@bsphack + \begingroup + \HD@target + \let\HDorg@encapchar\encapchar + \edef\encapchar usage{ + \HDorg@encapchar hdclindex{\the\c@HD@hypercount}{usage} + } + \index{ + #1\actualchar{\protect\ttfamily#1}~(option) + \encapchar usage + } + \index{ + options:\levelchar#1\actualchar{\protect\ttfamily#1} + \encapchar usage + } + \endgroup + \@esphack +} +\font\manual=manfnt +\cs_set_nopar:Npn \dbend { {\manual\char127} } +\newenvironment {danger} { + \begin{trivlist}\item[]\noindent + \begingroup\hangindent=2pc\hangafter=-2 + \cs_set_nopar:Npn \par{\endgraf\endgroup} + \hbox to0pt{\hskip-\hangindent\dbend\hfill}\ignorespaces +}{ + \par\end{trivlist} +} +\newenvironment {ddanger} { + \begin{trivlist}\item[]\noindent + \begingroup\hangindent=3.5pc\hangafter=-2 + \cs_set_nopar:Npn \par{\endgraf\endgroup} + \hbox to0pt{\hskip-\hangindent\dbend\kern2pt\dbend\hfill}\ignorespaces +}{ + \par\end{trivlist} +} +\newenvironment{TemplateInterfaceDescription}[1] + {\subsection{The~object~type~`#1'}% + \begingroup + \@beginparpenalty\@M + \description + \def\TemplateArgument##1##2{\item[Arg:~##1]##2\par}% + \def\TemplateSemantics{\enddescription\endgroup + \subsubsection*{Semantics:}}% + } + {\par\bigskip} +\newenvironment{TemplateDescription}[2] + {\subsection{The~template~`#2'~(object~type~#1)}% + \subsubsection*{Attributes:}% + \begingroup + \@beginparpenalty\@M + \description + \def\TemplateKey##1##2##3##4{\item[##1~(##2)]##3% + \ifx\TemplateKey##4\TemplateKey\else + \hfill\penalty500\hbox{}\hfill Default:~##4% + \nobreak\hskip-\parfillskip\hskip0pt\relax + \fi + \par}% + \def\TemplateSemantics{\enddescription\endgroup + \subsubsection*{Semantics~\&~Comments:}}% + } + {\par\bigskip} +\newenvironment{InstanceDescription}[4][xxxxxxxxxxxxxxx] + {\subsubsection{The~instance~`#3'~(template~#2/#4)}% + \subsubsection*{Attribute~values:}% + \begingroup + \@beginparpenalty\@M + \def\InstanceKey##1##2{\>\textbf{##1}\>##2\\}% + \def\InstanceSemantics{\endtabbing\endgroup + \vskip-30pt\vskip0pt + \subsubsection*{Layout~description~\&~Comments:}}% + \tabbing + xxxx\=#1\=\kill + } + {\par\bigskip} +\bool_new:N \g_doc_implementation_bool +\cs_set_nopar:Npn \AlsoImplementation { + \bool_set_true:N \g_doc_implementation_bool + \cs_set:Npn \StopEventually ##1 { + \@bsphack + \cs_gset_nopar:Npn \Finale { ##1 \check@checksum } + \init@checksum + \@esphack + } +} +\AlsoImplementation +\cs_set_nopar:Npn \OnlyDescription { + \@bsphack + \bool_set_false:N \g_doc_implementation_bool + \cs_set:Npn \StopEventually ##1 { ##1 \endinput } + \@esphack +} +\cs_set_eq:NN \Finale \relax +\cs_set_nopar:Npn \partname{File} +\clist_new:N \g_docinput_clist +\cs_set:Npn \DocInput #1 { + \clist_map_inline:nn {#1} { + \clist_put_right:Nn \g_docinput_clist {##1} + \MakePercentIgnore + \input{##1} + \MakePercentComment + } +} +\cs_set:Npn \DocInputAgain { + \clist_map_inline:Nn \g_docinput_clist { + \MakePercentIgnore + \input{##1} + \MakePercentComment + } +} +\cs_set_nopar:Npn \partname{File} +\newcommand*{\DocInclude}[1]{% + \relax\clearpage + \docincludeaux + \IfFileExists{#1.fdd}{ + \cs_set_nopar:Npn \currentfile{#1.fdd} + }{ + \cs_set_nopar:Npn \currentfile{#1.dtx} + } + \ifnum\@auxout=\@partaux + \@latexerr{\string\include\space cannot~be~nested}\@eha + \else + \@docinclude #1 + \fi +} +\cs_set_nopar:Npn \@docinclude #1 { + \clearpage + \immediate\write\@mainaux{\string\@input{#1.aux}} + \@tempswatrue + \if@partsw + \@tempswafalse + \cs_set_nopar:Npx \@tempb{#1} + \@for\@tempa:=\@partlist\do{ + \ifx\@tempa\@tempb\@tempswatrue\fi + } + \fi + \if@tempswa + \cs_set_eq:NN \@auxout\@partaux + \immediate\openout\@partaux #1.aux + \immediate\write\@partaux{\relax} + \cs_set_eq:NN \@ltxdoc@PrintIndex\PrintIndex + \cs_set_eq:NN \PrintIndex\relax + \cs_set_eq:NN \@ltxdoc@PrintChanges\PrintChanges + \cs_set_eq:NN \PrintChanges\relax + \cs_set_eq:NN \@ltxdoc@theglossary\theglossary + \cs_set_eq:NN \@ltxdoc@endtheglossary\endtheglossary + \part{\currentfile} + { + \cs_set_eq:NN \ttfamily\relax + \cs_gset_nopar:Npx \filekey{\filekey, \thepart={\ttfamily\currentfile}} + } + \DocInput{\currentfile} + \cs_set_eq:NN \PrintIndex\@ltxdoc@PrintIndex + \cs_set_eq:NN \PrintChanges\@ltxdoc@PrintChanges + \cs_set_eq:NN \theglossary\@ltxdoc@theglossary + \cs_set_eq:NN \endtheglossary\@ltxdoc@endtheglossary + \clearpage + \@writeckpt{#1} + \immediate\closeout\@partaux + \else + \@nameuse{cp@#1} + \fi + \cs_set_eq:NN \@auxout\@mainaux +} +\cs_gset_nopar:Npn \codeline@wrindex #1 { + \immediate\write\@indexfile { + \string\indexentry{#1} + {\filesep\number\c@CodelineNo} + } +} +\cs_set_eq:NN \filesep \@empty +\cs_set_nopar:Npn \docincludeaux { + \cs_set_nopar:Npn \thepart {\alphalph{part}} + \cs_set_nopar:Npn \filesep {\thepart-} + \cs_set_eq:NN \filekey\@gobble + \g@addto@macro\index@prologue{ + \cs_gset_nopar:Npn\@oddfoot{ + \parbox{\textwidth}{ + \strut\footnotesize + \raggedright{\bfseries File~Key:}~\filekey + } + } + \cs_set_eq:NN \@evenfoot\@oddfoot + } + \cs_gset_eq:NN \docincludeaux\relax + \cs_gset_nopar:Npn\@oddfoot{ + \expandafter\ifx\csname ver@\currentfile\endcsname\relax + File~\thepart :~{\ttfamily\currentfile}~ + \else + \GetFileInfo{\currentfile} + File~\thepart :~{\ttfamily\filename}~ + Date:~\ExplFileDate\ % space + Version~\ExplFileVersion + \fi + \hfill\thepage + } + \cs_set_eq:NN \@evenfoot \@oddfoot +} +\seq_new:N \g_doc_functions_seq +\seq_new:N \g_doc_macros_seq +\seq_new:N \g_doc_not_tested_seq +\iow_open:Nn \g_write_func_stream { \jobname.cmds } +\cs_new_nopar:Npn \doc_show_functions_defined: { + \bool_if:nT { \g_doc_implementation_bool && \g_doc_checkfunc_bool } { + \typeout{ ======================================== ^^J } + + \tl_clear:N \l_tmpa_tl + \seq_map_inline:Nn \g_doc_functions_seq { + \seq_if_in:NnT \g_doc_macros_seq {##1} { + \tl_put_right:Nn \l_tmpa_tl { ##1 ^^J } + \iow_now:Nn \g_write_func_stream { ##1 } + } + } + \iow_close:N \g_write_func_stream + \doc_functions_typeout:n { + Functions~both~documented~and~defined:^^J (In~order~of~being~documented) + } + + \seq_map_inline:Nn \g_doc_functions_seq { + \seq_if_in:NnF \g_doc_macros_seq {##1} { + \tl_put_right:Nn \l_tmpa_tl { ##1 ^^J } + } + } + \doc_functions_typeout:n { Functions~documented~but~not~defined: } + + \seq_map_inline:Nn \g_doc_macros_seq { + \seq_if_in:NnF \g_doc_functions_seq {##1} { + \tl_put_right:Nn \l_tmpa_tl { ##1 ^^J } + } + } + \doc_functions_typeout:n { Functions~defined~but~not~documented: } + + \typeout{ ======================================== } + } +} +\AtEndDocument{ \doc_show_functions_defined: } +\cs_set_nopar:Npn \doc_functions_typeout:n #1 { + \tl_if_empty:NF \l_tmpa_tl { + \typeout{ + -------------------------------------- ^^J #1 ^^J + -------------------------------------- ^^J \l_tmpa_tl + } + \tl_clear:N \l_tmpa_tl + } +} +\cs_new:Npn \doc_show_not_tested: { + \bool_if:NT \g_doc_checktest_bool + { + \bool_if:nT { !(\seq_if_empty_p:N \g_doc_not_tested_seq) || + !(\prop_if_empty_p:N \g_doc_missing_tests_prop) } + { + \tl_clear:N \l_tmpa_tl + \prop_if_empty:NF \g_doc_missing_tests_prop + { + \tl_put_right:Nn \l_tmpa_tl + { + ^^J^^JThe~ following~ macro(s)~ have~ incomplete~ tests:^^J + } + \prop_map_inline:Nn \g_doc_missing_tests_prop + { + \tl_put_right:Nn \l_tmpa_tl + {^^J\space\space\space\space ##1 + ^^J\space\space\space\space\space\space ##2} + } + } + \seq_if_empty:NF \g_doc_not_tested_seq + { + \tl_put_right:Nn \l_tmpa_tl + { + ^^J^^J + The~ following~ macro(s)~ do~ not~ have~ any~ tests:^^J + } + \seq_map_inline:Nn \g_doc_not_tested_seq + { + \clist_map_inline:nn {##1} + { + \tl_put_right:Nn \l_tmpa_tl {^^J\space\space\space\space ####1} + } + } + \int_set:Nn \l_tmpa_int {\etex_interactionmode:D} + \errorstopmode + \ClassError{l3doc}{\l_tmpa_tl}{} + \int_set:Nn \etex_interactionmode:D {\l_tmpa_int} + } + } + } +} +\AtEndDocument{ \doc_show_not_tested: } +\g@addto@macro\theindex{\MakePrivateLetters} +\cs_set:Npn \verbatimchar {&} +\setcounter{IndexColumns}{2} +\IndexPrologue{ + \part*{Index} + \markboth{Index}{Index} + \addcontentsline{toc}{part}{Index} + The~italic~numbers~denote~the~pages~where~the~ + corresponding~entry~is~described,~ + numbers~underlined~point~to~the~definition,~ + all~others~indicate~the~places~where~it~is~used. +} + +\cs_set_nopar:Npn \doc_special_main_index:n #1 { + \index{ + \@gobble#1 + \actualchar + \string\verb\quotechar*\verbatimchar#1\verbatimchar + \encapchar + hdpgindex{\thepage}{usage} + } +} +\cs_set_nopar:Npn \doc_special_main_index:o { \exp_args:No \doc_special_main_index:n } +\cs_set_nopar:Npn \hdpgindex #1#2#3 { + \csname\ifx\\#2\\relax\else#2\fi\endcsname{ + \hyperlink{page.#1}{#3} + } +} +\g@addto@macro \PrintIndex { \AtEndDocument{ \typeout{^^J + ========================================^^J + Generate~the~index~by~executing^^J + \c_space_tl \c_space_tl \c_space_tl \c_space_tl + makeindex~-s~l3doc.ist~-o~\jobname.ind~\jobname.idx^^J + ========================================^^J + }} +} +\GlossaryPrologue{ + \part*{Change~History} + {\GlossaryParms\ttfamily\hyphenchar\font=`\-} + \markboth{Change~History}{Change~History} + \addcontentsline{toc}{part}{Change~History} +} +\g@addto@macro \PrintChanges { \AtEndDocument{ \typeout{^^J + ========================================^^J + Generate~the~change~list~by~executing^^J + \c_space_tl \c_space_tl \c_space_tl \c_space_tl + makeindex~-s~gglo.ist~~-o~\jobname.gls~\jobname.glo^^J + ========================================^^J + }} +} +\bool_if:NTF \g_doc_full_bool { + \RecordChanges + \CodelineIndex + \EnableCrossrefs + \AlsoImplementation +}{ + \CodelineNumbered + \DisableCrossrefs + \OnlyDescription +} +%% +%% +%% End of file `l3doc.cls'. diff --git a/Master/texmf-dist/tex/latex/l3kernel/l3expan.sty b/Master/texmf-dist/tex/latex/l3kernel/l3expan.sty new file mode 100644 index 00000000000..028e9cd3bc0 --- /dev/null +++ b/Master/texmf-dist/tex/latex/l3kernel/l3expan.sty @@ -0,0 +1,394 @@ +%% +%% This is file `l3expan.sty', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% l3expan.dtx (with options: `package') +%% +%% EXPERIMENTAL CODE +%% +%% Do not distribute this file without also distributing the +%% source files specified above. +%% +%% Do not distribute a modified version of this file. +%% +%% File: l3expan.dtx Copyright (C) 1990-2011 The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +\RequirePackage{l3names} +\GetIdInfo$Id: l3expan.dtx 2480 2011-06-20 17:25:23Z bruno $ + {L3 Experimental argument expansion} +\ProvidesExplPackage + {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +\package_check_loaded_expl: +\cs_new_nopar:Npn \l_exp_tl { } +\cs_new:Npn \exp_arg_next:nnn #1#2#3 { #2 \::: { #3 {#1} } } +\cs_new:Npn \exp_arg_next_nobrace:nnn #1#2#3 { #2 \::: { #3 #1 } } +\cs_new:Npn \::: #1 {#1} +\cs_new:Npn \::n #1 \::: #2#3 { #1 \::: { #2 {#3} } } +\cs_new:Npn \::N #1 \::: #2#3 { #1 \::: {#2#3} } +\cs_new:Npn \::c #1 \::: #2#3 + { \exp_after:wN \exp_arg_next_nobrace:nnn \cs:w #3 \cs_end: {#1} {#2} } +\cs_new:Npn \::o #1 \::: #2#3 + { \exp_after:wN \exp_arg_next:nnn \exp_after:wN {#3} {#1} {#2} } +\cs_new:Npn \::f #1 \::: #2#3 + { + \exp_after:wN \exp_arg_next:nnn + \exp_after:wN { \tex_romannumeral:D -`0 #3 } + {#1} {#2} + } +\use:nn { \cs_new_eq:NN \exp_stop_f: } { ~ } +\cs_new_protected:Npn \::x #1 \::: #2#3 + { + \cs_set_nopar:Npx \l_exp_tl { {#3} } + \exp_after:wN \exp_arg_next:nnn \l_exp_tl {#1} {#2} + } +\cs_new:Npn \::V #1 \::: #2#3 + { + \exp_after:wN \exp_arg_next:nnn + \exp_after:wN { \tex_romannumeral:D \exp_eval_register:N #3 } + {#1} {#2} +} +\cs_new:Npn \::v # 1\::: #2#3 + { + \exp_after:wN \exp_arg_next:nnn + \exp_after:wN { \tex_romannumeral:D \exp_eval_register:c {#3} } + {#1} {#2} + } +\cs_new_nopar:Npn \exp_eval_register:N #1 + { + \exp_after:wN \if_meaning:w \exp_not:N #1 #1 + \if_meaning:w \scan_stop: #1 + \exp_eval_error_msg:w + \fi: + \else: + \exp_after:wN \use_i_ii:nnn + \fi: + \exp_after:wN \c_zero \tex_the:D #1 + } +\cs_new_nopar:Npn \exp_eval_register:c #1 + { \exp_after:wN \exp_eval_register:N \cs:w #1 \cs_end: } +\group_begin:% +\tex_catcode:D`\!=11\scan_stop:% +\tex_catcode:D`\ =11\scan_stop:% +\cs_new:Npn\exp_eval_error_msg:w#1\tex_the:D#2{% +\fi:\fi:\exp_after:wN\c_zero\erroneous variable used!}% +\group_end:% +\cs_new:Npn \exp_args:No #1#2 { \exp_after:wN #1 \exp_after:wN {#2} } +\cs_new:Npn \exp_args:NNo #1#2#3 + { \exp_after:wN #1 \exp_after:wN #2 \exp_after:wN {#3} } +\cs_new:Npn \exp_args:NNNo #1#2#3#4 + { \exp_after:wN #1 \exp_after:wN#2 \exp_after:wN #3 \exp_after:wN {#4} } +\cs_new:Npn \exp_args:cc #1#2 + { \cs:w #1 \exp_after:wN \cs_end: \cs:w #2 \cs_end: } +\cs_new:Npn \exp_args:NNc #1#2#3 + { \exp_after:wN #1 \exp_after:wN #2 \cs:w # 3\cs_end: } +\cs_new:Npn \exp_args:Ncc #1#2#3 + { \exp_after:wN #1 \cs:w #2 \exp_after:wN \cs_end: \cs:w #3 \cs_end: } +\cs_new:Npn \exp_args:Nccc #1#2#3#4 + { + \exp_after:wN #1 + \cs:w #2 \exp_after:wN \cs_end: + \cs:w #3 \exp_after:wN \cs_end: + \cs:w #4 \cs_end: + } +\cs_new:Npn \exp_args:Nf #1#2 + { \exp_after:wN #1 \exp_after:wN { \tex_romannumeral:D -`0 #2 } } +\cs_new:Npn \exp_args:Nv #1#2 + { + \exp_after:wN #1 \exp_after:wN + { \tex_romannumeral:D \exp_eval_register:c {#2} } + } +\cs_new:Npn \exp_args:NV #1#2 + { + \exp_after:wN #1 \exp_after:wN + { \tex_romannumeral:D \exp_eval_register:N #2 } + } +\cs_new:Npn \exp_args:NNf #1#2#3 + { + \exp_after:wN #1 + \exp_after:wN #2 + \exp_after:wN { \tex_romannumeral:D -`0 #3 } + } +\cs_new:Npn \exp_args:NNv #1#2#3 + { + \exp_after:wN #1 + \exp_after:wN #2 + \exp_after:wN { \tex_romannumeral:D \exp_eval_register:c {#3} } + } +\cs_new:Npn \exp_args:NNV #1#2#3 + { + \exp_after:wN #1 + \exp_after:wN #2 + \exp_after:wN { \tex_romannumeral:D \exp_eval_register:N #3 } + } +\cs_new:Npn \exp_args:Nco #1#2#3 + { + \exp_after:wN #1 + \cs:w #2 \exp_after:wN \cs_end: + \exp_after:wN {#3} + } +\cs_new:Npn \exp_args:Ncf #1#2#3 + { + \exp_after:wN #1 + \cs:w #2 \exp_after:wN \cs_end: + \exp_after:wN { \tex_romannumeral:D -`0 #3 } + } +\cs_new_nopar:Npn \exp_args:NVV #1#2#3 + { + \exp_after:wN #1 + \exp_after:wN { \tex_romannumeral:D \exp_after:wN + \exp_eval_register:N \exp_after:wN #2 \exp_after:wN } + \exp_after:wN { \tex_romannumeral:D \exp_eval_register:N #3 } + } +\cs_new:Npn \exp_args:NNNV #1#2#3#4 + { + \exp_after:wN #1 + \exp_after:wN #2 + \exp_after:wN #3 + \exp_after:wN { \tex_romannumeral:D \exp_eval_register:N #4 } + } +\cs_new:Npn \exp_args:NcNc #1#2#3#4 + { + \exp_after:wN #1 + \cs:w #2 \exp_after:wN \cs_end: + \exp_after:wN #3 + \cs:w #4 \cs_end: + } +\cs_new:Npn \exp_args:NcNo #1#2#3#4 + { + \exp_after:wN #1 + \cs:w #2 \exp_after:wN \cs_end: + \exp_after:wN #3 + \exp_after:wN {#4} + } +\cs_new:Npn \exp_args:Ncco #1#2#3#4 + { + \exp_after:wN #1 + \cs:w #2 \exp_after:wN \cs_end: + \cs:w #3 \exp_after:wN \cs_end: + \exp_after:wN {#4} + } +\cs_new_protected_nopar:Npn \exp_args:Nx { \::x \::: } +\cs_new_nopar:Npn \exp_args:Nnc { \::n \::c \::: } +\cs_new_nopar:Npn \exp_args:Nfo { \::f \::o \::: } +\cs_new_nopar:Npn \exp_args:Nff { \::f \::f \::: } +\cs_new_nopar:Npn \exp_args:Nnf { \::n \::f \::: } +\cs_new_nopar:Npn \exp_args:Nno { \::n \::o \::: } +\cs_new_nopar:Npn \exp_args:NnV { \::n \::V \::: } +\cs_new_nopar:Npn \exp_args:Noc { \::o \::c \::: } +\cs_new_nopar:Npn \exp_args:Noo { \::o \::o \::: } +\cs_new_protected_nopar:Npn \exp_args:NNx { \::N \::x \::: } +\cs_new_protected_nopar:Npn \exp_args:Ncx { \::c \::x \::: } +\cs_new_protected_nopar:Npn \exp_args:Nnx { \::n \::x \::: } +\cs_new_protected_nopar:Npn \exp_args:Nox { \::o \::x \::: } +\cs_new_protected_nopar:Npn \exp_args:Nxo { \::x \::o \::: } +\cs_new_protected_nopar:Npn \exp_args:Nxx { \::x \::x \::: } +\cs_new_nopar:Npn \exp_args:NNno { \::N \::n \::o \::: } +\cs_new_nopar:Npn \exp_args:NNoo { \::N \::o \::o \::: } +\cs_new_nopar:Npn \exp_args:Nnnc { \::n \::n \::c \::: } +\cs_new_nopar:Npn \exp_args:Nnno { \::n \::n \::o \::: } +\cs_new_nopar:Npn \exp_args:Nooo { \::o \::o \::o \::: } +\cs_new_protected_nopar:Npn \exp_args:NNnx { \::N \::n \::x \::: } +\cs_new_protected_nopar:Npn \exp_args:NNox { \::N \::o \::x \::: } +\cs_new_protected_nopar:Npn \exp_args:Nnnx { \::n \::n \::x \::: } +\cs_new_protected_nopar:Npn \exp_args:Nnox { \::n \::o \::x \::: } +\cs_new_protected_nopar:Npn \exp_args:Nccx { \::c \::c \::x \::: } +\cs_new_protected_nopar:Npn \exp_args:Ncnx { \::c \::n \::x \::: } +\cs_new_protected_nopar:Npn \exp_args:Noox { \::o \::o \::x \::: } +\cs_new:Npn \exp_arg_last_unbraced:nn #1#2 { #2#1 } +\cs_new:Npn \::f_unbraced \::: #1#2 + { + \exp_after:wN \exp_arg_last_unbraced:nn + \exp_after:wN { \tex_romannumeral:D -`0 #2 } {#1} + } +\cs_new:Npn \::o_unbraced \::: #1#2 + { \exp_after:wN \exp_arg_last_unbraced:nn \exp_after:wN {#2} {#1} } +\cs_new:Npn \::V_unbraced \::: #1#2 + { + \exp_after:wN \exp_arg_last_unbraced:nn + \exp_after:wN { \tex_romannumeral:D \exp_eval_register:N #2 } {#1} + } +\cs_new:Npn \::v_unbraced \::: #1#2 + { + \exp_after:wN \exp_arg_last_unbraced:nn + \exp_after:wN { \tex_romannumeral:D \exp_eval_register:c {#2} } {#1} + } +\cs_new:Npn \exp_last_unbraced:NV #1#2 + { \exp_after:wN #1 \tex_romannumeral:D \exp_eval_register:N #2 } +\cs_new:Npn \exp_last_unbraced:Nv #1#2 + { \exp_after:wN #1 \tex_romannumeral:D \exp_eval_register:c {#2} } +\cs_new:Npn \exp_last_unbraced:No #1#2 { \exp_after:wN #1 #2 } +\cs_new:Npn \exp_last_unbraced:Nf #1#2 + { \exp_after:wN #1 \tex_romannumeral:D -`0 #2 } +\cs_new:Npn \exp_last_unbraced:NcV #1#2#3 + { + \exp_after:wN #1 + \cs:w #2 \exp_after:wN \cs_end: + \tex_romannumeral:D \exp_eval_register:N #3 + } +\cs_new:Npn \exp_last_unbraced:NNV #1#2#3 + { + \exp_after:wN #1 + \exp_after:wN #2 + \tex_romannumeral:D \exp_eval_register:N #3 + } +\cs_new:Npn \exp_last_unbraced:NNo #1#2#3 + { \exp_after:wN #1 \exp_after:wN #2 #3 } +\cs_new_nopar:Npn \exp_last_unbraced:Noo { \::o \::o_unbraced \::: } +\cs_new_nopar:Npn \exp_last_unbraced:Nfo { \::f \::o_unbraced \::: } +\cs_new:Npn \exp_last_unbraced:NNNV #1#2#3#4 + { + \exp_after:wN #1 + \exp_after:wN #2 + \exp_after:wN #3 + \tex_romannumeral:D \exp_eval_register:N #4 + } +\cs_new:Npn \exp_last_unbraced:NNNo #1#2#3#4 + { \exp_after:wN #1 \exp_after:wN #2 \exp_after:wN #3 #4 } +\cs_new:Npn \exp_last_two_unbraced:Noo #1#2#3 + { \exp_after:wN \exp_last_two_unbraced_aux:nnN \exp_after:wN {#3} {#2} #1 } +\cs_new:Npn \exp_last_two_unbraced_aux:nnN #1#2#3 + { \exp_after:wN #3 #2 #1 } +\cs_new:Npn \exp_not:o #1 { \etex_unexpanded:D \exp_after:wN {#1} } +\cs_new:Npn \exp_not:f #1 + { \etex_unexpanded:D \exp_after:wN { \tex_romannumeral:D -`0 #1 } } +\cs_new:Npn \exp_not:V #1 + { + \etex_unexpanded:D \exp_after:wN + { \tex_romannumeral:D \exp_eval_register:N #1 } + } +\cs_new:Npn \exp_not:v #1 + { + \etex_unexpanded:D \exp_after:wN + { \tex_romannumeral:D \exp_eval_register:c {#1} } + } +\cs_new:Npn \exp_not:c #1 { \exp_after:wN \exp_not:N \cs:w #1 \cs_end: } +\cs_new_protected:Npn \cs_generate_variant:Nn #1 + { + \chk_if_exist_cs:N #1 + \cs_split_function:NN #1 \cs_generate_variant_aux:nnNNn + #1 + } +\cs_new:Npn \cs_generate_variant_aux:nnNNn #1#2#3#4#5 + { \cs_generate_variant_aux:Nnnw #4 {#1}{#2} #5 , ? , \q_recursion_stop } +\cs_new:Npn \cs_generate_variant_aux:Nnnw #1#2#3#4 , + { + \if:w ? #4 + \exp_after:wN \use_none_delimit_by_q_recursion_stop:w + \fi: + \exp_args:NNc \cs_generate_variant_aux:NNn + #1 + { #2 : #4 \use:c { use_none: \cs_generate_variant_aux:N #4 ? } #3 } + {#4} + \cs_generate_variant_aux:Nnnw #1 {#2} {#3} + } +\cs_new:Npn \cs_generate_variant_aux:NNn #1 #2 #3 + { + \cs_if_free:NTF #2 + { + \cs_generate_variant_aux:NNpx #1 #2 + { \exp_not:c { exp_args:N #3 } \exp_not:N #1 } + \cs_generate_internal_variant:n {#3} + } + { + \iow_log:x + { + Variant~\token_to_str:N #2~% + already~defined;~ not~ changing~ it~on~line~% + \tex_the:D \tex_inputlineno:D + } + } + } +\cs_new:Npn \cs_generate_variant_aux:N #1 + { + \if:w ? #1 + \exp_after:wN \use_none:nn + \fi: + n + \cs_generate_variant_aux:N + } +\group_begin: + \tex_lccode:D `\Z = `\d \scan_stop: + \tex_lccode:D `\? =`\\ \scan_stop: + \tex_catcode:D `\P = 12 \scan_stop: + \tex_catcode:D `\R = 12 \scan_stop: + \tex_catcode:D `\O = 12 \scan_stop: + \tex_catcode:D `\T = 12 \scan_stop: + \tex_catcode:D `\E = 12 \scan_stop: + \tex_catcode:D `\C = 12 \scan_stop: + \tex_catcode:D `\Z = 12 \scan_stop: +\tex_lowercase:D + { + \group_end: + \cs_new_nopar:Npn \cs_generate_variant_aux:NNpx #1 + { + \exp_after:wN \cs_generate_variant_aux:w + \token_to_meaning:N #1 ? PROTECTEZ \q_stop + } + \cs_new:Npn \cs_generate_variant_aux:w #1 ? PROTECTEZ #2 \q_stop + { + \if_catcode:w a \etex_detokenize:D \exp_after:wN {#1} a + \exp_after:wN \cs_new_protected_nopar:Npx + \else: + \exp_after:wN \cs_new_nopar:Npx + \fi: + } + } +\cs_new_protected:Npn \cs_generate_internal_variant:n #1 + { + \cs_if_free:cT { exp_args:N #1 } + { + \cs_new:cpx { exp_args:N #1 } + { \cs_generate_internal_variant_aux:N #1 : } + } + } +\cs_new:Npn \cs_generate_internal_variant_aux:N #1 + { + \exp_not:c { :: #1 } + \if_meaning:w #1 : + \exp_after:wN \use_none:n + \fi: + \cs_generate_internal_variant_aux:N + } +\cs_generate_variant:Nn \str_if_eq_p:nn { V , o } +\cs_generate_variant:Nn \str_if_eq_p:nn { nV , no , VV } +\cs_generate_variant:Nn \str_if_eq:nnT { V , o } +\cs_generate_variant:Nn \str_if_eq:nnT { nV , no , VV } +\cs_generate_variant:Nn \str_if_eq:nnF { V , o } +\cs_generate_variant:Nn \str_if_eq:nnF { nV , no , VV } +\cs_generate_variant:Nn \str_if_eq:nnTF { V , o } +\cs_generate_variant:Nn \str_if_eq:nnTF { nV , no , VV } +%% +%% +%% End of file `l3expan.sty'. diff --git a/Master/texmf-dist/tex/latex/l3kernel/l3file.sty b/Master/texmf-dist/tex/latex/l3kernel/l3file.sty new file mode 100644 index 00000000000..e8272cde35f --- /dev/null +++ b/Master/texmf-dist/tex/latex/l3kernel/l3file.sty @@ -0,0 +1,133 @@ +%% +%% This is file `l3file.sty', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% l3file.dtx (with options: `package') +%% +%% EXPERIMENTAL CODE +%% +%% Do not distribute this file without also distributing the +%% source files specified above. +%% +%% Do not distribute a modified version of this file. +%% +%% File: l3file.dtx Copyright (C) 2009-2011 The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +\RequirePackage{l3names} +\GetIdInfo$Id: l3file.dtx 2478 2011-06-19 21:34:23Z joseph $ + {L3 Experimental file operations} +\ProvidesExplPackage + {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +\package_check_loaded_expl: +\tl_new:N \g_file_current_name_tl +\tl_gset_eq:NN \g_file_current_name_tl \@currname +\seq_new:N \g_file_stack_seq +\seq_new:N \g_file_record_seq +\tl_new:N \l_file_name_tl +\seq_new:N \l_file_search_path_seq +\seq_new:N \l_file_search_path_saved_seq +\cs_new_protected_nopar:Npn \file_add_path:nN #1#2 + { + \ior_open:Nn \g_file_test_stream {#1} + \ior_if_eof:NTF \g_file_test_stream + { \file_add_path_search:nN {#1} #2 } + { + \ior_close:N \g_file_test_stream + \tl_set:Nx #2 {#1} + } + } +\cs_new_protected_nopar:Npn \file_add_path_search:nN #1#2 + { + \tl_clear:N #2 + \cs_if_exist:NT \input@path + { + \seq_set_eq:NN \l_file_search_path_saved_seq \l_file_search_path_seq + \clist_map_inline:Nn \input@path + { \seq_put_right:Nn \l_file_search_path_seq {##1} } + } + \seq_map_inline:Nn \l_file_search_path_seq + { + \ior_open:Nn \g_file_test_stream { ##1 #1 } + \ior_if_eof:NF \g_file_test_stream + { + \tl_set:Nx #2 { ##1 #1 } + \seq_map_break: + } + } + \cs_if_exist:NT \input@path + { \seq_set_eq:NN \l_file_search_path_seq \l_file_search_path_saved_seq } + \ior_close:N \g_file_test_stream + } +\prg_new_protected_conditional:Nnn \file_if_exist:n { T , F , TF } + { + \file_add_path:nN {#1} \l_file_name_tl + \tl_if_empty:NTF \l_file_name_tl + { \prg_return_false: } + { \prg_return_true: } + } +\cs_new_protected_nopar:Npn \file_input:n #1 + { + \file_add_path:nN {#1} \l_file_name_tl + \tl_if_empty:NF \l_file_name_tl + { + \@addtofilelist {#1} + \seq_gpush:NV \g_file_stack_seq \g_file_current_name_tl + \tl_gset:Nn \g_file_current_name_tl {#1} + \exp_after:wN \tex_input:D \l_file_name_tl ~ + \seq_gpop:NN \g_file_stack_seq \g_file_current_name_tl + } + } +\cs_new_protected_nopar:Npn \file_path_include:n #1 + { + \seq_if_in:NnF \l_file_search_path_seq {#1} + { \seq_put_right:Nn \l_file_search_path_seq {#1} } + } +\cs_new_protected_nopar:Npn \file_path_remove:n #1 + { \seq_remove_all:Nn \l_file_search_path_seq {#1} } +\cs_new_protected_nopar:Npn \file_list: + { + \seq_remove_duplicates:N \g_file_record_seq + \iow_log:n { *~File~List~* } + \seq_map_inline:Nn \g_file_record_seq { \iow_log:n {##1} } + \iow_log:n { ************* } + } +\AtBeginDocument + { + \clist_map_inline:Nn \@filelist + { \seq_put_right:Nn \g_file_record_seq {#1} } + } +%% +%% +%% End of file `l3file.sty'. diff --git a/Master/texmf-dist/tex/latex/l3kernel/l3fp.sty b/Master/texmf-dist/tex/latex/l3kernel/l3fp.sty new file mode 100644 index 00000000000..d3f98d4353a --- /dev/null +++ b/Master/texmf-dist/tex/latex/l3kernel/l3fp.sty @@ -0,0 +1,3403 @@ +%% +%% This is file `l3fp.sty', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% l3fp.dtx (with options: `package') +%% +%% EXPERIMENTAL CODE +%% +%% Do not distribute this file without also distributing the +%% source files specified above. +%% +%% Do not distribute a modified version of this file. +%% +%% File: l3fp.dtx Copyright (C) 2010,2011 The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +\RequirePackage{l3names} +\GetIdInfo$Id: l3fp.dtx 2478 2011-06-19 21:34:23Z joseph $ + {L3 Experimental floating-point operations} +\ProvidesExplPackage + {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +\package_check_loaded_expl: +\int_const:Nn \c_forty_four { 44 } +\int_const:Nn \c_one_million { 1 000 000 } +\int_const:Nn \c_one_hundred_million { 100 000 000 } +\int_const:Nn \c_five_hundred_million { 500 000 000 } +\int_const:Nn \c_one_thousand_million { 1 000 000 000 } +\int_new:N \c_fp_pi_by_four_decimal_int +\int_set:Nn \c_fp_pi_by_four_decimal_int { 785 398 158 } +\int_new:N \c_fp_pi_by_four_extended_int +\int_set:Nn \c_fp_pi_by_four_extended_int { 897 448 310 } +\int_new:N \c_fp_pi_decimal_int +\int_set:Nn \c_fp_pi_decimal_int { 141 592 653 } +\int_new:N \c_fp_pi_extended_int +\int_set:Nn \c_fp_pi_extended_int { 589 793 238 } +\int_new:N \c_fp_two_pi_decimal_int +\int_set:Nn \c_fp_two_pi_decimal_int { 283 185 307 } +\int_new:N \c_fp_two_pi_extended_int +\int_set:Nn \c_fp_two_pi_extended_int { 179 586 477 } +\tl_const:Nn \c_e_fp { + 2.718281828 e 0 } +\tl_const:Nn \c_one_fp { + 1.000000000 e 0 } +\tl_const:Nn \c_pi_fp { + 3.141592654 e 0 } +\tl_const:Nn \c_undefined_fp { X 0.000000000 e 0 } +\tl_const:Nn \c_zero_fp { + 0.000000000 e 0 } +\tl_new:N \l_fp_arg_tl +\int_new:N \l_fp_count_int +\int_new:N \l_fp_div_offset_int +\int_new:N \l_fp_exp_integer_int +\int_new:N \l_fp_exp_decimal_int +\int_new:N \l_fp_exp_extended_int +\int_new:N \l_fp_exp_exponent_int +\int_new:N \l_fp_input_a_sign_int +\int_new:N \l_fp_input_a_integer_int +\int_new:N \l_fp_input_a_decimal_int +\int_new:N \l_fp_input_a_exponent_int +\int_new:N \l_fp_input_b_sign_int +\int_new:N \l_fp_input_b_integer_int +\int_new:N \l_fp_input_b_decimal_int +\int_new:N \l_fp_input_b_exponent_int +\int_new:N \l_fp_input_a_extended_int +\int_new:N \l_fp_input_b_extended_int +\int_new:N \l_fp_mul_a_i_int +\int_new:N \l_fp_mul_a_ii_int +\int_new:N \l_fp_mul_a_iii_int +\int_new:N \l_fp_mul_a_iv_int +\int_new:N \l_fp_mul_a_v_int +\int_new:N \l_fp_mul_a_vi_int +\int_new:N \l_fp_mul_b_i_int +\int_new:N \l_fp_mul_b_ii_int +\int_new:N \l_fp_mul_b_iii_int +\int_new:N \l_fp_mul_b_iv_int +\int_new:N \l_fp_mul_b_v_int +\int_new:N \l_fp_mul_b_vi_int +\int_new:N \l_fp_mul_output_int +\tl_new:N \l_fp_mul_output_tl +\int_new:N \l_fp_output_sign_int +\int_new:N \l_fp_output_integer_int +\int_new:N \l_fp_output_decimal_int +\int_new:N \l_fp_output_exponent_int +\int_new:N \l_fp_output_extended_int +\bool_new:N \l_fp_round_carry_bool +\tl_new:N \l_fp_round_decimal_tl +\int_new:N \l_fp_round_position_int +\int_new:N \l_fp_round_target_int +\tl_new:N \l_fp_sign_tl +\int_new:N \l_fp_split_sign_int +\int_new:N \l_fp_tmp_int +\tl_new:N \l_fp_tmp_tl +\int_new:N \l_fp_trig_octant_int +\int_new:N \l_fp_trig_sign_int +\int_new:N \l_fp_trig_decimal_int +\int_new:N \l_fp_trig_extended_int +\cs_new_protected_nopar:Npn \fp_read:N #1 + { \exp_after:wN \fp_read_aux:w #1 \q_stop } +\cs_new_protected_nopar:Npn \fp_read_aux:w #1#2 . #3 e #4 \q_stop + { + \if:w #1 - + \l_fp_input_a_sign_int \c_minus_one + \else: + \l_fp_input_a_sign_int \c_one + \fi: + \l_fp_input_a_integer_int #2 \scan_stop: + \l_fp_input_a_decimal_int #3 \scan_stop: + \l_fp_input_a_exponent_int #4 \scan_stop: + } +\cs_new_protected_nopar:Npn \fp_split:Nn #1#2 + { + \tl_set:Nx \l_fp_tmp_tl {#2} + \tl_set_rescan:Nno \l_fp_tmp_tl { \char_set_catcode_ignore:n { 32 } } + { \l_fp_tmp_tl } + \l_fp_split_sign_int \c_one + \fp_split_sign: + \use:c { l_fp_input_ #1 _sign_int } \l_fp_split_sign_int + \exp_after:wN \fp_split_exponent:w \l_fp_tmp_tl e e \q_stop #1 + } +\cs_new_protected_nopar:Npn \fp_split_sign: + { + \if_int_compare:w \pdftex_strcmp:D + { \exp_after:wN \tl_head:w \l_fp_tmp_tl ? \q_stop } { - } + = \c_zero + \tl_set:Nx \l_fp_tmp_tl + { + \exp_after:wN + \tl_tail:w \l_fp_tmp_tl \prg_do_nothing: \q_stop + } + \l_fp_split_sign_int -\l_fp_split_sign_int + \exp_after:wN \fp_split_sign: + \else: + \if_int_compare:w \pdftex_strcmp:D + { \exp_after:wN \tl_head:w \l_fp_tmp_tl ? \q_stop } { + } + = \c_zero + \tl_set:Nx \l_fp_tmp_tl + { + \exp_after:wN + \tl_tail:w \l_fp_tmp_tl \prg_do_nothing: \q_stop + } + \exp_after:wN \exp_after:wN \exp_after:wN \fp_split_sign: + \fi: + \fi: + } +\cs_new_protected_nopar:Npn \fp_split_exponent:w #1 e #2 e #3 \q_stop #4 + { + \use:c { l_fp_input_ #4 _exponent_int } + \int_eval:w 0 #2 \scan_stop: + \tex_afterassignment:D \fp_split_aux_i:w + \use:c { l_fp_input_ #4 _integer_int } + \int_eval:w 0 #1 . . \q_stop #4 + } +\cs_new_protected_nopar:Npn \fp_split_aux_i:w #1 . #2 . #3 \q_stop + { \fp_split_aux_ii:w #2 000000000 \q_stop } +\cs_new_protected_nopar:Npn \fp_split_aux_ii:w #1#2#3#4#5#6#7#8#9 + { \fp_split_aux_iii:w {#1#2#3#4#5#6#7#8#9} } +\cs_new_protected_nopar:Npn \fp_split_aux_iii:w #1#2 \q_stop + { + \l_fp_tmp_int 1 #1 \scan_stop: + \exp_after:wN \fp_split_decimal:w + \int_use:N \l_fp_tmp_int 000000000 \q_stop + } +\cs_new_protected_nopar:Npn \fp_split_decimal:w #1#2#3#4#5#6#7#8#9 + { \fp_split_decimal_aux:w {#2#3#4#5#6#7#8#9} } +\cs_new_protected_nopar:Npn \fp_split_decimal_aux:w #1#2#3 \q_stop #4 + { + \use:c { l_fp_input_ #4 _decimal_int } #1#2 \scan_stop: + \if_int_compare:w + \int_eval:w + \use:c { l_fp_input_ #4 _integer_int } + + \use:c { l_fp_input_ #4 _decimal_int } + \scan_stop: + = \c_zero + \use:c { l_fp_input_ #4 _sign_int } \c_one + \fi: + \if_int_compare:w + \use:c { l_fp_input_ #4 _integer_int } < \c_one_thousand_million + \else: + \exp_after:wN \fp_overflow_msg: + \fi: + } +\cs_new_protected_nopar:Npn \fp_standardise:NNNN #1#2#3#4 + { + \if_int_compare:w + \int_eval:w #2 + #3 = \c_zero + #1 \c_one + #4 \c_zero + \exp_after:wN \use_none:nnnn + \else: + \exp_after:wN \fp_standardise_aux:NNNN + \fi: + #1#2#3#4 + } +\cs_new_protected_nopar:Npn \fp_standardise_aux:NNNN #1#2#3#4 + { + \cs_set_protected_nopar:Npn \fp_standardise_aux: + { + \if_int_compare:w #2 = \c_zero + \tex_advance:D #3 \c_one_thousand_million + \exp_after:wN \fp_standardise_aux:w + \int_use:N #3 \q_stop + \exp_after:wN \fp_standardise_aux: + \fi: + } + \cs_set_protected_nopar:Npn + \fp_standardise_aux:w ##1##2##3##4##5##6##7##8##9 \q_stop + { + #2 ##2 \scan_stop: + #3 ##3##4##5##6##7##8##9 0 \scan_stop: + \tex_advance:D #4 \c_minus_one + } + \fp_standardise_aux: + \cs_set_protected_nopar:Npn \fp_standardise_aux: + { + \if_int_compare:w #2 > \c_nine + \tex_advance:D #2 \c_one_thousand_million + \exp_after:wN \use_i:nn \exp_after:wN + \fp_standardise_aux:w \int_use:N #2 + \exp_after:wN \fp_standardise_aux: + \fi: + } + \cs_set_protected_nopar:Npn + \fp_standardise_aux:w ##1##2##3##4##5##6##7##8##9 + { + #2 ##1##2##3##4##5##6##7##8 \scan_stop: + \tex_advance:D #3 \c_one_thousand_million + \tex_divide:D #3 \c_ten + \tl_set:Nx \l_fp_tmp_tl + { + ##9 + \exp_after:wN \use_none:n \int_use:N #3 + } + #3 \l_fp_tmp_tl \scan_stop: + \tex_advance:D #4 \c_one + } + \fp_standardise_aux: + \if_int_compare:w #4 < \c_one_hundred + \if_int_compare:w #4 > -\c_one_hundred + \else: + #1 \c_one + #2 \c_zero + #3 \c_zero + #4 \c_zero + \fi: + \else: + \exp_after:wN \fp_overflow_msg: + \fi: + } +\cs_new_protected_nopar:Npn \fp_standardise_aux: { } +\cs_new_protected_nopar:Npn \fp_standardise_aux:w { } +\cs_new_protected_nopar:Npn \fp_level_input_exponents: + { + \if_int_compare:w \l_fp_input_a_exponent_int > \l_fp_input_b_exponent_int + \exp_after:wN \fp_level_input_exponents_a: + \else: + \exp_after:wN \fp_level_input_exponents_b: + \fi: + } +\cs_new_protected_nopar:Npn \fp_level_input_exponents_a: + { + \if_int_compare:w \l_fp_input_a_exponent_int > \l_fp_input_b_exponent_int + \tex_advance:D \l_fp_input_b_integer_int \c_one_thousand_million + \exp_after:wN \use_i:nn \exp_after:wN + \fp_level_input_exponents_a:NNNNNNNNN + \int_use:N \l_fp_input_b_integer_int + \exp_after:wN \fp_level_input_exponents_a: + \fi: + } +\cs_new_protected_nopar:Npn \fp_level_input_exponents_a:NNNNNNNNN + #1#2#3#4#5#6#7#8#9 + { + \l_fp_input_b_integer_int #1#2#3#4#5#6#7#8 \scan_stop: + \tex_advance:D \l_fp_input_b_decimal_int \c_one_thousand_million + \tex_divide:D \l_fp_input_b_decimal_int \c_ten + \tl_set:Nx \l_fp_tmp_tl + { + #9 + \exp_after:wN \use_none:n + \int_use:N \l_fp_input_b_decimal_int + } + \l_fp_input_b_decimal_int \l_fp_tmp_tl \scan_stop: + \tex_advance:D \l_fp_input_b_exponent_int \c_one + } +\cs_new_protected_nopar:Npn \fp_level_input_exponents_b: + { + \if_int_compare:w \l_fp_input_b_exponent_int > \l_fp_input_a_exponent_int + \tex_advance:D \l_fp_input_a_integer_int \c_one_thousand_million + \exp_after:wN \use_i:nn \exp_after:wN + \fp_level_input_exponents_b:NNNNNNNNN + \int_use:N \l_fp_input_a_integer_int + \exp_after:wN \fp_level_input_exponents_b: + \fi: + } +\cs_new_protected_nopar:Npn \fp_level_input_exponents_b:NNNNNNNNN + #1#2#3#4#5#6#7#8#9 + { + \l_fp_input_a_integer_int #1#2#3#4#5#6#7#8 \scan_stop: + \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million + \tex_divide:D \l_fp_input_a_decimal_int \c_ten + \tl_set:Nx \l_fp_tmp_tl + { + #9 + \exp_after:wN \use_none:n + \int_use:N \l_fp_input_a_decimal_int + } + \l_fp_input_a_decimal_int \l_fp_tmp_tl \scan_stop: + \tex_advance:D \l_fp_input_a_exponent_int \c_one + } +\cs_new_protected_nopar:Npn \fp_tmp:w #1#2 { } +\cs_new_protected_nopar:Npn \fp_new:N #1 + { + \tl_new:N #1 + \tl_gset_eq:NN #1 \c_zero_fp + } +\cs_generate_variant:Nn \fp_new:N { c } +\cs_new_protected_nopar:Npn \fp_const:Nn #1#2 + { + \fp_new:N #1 + \fp_gset:Nn #1 {#2} + } +\cs_generate_variant:Nn \fp_const:Nn { c } +\cs_new_protected_nopar:Npn \fp_zero:N #1 + { \tl_set_eq:NN #1 \c_zero_fp } +\cs_new_protected_nopar:Npn \fp_gzero:N #1 + { \tl_gset_eq:NN #1 \c_zero_fp } +\cs_generate_variant:Nn \fp_zero:N { c } +\cs_generate_variant:Nn \fp_gzero:N { c } +\cs_new_protected_nopar:Npn \fp_set:Nn { \fp_set_aux:NNn \tl_set:Nn } +\cs_new_protected_nopar:Npn \fp_gset:Nn { \fp_set_aux:NNn \tl_gset:Nn } +\cs_new_protected_nopar:Npn \fp_set_aux:NNn #1#2#3 + { + \group_begin: + \fp_split:Nn a {#3} + \fp_standardise:NNNN + \l_fp_input_a_sign_int + \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int + \l_fp_input_a_exponent_int + \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million + \cs_set_protected_nopar:Npx \fp_tmp:w + { + \group_end: + #1 \exp_not:N #2 + { + \if_int_compare:w \l_fp_input_a_sign_int < \c_zero + - + \else: + + + \fi: + \int_use:N \l_fp_input_a_integer_int + . + \exp_after:wN \use_none:n + \int_use:N \l_fp_input_a_decimal_int + e + \int_use:N \l_fp_input_a_exponent_int + } + } + \fp_tmp:w + } +\cs_generate_variant:Nn \fp_set:Nn { c } +\cs_generate_variant:Nn \fp_gset:Nn { c } +\cs_new_protected_nopar:Npn \fp_set_from_dim:Nn + { \fp_set_from_dim_aux:NNn \tl_set:Nx } +\cs_new_protected_nopar:Npn \fp_gset_from_dim:Nn + { \fp_set_from_dim_aux:NNn \tl_gset:Nx } +\cs_new_protected_nopar:Npn \fp_set_from_dim_aux:NNn #1#2#3 + { + \group_begin: + \l_fp_tmp_skip \etex_glueexpr:D #3 \scan_stop: + \l_fp_tmp_dim \l_fp_tmp_skip + \fp_split:Nn a + { + \exp_after:wN \fp_set_from_dim_aux:w + \dim_use:N \l_fp_tmp_dim + } + \fp_standardise:NNNN + \l_fp_input_a_sign_int + \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int + \l_fp_input_a_exponent_int + \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million + \cs_set_protected_nopar:Npx \fp_tmp:w + { + \group_end: + #1 \exp_not:N #2 + { + \if_int_compare:w \l_fp_input_a_sign_int < \c_zero + - + \else: + + + \fi: + \int_use:N \l_fp_input_a_integer_int + . + \exp_after:wN \use_none:n + \int_use:N \l_fp_input_a_decimal_int + e + \int_use:N \l_fp_input_a_exponent_int + } + } + \fp_tmp:w + } +\cs_set_protected_nopar:Npx \fp_set_from_dim_aux:w + { + \cs_set_nopar:Npn \exp_not:N \fp_set_from_dim_aux:w + ##1 \tl_to_str:n { pt } {##1} + } +\fp_set_from_dim_aux:w +\cs_generate_variant:Nn \fp_set_from_dim:Nn { c } +\cs_generate_variant:Nn \fp_gset_from_dim:Nn { c } +\dim_new:N \l_fp_tmp_dim +\skip_new:N \l_fp_tmp_skip +\cs_new_eq:NN \fp_set_eq:NN \tl_set_eq:NN +\cs_new_eq:NN \fp_set_eq:cN \tl_set_eq:cN +\cs_new_eq:NN \fp_set_eq:Nc \tl_set_eq:Nc +\cs_new_eq:NN \fp_set_eq:cc \tl_set_eq:cc +\cs_new_eq:NN \fp_gset_eq:NN \tl_gset_eq:NN +\cs_new_eq:NN \fp_gset_eq:cN \tl_gset_eq:cN +\cs_new_eq:NN \fp_gset_eq:Nc \tl_gset_eq:Nc +\cs_new_eq:NN \fp_gset_eq:cc \tl_gset_eq:cc +\cs_new_eq:NN \fp_show:N \tl_show:N +\cs_new_eq:NN \fp_show:c \tl_show:c +\cs_new_nopar:Npn \fp_use:N #1 + { \exp_after:wN \fp_use_aux:w #1 \q_stop } +\cs_generate_variant:Nn \fp_use:N { c } +\cs_new_nopar:Npn \fp_use_aux:w #1#2 e #3 \q_stop + { + \if:w #1 - + - + \fi: + \if_int_compare:w #3 > \c_zero + \exp_after:wN \fp_use_large:w + \else: + \if_int_compare:w #3 < \c_zero + \exp_after:wN \exp_after:wN \exp_after:wN + \fp_use_small:w + \else: + \exp_after:wN \exp_after:wN \exp_after:wN \fp_use_none:w + \fi: + \fi: + #2 e #3 \q_stop + } +\cs_new_nopar:Npn \fp_use_none:w #1 e #2 \q_stop {#1} +\cs_new_nopar:Npn \fp_use_small:w #1 . #2 e #3 \q_stop + { + 0 . + \prg_replicate:nn { -#3 - 1 } { 0 } + #1#2 + } +\cs_new_nopar:Npn \fp_use_large:w #1 . #2 e #3 \q_stop + { + \if_int_compare:w #3 < \c_ten + \exp_after:wN \fp_use_large_aux_i:w + \else: + \exp_after:wN \fp_use_large_aux_ii:w + \fi: + #1#2 e #3 \q_stop + } +\cs_new_nopar:Npn \fp_use_large_aux_i:w #1#2 e #3 \q_stop + { + #1 + \use:c { fp_use_large_aux_ #3 :w } #2 \q_stop + } +\cs_new_nopar:cpn { fp_use_large_aux_1:w } #1#2 \q_stop { #1 . #2 } +\cs_new_nopar:cpn { fp_use_large_aux_2:w } #1#2#3 \q_stop + { #1#2 . #3 } +\cs_new_nopar:cpn { fp_use_large_aux_3:w } #1#2#3#4 \q_stop + { #1#2#3 . #4 } +\cs_new_nopar:cpn { fp_use_large_aux_4:w } #1#2#3#4#5 \q_stop + { #1#2#3#4 . #5 } +\cs_new_nopar:cpn { fp_use_large_aux_5:w } #1#2#3#4#5#6 \q_stop + { #1#2#3#4#5 . #6 } +\cs_new_nopar:cpn { fp_use_large_aux_6:w } #1#2#3#4#5#6#7 \q_stop + { #1#2#3#4#5#6 . #7 } +\cs_new_nopar:cpn { fp_use_large_aux_7:w } #1#2#3#4#5#6#7#8 \q_stop + { #1#2#3#4#6#7 . #8 } +\cs_new_nopar:cpn { fp_use_large_aux_8:w } #1#2#3#4#5#6#7#8#9 \q_stop + { #1#2#3#4#5#6#7#8 . #9 } +\cs_new_nopar:cpn { fp_use_large_aux_9:w } #1 \q_stop { #1 . } +\cs_new_nopar:Npn \fp_use_large_aux_ii:w #1 e #2 \q_stop + { + #1 + \prg_replicate:nn { #2 - 9 } { 0 } + . + } +\cs_new_nopar:Npn \fp_to_dim:N #1 { \fp_use:N #1 pt } +\cs_generate_variant:Nn \fp_to_dim:N { c } +\cs_new_nopar:Npn \fp_to_int:N #1 + { \exp_after:wN \fp_to_int_aux:w #1 \q_stop } +\cs_generate_variant:Nn \fp_to_int:N { c } +\cs_new_nopar:Npn \fp_to_int_aux:w #1#2 e #3 \q_stop + { + \if:w #1 - + - + \fi: + \if_int_compare:w #3 < \c_zero + \exp_after:wN \fp_to_int_small:w + \else: + \exp_after:wN \fp_to_int_large:w + \fi: + #2 e #3 \q_stop + } +\cs_new_nopar:Npn \fp_to_int_small:w #1 . #2 e #3 \q_stop + { + \if_int_compare:w #3 > \c_one + \else: + \if_int_compare:w #1 < \c_five + 0 + \else: + 1 + \fi: + \fi: + } +\cs_new_nopar:Npn \fp_to_int_large:w #1 . #2 e #3 \q_stop + { + \if_int_compare:w #3 < \c_ten + \exp_after:wN \fp_to_int_large_aux_i:w + \else: + \exp_after:wN \fp_to_int_large_aux_ii:w + \fi: + #1#2 e #3 \q_stop + } +\cs_new_nopar:Npn \fp_to_int_large_aux_i:w #1#2 e #3 \q_stop + { \use:c { fp_to_int_large_aux_ #3 :w } #2 \q_stop {#1} } +\cs_new_nopar:cpn { fp_to_int_large_aux_1:w } #1#2 \q_stop + { \fp_to_int_large_aux:nnn { #2 0 } {#1} } +\cs_new_nopar:cpn { fp_to_int_large_aux_2:w } #1#2#3 \q_stop + { \fp_to_int_large_aux:nnn { #3 00 } {#1#2} } +\cs_new_nopar:cpn { fp_to_int_large_aux_3:w } #1#2#3#4 \q_stop + { \fp_to_int_large_aux:nnn { #4 000 } {#1#2#3} } +\cs_new_nopar:cpn { fp_to_int_large_aux_4:w } #1#2#3#4#5 \q_stop + { \fp_to_int_large_aux:nnn { #5 0000 } {#1#2#3#4} } +\cs_new_nopar:cpn { fp_to_int_large_aux_5:w } #1#2#3#4#5#6 \q_stop + { \fp_to_int_large_aux:nnn { #6 00000 } {#1#2#3#4#5} } +\cs_new_nopar:cpn { fp_to_int_large_aux_6:w } #1#2#3#4#5#6#7 \q_stop + { \fp_to_int_large_aux:nnn { #7 000000 } {#1#2#3#4#5#6} } +\cs_new_nopar:cpn { fp_to_int_large_aux_7:w } #1#2#3#4#5#6#7#8 \q_stop + { \fp_to_int_large_aux:nnn { #8 0000000 } {#1#2#3#4#5#6#7} } +\cs_new_nopar:cpn { fp_to_int_large_aux_8:w } #1#2#3#4#5#6#7#8#9 \q_stop + { \fp_to_int_large_aux:nnn { #9 00000000 } {#1#2#3#4#5#6#7#8} } +\cs_new_nopar:cpn { fp_to_int_large_aux_9:w } #1 \q_stop {#1} +\cs_new_nopar:Npn \fp_to_int_large_aux:nnn #1#2#3 + { + \if_int_compare:w #1 < \c_five_hundred_million + #3#2 + \else: + \int_value:w \int_eval:w #3#2 + 1 \int_eval_end: + \fi: + } +\cs_new_nopar:Npn \fp_to_int_large_aux_ii:w #1 e #2 \q_stop + { + #1 + \prg_replicate:nn { #2 - 9 } { 0 } + } +\cs_new_nopar:Npn \fp_to_tl:N #1 + { \exp_after:wN \fp_to_tl_aux:w #1 \q_stop } +\cs_generate_variant:Nn \fp_to_tl:N { c } +\cs_new_nopar:Npn \fp_to_tl_aux:w #1#2 e #3 \q_stop + { + \if:w #1 - + - + \fi: + \if_int_compare:w #3 < \c_zero + \exp_after:wN \fp_to_tl_small:w + \else: + \exp_after:wN \fp_to_tl_large:w + \fi: + #2 e #3 \q_stop + } +\cs_new_nopar:Npn \fp_to_tl_large:w #1 e #2 \q_stop + { + \if_int_compare:w #2 < \c_ten + \exp_after:wN \fp_to_tl_large_aux_i:w + \else: + \exp_after:wN \fp_to_tl_large_aux_ii:w + \fi: + #1 e #2 \q_stop + } +\cs_new_nopar:Npn \fp_to_tl_large_aux_i:w #1 e #2 \q_stop + { \use:c { fp_to_tl_large_ #2 :w } #1 \q_stop } +\cs_new_nopar:Npn \fp_to_tl_large_aux_ii:w #1 . #2 e #3 \q_stop + { + #1 + \fp_to_tl_large_zeros:NNNNNNNNN #2 + e #3 + } +\cs_new_nopar:cpn { fp_to_tl_large_0:w } #1 . #2 \q_stop + { + #1 + \fp_to_tl_large_zeros:NNNNNNNNN #2 + } +\cs_new_nopar:cpn { fp_to_tl_large_1:w } #1 . #2#3 \q_stop + { + #1#2 + \fp_to_tl_large_zeros:NNNNNNNNN #3 0 + } +\cs_new_nopar:cpn { fp_to_tl_large_2:w } #1 . #2#3#4 \q_stop + { + #1#2#3 + \fp_to_tl_large_zeros:NNNNNNNNN #4 00 + } +\cs_new_nopar:cpn { fp_to_tl_large_3:w } #1 . #2#3#4#5 \q_stop + { + #1#2#3#4 + \fp_to_tl_large_zeros:NNNNNNNNN #5 000 + } +\cs_new_nopar:cpn { fp_to_tl_large_4:w } #1 . #2#3#4#5#6 \q_stop + { + #1#2#3#4#5 + \fp_to_tl_large_zeros:NNNNNNNNN #6 0000 + } +\cs_new_nopar:cpn { fp_to_tl_large_5:w } #1 . #2#3#4#5#6#7 \q_stop + { + #1#2#3#4#5#6 + \fp_to_tl_large_zeros:NNNNNNNNN #7 00000 + } +\cs_new_nopar:cpn { fp_to_tl_large_6:w } #1 . #2#3#4#5#6#7#8 \q_stop + { + #1#2#3#4#5#6#7 + \fp_to_tl_large_zeros:NNNNNNNNN #8 000000 + } +\cs_new_nopar:cpn { fp_to_tl_large_7:w } #1 . #2#3#4#5#6#7#8#9 \q_stop + { + #1#2#3#4#5#6#7#8 + \fp_to_tl_large_zeros:NNNNNNNNN #9 0000000 + } +\cs_new_nopar:cpn { fp_to_tl_large_8:w } #1 . + { + #1 + \use:c { fp_to_tl_large_8_aux:w } + } +\cs_new_nopar:cpn { fp_to_tl_large_8_aux:w } #1#2#3#4#5#6#7#8#9 \q_stop + { + #1#2#3#4#5#6#7#8 + \fp_to_tl_large_zeros:NNNNNNNNN #9 00000000 + } +\cs_new_nopar:cpn { fp_to_tl_large_9:w } #1 . #2 \q_stop {#1#2} +\cs_new_nopar:Npn \fp_to_tl_small:w #1 e #2 \q_stop + { + \if_int_compare:w #2 = \c_minus_one + \exp_after:wN \fp_to_tl_small_one:w + \else: + \if_int_compare:w #2 = -\c_two + \exp_after:wN \exp_after:wN \exp_after:wN \fp_to_tl_small_two:w + \else: + \exp_after:wN \exp_after:wN \exp_after:wN \fp_to_tl_small_aux:w + \fi: + \fi: + #1 e #2 \q_stop + } +\cs_new_nopar:Npn \fp_to_tl_small_one:w #1 . #2 e #3 \q_stop + { + \if_int_compare:w \fp_use_ix:NNNNNNNNN #2 > \c_four + \if_int_compare:w + \int_eval:w #1 \fp_use_i_to_iix:NNNNNNNNN #2 + 1 + < \c_one_thousand_million + 0. + \exp_after:wN \fp_to_tl_small_zeros:NNNNNNNNN + \int_value:w \int_eval:w + #1 \fp_use_i_to_iix:NNNNNNNNN #2 + 1 + \int_eval_end: + \else: + 1 + \fi: + \else: + 0. #1 + \fp_to_tl_small_zeros:NNNNNNNNN #2 + \fi: + } +\cs_new_nopar:Npn \fp_to_tl_small_two:w #1 . #2 e #3 \q_stop + { + \if_int_compare:w \fp_use_iix_ix:NNNNNNNNN #2 > \c_forty_four + \if_int_compare:w + \int_eval:w #1 \fp_use_i_to_vii:NNNNNNNNN #2 0 + \c_ten + < \c_one_thousand_million + 0.0 + \exp_after:wN \fp_to_tl_small_zeros:NNNNNNNNN + \int_value:w \int_eval:w + #1 \fp_use_i_to_vii:NNNNNNNNN #2 0 + \c_ten + \int_eval_end: + \else: + 0.1 + \fi: + \else: + 0.0 + #1 + \fp_to_tl_small_zeros:NNNNNNNNN #2 + \fi: + } +\cs_new_nopar:Npn \fp_to_tl_small_aux:w #1 . #2 e #3 \q_stop + { + #1 + \fp_to_tl_large_zeros:NNNNNNNNN #2 + e #3 + } +\cs_new_nopar:Npn \fp_to_tl_large_zeros:NNNNNNNNN #1#2#3#4#5#6#7#8#9 + { + \if_int_compare:w #9 = \c_zero + \if_int_compare:w #8 = \c_zero + \if_int_compare:w #7 = \c_zero + \if_int_compare:w #6 = \c_zero + \if_int_compare:w #5 = \c_zero + \if_int_compare:w #4 = \c_zero + \if_int_compare:w #3 = \c_zero + \if_int_compare:w #2 = \c_zero + \if_int_compare:w #1 = \c_zero + \else: + . #1 + \fi: + \else: + . #1#2 + \fi: + \else: + . #1#2#3 + \fi: + \else: + . #1#2#3#4 + \fi: + \else: + . #1#2#3#4#5 + \fi: + \else: + . #1#2#3#4#5#6 + \fi: + \else: + . #1#2#3#4#5#6#7 + \fi: + \else: + . #1#2#3#4#5#6#7#8 + \fi: + \else: + . #1#2#3#4#5#6#7#8#9 + \fi: + } +\cs_new_nopar:Npn \fp_to_tl_small_zeros:NNNNNNNNN #1#2#3#4#5#6#7#8#9 + { + \if_int_compare:w #9 = \c_zero + \if_int_compare:w #8 = \c_zero + \if_int_compare:w #7 = \c_zero + \if_int_compare:w #6 = \c_zero + \if_int_compare:w #5 = \c_zero + \if_int_compare:w #4 = \c_zero + \if_int_compare:w #3 = \c_zero + \if_int_compare:w #2 = \c_zero + \if_int_compare:w #1 = \c_zero + \else: + #1 + \fi: + \else: + #1#2 + \fi: + \else: + #1#2#3 + \fi: + \else: + #1#2#3#4 + \fi: + \else: + #1#2#3#4#5 + \fi: + \else: + #1#2#3#4#5#6 + \fi: + \else: + #1#2#3#4#5#6#7 + \fi: + \else: + #1#2#3#4#5#6#7#8 + \fi: + \else: + #1#2#3#4#5#6#7#8#9 + \fi: + } +\cs_new_nopar:Npn \fp_use_iix_ix:NNNNNNNNN #1#2#3#4#5#6#7#8#9 {#8#9} +\cs_new_nopar:Npn \fp_use_ix:NNNNNNNNN #1#2#3#4#5#6#7#8#9 {#9} +\cs_new_nopar:Npn \fp_use_i_to_vii:NNNNNNNNN #1#2#3#4#5#6#7#8#9 + {#1#2#3#4#5#6#7} +\cs_new_nopar:Npn \fp_use_i_to_iix:NNNNNNNNN #1#2#3#4#5#6#7#8#9 + {#1#2#3#4#5#6#7#8} +\cs_new_protected_nopar:Npn \fp_round_figures:Nn + { \fp_round_figures_aux:NNn \tl_set:Nn } +\cs_generate_variant:Nn \fp_round_figures:Nn { c } +\cs_new_protected_nopar:Npn \fp_ground_figures:Nn + { \fp_round_figures_aux:NNn \tl_gset:Nn } +\cs_generate_variant:Nn \fp_ground_figures:Nn { c } +\cs_new_protected_nopar:Npn \fp_round_figures_aux:NNn #1#2#3 + { + \group_begin: + \fp_read:N #2 + \int_set:Nn \l_fp_round_target_int { #3 - 1 } + \if_int_compare:w \l_fp_round_target_int < \c_ten + \exp_after:wN \fp_round: + \fi: + \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million + \cs_set_protected_nopar:Npx \fp_tmp:w + { + \group_end: + #1 \exp_not:N #2 + { + \if_int_compare:w \l_fp_input_a_sign_int < \c_zero + - + \else: + + + \fi: + \int_use:N \l_fp_input_a_integer_int + . + \exp_after:wN \use_none:n + \int_use:N \l_fp_input_a_decimal_int + e + \int_use:N \l_fp_input_a_exponent_int + } + } + \fp_tmp:w + } +\cs_new_protected_nopar:Npn \fp_round_places:Nn + { \fp_round_places_aux:NNn \tl_set:Nn } +\cs_generate_variant:Nn \fp_round_places:Nn { c } +\cs_new_protected_nopar:Npn \fp_ground_places:Nn + { \fp_round_places_aux:NNn \tl_gset:Nn } +\cs_generate_variant:Nn \fp_ground_places:Nn { c } +\cs_new_protected_nopar:Npn \fp_round_places_aux:NNn #1#2#3 + { + \group_begin: + \fp_read:N #2 + \int_set:Nn \l_fp_round_target_int + { #3 + \l_fp_input_a_exponent_int } + \if_int_compare:w \l_fp_round_target_int < \c_ten + \exp_after:wN \fp_round: + \fi: + \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million + \cs_set_protected_nopar:Npx \fp_tmp:w + { + \group_end: + #1 \exp_not:N #2 + { + \if_int_compare:w \l_fp_input_a_sign_int < \c_zero + - + \else: + + + \fi: + \int_use:N \l_fp_input_a_integer_int + . + \exp_after:wN \use_none:n + \int_use:N \l_fp_input_a_decimal_int + e + \int_use:N \l_fp_input_a_exponent_int + } + } + \fp_tmp:w + } +\cs_new_protected_nopar:Npn \fp_round: + { + \bool_set_false:N \l_fp_round_carry_bool + \l_fp_round_position_int \c_eight + \tl_clear:N \l_fp_round_decimal_tl + \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million + \exp_after:wN \use_i:nn \exp_after:wN + \fp_round_aux:NNNNNNNNN \int_use:N \l_fp_input_a_decimal_int + } +\cs_new_protected_nopar:Npn \fp_round_aux:NNNNNNNNN #1#2#3#4#5#6#7#8#9 + { + \fp_round_loop:N #9#8#7#6#5#4#3#2#1 + \bool_if:NT \l_fp_round_carry_bool + { \tex_advance:D \l_fp_input_a_integer_int \c_one } + \l_fp_input_a_decimal_int \l_fp_round_decimal_tl \scan_stop: + \if_int_compare:w \l_fp_input_a_integer_int < \c_ten + \else: + \l_fp_input_a_integer_int \c_one + \tex_divide:D \l_fp_input_a_decimal_int \c_ten + \tex_advance:D \l_fp_input_a_exponent_int \c_one + \fi: + } +\cs_new_protected_nopar:Npn \fp_round_loop:N #1 + { + \if_int_compare:w \l_fp_round_position_int < \l_fp_round_target_int + \bool_if:NTF \l_fp_round_carry_bool + { \l_fp_tmp_int \int_eval:w #1 + \c_one \scan_stop: } + { \l_fp_tmp_int \int_eval:w #1 \scan_stop: } + \if_int_compare:w \l_fp_tmp_int = \c_ten + \l_fp_tmp_int \c_zero + \else: + \bool_set_false:N \l_fp_round_carry_bool + \fi: + \tl_set:Nx \l_fp_round_decimal_tl + { \int_use:N \l_fp_tmp_int \l_fp_round_decimal_tl } + \else: + \tl_set:Nx \l_fp_round_decimal_tl { 0 \l_fp_round_decimal_tl } + \if_int_compare:w \l_fp_round_position_int = \l_fp_round_target_int + \if_int_compare:w #1 > \c_four + \bool_set_true:N \l_fp_round_carry_bool + \fi: + \fi: + \fi: + \tex_advance:D \l_fp_round_position_int \c_minus_one + \if_int_compare:w \l_fp_round_position_int > \c_minus_one + \exp_after:wN \fp_round_loop:N + \fi: + } +\cs_new_protected_nopar:Npn \fp_abs:N { \fp_abs_aux:NN \tl_set:Nn } +\cs_new_protected_nopar:Npn \fp_gabs:N { \fp_abs_aux:NN \tl_gset:Nn } +\cs_generate_variant:Nn \fp_abs:N { c } +\cs_generate_variant:Nn \fp_gabs:N { c } +\cs_new_protected_nopar:Npn \fp_abs_aux:NN #1#2 + { + \group_begin: + \fp_read:N #2 + \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million + \cs_set_protected_nopar:Npx \fp_tmp:w + { + \group_end: + #1 \exp_not:N #2 + { + + + \int_use:N \l_fp_input_a_integer_int + . + \exp_after:wN \use_none:n + \int_use:N \l_fp_input_a_decimal_int + e + \int_use:N \l_fp_input_a_exponent_int + } + } + \fp_tmp:w + } +\cs_new_protected_nopar:Npn \fp_neg:N { \fp_neg_aux:NN \tl_set:Nn } +\cs_new_protected_nopar:Npn \fp_gneg:N { \fp_neg_aux:NN \tl_gset:Nn } +\cs_generate_variant:Nn \fp_neg:N { c } +\cs_generate_variant:Nn \fp_gneg:N { c } +\cs_new_protected_nopar:Npn \fp_neg_aux:NN #1#2 + { + \group_begin: + \fp_read:N #2 + \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million + \tl_set:Nx \l_fp_tmp_tl + { + \if_int_compare:w \l_fp_input_a_sign_int < \c_zero + + + \else: + - + \fi: + \int_use:N \l_fp_input_a_integer_int + . + \exp_after:wN \use_none:n + \int_use:N \l_fp_input_a_decimal_int + e + \int_use:N \l_fp_input_a_exponent_int + } + \exp_after:wN \group_end: \exp_after:wN + #1 \exp_after:wN #2 \exp_after:wN { \l_fp_tmp_tl } + } +\cs_new_protected_nopar:Npn \fp_add:Nn { \fp_add_aux:NNn \tl_set:Nn } +\cs_new_protected_nopar:Npn \fp_gadd:Nn { \fp_add_aux:NNn \tl_gset:Nn } +\cs_generate_variant:Nn \fp_add:Nn { c } +\cs_generate_variant:Nn \fp_gadd:Nn { c } +\cs_new_protected_nopar:Npn \fp_add_aux:NNn #1#2#3 + { + \group_begin: + \fp_read:N #2 + \fp_split:Nn b {#3} + \fp_standardise:NNNN + \l_fp_input_b_sign_int + \l_fp_input_b_integer_int + \l_fp_input_b_decimal_int + \l_fp_input_b_exponent_int + \fp_add_core: + \fp_tmp:w #1#2 + } +\cs_new_protected_nopar:Npn \fp_add_core: + { + \fp_level_input_exponents: + \if_int_compare:w + \int_eval:w + \l_fp_input_a_sign_int * \l_fp_input_b_sign_int + > \c_zero + \exp_after:wN \fp_add_sum: + \else: + \exp_after:wN \fp_add_difference: + \fi: + \l_fp_output_exponent_int \l_fp_input_a_exponent_int + \fp_standardise:NNNN + \l_fp_output_sign_int + \l_fp_output_integer_int + \l_fp_output_decimal_int + \l_fp_output_exponent_int + \cs_set_protected_nopar:Npx \fp_tmp:w ##1##2 + { + \group_end: + ##1 ##2 + { + \if_int_compare:w \l_fp_output_sign_int < \c_zero + - + \else: + + + \fi: + \int_use:N \l_fp_output_integer_int + . + \exp_after:wN \use_none:n + \int_value:w \int_eval:w + \l_fp_output_decimal_int + \c_one_thousand_million + e + \int_use:N \l_fp_output_exponent_int + } + } + } +\cs_new_protected_nopar:Npn \fp_add_sum: + { + \l_fp_output_sign_int \l_fp_input_a_sign_int + \l_fp_output_integer_int + \int_eval:w + \l_fp_input_a_integer_int + \l_fp_input_b_integer_int + \scan_stop: + \l_fp_output_decimal_int + \int_eval:w + \l_fp_input_a_decimal_int + \l_fp_input_b_decimal_int + \scan_stop: + \if_int_compare:w \l_fp_output_decimal_int < \c_one_thousand_million + \else: + \tex_advance:D \l_fp_output_integer_int \c_one + \tex_advance:D \l_fp_output_decimal_int -\c_one_thousand_million + \fi: + } +\cs_new_protected_nopar:Npn \fp_add_difference: + { + \l_fp_output_integer_int + \int_eval:w + \l_fp_input_a_integer_int - \l_fp_input_b_integer_int + \scan_stop: + \l_fp_output_decimal_int + \int_eval:w + \l_fp_input_a_decimal_int - \l_fp_input_b_decimal_int + \scan_stop: + \if_int_compare:w \l_fp_output_decimal_int < \c_zero + \tex_advance:D \l_fp_output_integer_int \c_minus_one + \tex_advance:D \l_fp_output_decimal_int \c_one_thousand_million + \fi: + \if_int_compare:w \l_fp_output_integer_int < \c_zero + \l_fp_output_sign_int \l_fp_input_b_sign_int + \if_int_compare:w \l_fp_output_decimal_int = \c_zero + \l_fp_output_integer_int -\l_fp_output_integer_int + \else: + \l_fp_output_decimal_int + \int_eval:w + \c_one_thousand_million - \l_fp_output_decimal_int + \scan_stop: + \l_fp_output_integer_int + \int_eval:w + - \l_fp_output_integer_int - \c_one + \scan_stop: + \fi: + \else: + \l_fp_output_sign_int \l_fp_input_a_sign_int + \fi: + } +\cs_new_protected_nopar:Npn \fp_sub:Nn { \fp_sub_aux:NNn \tl_set:Nn } +\cs_new_protected_nopar:Npn \fp_gsub:Nn { \fp_sub_aux:NNn \tl_gset:Nn } +\cs_generate_variant:Nn \fp_sub:Nn { c } +\cs_generate_variant:Nn \fp_gsub:Nn { c } +\cs_new_protected_nopar:Npn \fp_sub_aux:NNn #1#2#3 + { + \group_begin: + \fp_read:N #2 + \fp_split:Nn b {#3} + \fp_standardise:NNNN + \l_fp_input_b_sign_int + \l_fp_input_b_integer_int + \l_fp_input_b_decimal_int + \l_fp_input_b_exponent_int + \tex_multiply:D \l_fp_input_b_sign_int \c_minus_one + \fp_add_core: + \fp_tmp:w #1#2 + } +\cs_new_protected_nopar:Npn \fp_mul:Nn { \fp_mul_aux:NNn \tl_set:Nn } +\cs_new_protected_nopar:Npn \fp_gmul:Nn { \fp_mul_aux:NNn \tl_gset:Nn } +\cs_generate_variant:Nn \fp_mul:Nn { c } +\cs_generate_variant:Nn \fp_gmul:Nn { c } +\cs_new_protected_nopar:Npn \fp_mul_aux:NNn #1#2#3 + { + \group_begin: + \fp_read:N #2 + \fp_split:Nn b {#3} + \fp_standardise:NNNN + \l_fp_input_b_sign_int + \l_fp_input_b_integer_int + \l_fp_input_b_decimal_int + \l_fp_input_b_exponent_int + \fp_mul_internal: + \l_fp_output_exponent_int + \int_eval:w + \l_fp_input_a_exponent_int + \l_fp_input_b_exponent_int + \scan_stop: + \fp_standardise:NNNN + \l_fp_output_sign_int + \l_fp_output_integer_int + \l_fp_output_decimal_int + \l_fp_output_exponent_int + \cs_set_protected_nopar:Npx \fp_tmp:w + { + \group_end: + #1 \exp_not:N #2 + { + \if_int_compare:w + \int_eval:w + \l_fp_input_a_sign_int * \l_fp_input_b_sign_int + < \c_zero + \if_int_compare:w + \int_eval:w + \l_fp_output_integer_int + \l_fp_output_decimal_int + = \c_zero + + + \else: + - + \fi: + \else: + + + \fi: + \int_use:N \l_fp_output_integer_int + . + \exp_after:wN \use_none:n + \int_value:w \int_eval:w + \l_fp_output_decimal_int + \c_one_thousand_million + e + \int_use:N \l_fp_output_exponent_int + } + } + \fp_tmp:w + } +\cs_new_protected_nopar:Npn \fp_mul_internal: + { + \fp_mul_split:NNNN \l_fp_input_a_decimal_int + \l_fp_mul_a_i_int \l_fp_mul_a_ii_int \l_fp_mul_a_iii_int + \fp_mul_split:NNNN \l_fp_input_b_decimal_int + \l_fp_mul_b_i_int \l_fp_mul_b_ii_int \l_fp_mul_b_iii_int + \l_fp_mul_output_int \c_zero + \tl_clear:N \l_fp_mul_output_tl + \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_iii_int + \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_ii_int + \fp_mul_product:NN \l_fp_mul_a_iii_int \l_fp_mul_b_i_int + \tex_divide:D \l_fp_mul_output_int \c_one_thousand + \fp_mul_product:NN \l_fp_input_a_integer_int \l_fp_mul_b_iii_int + \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_ii_int + \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_i_int + \fp_mul_product:NN \l_fp_mul_a_iii_int \l_fp_input_b_integer_int + \fp_mul_end_level: + \fp_mul_product:NN \l_fp_input_a_integer_int \l_fp_mul_b_ii_int + \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_i_int + \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_input_b_integer_int + \fp_mul_end_level: + \fp_mul_product:NN \l_fp_input_a_integer_int \l_fp_mul_b_i_int + \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_input_b_integer_int + \fp_mul_end_level: + \l_fp_output_decimal_int 0 \l_fp_mul_output_tl \scan_stop: + \tl_clear:N \l_fp_mul_output_tl + \fp_mul_product:NN \l_fp_input_a_integer_int \l_fp_input_b_integer_int + \fp_mul_end_level: + \l_fp_output_integer_int 0 \l_fp_mul_output_tl \scan_stop: + } +\cs_new_protected_nopar:Npn \fp_mul_split:NNNN #1#2#3#4 + { + \tex_advance:D #1 \c_one_thousand_million + \cs_set_protected_nopar:Npn \fp_mul_split_aux:w + ##1##2##3##4##5##6##7##8##9 \q_stop { + #2 ##2##3##4 \scan_stop: + #3 ##5##6##7 \scan_stop: + #4 ##8##9 \scan_stop: + } + \exp_after:wN \fp_mul_split_aux:w \int_use:N #1 \q_stop + \tex_advance:D #1 -\c_one_thousand_million + } +\cs_new_protected_nopar:Npn \fp_mul_product:NN #1#2 + { + \l_fp_mul_output_int + \int_eval:w \l_fp_mul_output_int + #1 * #2 \scan_stop: + } +\cs_new_protected_nopar:Npn \fp_mul_end_level: + { + \tex_advance:D \l_fp_mul_output_int \c_one_thousand_million + \exp_after:wN \use_i:nn \exp_after:wN + \fp_mul_end_level:NNNNNNNNN \int_use:N \l_fp_mul_output_int + } +\cs_new_protected_nopar:Npn \fp_mul_end_level:NNNNNNNNN #1#2#3#4#5#6#7#8#9 + { + \tl_set:Nx \l_fp_mul_output_tl { #7#8#9 \l_fp_mul_output_tl } + \l_fp_mul_output_int #1#2#3#4#5#6 \scan_stop: + } +\cs_new_protected_nopar:Npn \fp_div:Nn { \fp_div_aux:NNn \tl_set:Nn } +\cs_new_protected_nopar:Npn \fp_gdiv:Nn { \fp_div_aux:NNn \tl_gset:Nn } +\cs_generate_variant:Nn \fp_div:Nn { c } +\cs_generate_variant:Nn \fp_gdiv:Nn { c } +\cs_new_protected_nopar:Npn \fp_div_aux:NNn #1#2#3 + { + \group_begin: + \fp_read:N #2 + \fp_split:Nn b {#3} + \fp_standardise:NNNN + \l_fp_input_b_sign_int + \l_fp_input_b_integer_int + \l_fp_input_b_decimal_int + \l_fp_input_b_exponent_int + \if_int_compare:w + \int_eval:w + \l_fp_input_b_integer_int + \l_fp_input_b_decimal_int + = \c_zero + \cs_set_protected_nopar:Npx \fp_tmp:w ##1##2 + { + \group_end: + #1 \exp_not:N #2 { \c_undefined_fp } + } + \else: + \if_int_compare:w + \int_eval:w + \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int + = \c_zero + \cs_set_protected_nopar:Npx \fp_tmp:w ##1##2 + { + \group_end: + #1 \exp_not:N #2 { \c_zero_fp } + } + \else: + \exp_after:wN \exp_after:wN \exp_after:wN \fp_div_internal: + \fi: + \fi: + \fp_tmp:w #1#2 + } +\cs_new_protected_nopar:Npn \fp_div_internal: { + \l_fp_output_integer_int \c_zero + \l_fp_output_decimal_int \c_zero + \cs_set_eq:NN \fp_div_store: \fp_div_store_integer: + \l_fp_div_offset_int \c_one_hundred_million + \fp_div_loop: + \l_fp_output_exponent_int + \int_eval:w + \l_fp_input_a_exponent_int - \l_fp_input_b_exponent_int + \scan_stop: + \fp_standardise:NNNN + \l_fp_output_sign_int + \l_fp_output_integer_int + \l_fp_output_decimal_int + \l_fp_output_exponent_int + \cs_set_protected_nopar:Npx \fp_tmp:w ##1##2 + { + \group_end: + ##1 ##2 + { + \if_int_compare:w + \int_eval:w + \l_fp_input_a_sign_int * \l_fp_input_b_sign_int + < \c_zero + \if_int_compare:w + \int_eval:w + \l_fp_output_integer_int + \l_fp_output_decimal_int + = \c_zero + + + \else: + - + \fi: + \else: + + + \fi: + \int_use:N \l_fp_output_integer_int + . + \exp_after:wN \use_none:n + \int_value:w \int_eval:w + \l_fp_output_decimal_int + \c_one_thousand_million + \int_eval_end: + e + \int_use:N \l_fp_output_exponent_int + } + } +} +\cs_new_protected_nopar:Npn \fp_div_loop: + { + \l_fp_count_int \c_zero + \fp_div_divide: + \fp_div_store: + \tex_multiply:D \l_fp_input_a_integer_int \c_ten + \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million + \exp_after:wN \fp_div_loop_step:w + \int_use:N \l_fp_input_a_decimal_int \q_stop + \if_int_compare:w + \int_eval:w \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int + > \c_zero + \if_int_compare:w \l_fp_div_offset_int > \c_zero + \exp_after:wN \exp_after:wN \exp_after:wN + \fp_div_loop: + \fi: + \fi: + } +\cs_new_protected_nopar:Npn \fp_div_divide: + { + \if_int_compare:w \l_fp_input_a_integer_int > \l_fp_input_b_integer_int + \exp_after:wN \fp_div_divide_aux: + \else: + \if_int_compare:w \l_fp_input_a_integer_int < \l_fp_input_b_integer_int + \else: + \if_int_compare:w + \l_fp_input_a_decimal_int < \l_fp_input_b_decimal_int + \else: + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \fp_div_divide_aux: + \fi: + \fi: + \fi: + } +\cs_new_protected_nopar:Npn \fp_div_divide_aux: + { + \tex_advance:D \l_fp_count_int \c_one + \tex_advance:D \l_fp_input_a_integer_int -\l_fp_input_b_integer_int + \tex_advance:D \l_fp_input_a_decimal_int -\l_fp_input_b_decimal_int + \if_int_compare:w \l_fp_input_a_decimal_int < \c_zero + \tex_advance:D \l_fp_input_a_integer_int \c_minus_one + \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million + \fi: + \fp_div_divide: + } +\cs_new_protected_nopar:Npn \fp_div_store: { } +\cs_new_protected_nopar:Npn \fp_div_store_integer: + { + \l_fp_output_integer_int \l_fp_count_int + \cs_set_eq:NN \fp_div_store: \fp_div_store_decimal: + } +\cs_new_protected_nopar:Npn \fp_div_store_decimal: + { + \l_fp_output_decimal_int + \int_eval:w + \l_fp_output_decimal_int + + \l_fp_count_int * \l_fp_div_offset_int + \int_eval_end: + \tex_divide:D \l_fp_div_offset_int \c_ten + } +\cs_new_protected_nopar:Npn \fp_div_loop_step:w #1#2#3#4#5#6#7#8#9 \q_stop + { + \l_fp_input_a_integer_int + \int_eval:w #2 + \l_fp_input_a_integer_int \int_eval_end: + \l_fp_input_a_decimal_int #3#4#5#6#7#8#9 0 \scan_stop: + } +\cs_new_protected_nopar:Npn \fp_add:NNNNNNNNN #1#2#3#4#5#6#7#8#9 + { + #7 \int_eval:w #1 + #4 \int_eval_end: + #8 \int_eval:w #2 + #5 \int_eval_end: + #9 \int_eval:w #3 + #6 \int_eval_end: + \if_int_compare:w #9 < \c_one_thousand_million + \else: + \tex_advance:D #8 \c_one + \tex_advance:D #9 -\c_one_thousand_million + \fi: + \if_int_compare:w #8 < \c_one_thousand_million + \else: + \tex_advance:D #7 \c_one + \tex_advance:D #8 -\c_one_thousand_million + \fi: + } +\cs_new_protected_nopar:Npn \fp_sub:NNNNNNNNN #1#2#3#4#5#6#7#8#9 + { + #7 \int_eval:w #1 - #4 \int_eval_end: + #8 \int_eval:w #2 - #5 \int_eval_end: + #9 \int_eval:w #3 - #6 \int_eval_end: + \if_int_compare:w #9 < \c_zero + \tex_advance:D #8 \c_minus_one + \tex_advance:D #9 \c_one_thousand_million + \fi: + \if_int_compare:w #8 < \c_zero + \tex_advance:D #7 \c_minus_one + \tex_advance:D #8 \c_one_thousand_million + \fi: + \if_int_compare:w #7 < \c_zero + \if_int_compare:w \int_eval:w #8 + #9 = \c_zero + #7 -#7 + \else: + \tex_advance:D #7 \c_one + #8 \int_eval:w \c_one_thousand_million - #8 \int_eval_end: + #9 \int_eval:w \c_one_thousand_million - #9 \int_eval_end: + \fi: + \fi: + } +\cs_new_protected_nopar:Npn \fp_mul:NNNNNN #1#2#3#4#5#6 + { + \fp_mul_split:NNNN #1 + \l_fp_mul_a_i_int \l_fp_mul_a_ii_int \l_fp_mul_a_iii_int + \fp_mul_split:NNNN #2 + \l_fp_mul_a_iv_int \l_fp_mul_a_v_int \l_fp_mul_a_vi_int + \fp_mul_split:NNNN #3 + \l_fp_mul_b_i_int \l_fp_mul_b_ii_int \l_fp_mul_b_iii_int + \fp_mul_split:NNNN #4 + \l_fp_mul_b_iv_int \l_fp_mul_b_v_int \l_fp_mul_b_vi_int + \l_fp_mul_output_int \c_zero + \tl_clear:N \l_fp_mul_output_tl + \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_vi_int + \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_v_int + \fp_mul_product:NN \l_fp_mul_a_iii_int \l_fp_mul_b_iv_int + \fp_mul_product:NN \l_fp_mul_a_iv_int \l_fp_mul_b_iii_int + \fp_mul_product:NN \l_fp_mul_a_v_int \l_fp_mul_b_ii_int + \fp_mul_product:NN \l_fp_mul_a_vi_int \l_fp_mul_b_i_int + \tex_divide:D \l_fp_mul_output_int \c_one_thousand + \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_v_int + \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_iv_int + \fp_mul_product:NN \l_fp_mul_a_iii_int \l_fp_mul_b_iii_int + \fp_mul_product:NN \l_fp_mul_a_iv_int \l_fp_mul_b_ii_int + \fp_mul_product:NN \l_fp_mul_a_v_int \l_fp_mul_b_i_int + \fp_mul_end_level: + \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_iv_int + \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_iii_int + \fp_mul_product:NN \l_fp_mul_a_iii_int \l_fp_mul_b_ii_int + \fp_mul_product:NN \l_fp_mul_a_iv_int \l_fp_mul_b_i_int + \fp_mul_end_level: + \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_iii_int + \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_ii_int + \fp_mul_product:NN \l_fp_mul_a_iii_int \l_fp_mul_b_i_int + \fp_mul_end_level: + #6 0 \l_fp_mul_output_tl \scan_stop: + \tl_clear:N \l_fp_mul_output_tl + \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_ii_int + \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_i_int + \fp_mul_end_level: + \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_i_int + \fp_mul_end_level: + \fp_mul_end_level: + #5 0 \l_fp_mul_output_tl \scan_stop: + } +\cs_new_protected_nopar:Npn \fp_mul:NNNNNNNNN #1#2#3#4#5#6#7#8#9 + { + \fp_mul_split:NNNN #2 + \l_fp_mul_a_i_int \l_fp_mul_a_ii_int \l_fp_mul_a_iii_int + \fp_mul_split:NNNN #3 + \l_fp_mul_a_iv_int \l_fp_mul_a_v_int \l_fp_mul_a_vi_int + \fp_mul_split:NNNN #5 + \l_fp_mul_b_i_int \l_fp_mul_b_ii_int \l_fp_mul_b_iii_int + \fp_mul_split:NNNN #6 + \l_fp_mul_b_iv_int \l_fp_mul_b_v_int \l_fp_mul_b_vi_int + \l_fp_mul_output_int \c_zero + \tl_clear:N \l_fp_mul_output_tl + \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_vi_int + \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_v_int + \fp_mul_product:NN \l_fp_mul_a_iii_int \l_fp_mul_b_iv_int + \fp_mul_product:NN \l_fp_mul_a_iv_int \l_fp_mul_b_iii_int + \fp_mul_product:NN \l_fp_mul_a_v_int \l_fp_mul_b_ii_int + \fp_mul_product:NN \l_fp_mul_a_vi_int \l_fp_mul_b_i_int + \tex_divide:D \l_fp_mul_output_int \c_one_thousand + \fp_mul_product:NN #1 \l_fp_mul_b_vi_int + \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_v_int + \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_iv_int + \fp_mul_product:NN \l_fp_mul_a_iii_int \l_fp_mul_b_iii_int + \fp_mul_product:NN \l_fp_mul_a_iv_int \l_fp_mul_b_ii_int + \fp_mul_product:NN \l_fp_mul_a_v_int \l_fp_mul_b_i_int + \fp_mul_product:NN \l_fp_mul_a_vi_int #4 + \fp_mul_end_level: + \fp_mul_product:NN #1 \l_fp_mul_b_v_int + \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_iv_int + \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_iii_int + \fp_mul_product:NN \l_fp_mul_a_iii_int \l_fp_mul_b_ii_int + \fp_mul_product:NN \l_fp_mul_a_iv_int \l_fp_mul_b_i_int + \fp_mul_product:NN \l_fp_mul_a_v_int #4 + \fp_mul_end_level: + \fp_mul_product:NN #1 \l_fp_mul_b_iv_int + \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_iii_int + \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_ii_int + \fp_mul_product:NN \l_fp_mul_a_iii_int \l_fp_mul_b_i_int + \fp_mul_product:NN \l_fp_mul_a_iv_int #4 + \fp_mul_end_level: + #9 0 \l_fp_mul_output_tl \scan_stop: + \tl_clear:N \l_fp_mul_output_tl + \fp_mul_product:NN #1 \l_fp_mul_b_iii_int + \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_ii_int + \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_i_int + \fp_mul_product:NN \l_fp_mul_a_iii_int #4 + \fp_mul_end_level: + \fp_mul_product:NN #1 \l_fp_mul_b_ii_int + \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_i_int + \fp_mul_product:NN \l_fp_mul_a_ii_int #4 + \fp_mul_end_level: + \fp_mul_product:NN #1 \l_fp_mul_b_i_int + \fp_mul_product:NN \l_fp_mul_a_i_int #4 + \fp_mul_end_level: + #8 0 \l_fp_mul_output_tl \scan_stop: + \tl_clear:N \l_fp_mul_output_tl + \fp_mul_product:NN #1 #4 + \fp_mul_end_level: + #7 0 \l_fp_mul_output_tl \scan_stop: + } +\cs_new_protected_nopar:Npn \fp_div_integer:NNNNN #1#2#3#4#5 + { + \l_fp_tmp_int #1 + \tex_divide:D \l_fp_tmp_int #3 + \l_fp_tmp_int \int_eval:w #1 - \l_fp_tmp_int * #3 \int_eval_end: + #4 #1 + \tex_divide:D #4 #3 + #5 #2 + \tex_divide:D #5 #3 + \tex_multiply:D \l_fp_tmp_int \c_one_thousand + \tex_divide:D \l_fp_tmp_int #3 + #5 \int_eval:w #5 + \l_fp_tmp_int * \c_one_million \int_eval_end: + \if_int_compare:w #5 > \c_one_thousand_million + \tex_advance:D #4 \c_one + \tex_advance:D #5 -\c_one_thousand_million + \fi: + } +\cs_new_protected_nopar:Npn \fp_extended_normalise: + { + \fp_extended_normalise_aux_i: + \fp_extended_normalise_aux_ii: + } +\cs_new_protected_nopar:Npn \fp_extended_normalise_aux_i: + { + \if_int_compare:w \l_fp_input_a_exponent_int > \c_zero + \tex_multiply:D \l_fp_input_a_integer_int \c_ten + \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million + \exp_after:wN \fp_extended_normalise_aux_i:w + \int_use:N \l_fp_input_a_decimal_int \q_stop + \exp_after:wN \fp_extended_normalise_aux_i: + \fi: + } +\cs_new_protected_nopar:Npn \fp_extended_normalise_aux_i:w + #1#2#3#4#5#6#7#8#9 \q_stop + { + \l_fp_input_a_integer_int + \int_eval:w \l_fp_input_a_integer_int + #2 \scan_stop: + \l_fp_input_a_decimal_int #3#4#5#6#7#8#9 0 \scan_stop: + \tex_advance:D \l_fp_input_a_extended_int \c_one_thousand_million + \exp_after:wN \fp_extended_normalise_aux_ii:w + \int_use:N \l_fp_input_a_extended_int \q_stop + } +\cs_new_protected_nopar:Npn \fp_extended_normalise_aux_ii:w + #1#2#3#4#5#6#7#8#9 \q_stop + { + \l_fp_input_a_decimal_int + \int_eval:w \l_fp_input_a_decimal_int + #2 \scan_stop: + \l_fp_input_a_extended_int #3#4#5#6#7#8#9 0 \scan_stop: + \tex_advance:D \l_fp_input_a_exponent_int \c_minus_one + } +\cs_new_protected_nopar:Npn \fp_extended_normalise_aux_ii: + { + \if_int_compare:w \l_fp_input_a_exponent_int < \c_zero + \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million + \exp_after:wN \use_i:nn \exp_after:wN + \fp_extended_normalise_ii_aux:NNNNNNNNN + \int_use:N \l_fp_input_a_decimal_int + \exp_after:wN \fp_extended_normalise_aux_ii: + \fi: + } +\cs_new_protected_nopar:Npn \fp_extended_normalise_ii_aux:NNNNNNNNN + #1#2#3#4#5#6#7#8#9 + { + \if_int_compare:w \l_fp_input_a_integer_int = \c_zero + \l_fp_input_a_decimal_int #1#2#3#4#5#6#7#8 \scan_stop: + \else: + \tl_set:Nx \l_fp_tmp_tl + { + \int_use:N \l_fp_input_a_integer_int + #1#2#3#4#5#6#7#8 + } + \l_fp_input_a_integer_int \c_zero + \l_fp_input_a_decimal_int \l_fp_tmp_tl \scan_stop: + \fi: + \tex_divide:D \l_fp_input_a_extended_int \c_ten + \tl_set:Nx \l_fp_tmp_tl + { + #9 + \int_use:N \l_fp_input_a_extended_int + } + \l_fp_input_a_extended_int \l_fp_tmp_tl \scan_stop: + \tex_advance:D \l_fp_input_a_exponent_int \c_one + } +\cs_new_protected_nopar:Npn \fp_extended_normalise_output: + { + \if_int_compare:w \l_fp_output_integer_int > \c_nine + \tex_advance:D \l_fp_output_integer_int \c_one_thousand_million + \exp_after:wN \use_i:nn \exp_after:wN + \fp_extended_normalise_output_aux_i:NNNNNNNNN + \int_use:N \l_fp_output_integer_int + \exp_after:wN \fp_extended_normalise_output: + \fi: + } +\cs_new_protected_nopar:Npn \fp_extended_normalise_output_aux_i:NNNNNNNNN + #1#2#3#4#5#6#7#8#9 + { + \l_fp_output_integer_int #1#2#3#4#5#6#7#8 \scan_stop: + \tex_advance:D \l_fp_output_decimal_int \c_one_thousand_million + \tl_set:Nx \l_fp_tmp_tl + { + #9 + \exp_after:wN \use_none:n + \int_use:N \l_fp_output_decimal_int + } + \exp_after:wN \fp_extended_normalise_output_aux_ii:NNNNNNNNN + \l_fp_tmp_tl + } +\cs_new_protected_nopar:Npn \fp_extended_normalise_output_aux_ii:NNNNNNNNN + #1#2#3#4#5#6#7#8#9 + { + \l_fp_output_decimal_int #1#2#3#4#5#6#7#8#9 \scan_stop: + \fp_extended_normalise_output_aux:N + } +\cs_new_protected_nopar:Npn \fp_extended_normalise_output_aux:N #1 + { + \tex_advance:D \l_fp_output_extended_int \c_one_thousand_million + \tex_divide:D \l_fp_output_extended_int \c_ten + \tl_set:Nx \l_fp_tmp_tl + { + #1 + \exp_after:wN \use_none:n + \int_use:N \l_fp_output_extended_int + } + \l_fp_output_extended_int \l_fp_tmp_tl \scan_stop: + \tex_advance:D \l_fp_output_exponent_int \c_one + } +\cs_new_protected_nopar:Npn \fp_trig_normalise: + { + \if_int_compare:w \l_fp_input_a_exponent_int < \c_ten + \l_fp_input_a_extended_int \c_zero + \fp_extended_normalise: + \fp_trig_normalise_aux: + \if_int_compare:w \l_fp_input_a_integer_int < \c_zero + \l_fp_input_a_sign_int -\l_fp_input_a_sign_int + \l_fp_input_a_integer_int -\l_fp_input_a_integer_int + \fi: + \exp_after:wN \fp_trig_octant: + \else: + \l_fp_input_a_sign_int \c_one + \l_fp_output_integer_int \c_zero + \l_fp_output_decimal_int \c_zero + \l_fp_output_exponent_int \c_zero + \exp_after:wN \fp_trig_overflow_msg: + \fi: + } +\cs_new_protected_nopar:Npn \fp_trig_normalise_aux: + { + \if_int_compare:w \l_fp_input_a_integer_int > \c_three + \fp_trig_sub:NNN + \c_six \c_fp_two_pi_decimal_int \c_fp_two_pi_extended_int + \exp_after:wN \fp_trig_normalise_aux: + \else: + \if_int_compare:w \l_fp_input_a_integer_int > \c_two + \if_int_compare:w \l_fp_input_a_decimal_int > \c_fp_pi_decimal_int + \fp_trig_sub:NNN + \c_six \c_fp_two_pi_decimal_int \c_fp_two_pi_extended_int + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \fp_trig_normalise_aux: + \fi: + \fi: + \fi: + } +\cs_new_protected_nopar:Npn \fp_trig_sub:NNN #1#2#3 + { + \l_fp_input_a_integer_int + \int_eval:w \l_fp_input_a_integer_int - #1 \int_eval_end: + \l_fp_input_a_decimal_int + \int_eval:w \l_fp_input_a_decimal_int - #2 \int_eval_end: + \l_fp_input_a_extended_int + \int_eval:w \l_fp_input_a_extended_int - #3 \int_eval_end: + \if_int_compare:w \l_fp_input_a_extended_int < \c_zero + \tex_advance:D \l_fp_input_a_decimal_int \c_minus_one + \tex_advance:D \l_fp_input_a_extended_int \c_one_thousand_million + \fi: + \if_int_compare:w \l_fp_input_a_decimal_int < \c_zero + \tex_advance:D \l_fp_input_a_integer_int \c_minus_one + \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million + \fi: + \if_int_compare:w \l_fp_input_a_integer_int < \c_zero + \l_fp_input_a_sign_int -\l_fp_input_a_sign_int + \if_int_compare:w + \int_eval:w + \l_fp_input_a_decimal_int + \l_fp_input_a_extended_int + = \c_zero + \l_fp_input_a_integer_int -\l_fp_input_a_integer_int + \else: + \l_fp_input_a_integer_int + \int_eval:w + - \l_fp_input_a_integer_int - \c_one + \int_eval_end: + \l_fp_input_a_decimal_int + \int_eval:w + \c_one_thousand_million - \l_fp_input_a_decimal_int + \int_eval_end: + \l_fp_input_a_extended_int + \int_eval:w + \c_one_thousand_million - \l_fp_input_a_extended_int + \int_eval_end: + \fi: + \fi: + } +\cs_new_protected_nopar:Npn \fp_trig_octant: + { + \l_fp_trig_octant_int \c_one + \fp_trig_octant_aux: + \if_int_compare:w \l_fp_input_a_decimal_int < \c_ten + \l_fp_input_a_decimal_int \c_zero + \l_fp_input_a_extended_int \c_zero + \fi: + \if_int_odd:w \l_fp_trig_octant_int + \else: + \fp_sub:NNNNNNNNN + \c_zero \c_fp_pi_by_four_decimal_int \c_fp_pi_by_four_extended_int + \l_fp_input_a_integer_int \l_fp_input_a_decimal_int + \l_fp_input_a_extended_int + \l_fp_input_a_integer_int \l_fp_input_a_decimal_int + \l_fp_input_a_extended_int + \fi: + } +\cs_new_protected_nopar:Npn \fp_trig_octant_aux: + { + \if_int_compare:w \l_fp_input_a_integer_int > \c_zero + \fp_sub:NNNNNNNNN + \l_fp_input_a_integer_int \l_fp_input_a_decimal_int + \l_fp_input_a_extended_int + \c_zero \c_fp_pi_by_four_decimal_int \c_fp_pi_by_four_extended_int + \l_fp_input_a_integer_int \l_fp_input_a_decimal_int + \l_fp_input_a_extended_int + \tex_advance:D \l_fp_trig_octant_int \c_one + \exp_after:wN \fp_trig_octant_aux: + \else: + \if_int_compare:w + \l_fp_input_a_decimal_int > \c_fp_pi_by_four_decimal_int + \fp_sub:NNNNNNNNN + \l_fp_input_a_integer_int \l_fp_input_a_decimal_int + \l_fp_input_a_extended_int + \c_zero \c_fp_pi_by_four_decimal_int + \c_fp_pi_by_four_extended_int + \l_fp_input_a_integer_int \l_fp_input_a_decimal_int + \l_fp_input_a_extended_int + \tex_advance:D \l_fp_trig_octant_int \c_one + \exp_after:wN \exp_after:wN \exp_after:wN + \fp_trig_octant_aux: + \fi: + \fi: + } +\cs_new_protected_nopar:Npn \fp_sin:Nn { \fp_sin_aux:NNn \tl_set:Nn } +\cs_new_protected_nopar:Npn \fp_gsin:Nn { \fp_sin_aux:NNn \tl_gset:Nn } +\cs_generate_variant:Nn \fp_sin:Nn { c } +\cs_generate_variant:Nn \fp_gsin:Nn { c } +\cs_new_protected_nopar:Npn \fp_sin_aux:NNn #1#2#3 + { + \group_begin: + \fp_split:Nn a {#3} + \fp_standardise:NNNN + \l_fp_input_a_sign_int + \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int + \l_fp_input_a_exponent_int + \tl_set:Nx \l_fp_arg_tl + { + \if_int_compare:w \l_fp_input_a_sign_int < \c_zero + - + \else: + + + \fi: + \int_use:N \l_fp_input_a_integer_int + . + \exp_after:wN \use_none:n + \int_value:w \int_eval:w + \l_fp_input_a_decimal_int + \c_one_thousand_million + e + \int_use:N \l_fp_input_a_exponent_int + } + \if_int_compare:w \l_fp_input_a_exponent_int < -\c_five + \cs_set_protected_nopar:Npx \fp_tmp:w + { + \group_end: + #1 \exp_not:N #2 { \l_fp_arg_tl } + } + \else: + \if_cs_exist:w + c_fp_sin ( \l_fp_arg_tl ) _fp + \cs_end: + \else: + \exp_after:wN \exp_after:wN \exp_after:wN + \fp_sin_aux_i: + \fi: + \cs_set_protected_nopar:Npx \fp_tmp:w + { + \group_end: + #1 \exp_not:N #2 + { \use:c { c_fp_sin ( \l_fp_arg_tl ) _fp } } + } + \fi: + \fp_tmp:w + } +\cs_new_protected_nopar:Npn \fp_sin_aux_i: + { + \fp_trig_normalise: + \fp_sin_aux_ii: + \if_int_compare:w \l_fp_output_integer_int = \c_one + \l_fp_output_exponent_int \c_zero + \else: + \l_fp_output_integer_int \l_fp_output_decimal_int + \l_fp_output_decimal_int \l_fp_output_extended_int + \l_fp_output_exponent_int -\c_nine + \fi: + \fp_standardise:NNNN + \l_fp_input_a_sign_int + \l_fp_output_integer_int + \l_fp_output_decimal_int + \l_fp_output_exponent_int + \tl_new:c { c_fp_sin ( \l_fp_arg_tl ) _fp } + \tl_gset:cx { c_fp_sin ( \l_fp_arg_tl ) _fp } + { + \if_int_compare:w \l_fp_input_a_sign_int > \c_zero + + + \else: + - + \fi: + \int_use:N \l_fp_output_integer_int + . + \exp_after:wN \use_none:n + \int_value:w \int_eval:w + \l_fp_output_decimal_int + \c_one_thousand_million + e + \int_use:N \l_fp_output_exponent_int + } + } +\cs_new_protected_nopar:Npn \fp_sin_aux_ii: + { + \if_case:w \l_fp_trig_octant_int + \or: + \exp_after:wN \fp_trig_calc_sin: + \or: + \exp_after:wN \fp_trig_calc_cos: + \or: + \exp_after:wN \fp_trig_calc_cos: + \or: + \exp_after:wN \fp_trig_calc_sin: + \fi: + } +\cs_new_protected_nopar:Npn \fp_cos:Nn { \fp_cos_aux:NNn \tl_set:Nn } +\cs_new_protected_nopar:Npn \fp_gcos:Nn { \fp_cos_aux:NNn \tl_gset:Nn } +\cs_generate_variant:Nn \fp_cos:Nn { c } +\cs_generate_variant:Nn \fp_gcos:Nn { c } +\cs_new_protected_nopar:Npn \fp_cos_aux:NNn #1#2#3 + { + \group_begin: + \fp_split:Nn a {#3} + \fp_standardise:NNNN + \l_fp_input_a_sign_int + \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int + \l_fp_input_a_exponent_int + \tl_set:Nx \l_fp_arg_tl + { + \if_int_compare:w \l_fp_input_a_sign_int < \c_zero + - + \else: + + + \fi: + \int_use:N \l_fp_input_a_integer_int + . + \exp_after:wN \use_none:n + \int_value:w \int_eval:w + \l_fp_input_a_decimal_int + \c_one_thousand_million + e + \int_use:N \l_fp_input_a_exponent_int + } + \if_cs_exist:w c_fp_cos ( \l_fp_arg_tl ) _fp \cs_end: + \else: + \exp_after:wN \fp_cos_aux_i: + \fi: + \cs_set_protected_nopar:Npx \fp_tmp:w + { + \group_end: + #1 \exp_not:N #2 + { \use:c { c_fp_cos ( \l_fp_arg_tl ) _fp } } + } + \fp_tmp:w + } +\cs_new_protected_nopar:Npn \fp_cos_aux_i: + { + \fp_trig_normalise: + \fp_cos_aux_ii: + \if_int_compare:w \l_fp_output_integer_int = \c_one + \l_fp_output_exponent_int \c_zero + \else: + \l_fp_output_integer_int \l_fp_output_decimal_int + \l_fp_output_decimal_int \l_fp_output_extended_int + \l_fp_output_exponent_int -\c_nine + \fi: + \fp_standardise:NNNN + \l_fp_input_a_sign_int + \l_fp_output_integer_int + \l_fp_output_decimal_int + \l_fp_output_exponent_int + \tl_new:c { c_fp_cos ( \l_fp_arg_tl ) _fp } + \tl_gset:cx { c_fp_cos ( \l_fp_arg_tl ) _fp } + { + \if_int_compare:w \l_fp_input_a_sign_int > \c_zero + + + \else: + - + \fi: + \int_use:N \l_fp_output_integer_int + . + \exp_after:wN \use_none:n + \int_value:w \int_eval:w + \l_fp_output_decimal_int + \c_one_thousand_million + e + \int_use:N \l_fp_output_exponent_int + } + } +\cs_new_protected_nopar:Npn \fp_cos_aux_ii: + { + \if_case:w \l_fp_trig_octant_int + \or: + \exp_after:wN \fp_trig_calc_cos: + \or: + \exp_after:wN \fp_trig_calc_sin: + \or: + \exp_after:wN \fp_trig_calc_sin: + \or: + \exp_after:wN \fp_trig_calc_cos: + \fi: + \if_int_compare:w \l_fp_input_a_sign_int > \c_zero + \if_int_compare:w \l_fp_trig_octant_int > \c_two + \l_fp_input_a_sign_int \c_minus_one + \fi: + \else: + \if_int_compare:w \l_fp_trig_octant_int > \c_two + \else: + \l_fp_input_a_sign_int \c_one + \fi: + \fi: + } +\cs_new_protected_nopar:Npn \fp_trig_calc_cos: + { + \if_int_compare:w \l_fp_input_a_decimal_int = \c_zero + \l_fp_output_integer_int \c_one + \l_fp_output_decimal_int \c_zero + \else: + \l_fp_trig_sign_int \c_minus_one + \fp_mul:NNNNNN + \l_fp_input_a_decimal_int \l_fp_input_a_extended_int + \l_fp_input_a_decimal_int \l_fp_input_a_extended_int + \l_fp_trig_decimal_int \l_fp_trig_extended_int + \fp_div_integer:NNNNN + \l_fp_trig_decimal_int \l_fp_trig_extended_int + \c_two + \l_fp_trig_decimal_int \l_fp_trig_extended_int + \l_fp_count_int \c_three + \if_int_compare:w \l_fp_trig_extended_int = \c_zero + \if_int_compare:w \l_fp_trig_decimal_int = \c_zero + \l_fp_output_integer_int \c_one + \l_fp_output_decimal_int \c_zero + \l_fp_output_extended_int \c_zero + \else: + \l_fp_output_integer_int \c_zero + \l_fp_output_decimal_int \c_one_thousand_million + \l_fp_output_extended_int \c_zero + \fi: + \else: + \l_fp_output_integer_int \c_zero + \l_fp_output_decimal_int 999999999 \scan_stop: + \l_fp_output_extended_int \c_one_thousand_million + \fi: + \tex_advance:D \l_fp_output_extended_int -\l_fp_trig_extended_int + \tex_advance:D \l_fp_output_decimal_int -\l_fp_trig_decimal_int + \exp_after:wN \fp_trig_calc_Taylor: + \fi: + } +\cs_new_protected_nopar:Npn \fp_trig_calc_sin: + { + \l_fp_output_integer_int \c_zero + \if_int_compare:w \l_fp_input_a_decimal_int = \c_zero + \l_fp_output_decimal_int \c_zero + \else: + \l_fp_output_decimal_int \l_fp_input_a_decimal_int + \l_fp_output_extended_int \l_fp_input_a_extended_int + \l_fp_trig_sign_int \c_one + \l_fp_trig_decimal_int \l_fp_input_a_decimal_int + \l_fp_trig_extended_int \l_fp_input_a_extended_int + \l_fp_count_int \c_two + \exp_after:wN \fp_trig_calc_Taylor: + \fi: + } +\cs_new_protected_nopar:Npn \fp_trig_calc_Taylor: + { + \l_fp_trig_sign_int -\l_fp_trig_sign_int + \fp_mul:NNNNNN + \l_fp_trig_decimal_int \l_fp_trig_extended_int + \l_fp_input_a_decimal_int \l_fp_input_a_extended_int + \l_fp_trig_decimal_int \l_fp_trig_extended_int + \fp_mul:NNNNNN + \l_fp_trig_decimal_int \l_fp_trig_extended_int + \l_fp_input_a_decimal_int \l_fp_input_a_extended_int + \l_fp_trig_decimal_int \l_fp_trig_extended_int + \fp_div_integer:NNNNN + \l_fp_trig_decimal_int \l_fp_trig_extended_int + \l_fp_count_int + \l_fp_trig_decimal_int \l_fp_trig_extended_int + \tex_advance:D \l_fp_count_int \c_one + \fp_div_integer:NNNNN + \l_fp_trig_decimal_int \l_fp_trig_extended_int + \l_fp_count_int + \l_fp_trig_decimal_int \l_fp_trig_extended_int + \tex_advance:D \l_fp_count_int \c_one + \if_int_compare:w \l_fp_trig_decimal_int > \c_zero + \if_int_compare:w \l_fp_trig_sign_int > \c_zero + \tex_advance:D \l_fp_output_decimal_int \l_fp_trig_decimal_int + \tex_advance:D \l_fp_output_extended_int + \l_fp_trig_extended_int + \if_int_compare:w \l_fp_output_extended_int < \c_one_thousand_million + \else: + \tex_advance:D \l_fp_output_decimal_int \c_one + \tex_advance:D \l_fp_output_extended_int + -\c_one_thousand_million + \fi: + \if_int_compare:w \l_fp_output_decimal_int < \c_one_thousand_million + \else: + \tex_advance:D \l_fp_output_integer_int \c_one + \tex_advance:D \l_fp_output_decimal_int + -\c_one_thousand_million + \fi: + \else: + \tex_advance:D \l_fp_output_decimal_int -\l_fp_trig_decimal_int + \tex_advance:D \l_fp_output_extended_int + -\l_fp_input_a_extended_int + \if_int_compare:w \l_fp_output_extended_int < \c_zero + \tex_advance:D \l_fp_output_decimal_int \c_minus_one + \tex_advance:D \l_fp_output_extended_int \c_one_thousand_million + \fi: + \if_int_compare:w \l_fp_output_decimal_int < \c_zero + \tex_advance:D \l_fp_output_integer_int \c_minus_one + \tex_advance:D \l_fp_output_decimal_int \c_one_thousand_million + \fi: + \fi: + \exp_after:wN \fp_trig_calc_Taylor: + \fi: + } +\cs_new_protected_nopar:Npn \fp_tan:Nn { \fp_tan_aux:NNn \tl_set:Nn } +\cs_new_protected_nopar:Npn \fp_gtan:Nn { \fp_tan_aux:NNn \tl_gset:Nn } +\cs_generate_variant:Nn \fp_tan:Nn { c } +\cs_generate_variant:Nn \fp_gtan:Nn { c } +\cs_new_protected_nopar:Npn \fp_tan_aux:NNn #1#2#3 + { + \group_begin: + \fp_split:Nn a {#3} + \fp_standardise:NNNN + \l_fp_input_a_sign_int + \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int + \l_fp_input_a_exponent_int + \tl_set:Nx \l_fp_arg_tl + { + \if_int_compare:w \l_fp_input_a_sign_int < \c_zero + - + \else: + + + \fi: + \int_use:N \l_fp_input_a_integer_int + . + \exp_after:wN \use_none:n + \int_value:w \int_eval:w + \l_fp_input_a_decimal_int + \c_one_thousand_million + e + \int_use:N \l_fp_input_a_exponent_int + } + \if_int_compare:w \l_fp_input_a_exponent_int < -\c_five + \cs_set_protected_nopar:Npx \fp_tmp:w + { + \group_end: + #1 \exp_not:N #2 { \l_fp_arg_tl } + } + \else: + \if_cs_exist:w + c_fp_tan ( \l_fp_arg_tl ) _fp + \cs_end: + \else: + \exp_after:wN \exp_after:wN \exp_after:wN + \fp_tan_aux_i: + \fi: + \cs_set_protected_nopar:Npx \fp_tmp:w + { + \group_end: + #1 \exp_not:N #2 + { \use:c { c_fp_tan ( \l_fp_arg_tl ) _fp } } + } + \fi: + \fp_tmp:w + } +\cs_new_protected_nopar:Npn \fp_tan_aux_i: + { + \if_int_compare:w \l_fp_input_a_exponent_int < \c_ten + \exp_after:wN \fp_tan_aux_ii: + \else: + \cs_new_eq:cN { c_fp_tan ( \l_fp_arg_tl ) _fp } + \c_zero_fp + \exp_after:wN \fp_trig_overflow_msg: + \fi: + } +\cs_new_protected_nopar:Npn \fp_tan_aux_ii: + { + \fp_trig_normalise: + \if_int_compare:w \l_fp_input_a_sign_int > \c_zero + \if_int_compare:w \l_fp_trig_octant_int > \c_two + \l_fp_output_sign_int \c_minus_one + \else: + \l_fp_output_sign_int \c_one + \fi: + \else: + \if_int_compare:w \l_fp_trig_octant_int > \c_two + \l_fp_output_sign_int \c_one + \else: + \l_fp_output_sign_int \c_minus_one + \fi: + \fi: + \fp_cos_aux_ii: + \if_int_compare:w \l_fp_input_a_decimal_int = \c_zero + \if_int_compare:w \l_fp_input_a_integer_int = \c_zero + \cs_new_eq:cN { c_fp_tan ( \l_fp_arg_tl ) _fp } + \c_undefined_fp + \else: + \exp_after:wN \exp_after:wN \exp_after:wN + \fp_tan_aux_iii: + \fi: + \else: + \exp_after:wN \fp_tan_aux_iii: + \fi: + } +\cs_new_protected_nopar:Npn \fp_tan_aux_iii: + { + \l_fp_input_b_integer_int \l_fp_output_decimal_int + \l_fp_input_b_decimal_int \l_fp_output_extended_int + \l_fp_input_b_exponent_int -\c_nine + \fp_standardise:NNNN + \l_fp_input_b_sign_int + \l_fp_input_b_integer_int + \l_fp_input_b_decimal_int + \l_fp_input_b_exponent_int + \fp_sin_aux_ii: + \l_fp_input_a_integer_int \l_fp_output_decimal_int + \l_fp_input_a_decimal_int \l_fp_output_extended_int + \l_fp_input_a_exponent_int -\c_nine + \fp_standardise:NNNN + \l_fp_input_a_sign_int + \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int + \l_fp_input_a_exponent_int + \if_int_compare:w \l_fp_input_a_decimal_int = \c_zero + \if_int_compare:w \l_fp_input_a_integer_int = \c_zero + \cs_new_eq:cN { c_fp_tan ( \l_fp_arg_tl ) _fp } + \c_zero_fp + \else: + \exp_after:wN \exp_after:wN \exp_after:wN \fp_tan_aux_iv: + \fi: + \else: + \exp_after:wN \fp_tan_aux_iv: + \fi: + } +\cs_new_protected_nopar:Npn \fp_tan_aux_iv: + { + \l_fp_output_integer_int \c_zero + \l_fp_output_decimal_int \c_zero + \cs_set_eq:NN \fp_div_store: \fp_div_store_integer: + \l_fp_div_offset_int \c_one_hundred_million + \fp_div_loop: + \l_fp_output_exponent_int + \int_eval:w + \l_fp_input_a_exponent_int - \l_fp_input_b_exponent_int + \int_eval_end: + \fp_standardise:NNNN + \l_fp_output_sign_int + \l_fp_output_integer_int + \l_fp_output_decimal_int + \l_fp_output_exponent_int + \tl_new:c { c_fp_tan ( \l_fp_arg_tl ) _fp } + \tl_gset:cx { c_fp_tan ( \l_fp_arg_tl ) _fp } + { + \if_int_compare:w \l_fp_output_sign_int > \c_zero + + + \else: + - + \fi: + \int_use:N \l_fp_output_integer_int + . + \exp_after:wN \use_none:n + \int_value:w \int_eval:w + \l_fp_output_decimal_int + \c_one_thousand_million + e + \int_use:N \l_fp_output_exponent_int + } + } +\tl_const:cn { c_fp_exp_1_tl } { { 2 } { 718281828 } { 459045235 } { 0 } } +\tl_const:cn { c_fp_exp_2_tl } { { 7 } { 389056098 } { 930650227 } { 0 } } +\tl_const:cn { c_fp_exp_3_tl } { { 2 } { 008553692 } { 318766774 } { 1 } } +\tl_const:cn { c_fp_exp_4_tl } { { 5 } { 459815003 } { 314423908 } { 1 } } +\tl_const:cn { c_fp_exp_5_tl } { { 1 } { 484131591 } { 025766034 } { 2 } } +\tl_const:cn { c_fp_exp_6_tl } { { 4 } { 034287934 } { 927351226 } { 2 } } +\tl_const:cn { c_fp_exp_7_tl } { { 1 } { 096633158 } { 428458599 } { 3 } } +\tl_const:cn { c_fp_exp_8_tl } { { 2 } { 980957987 } { 041728275 } { 3 } } +\tl_const:cn { c_fp_exp_9_tl } { { 8 } { 103083927 } { 575384008 } { 3 } } +\tl_const:cn { c_fp_exp_10_tl } { { 2 } { 202646579 } { 480671652 } { 4 } } +\tl_const:cn { c_fp_exp_20_tl } { { 4 } { 851651954 } { 097902280 } { 8 } } +\tl_const:cn { c_fp_exp_30_tl } { { 1 } { 068647458 } { 152446215 } { 13 } } +\tl_const:cn { c_fp_exp_40_tl } { { 2 } { 353852668 } { 370199854 } { 17 } } +\tl_const:cn { c_fp_exp_50_tl } { { 5 } { 184705528 } { 587072464 } { 21 } } +\tl_const:cn { c_fp_exp_60_tl } { { 1 } { 142007389 } { 815684284 } { 26 } } +\tl_const:cn { c_fp_exp_70_tl } { { 2 } { 515438670 } { 919167006 } { 30 } } +\tl_const:cn { c_fp_exp_80_tl } { { 5 } { 540622384 } { 393510053 } { 34 } } +\tl_const:cn { c_fp_exp_90_tl } { { 1 } { 220403294 } { 317840802 } { 39 } } +\tl_const:cn { c_fp_exp_100_tl } { { 2 } { 688117141 } { 816135448 } { 43 } } +\tl_const:cn { c_fp_exp_200_tl } { { 7 } { 225973768 } { 125749258 } { 86 } } +\tl_const:cn { c_fp_exp_-1_tl } { { 3 } { 678794411 } { 71442322 } { -1 } } +\tl_const:cn { c_fp_exp_-2_tl } { { 1 } { 353352832 } { 366132692 } { -1 } } +\tl_const:cn { c_fp_exp_-3_tl } { { 4 } { 978706836 } { 786394298 } { -2 } } +\tl_const:cn { c_fp_exp_-4_tl } { { 1 } { 831563888 } { 873418029 } { -2 } } +\tl_const:cn { c_fp_exp_-5_tl } { { 6 } { 737946999 } { 085467097 } { -3 } } +\tl_const:cn { c_fp_exp_-6_tl } { { 2 } { 478752176 } { 666358423 } { -3 } } +\tl_const:cn { c_fp_exp_-7_tl } { { 9 } { 118819655 } { 545162080 } { -4 } } +\tl_const:cn { c_fp_exp_-8_tl } { { 3 } { 354626279 } { 025118388 } { -4 } } +\tl_const:cn { c_fp_exp_-9_tl } { { 1 } { 234098040 } { 866795495 } { -4 } } +\tl_const:cn { c_fp_exp_-10_tl } { { 4 } { 539992976 } { 248451536 } { -5 } } +\tl_const:cn { c_fp_exp_-20_tl } { { 2 } { 061153622 } { 438557828 } { -9 } } +\tl_const:cn { c_fp_exp_-30_tl } { { 9 } { 357622968 } { 840174605 } { -14 } } +\tl_const:cn { c_fp_exp_-40_tl } { { 4 } { 248354255 } { 291588995 } { -18 } } +\tl_const:cn { c_fp_exp_-50_tl } { { 1 } { 928749847 } { 963917783 } { -22 } } +\tl_const:cn { c_fp_exp_-60_tl } { { 8 } { 756510762 } { 696520338 } { -27 } } +\tl_const:cn { c_fp_exp_-70_tl } { { 3 } { 975449735 } { 908646808 } { -31 } } +\tl_const:cn { c_fp_exp_-80_tl } { { 1 } { 804851387 } { 845415172 } { -35 } } +\tl_const:cn { c_fp_exp_-90_tl } { { 8 } { 194012623 } { 990515430 } { -40 } } +\tl_const:cn { c_fp_exp_-100_tl } { { 3 } { 720075976 } { 020835963 } { -44 } } +\tl_const:cn { c_fp_exp_-200_tl } { { 1 } { 383896526 } { 736737530 } { -87 } } +\cs_new_protected_nopar:Npn \fp_exp:Nn { \fp_exp_aux:NNn \tl_set:Nn } +\cs_new_protected_nopar:Npn \fp_gexp:Nn { \fp_exp_aux:NNn \tl_gset:Nn } +\cs_generate_variant:Nn \fp_exp:Nn { c } +\cs_generate_variant:Nn \fp_gexp:Nn { c } +\cs_new_protected_nopar:Npn \fp_exp_aux:NNn #1#2#3 + { + \group_begin: + \fp_split:Nn a {#3} + \fp_standardise:NNNN + \l_fp_input_a_sign_int + \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int + \l_fp_input_a_exponent_int + \l_fp_input_a_extended_int \c_zero + \tl_set:Nx \l_fp_arg_tl + { + \if_int_compare:w \l_fp_input_a_sign_int < \c_zero + - + \else: + + + \fi: + \int_use:N \l_fp_input_a_integer_int + . + \exp_after:wN \use_none:n + \int_value:w \int_eval:w + \l_fp_input_a_decimal_int + \c_one_thousand_million + e + \int_use:N \l_fp_input_a_exponent_int + } + \if_cs_exist:w c_fp_exp ( \l_fp_arg_tl ) _fp \cs_end: + \else: + \exp_after:wN \fp_exp_internal: + \fi: + \cs_set_protected_nopar:Npx \fp_tmp:w + { + \group_end: + #1 \exp_not:N #2 + { + \if_cs_exist:w c_fp_exp ( \l_fp_arg_tl ) _fp + \cs_end: + \use:c { c_fp_exp ( \l_fp_arg_tl ) _fp } + \else: + \c_zero_fp + \fi: + } + } + \fp_tmp:w + } +\cs_new_protected_nopar:Npn \fp_exp_internal: + { + \if_int_compare:w \l_fp_input_a_exponent_int < \c_three + \fp_extended_normalise: + \if_int_compare:w \l_fp_input_a_sign_int > \c_zero + \if_int_compare:w \l_fp_input_a_integer_int < 230 \scan_stop: + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \fp_exp_aux: + \else: + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \fp_exp_overflow_msg: + \fi: + \else: + \if_int_compare:w \l_fp_input_a_integer_int < 230 \scan_stop: + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \fp_exp_aux: + \else: + \fp_exp_const:cx { c_fp_exp ( \l_fp_arg_tl ) _fp } + { \c_zero_fp } + \fi: + \fi: + \else: + \exp_after:wN \fp_exp_overflow_msg: + \fi: + } +\cs_new_protected_nopar:Npn \fp_exp_aux: + { + \if_int_compare:w \l_fp_input_a_integer_int > \c_zero + \exp_after:wN \fp_exp_integer: + \else: + \l_fp_output_integer_int \c_one + \l_fp_output_decimal_int \c_zero + \l_fp_output_extended_int \c_zero + \l_fp_output_exponent_int \c_zero + \exp_after:wN \fp_exp_decimal: + \fi: + } +\cs_new_protected_nopar:Npn \fp_exp_integer: + { + \if_int_compare:w \l_fp_input_a_integer_int < \c_one_hundred + \l_fp_exp_integer_int \c_one + \l_fp_exp_decimal_int \c_zero + \l_fp_exp_extended_int \c_zero + \l_fp_exp_exponent_int \c_zero + \exp_after:wN \fp_exp_integer_tens: + \else: + \tl_set:Nx \l_fp_tmp_tl + { + \exp_after:wN \use_i:nnn + \int_use:N \l_fp_input_a_integer_int + } + \l_fp_input_a_integer_int + \int_eval:w + \l_fp_input_a_integer_int - \l_fp_tmp_tl 00 + \int_eval_end: + \if_int_compare:w \l_fp_input_a_sign_int < \c_zero + \if_int_compare:w \l_fp_output_integer_int > 200 \scan_stop: + \fp_exp_const:cx { c_fp_exp ( \l_fp_arg_tl ) _fp } + { \c_zero_fp } + \else: + \fp_exp_integer_const:n { - \l_fp_tmp_tl 00 } + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \fp_exp_integer_tens: + \fi: + \else: + \fp_exp_integer_const:n { \l_fp_tmp_tl 00 } + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \fp_exp_integer_tens: + \fi: + \fi: + } +\cs_new_protected_nopar:Npn \fp_exp_integer_tens: + { + \l_fp_output_integer_int \l_fp_exp_integer_int + \l_fp_output_decimal_int \l_fp_exp_decimal_int + \l_fp_output_extended_int \l_fp_exp_extended_int + \l_fp_output_exponent_int \l_fp_exp_exponent_int + \if_int_compare:w \l_fp_input_a_integer_int > \c_nine + \tl_set:Nx \l_fp_tmp_tl + { + \exp_after:wN \use_i:nn + \int_use:N \l_fp_input_a_integer_int + } + \l_fp_input_a_integer_int + \int_eval:w + \l_fp_input_a_integer_int - \l_fp_tmp_tl 0 + \int_eval_end: + \if_int_compare:w \l_fp_input_a_sign_int > \c_zero + \fp_exp_integer_const:n { \l_fp_tmp_tl 0 } + \else: + \fp_exp_integer_const:n { - \l_fp_tmp_tl 0 } + \fi: + \fp_mul:NNNNNNNNN + \l_fp_exp_integer_int \l_fp_exp_decimal_int \l_fp_exp_extended_int + \l_fp_output_integer_int \l_fp_output_decimal_int + \l_fp_output_extended_int + \l_fp_output_integer_int \l_fp_output_decimal_int + \l_fp_output_extended_int + \tex_advance:D \l_fp_output_exponent_int \l_fp_exp_exponent_int + \fp_extended_normalise_output: + \fi: + \fp_exp_integer_units: + } +\cs_new_protected_nopar:Npn \fp_exp_integer_units: + { + \if_int_compare:w \l_fp_input_a_integer_int > \c_zero + \if_int_compare:w \l_fp_input_a_sign_int > \c_zero + \fp_exp_integer_const:n { \int_use:N \l_fp_input_a_integer_int } + \else: + \fp_exp_integer_const:n + { - \int_use:N \l_fp_input_a_integer_int } + \fi: + \fp_mul:NNNNNNNNN + \l_fp_exp_integer_int \l_fp_exp_decimal_int \l_fp_exp_extended_int + \l_fp_output_integer_int \l_fp_output_decimal_int + \l_fp_output_extended_int + \l_fp_output_integer_int \l_fp_output_decimal_int + \l_fp_output_extended_int + \tex_advance:D \l_fp_output_exponent_int \l_fp_exp_exponent_int + \fp_extended_normalise_output: + \fi: + \fp_exp_decimal: + } +\cs_new_protected_nopar:Npn \fp_exp_integer_const:n #1 + { + \exp_after:wN \exp_after:wN \exp_after:wN + \fp_exp_integer_const:nnnn + \cs:w c_fp_exp_ #1 _tl \cs_end: + } +\cs_new_protected_nopar:Npn \fp_exp_integer_const:nnnn #1#2#3#4 + { + \l_fp_exp_integer_int #1 \scan_stop: + \l_fp_exp_decimal_int #2 \scan_stop: + \l_fp_exp_extended_int #3 \scan_stop: + \l_fp_exp_exponent_int #4 \scan_stop: + } +\cs_new_protected_nopar:Npn \fp_exp_decimal: + { + \if_int_compare:w \l_fp_input_a_decimal_int > \c_zero + \if_int_compare:w \l_fp_input_a_sign_int > \c_zero + \l_fp_exp_integer_int \c_one + \l_fp_exp_decimal_int \l_fp_input_a_decimal_int + \l_fp_exp_extended_int \l_fp_input_a_extended_int + \else: + \l_fp_exp_integer_int \c_zero + \if_int_compare:w \l_fp_exp_extended_int = \c_zero + \l_fp_exp_decimal_int + \int_eval:w + \c_one_thousand_million - \l_fp_input_a_decimal_int + \int_eval_end: + \l_fp_exp_extended_int \c_zero + \else: + \l_fp_exp_decimal_int + \int_eval:w + 999999999 - \l_fp_input_a_decimal_int + \scan_stop: + \l_fp_exp_extended_int + \int_eval:w + \c_one_thousand_million - \l_fp_input_a_extended_int + \int_eval_end: + \fi: + \fi: + \l_fp_input_b_sign_int \l_fp_input_a_sign_int + \l_fp_input_b_decimal_int \l_fp_input_a_decimal_int + \l_fp_input_b_extended_int \l_fp_input_a_extended_int + \l_fp_count_int \c_one + \fp_exp_Taylor: + \fp_mul:NNNNNNNNN + \l_fp_exp_integer_int \l_fp_exp_decimal_int \l_fp_exp_extended_int + \l_fp_output_integer_int \l_fp_output_decimal_int + \l_fp_output_extended_int + \l_fp_output_integer_int \l_fp_output_decimal_int + \l_fp_output_extended_int + \fi: + \if_int_compare:w \l_fp_output_extended_int < \c_five_hundred_million + \else: + \tex_advance:D \l_fp_output_decimal_int \c_one + \if_int_compare:w \l_fp_output_decimal_int < \c_one_thousand_million + \else: + \l_fp_output_decimal_int \c_zero + \tex_advance:D \l_fp_output_integer_int \c_one + \fi: + \fi: + \fp_standardise:NNNN + \l_fp_output_sign_int + \l_fp_output_integer_int + \l_fp_output_decimal_int + \l_fp_output_exponent_int + \fp_exp_const:cx { c_fp_exp ( \l_fp_arg_tl ) _fp } + { + + + \int_use:N \l_fp_output_integer_int + . + \exp_after:wN \use_none:n + \int_value:w \int_eval:w + \l_fp_output_decimal_int + \c_one_thousand_million + e + \int_use:N \l_fp_output_exponent_int + } + } +\cs_new_protected_nopar:Npn \fp_exp_Taylor: + { + \tex_advance:D \l_fp_count_int \c_one + \tex_multiply:D \l_fp_input_b_sign_int \l_fp_input_a_sign_int + \fp_mul:NNNNNN + \l_fp_input_a_decimal_int \l_fp_input_a_extended_int + \l_fp_input_b_decimal_int \l_fp_input_b_extended_int + \l_fp_input_b_decimal_int \l_fp_input_b_extended_int + \fp_div_integer:NNNNN + \l_fp_input_b_decimal_int \l_fp_input_b_extended_int + \l_fp_count_int + \l_fp_input_b_decimal_int \l_fp_input_b_extended_int + \if_int_compare:w + \int_eval:w + \l_fp_input_b_decimal_int + \l_fp_input_b_extended_int + > \c_zero + \if_int_compare:w \l_fp_input_b_sign_int > \c_zero + \tex_advance:D \l_fp_exp_decimal_int \l_fp_input_b_decimal_int + \tex_advance:D \l_fp_exp_extended_int + \l_fp_input_b_extended_int + \if_int_compare:w \l_fp_exp_extended_int < \c_one_thousand_million + \else: + \tex_advance:D \l_fp_exp_decimal_int \c_one + \tex_advance:D \l_fp_exp_extended_int + -\c_one_thousand_million + \fi: + \if_int_compare:w \l_fp_exp_decimal_int < \c_one_thousand_million + \else: + \tex_advance:D \l_fp_exp_integer_int \c_one + \tex_advance:D \l_fp_exp_decimal_int + -\c_one_thousand_million + \fi: + \else: + \tex_advance:D \l_fp_exp_decimal_int -\l_fp_input_b_decimal_int + \tex_advance:D \l_fp_exp_extended_int + -\l_fp_input_a_extended_int + \if_int_compare:w \l_fp_exp_extended_int < \c_zero + \tex_advance:D \l_fp_exp_decimal_int \c_minus_one + \tex_advance:D \l_fp_exp_extended_int \c_one_thousand_million + \fi: + \if_int_compare:w \l_fp_exp_decimal_int < \c_zero + \tex_advance:D \l_fp_exp_integer_int \c_minus_one + \tex_advance:D \l_fp_exp_decimal_int \c_one_thousand_million + \fi: + \fi: + \exp_after:wN \fp_exp_Taylor: + \fi: + } +\cs_new_protected_nopar:Npn \fp_exp_const:Nx #1#2 + { + \tl_new:N #1 + \tl_gset:Nx #1 {#2} + } +\cs_generate_variant:Nn \fp_exp_const:Nx { c } +\tl_const:cn { c_fp_ln_10_1_tl } { { 2 } { 302585092 } { 994045684 } { 0 } } +\tl_const:cn { c_fp_ln_10_2_tl } { { 4 } { 605170185 } { 988091368 } { 0 } } +\tl_const:cn { c_fp_ln_10_3_tl } { { 6 } { 907755278 } { 982137052 } { 0 } } +\tl_const:cn { c_fp_ln_10_4_tl } { { 9 } { 210340371 } { 976182736 } { 0 } } +\tl_const:cn { c_fp_ln_10_5_tl } { { 1 } { 151292546 } { 497022842 } { 1 } } +\tl_const:cn { c_fp_ln_10_6_tl } { { 1 } { 381551055 } { 796427410 } { 1 } } +\tl_const:cn { c_fp_ln_10_7_tl } { { 1 } { 611809565 } { 095831979 } { 1 } } +\tl_const:cn { c_fp_ln_10_8_tl } { { 1 } { 842068074 } { 395226547 } { 1 } } +\tl_const:cn { c_fp_ln_10_9_tl } { { 2 } { 072326583 } { 694641116 } { 1 } } +\tl_const:cn { c_fp_ln_2_1_tl } { { 0 } { 693147180 } { 559945309 } { 0 } } +\tl_const:cn { c_fp_ln_2_2_tl } { { 1 } { 386294361 } { 119890618 } { 0 } } +\tl_const:cn { c_fp_ln_2_3_tl } { { 2 } { 079441541 } { 679835928 } { 0 } } +\cs_new_protected_nopar:Npn \fp_ln:Nn { \fp_ln_aux:NNn \tl_set:Nn } +\cs_new_protected_nopar:Npn \fp_gln:Nn { \fp_ln_aux:NNn \tl_gset:Nn } +\cs_generate_variant:Nn \fp_ln:Nn { c } +\cs_generate_variant:Nn \fp_gln:Nn { c } +\cs_new_protected_nopar:Npn \fp_ln_aux:NNn #1#2#3 + { + \group_begin: + \fp_split:Nn a {#3} + \fp_standardise:NNNN + \l_fp_input_a_sign_int + \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int + \l_fp_input_a_exponent_int + \if_int_compare:w \l_fp_input_a_sign_int > \c_zero + \if_int_compare:w + \int_eval:w + \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int + > \c_zero + \exp_after:wN \exp_after:wN \exp_after:wN \fp_ln_aux: + \else: + \cs_set_protected_nopar:Npx \fp_tmp:w ##1##2 + { + \group_end: + ##1 \exp_not:N ##2 { \c_zero_fp } + } + \exp_after:wN \exp_after:wN \exp_after:wN \fp_ln_error_msg: + \fi: + \else: + \cs_set_protected_nopar:Npx \fp_tmp:w ##1##2 + { + \group_end: + ##1 \exp_not:N ##2 { \c_zero_fp } + } + \exp_after:wN \fp_ln_error_msg: + \fi: + \fp_tmp:w #1 #2 + } +\cs_new_protected_nopar:Npn \fp_ln_aux: + { + \tl_set:Nx \l_fp_arg_tl + { + + + \int_use:N \l_fp_input_a_integer_int + . + \exp_after:wN \use_none:n + \int_value:w \int_eval:w + \l_fp_input_a_decimal_int + \c_one_thousand_million + e + \int_use:N \l_fp_input_a_exponent_int + } + \if_cs_exist:w c_fp_ln ( \l_fp_arg_tl ) _fp \cs_end: + \else: + \exp_after:wN \fp_ln_exponent: + \fi: + \cs_set_protected_nopar:Npx \fp_tmp:w ##1##2 + { + \group_end: + ##1 \exp_not:N ##2 + { \use:c { c_fp_ln ( \l_fp_arg_tl ) _fp } } + } + } +\cs_new_protected_nopar:Npn \fp_ln_exponent: + { + \fp_ln_internal: + \if_int_compare:w \l_fp_output_extended_int < \c_five_hundred_million + \else: + \tex_advance:D \l_fp_output_decimal_int \c_one + \if_int_compare:w \l_fp_output_decimal_int < \c_one_thousand_million + \else: + \l_fp_output_decimal_int \c_zero + \tex_advance:D \l_fp_output_integer_int \c_one + \fi: + \fi: + \fp_standardise:NNNN + \l_fp_output_sign_int + \l_fp_output_integer_int + \l_fp_output_decimal_int + \l_fp_output_exponent_int + \tl_const:cx { c_fp_ln ( \l_fp_arg_tl ) _fp } + { + \if_int_compare:w \l_fp_output_sign_int > \c_zero + + + \else: + - + \fi: + \int_use:N \l_fp_output_integer_int + . + \exp_after:wN \use_none:n + \int_value:w \int_eval:w + \l_fp_output_decimal_int + \c_one_thousand_million + \scan_stop: + e + \int_use:N \l_fp_output_exponent_int + } + } +\cs_new_protected_nopar:Npn \fp_ln_internal: + { + \if_int_compare:w \l_fp_input_a_exponent_int < \c_zero + \l_fp_input_a_exponent_int -\l_fp_input_a_exponent_int + \l_fp_output_sign_int \c_minus_one + \else: + \l_fp_output_sign_int \c_one + \fi: + \if_int_compare:w \l_fp_input_a_exponent_int > \c_nine + \exp_after:wN \fp_ln_exponent_tens:NN + \int_use:N \l_fp_input_a_exponent_int + \else: + \l_fp_output_integer_int \c_zero + \l_fp_output_decimal_int \c_zero + \l_fp_output_extended_int \c_zero + \l_fp_output_exponent_int \c_zero + \fi: + \fp_ln_exponent_units: + } +\cs_new_protected_nopar:Npn \fp_ln_exponent_tens:NN #1 #2 + { + \l_fp_input_a_exponent_int #2 \scan_stop: + \fp_ln_const:nn { 10 } { #1 } + \tex_advance:D \l_fp_exp_exponent_int \c_one + \l_fp_output_integer_int \l_fp_exp_integer_int + \l_fp_output_decimal_int \l_fp_exp_decimal_int + \l_fp_output_extended_int \l_fp_exp_extended_int + \l_fp_output_exponent_int \l_fp_exp_exponent_int + } +\cs_new_protected_nopar:Npn \fp_ln_exponent_units: + { + \if_int_compare:w \l_fp_input_a_exponent_int > \c_zero + \fp_ln_const:nn { 10 } { \int_use:N \l_fp_input_a_exponent_int } + \fp_ln_normalise: + \fp_add:NNNNNNNNN + \l_fp_exp_integer_int \l_fp_exp_decimal_int \l_fp_exp_extended_int + \l_fp_output_integer_int \l_fp_output_decimal_int + \l_fp_output_extended_int + \l_fp_output_integer_int \l_fp_output_decimal_int + \l_fp_output_extended_int + \fi: + \fp_ln_mantissa: + } +\cs_new_protected_nopar:Npn \fp_ln_normalise: + { + \if_int_compare:w \l_fp_exp_exponent_int < \l_fp_output_exponent_int + \tex_advance:D \l_fp_exp_decimal_int \c_one_thousand_million + \exp_after:wN \use_i:nn \exp_after:wN + \fp_ln_normalise_aux:NNNNNNNNN + \int_use:N \l_fp_exp_decimal_int + \exp_after:wN \fp_ln_normalise: + \else: + \l_fp_output_exponent_int \l_fp_exp_exponent_int + \fi: + } +\cs_new_protected_nopar:Npn \fp_ln_normalise_aux:NNNNNNNNN #1#2#3#4#5#6#7#8#9 + { + \if_int_compare:w \l_fp_exp_integer_int = \c_zero + \l_fp_exp_decimal_int #1#2#3#4#5#6#7#8 \scan_stop: + \else: + \tl_set:Nx \l_fp_tmp_tl + { + \int_use:N \l_fp_exp_integer_int + #1#2#3#4#5#6#7#8 + } + \l_fp_exp_integer_int \c_zero + \l_fp_exp_decimal_int \l_fp_tmp_tl \scan_stop: + \fi: + \tex_divide:D \l_fp_exp_extended_int \c_ten + \tl_set:Nx \l_fp_tmp_tl + { + #9 + \int_use:N \l_fp_exp_extended_int + } + \l_fp_exp_extended_int \l_fp_tmp_tl \scan_stop: + \tex_advance:D \l_fp_exp_exponent_int \c_one + } +\cs_new_protected_nopar:Npn \fp_ln_mantissa: + { + \l_fp_count_int \c_zero + \l_fp_input_a_extended_int \c_zero + \fp_ln_mantissa_aux: + \if_int_compare:w \l_fp_count_int > \c_zero + \fp_ln_const:nn { 2 } { \int_use:N \l_fp_count_int } + \fp_ln_normalise: + \if_int_compare:w \l_fp_output_sign_int > \c_zero + \exp_after:wN \fp_add:NNNNNNNNN + \else: + \exp_after:wN \fp_sub:NNNNNNNNN + \fi: + \l_fp_output_integer_int \l_fp_output_decimal_int + \l_fp_output_extended_int + \l_fp_exp_integer_int \l_fp_exp_decimal_int \l_fp_exp_extended_int + \l_fp_output_integer_int \l_fp_output_decimal_int + \l_fp_output_extended_int + \fi: + \if_int_compare:w + \int_eval:w + \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int > \c_one + \exp_after:wN \fp_ln_Taylor: + \fi: + } +\cs_new_protected_nopar:Npn \fp_ln_mantissa_aux: + { + \if_int_compare:w \l_fp_input_a_integer_int > \c_one + \tex_advance:D \l_fp_count_int \c_one + \fp_ln_mantissa_divide_two: + \exp_after:wN \fp_ln_mantissa_aux: + \fi: + } +\cs_new_protected_nopar:Npn \fp_ln_mantissa_divide_two: + { + \if_int_odd:w \l_fp_input_a_decimal_int + \tex_advance:D \l_fp_input_a_extended_int \c_one_thousand_million + \fi: + \if_int_odd:w \l_fp_input_a_integer_int + \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million + \fi: + \tex_divide:D \l_fp_input_a_integer_int \c_two + \tex_divide:D \l_fp_input_a_decimal_int \c_two + \tex_divide:D \l_fp_input_a_extended_int \c_two + } +\cs_new_protected_nopar:Npn \fp_ln_const:nn #1#2 + { + \exp_after:wN \exp_after:wN \exp_after:wN + \fp_exp_integer_const:nnnn + \cs:w c_fp_ln_ #1 _ #2 _tl \cs_end: + } +\cs_new_protected_nopar:Npn \fp_ln_Taylor: + { + \group_begin: + \l_fp_input_a_integer_int \c_zero + \l_fp_input_a_exponent_int \c_zero + \l_fp_input_b_integer_int \c_two + \l_fp_input_b_decimal_int \l_fp_input_a_decimal_int + \l_fp_input_b_exponent_int \c_zero + \fp_div_internal: + \fp_ln_fixed: + \l_fp_input_a_integer_int \l_fp_output_integer_int + \l_fp_input_a_decimal_int \l_fp_output_decimal_int + \l_fp_input_a_extended_int \c_zero + \l_fp_input_a_exponent_int \l_fp_output_exponent_int + \l_fp_output_decimal_int \c_zero %^^A Bug? + \l_fp_output_decimal_int \l_fp_input_a_decimal_int + \l_fp_output_extended_int \l_fp_input_a_extended_int + \fp_mul:NNNNNN + \l_fp_input_a_decimal_int \l_fp_input_a_extended_int + \l_fp_input_a_decimal_int \l_fp_input_a_extended_int + \l_fp_input_b_decimal_int \l_fp_input_b_extended_int + \l_fp_count_int \c_one + \fp_ln_Taylor_aux: + \cs_set_protected_nopar:Npx \fp_tmp:w + { + \group_end: + \l_fp_exp_integer_int \c_zero + \exp_not:N \l_fp_exp_decimal_int + \int_use:N \l_fp_output_decimal_int \scan_stop: + \exp_not:N \l_fp_exp_extended_int + \int_use:N \l_fp_output_extended_int \scan_stop: + \exp_not:N \l_fp_exp_exponent_int + \int_use:N \l_fp_output_exponent_int \scan_stop: + } + \fp_tmp:w + \tex_advance:D \l_fp_exp_decimal_int \l_fp_exp_decimal_int + \if_int_compare:w \l_fp_exp_extended_int < \c_five_hundred_million + \else: + \tex_advance:D \l_fp_exp_extended_int -\c_five_hundred_million + \tex_advance:D \l_fp_exp_decimal_int \c_one + \fi: + \tex_advance:D \l_fp_exp_extended_int \l_fp_exp_extended_int + \fp_ln_normalise: + \if_int_compare:w \l_fp_output_sign_int > \c_zero + \exp_after:wN \fp_add:NNNNNNNNN + \else: + \exp_after:wN \fp_sub:NNNNNNNNN + \fi: + \l_fp_output_integer_int \l_fp_output_decimal_int + \l_fp_output_extended_int + \c_zero \l_fp_exp_decimal_int \l_fp_exp_extended_int + \l_fp_output_integer_int \l_fp_output_decimal_int + \l_fp_output_extended_int + } +\cs_new_protected_nopar:Npn \fp_ln_fixed: + { + \if_int_compare:w \l_fp_output_exponent_int < \c_zero + \tex_advance:D \l_fp_output_decimal_int \c_one_thousand_million + \exp_after:wN \use_i:nn \exp_after:wN + \fp_ln_fixed_aux:NNNNNNNNN + \int_use:N \l_fp_output_decimal_int + \exp_after:wN \fp_ln_fixed: + \fi: + } +\cs_new_protected_nopar:Npn \fp_ln_fixed_aux:NNNNNNNNN #1#2#3#4#5#6#7#8#9 + { + \if_int_compare:w \l_fp_output_integer_int = \c_zero + \l_fp_output_decimal_int #1#2#3#4#5#6#7#8 \scan_stop: + \else: + \tl_set:Nx \l_fp_tmp_tl + { + \int_use:N \l_fp_output_integer_int + #1#2#3#4#5#6#7#8 + } + \l_fp_output_integer_int \c_zero + \l_fp_output_decimal_int \l_fp_tmp_tl \scan_stop: + \fi: + \tex_advance:D \l_fp_output_exponent_int \c_one + } +\cs_new_protected_nopar:Npn \fp_ln_Taylor_aux: + { + \tex_advance:D \l_fp_count_int \c_two + \fp_mul:NNNNNN + \l_fp_input_a_decimal_int \l_fp_input_a_extended_int + \l_fp_input_b_decimal_int \l_fp_input_b_extended_int + \l_fp_input_a_decimal_int \l_fp_input_a_extended_int + \if_int_compare:w + \int_eval:w + \l_fp_input_a_decimal_int + \l_fp_input_a_extended_int + > \c_zero + \fp_div_integer:NNNNN + \l_fp_input_a_decimal_int \l_fp_input_a_extended_int + \l_fp_count_int + \l_fp_exp_decimal_int \l_fp_exp_extended_int + \tex_advance:D \l_fp_output_decimal_int \l_fp_exp_decimal_int + \tex_advance:D \l_fp_output_extended_int \l_fp_exp_extended_int + \if_int_compare:w \l_fp_output_extended_int < \c_one_thousand_million + \else: + \tex_advance:D \l_fp_output_decimal_int \c_one + \tex_advance:D \l_fp_output_extended_int + -\c_one_thousand_million + \fi: + \if_int_compare:w \l_fp_output_decimal_int < \c_one_thousand_million + \else: + \tex_advance:D \l_fp_output_integer_int \c_one + \tex_advance:D \l_fp_output_decimal_int + -\c_one_thousand_million + \fi: + \exp_after:wN \fp_ln_Taylor_aux: + \fi: + } +\cs_new_protected_nopar:Npn \fp_pow:Nn { \fp_pow_aux:NNn \tl_set:Nn } +\cs_new_protected_nopar:Npn \fp_gpow:Nn { \fp_pow_aux:NNn \tl_gset:Nn } +\cs_generate_variant:Nn \fp_pow:Nn { c } +\cs_generate_variant:Nn \fp_gpow:Nn { c } +\cs_new_protected_nopar:Npn \fp_pow_aux:NNn #1#2#3 + { + \group_begin: + \fp_read:N #2 + \l_fp_input_b_sign_int \l_fp_input_a_sign_int + \l_fp_input_b_integer_int \l_fp_input_a_integer_int + \l_fp_input_b_decimal_int \l_fp_input_a_decimal_int + \l_fp_input_b_exponent_int \l_fp_input_a_exponent_int + \fp_split:Nn a {#3} + \fp_standardise:NNNN + \l_fp_input_a_sign_int + \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int + \l_fp_input_a_exponent_int + \if_int_compare:w + \int_eval:w + \l_fp_input_b_integer_int + \l_fp_input_b_decimal_int + = \c_zero + \if_int_compare:w + \int_eval:w + \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int + = \c_zero + \cs_set_protected_nopar:Npx \fp_tmp:w ##1##2 + { + \group_end: + ##1 ##2 { \c_undefined_fp } + } + \else: + \cs_set_protected_nopar:Npx \fp_tmp:w ##1##2 + { + \group_end: + ##1 ##2 { \c_zero_fp } + } + \fi: + \else: + \if_int_compare:w + \int_eval:w + \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int + = \c_zero + \cs_set_protected_nopar:Npx \fp_tmp:w ##1##2 + { + \group_end: + ##1 ##2 { \c_one_fp } + } + \else: + \exp_after:wN \exp_after:wN \exp_after:wN + \fp_pow_aux_i: + \fi: + \fi: + \fp_tmp:w #1 #2 +} +\cs_new_protected_nopar:Npn \fp_pow_aux_i: + { + \if_int_compare:w \l_fp_input_b_sign_int > \c_zero + \tl_set:Nn \l_fp_sign_tl { + } + \exp_after:wN \fp_pow_aux_ii: + \else: + \l_fp_input_a_extended_int \c_zero + \if_int_compare:w \l_fp_input_a_exponent_int < \c_ten + \group_begin: + \fp_extended_normalise: + \if_int_compare:w + \int_eval:w + \l_fp_input_a_decimal_int + \l_fp_input_a_extended_int + = \c_zero + \group_end: + \tl_set:Nn \l_fp_sign_tl { - } + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \fp_pow_aux_ii: + \else: + \group_end: + \cs_set_protected_nopar:Npx \fp_tmp:w ##1##2 + { + \group_end: + ##1 ##2 { \c_undefined_fp } + } + \fi: + \else: + \cs_set_protected_nopar:Npx \fp_tmp:w ##1##2 + { + \group_end: + ##1 ##2 { \c_undefined_fp } + } + \fi: + \fi: + } +\cs_new_protected_nopar:Npn \fp_pow_aux_ii: + { + \if_int_compare:w \l_fp_input_a_sign_int > \c_zero + \exp_after:wN \fp_pow_aux_iv: + \else: + \if_int_compare:w \l_fp_input_a_exponent_int < \c_ten + \group_begin: + \l_fp_input_a_extended_int \c_zero + \fp_extended_normalise: + \if_int_compare:w \l_fp_input_a_decimal_int = \c_zero + \if_int_compare:w \l_fp_input_a_integer_int > \c_ten + \group_end: + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \exp_after:wN \exp_after:wN + \fp_pow_aux_iv: + \else: + \group_end: + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \fp_pow_aux_iii: + \fi: + \else: + \group_end: + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \fp_pow_aux_iv: + \fi: + \else: + \exp_after:wN \exp_after:wN \exp_after:wN + \fp_pow_aux_iv: + \fi: + \fi: + \cs_set_protected_nopar:Npx \fp_tmp:w ##1##2 + { + \group_end: + ##1 ##2 + { + \l_fp_sign_tl + \int_use:N \l_fp_output_integer_int + . + \exp_after:wN \use_none:n + \int_value:w \int_eval:w + \l_fp_output_decimal_int + \c_one_thousand_million + e + \int_use:N \l_fp_output_exponent_int + } + } + } +\cs_new_protected_nopar:Npn \fp_pow_aux_iii: + { + \l_fp_input_a_sign_int \c_one + \fp_pow_aux_iv: + \l_fp_input_a_integer_int \c_one + \l_fp_input_a_decimal_int \c_zero + \l_fp_input_a_exponent_int \c_zero + \l_fp_input_b_integer_int \l_fp_output_integer_int + \l_fp_input_b_decimal_int \l_fp_output_decimal_int + \l_fp_input_b_exponent_int \l_fp_output_exponent_int + \fp_div_internal: + } +\cs_new_protected_nopar:Npn \fp_pow_aux_iv: + { + \group_begin: + \l_fp_input_a_integer_int \l_fp_input_b_integer_int + \l_fp_input_a_decimal_int \l_fp_input_b_decimal_int + \l_fp_input_a_exponent_int \l_fp_input_b_exponent_int + \fp_ln_internal: + \cs_set_protected_nopar:Npx \fp_tmp:w + { + \group_end: + \exp_not:N \l_fp_input_b_sign_int + \int_use:N \l_fp_output_sign_int \scan_stop: + \exp_not:N \l_fp_input_b_integer_int + \int_use:N \l_fp_output_integer_int \scan_stop: + \exp_not:N \l_fp_input_b_decimal_int + \int_use:N \l_fp_output_decimal_int \scan_stop: + \exp_not:N \l_fp_input_b_extended_int + \int_use:N \l_fp_output_extended_int \scan_stop: + \exp_not:N \l_fp_input_b_exponent_int + \int_use:N \l_fp_output_exponent_int \scan_stop: + } + \fp_tmp:w + \l_fp_input_a_extended_int \c_zero + \fp_mul:NNNNNNNNN + \l_fp_input_a_integer_int \l_fp_input_a_decimal_int + \l_fp_input_a_extended_int + \l_fp_input_b_integer_int \l_fp_input_b_decimal_int + \l_fp_input_b_extended_int + \l_fp_output_integer_int \l_fp_output_decimal_int + \l_fp_output_extended_int + \l_fp_output_exponent_int + \int_eval:w + \l_fp_input_a_exponent_int + \l_fp_input_b_exponent_int + \scan_stop: + \fp_extended_normalise_output: + \tex_multiply:D \l_fp_input_a_sign_int \l_fp_input_b_sign_int + \l_fp_input_a_integer_int \l_fp_output_integer_int + \l_fp_input_a_decimal_int \l_fp_output_decimal_int + \l_fp_input_a_extended_int \l_fp_output_extended_int + \l_fp_input_a_exponent_int \l_fp_output_exponent_int + \l_fp_output_integer_int \c_zero + \l_fp_output_decimal_int \c_zero + \l_fp_output_extended_int \c_zero + \l_fp_output_exponent_int \c_zero + \cs_set_eq:NN \fp_exp_const:Nx \use_none:nn + \fp_exp_internal: + } +\prg_new_conditional:Npnn \fp_if_undefined:N #1 { p , T , F , TF } + { + \if_meaning:w #1 \c_undefined_fp + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +\prg_new_conditional:Npnn \fp_if_zero:N #1 { p , T , F , TF } + { + \if_meaning:w #1 \c_zero_fp + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +\prg_new_protected_conditional:Npnn \fp_compare:nNn #1#2#3 { T , F , TF } + { + \group_begin: + \fp_split:Nn a {#1} + \fp_standardise:NNNN + \l_fp_input_a_sign_int + \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int + \l_fp_input_a_exponent_int + \fp_split:Nn b {#3} + \fp_standardise:NNNN + \l_fp_input_b_sign_int + \l_fp_input_b_integer_int + \l_fp_input_b_decimal_int + \l_fp_input_b_exponent_int + \fp_compare_aux:N #2 + } +\prg_new_protected_conditional:Npnn \fp_compare:NNN #1#2#3 { T , F , TF } + { + \group_begin: + \fp_read:N #3 + \l_fp_input_b_sign_int \l_fp_input_a_sign_int + \l_fp_input_b_integer_int \l_fp_input_a_integer_int + \l_fp_input_b_decimal_int \l_fp_input_a_decimal_int + \l_fp_input_b_exponent_int \l_fp_input_a_exponent_int + \fp_read:N #1 + \fp_compare_aux:N #2 + } +\cs_new_protected_nopar:Npn \fp_compare_aux:N #1 + { + \cs_if_exist:cTF { fp_compare_#1: } + { \use:c { fp_compare_#1: } } + { + \group_end: + \prg_return_false: + } + } +\cs_new_protected_nopar:cpn { fp_compare_=: } + { + \if_int_compare:w \l_fp_input_a_sign_int = \l_fp_input_b_sign_int + \if_int_compare:w \l_fp_input_a_integer_int = \l_fp_input_b_integer_int + \if_int_compare:w \l_fp_input_a_decimal_int = \l_fp_input_b_decimal_int + \if_int_compare:w + \l_fp_input_a_exponent_int = \l_fp_input_b_exponent_int + \group_end: + \prg_return_true: + \else: + \group_end: + \prg_return_false: + \fi: + \else: + \group_end: + \prg_return_false: + \fi: + \else: + \group_end: + \prg_return_false: + \fi: + \else: + \group_end: + \prg_return_false: + \fi: + } +\cs_new_protected_nopar:cpn { fp_compare_>: } + { + \if_int_compare:w \int_eval:w + \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int + = \c_zero + \if_int_compare:w \int_eval:w + \l_fp_input_b_integer_int + \l_fp_input_b_decimal_int + = \c_zero + \group_end: + \prg_return_false: + \else: + \if_int_compare:w \l_fp_input_b_sign_int > \c_zero + \group_end: + \prg_return_false: + \else: + \group_end: + \prg_return_true: + \fi: + \fi: + \else: + \if_int_compare:w \int_eval:w + \l_fp_input_b_integer_int + \l_fp_input_b_decimal_int + = \c_zero + \if_int_compare:w \l_fp_input_a_sign_int > \c_zero + \group_end: + \prg_return_true: + \else: + \group_end: + \prg_return_false: + \fi: + \else: + \use:c { fp_compare_>_aux: } + \fi: + \fi: + } +\cs_new_protected_nopar:cpn { fp_compare_>_aux: } + { + \if_int_compare:w \l_fp_input_a_sign_int > \l_fp_input_b_sign_int + \group_end: + \prg_return_true: + \else: + \if_int_compare:w \l_fp_input_a_sign_int < \l_fp_input_b_sign_int + \group_end: + \prg_return_false: + \else: + \if_int_compare:w \l_fp_input_a_sign_int > \c_zero + \use:c { fp_compare_absolute_a>b: } + \else: + \use:c { fp_compare_absolute_a<b: } + \fi: + \fi: + \fi: + } +\cs_new_protected_nopar:cpn { fp_compare_absolute_a>b: } + { + \if_int_compare:w \l_fp_input_a_exponent_int > \l_fp_input_b_exponent_int + \group_end: + \prg_return_true: + \else: + \if_int_compare:w \l_fp_input_a_exponent_int < \l_fp_input_b_exponent_int + \group_end: + \prg_return_false: + \else: + \if_int_compare:w \l_fp_input_a_integer_int > \l_fp_input_b_integer_int + \group_end: + \prg_return_true: + \else: + \if_int_compare:w + \l_fp_input_a_integer_int < \l_fp_input_b_integer_int + \group_end: + \prg_return_false: + \else: + \if_int_compare:w + \l_fp_input_a_decimal_int > \l_fp_input_b_decimal_int + \group_end: + \prg_return_true: + \else: + \group_end: + \prg_return_false: + \fi: + \fi: + \fi: + \fi: + \fi: + } +\cs_new_protected_nopar:cpn { fp_compare_absolute_a<b: } + { + \if_int_compare:w \l_fp_input_b_exponent_int > \l_fp_input_a_exponent_int + \group_end: + \prg_return_true: + \else: + \if_int_compare:w \l_fp_input_b_exponent_int < \l_fp_input_a_exponent_int + \group_end: + \prg_return_false: + \else: + \if_int_compare:w \l_fp_input_b_integer_int > \l_fp_input_a_integer_int + \group_end: + \prg_return_true: + \else: + \if_int_compare:w + \l_fp_input_b_integer_int < \l_fp_input_a_integer_int + \group_end: + \prg_return_false: + \else: + \if_int_compare:w + \l_fp_input_b_decimal_int > \l_fp_input_a_decimal_int + \group_end: + \prg_return_true: + \else: + \group_end: + \prg_return_false: + \fi: + \fi: + \fi: + \fi: + \fi: + } +\cs_new_protected_nopar:cpn { fp_compare_<: } + { + \tl_set:Nx \l_fp_tmp_tl + { + \int_set:Nn \exp_not:N \l_fp_input_a_sign_int + { \int_use:N \l_fp_input_b_sign_int } + \int_set:Nn \exp_not:N \l_fp_input_a_integer_int + { \int_use:N \l_fp_input_b_integer_int } + \int_set:Nn \exp_not:N \l_fp_input_a_decimal_int + { \int_use:N \l_fp_input_b_decimal_int } + \int_set:Nn \exp_not:N \l_fp_input_a_exponent_int + { \int_use:N \l_fp_input_b_exponent_int } + \int_set:Nn \exp_not:N \l_fp_input_b_sign_int + { \int_use:N \l_fp_input_a_sign_int } + \int_set:Nn \exp_not:N \l_fp_input_b_integer_int + { \int_use:N \l_fp_input_a_integer_int } + \int_set:Nn \exp_not:N \l_fp_input_b_decimal_int + { \int_use:N \l_fp_input_a_decimal_int } + \int_set:Nn \exp_not:N \l_fp_input_b_exponent_int + { \int_use:N \l_fp_input_a_exponent_int } + } + \l_fp_tmp_tl + \use:c { fp_compare_>: } + } +\prg_new_protected_conditional:Npnn \fp_compare:n #1 { T , F , TF } + { + \group_begin: + \tl_set:Nx \l_fp_tmp_tl + { + \group_end: + \fp_compare_aux_i:w #1 \exp_not:n { == \q_nil == \q_stop } + } + \l_fp_tmp_tl + } +\cs_new_protected_nopar:Npn \fp_compare_aux_i:w #1 == #2 == #3 \q_stop + { + \quark_if_nil:nTF {#2} + { \fp_compare_aux_ii:w #1 != \q_nil != \q_stop } + { \fp_compare:nNnTF {#1} = {#2} \prg_return_true: \prg_return_false: } + } +\cs_new_protected_nopar:Npn \fp_compare_aux_ii:w #1 != #2 != #3 \q_stop + { + \quark_if_nil:nTF {#2} + { \fp_compare_aux_iii:w #1 <= \q_nil <= \q_stop } + { \fp_compare:nNnTF {#1} = {#2} \prg_return_false: \prg_return_true: } + } +\cs_new_protected_nopar:Npn \fp_compare_aux_iii:w #1 <= #2 <= #3 \q_stop + { + \quark_if_nil:nTF {#2} + { \fp_compare_aux_iv:w #1 >= \q_nil >= \q_stop } + { \fp_compare:nNnTF {#1} > {#2} \prg_return_false: \prg_return_true: } + } +\cs_new_protected_nopar:Npn \fp_compare_aux_iv:w #1 >= #2 >= #3 \q_stop + { + \quark_if_nil:nTF {#2} + { \fp_compare_aux_v:w #1 = \q_nil \q_stop } + { \fp_compare:nNnTF {#1} < {#2} \prg_return_false: \prg_return_true: } + } +\cs_new_protected_nopar:Npn \fp_compare_aux_v:w #1 = #2 = #3 \q_stop + { + \quark_if_nil:nTF {#2} + { \fp_compare_aux_vi:w #1 < \q_nil < \q_stop } + { \fp_compare:nNnTF {#1} = {#2} \prg_return_true: \prg_return_false: } + } +\cs_new_protected_nopar:Npn \fp_compare_aux_vi:w #1 < #2 < #3 \q_stop + { + \quark_if_nil:nTF {#2} + { \fp_compare_aux_vii:w #1 > \q_nil > \q_stop } + { \fp_compare:nNnTF {#1} < {#2} \prg_return_true: \prg_return_false: } + } +\cs_new_protected_nopar:Npn \fp_compare_aux_vii:w #1 > #2 > #3 \q_stop + { + \quark_if_nil:nTF {#2} + { \prg_return_false: } + { \fp_compare:nNnTF {#1} > {#2} \prg_return_true: \prg_return_false: } + } +\msg_kernel_new:nnnn { fpu } { overflow } + { Number~too~big. } + { + The~input~given~is~too~big~for~the~LaTeX~floating~point~unit. \\ + Further~errors~may~well~occur! + } +\cs_new_protected_nopar:Npn \fp_overflow_msg: + { \msg_kernel_error:nn { fpu } { overflow } } +\msg_kernel_new:nnnn { fpu } { exponent-overflow } + { Number~too~big~for~exponent~unit. } + { + The~exponent~of~the~input~given~is~too~big~for~the~floating~point~ + unit:~the~maximum~input~value~for~an~exponent~is~230. + } +\cs_new_protected_nopar:Npn \fp_exp_overflow_msg: + { \msg_kernel_error:nn { fpu } { exponent-overflow } } +\msg_kernel_new:nnnn { fpu } { logarithm-input-error } + { Invalid~input~to~ln~function. } + { Logarithms~can~only~be~calculated~for~positive~numbers. } +\cs_new_protected_nopar:Npn \fp_ln_error_msg: { + \msg_kernel_error:nn { fpu } { logarithm-input-error } +} +\msg_kernel_new:nnnn { fpu } { trigonometric-overflow } + { Number~too~big~for~trigonometry~unit. } + { + The~trigonometry~code~can~only~work~with~numbers~smaller~ + than~1000000000. + } +\cs_new_protected_nopar:Npn \fp_trig_overflow_msg: + { \msg_kernel_error:nn { fpu } { trigonometric-overflow } } +%% +%% +%% End of file `l3fp.sty'. diff --git a/Master/texmf-dist/tex/latex/l3kernel/l3int.sty b/Master/texmf-dist/tex/latex/l3kernel/l3int.sty new file mode 100644 index 00000000000..7f009832fcf --- /dev/null +++ b/Master/texmf-dist/tex/latex/l3kernel/l3int.sty @@ -0,0 +1,743 @@ +%% +%% This is file `l3int.sty', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% l3int.dtx (with options: `package') +%% +%% EXPERIMENTAL CODE +%% +%% Do not distribute this file without also distributing the +%% source files specified above. +%% +%% Do not distribute a modified version of this file. +%% +%% File: l3int.dtx Copyright (C) 1990-2011 The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +\RequirePackage{l3names} +\GetIdInfo$Id: l3int.dtx 2478 2011-06-19 21:34:23Z joseph $ + {L3 Experimental integers} +\ProvidesExplPackage + {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +\package_check_loaded_expl: +\cs_set_eq:NN \int_value:w \tex_number:D +\cs_set_eq:NN \int_eval:w \etex_numexpr:D +\cs_new_eq:NN \int_eval_end: \tex_relax:D +\cs_new_eq:NN \if_num:w \tex_ifnum:D +\cs_set_eq:NN \if_int_odd:w \tex_ifodd:D +\cs_new_eq:NN \if_case:w \tex_ifcase:D +\cs_new:Npn \int_eval:n #1 + { \int_value:w \int_eval:w #1 \int_eval_end: } +\cs_new:Npn \int_abs:n #1 + { + \int_value:w + \if_int_compare:w \int_eval:w #1 < \c_zero + - + \fi: + \int_eval:w #1 \int_eval_end: + } +\cs_new:Npn \int_max:nn #1#2 + { + \int_value:w \int_eval:w + \if_int_compare:w + \int_eval:w #1 > \int_eval:w #2 \int_eval_end: + #1 + \else: + #2 + \fi: + \int_eval_end: + } +\cs_new:Npn \int_min:nn #1#2 + { + \int_value:w \int_eval:w + \if_int_compare:w + \int_eval:w #1 < \int_eval:w #2 \int_eval_end: + #1 + \else: + #2 + \fi: + \int_eval_end: + } +\cs_new:Npn \int_div_truncate:nn #1#2 + { + \int_value:w \int_eval:w + \if_int_compare:w \int_eval:w #1 = \c_zero + 0 + \else: + ( #1 % ) + \if_int_compare:w \int_eval:w #1 < \c_zero + \if_int_compare:w \int_eval:w #2 < \c_zero + - ( #2 + % ) + \else: + + ( #2 - % ) + \fi: + \else: + \if_int_compare:w \int_eval:w #2 < \c_zero + + ( #2 + % ) + \else: + - ( #2 - % ) + \fi: + \fi: % ( ( + 1 ) / 2 ) + \fi: + / ( #2 ) + \int_eval_end: + } +\cs_new:Npn \int_div_round:nn #1#2 { \int_eval:n { ( #1 ) / ( #2 ) } } +\cs_new:Npn \int_mod:nn #1#2 + { + \int_value:w \int_eval:w + #1 - \int_div_truncate:nn {#1} {#2} * ( #2 ) + \int_eval_end: + } +\cs_new_protected_nopar:Npn \int_new:N #1 + { + \chk_if_free_cs:N #1 + \newcount #1 + } +\cs_generate_variant:Nn \int_new:N { c } +\cs_new_protected_nopar:Npn \int_const:Nn #1#2 + { + \int_compare:nNnTF {#2} > \c_minus_one + { + \int_compare:nNnTF {#2} > \c_max_register_int + { + \int_new:N #1 + \int_gset:Nn #1 {#2} + } + { + \chk_if_free_cs:N #1 + \pref_global:D \tex_mathchardef:D #1 = + \int_eval:w #2 \int_eval_end: + } + } + { + \int_new:N #1 + \int_gset:Nn #1 {#2} + } + } +\cs_generate_variant:Nn \int_const:Nn { c } +\cs_new_protected_nopar:Npn \int_zero:N #1 { #1 = \c_zero } +\cs_new_protected_nopar:Npn \int_gzero:N #1 { \pref_global:D #1 = \c_zero } +\cs_generate_variant:Nn \int_zero:N { c } +\cs_generate_variant:Nn \int_gzero:N { c } +\cs_new_protected_nopar:Npn \int_set_eq:NN #1#2 { #1 = #2 } +\cs_generate_variant:Nn \int_set_eq:NN { c } +\cs_generate_variant:Nn \int_set_eq:NN { Nc , cc } +\cs_new_protected_nopar:Npn \int_gset_eq:NN #1#2 { \pref_global:D #1 = #2 } +\cs_generate_variant:Nn \int_gset_eq:NN { c } +\cs_generate_variant:Nn \int_gset_eq:NN { Nc , cc } +\cs_new_protected_nopar:Npn \int_add:Nn #1#2 + { \tex_advance:D #1 by \int_eval:w #2 \int_eval_end: } +\cs_new_nopar:Npn \int_sub:Nn #1#2 + { \tex_advance:D #1 by - \int_eval:w #2 \int_eval_end: } +\cs_new_protected_nopar:Npn \int_gadd:Nn + { \pref_global:D \int_add:Nn } +\cs_new_protected_nopar:Npn \int_gsub:Nn + { \pref_global:D \int_sub:Nn } +\cs_generate_variant:Nn \int_add:Nn { c } +\cs_generate_variant:Nn \int_gadd:Nn { c } +\cs_generate_variant:Nn \int_sub:Nn { c } +\cs_generate_variant:Nn \int_gsub:Nn { c } +\cs_new_protected_nopar:Npn \int_incr:N #1 + { \tex_advance:D #1 \c_one } +\cs_new_protected_nopar:Npn \int_decr:N #1 + { \tex_advance:D #1 \c_minus_one } +\cs_new_protected_nopar:Npn \int_gincr:N + { \pref_global:D \int_incr:N } +\cs_new_protected_nopar:Npn \int_gdecr:N + { \pref_global:D \int_decr:N } +\cs_generate_variant:Nn \int_incr:N { c } +\cs_generate_variant:Nn \int_decr:N { c } +\cs_generate_variant:Nn \int_gincr:N { c } +\cs_generate_variant:Nn \int_gdecr:N { c } +\cs_new_protected_nopar:Npn \int_set:Nn #1#2 + { #1 ~ \int_eval:w #2\int_eval_end: } +\cs_new_protected_nopar:Npn \int_gset:Nn { \pref_global:D \int_set:Nn } +\cs_generate_variant:Nn \int_set:Nn { c } +\cs_generate_variant:Nn \int_gset:Nn { c } +\cs_new_eq:NN \int_use:N \tex_the:D +\cs_new_nopar:Npn \int_use:c #1 { \int_use:N \cs:w #1 \cs_end: } +\prg_new_conditional:Npnn \int_compare:n #1 { p , T , F , TF } + { \exp_after:wN \int_compare_aux:nw \int_value:w \int_eval:w #1 \q_stop } +\cs_new:Npn \int_compare_aux:nw #1#2 \q_stop + { + \exp_after:wN \int_compare_aux:Nw + \int_to_roman:w + \if:w #1 - + \else: + - + \fi: + #1#2 \q_mark #1#2 \q_stop + } +\cs_new:Npn \int_compare_aux:Nw #1#2#3 \q_mark + { \use:c { int_compare_ #1 \if_meaning:w = #2 = \fi: :w } } +\cs_new:cpn { int_compare_=:w } #1 = #2 \q_stop + { + \if_int_compare:w #1 = \int_eval:w #2 \int_eval_end: + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +\cs_new:cpn { int_compare_==:w } #1 == #2 \q_stop + { + \if_int_compare:w #1 = \int_eval:w #2 \int_eval_end: + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +\cs_new:cpn { int_compare_!=:w } #1 != #2 \q_stop + { + \if_int_compare:w #1 = \int_eval:w #2 \int_eval_end: + \prg_return_false: + \else: + \prg_return_true: + \fi: + } +\cs_new:cpn { int_compare_<:w } #1 < #2 \q_stop + { + \if_int_compare:w #1 < \int_eval:w #2 \int_eval_end: + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +\cs_new:cpn { int_compare_>:w } #1 > #2 \q_stop + { + \if_int_compare:w #1 > \int_eval:w #2 \int_eval_end: + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +\cs_new:cpn { int_compare_<=:w } #1 <= #2 \q_stop + { + \if_int_compare:w #1 > \int_eval:w #2 \int_eval_end: + \prg_return_false: + \else: + \prg_return_true: + \fi: + } +\cs_new:cpn { int_compare_>=:w } #1 >= #2 \q_stop + { + \if_int_compare:w #1 < \int_eval:w #2 \int_eval_end: + \prg_return_false: + \else: + \prg_return_true: + \fi: + } +\prg_new_conditional:Npnn \int_compare:nNn #1#2#3 { p , T , F , TF} + { + \if_int_compare:w \int_eval:w #1 #2 \int_eval:w #3 \int_eval_end: + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +\prg_new_conditional:Npnn \int_if_odd:n #1 { p , T , F , TF} + { + \if_int_odd:w \int_eval:w #1 \int_eval_end: + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +\prg_new_conditional:Npnn \int_if_even:n #1 { p , T , F , TF} + { + \if_int_odd:w \int_eval:w #1 \int_eval_end: + \prg_return_false: + \else: + \prg_return_true: + \fi: + } +\cs_new:Npn \int_while_do:nn #1#2 + { + \int_compare:nT {#1} + { + #2 + \int_while_do:nn {#1} {#2} + } + } +\cs_new:Npn \int_until_do:nn #1#2 + { + \int_compare:nF {#1} + { + #2 + \int_until_do:nn {#1} {#2} + } + } +\cs_new:Npn \int_do_while:nn #1#2 + { + #2 + \int_compare:nT {#1} + { \int_do_while:nNnn {#1} {#2} } + } +\cs_new:Npn \int_do_until:nn #1#2 + { + #2 + \int_compare:nF {#1} + { \int_do_until:nn {#1} {#2} } + } +\cs_new:Npn \int_while_do:nNnn #1#2#3#4 + { + \int_compare:nNnT {#1} #2 {#3} + { + #4 + \int_while_do:nNnn {#1} #2 {#3} {#4} + } + } +\cs_new:Npn \int_until_do:nNnn #1#2#3#4 + { + \int_compare:nNnF {#1} #2 {#3} + { + #4 + \int_until_do:nNnn {#1} #2 {#3} {#4} + } + } +\cs_new:Npn \int_do_while:nNnn #1#2#3#4 + { + #4 + \int_compare:nNnT {#1} #2 {#3} + { \int_do_while:nNnn {#1} #2 {#3} {#4} } + } +\cs_new:Npn \int_do_until:nNnn #1#2#3#4 + { + #4 + \int_compare:nNnF {#1} #2 {#3} + { \int_do_until:nNnn {#1} #2 {#3} {#4} } + } +\cs_new_nopar:Npn \int_to_arabic:n #1 { \int_eval:n {#1} } +\cs_new_nopar:Npn \int_to_symbols:nnn #1#2#3 + { + \int_compare:nNnTF {#1} > {#2} + { + \exp_args:Nf \int_to_symbols:nnn + { \int_div_truncate:nn { #1 - 1 } {#2} } {#2} {#3} + \exp_args:Nf \prg_case_int:nnn + { \int_eval:n { 1 + \int_mod:nn { #1 - 1 } {#2} } } + {#3} { } + } + { \exp_args:Nf \prg_case_int:nnn { \int_eval:n {#1} } {#3} { } } + } +\cs_new:Npn \int_to_alph:n #1 + { + \int_to_symbols:nnn {#1} { 26 } + { + { 1 } { a } + { 2 } { b } + { 3 } { c } + { 4 } { d } + { 5 } { e } + { 6 } { f } + { 7 } { g } + { 8 } { h } + { 9 } { i } + { 10 } { j } + { 11 } { k } + { 12 } { l } + { 13 } { m } + { 14 } { n } + { 15 } { o } + { 16 } { p } + { 17 } { q } + { 18 } { r } + { 19 } { s } + { 20 } { t } + { 21 } { u } + { 22 } { v } + { 23 } { w } + { 24 } { x } + { 25 } { y } + { 26 } { z } + } + } +\cs_new:Npn \int_to_Alph:n #1 + { + \int_to_symbols:nnn {#1} { 26 } + { + { 1 } { A } + { 2 } { B } + { 3 } { C } + { 4 } { D } + { 5 } { E } + { 6 } { F } + { 7 } { G } + { 8 } { H } + { 9 } { I } + { 10 } { J } + { 11 } { K } + { 12 } { L } + { 13 } { M } + { 14 } { N } + { 15 } { O } + { 16 } { P } + { 17 } { Q } + { 18 } { R } + { 19 } { S } + { 20 } { T } + { 21 } { U } + { 22 } { V } + { 23 } { W } + { 24 } { X } + { 25 } { Y } + { 26 } { Z } + } + } +\cs_new:Npn \int_to_base:nn #1#2 + { + \int_compare:nNnTF {#1} < \c_zero + { + - + \exp_args:Nnf \int_to_base_aux:nnn + { } { \int_eval:n { 0 - ( #1 ) } } {#2} + } + { + \exp_args:Nnf \int_to_base_aux:nnn + { } { \int_eval:n {#1} } {#2} + } +} +\cs_new:Npn \int_to_base_aux:nnn #1#2#3 { + \int_compare:nNnTF {#2} < {#3} + { + \int_to_letter:n {#2} + #1 + } + { + \exp_args:Nff \int_to_base_aux:nnn + { + \int_to_letter:n { \int_mod:nn {#2} {#3} } + #1 + } + { \int_div_truncate:nn {#2} {#3} } + {#3} + } + } +\cs_new:Npn \int_to_letter:n #1 + { + \prg_case_int:nnn { #1 - 9 } + { + { 1 } { A } + { 2 } { B } + { 3 } { C } + { 4 } { D } + { 5 } { E } + { 6 } { F } + { 7 } { G } + { 8 } { H } + { 9 } { I } + { 10 } { J } + { 11 } { K } + { 12 } { L } + { 13 } { M } + { 14 } { N } + { 15 } { O } + { 16 } { P } + { 17 } { Q } + { 18 } { R } + { 19 } { S } + { 20 } { T } + { 21 } { U } + { 22 } { V } + { 23 } { W } + { 24 } { X } + { 25 } { Y } + { 26 } { Z } + } + {#1} + } +\cs_new:Npn \int_to_binary:n #1 + { \int_to_base:nn {#1} { 2 } } +\cs_new:Npn \int_to_hexadecimal:n #1 + { \int_to_base:nn {#1} { 16 } } +\cs_new:Npn \int_to_octal:n #1 + { \int_to_base:nn {#1} { 8 } } +\cs_new_nopar:Npn \int_to_roman:n #1 + { + \exp_after:wN \int_to_roman_aux:N + \int_to_roman:w \int_eval:n {#1} Q + } +\cs_new_nopar:Npn \int_to_roman_aux:N #1 + { + \use:c { int_to_roman_ #1 :w } + \int_to_roman_aux:N + } +\cs_new_nopar:Npn \int_to_Roman:n #1 + { + \exp_after:wN \int_to_Roman_aux:N + \int_to_roman:w \int_eval:n {#1} Q + } +\cs_new_nopar:Npn \int_to_Roman_aux:N #1 + { + \use:c { int_to_Roman_ #1 :w } + \int_to_Roman_aux:N + } +\cs_new_nopar:Npn \int_to_roman_i:w { i } +\cs_new_nopar:Npn \int_to_roman_v:w { v } +\cs_new_nopar:Npn \int_to_roman_x:w { x } +\cs_new_nopar:Npn \int_to_roman_l:w { l } +\cs_new_nopar:Npn \int_to_roman_c:w { c } +\cs_new_nopar:Npn \int_to_roman_d:w { d } +\cs_new_nopar:Npn \int_to_roman_m:w { m } +\cs_new_nopar:Npn \int_to_roman_Q:w #1 { } +\cs_new_nopar:Npn \int_to_Roman_i:w { I } +\cs_new_nopar:Npn \int_to_Roman_v:w { V } +\cs_new_nopar:Npn \int_to_Roman_x:w { X } +\cs_new_nopar:Npn \int_to_Roman_l:w { L } +\cs_new_nopar:Npn \int_to_Roman_c:w { C } +\cs_new_nopar:Npn \int_to_Roman_d:w { D } +\cs_new_nopar:Npn \int_to_Roman_m:w { M } +\cs_new_nopar:Npn \int_to_Roman_Q:w #1 { } +\cs_new:Npn \int_get_sign:n #1 + { + \int_get_sign_and_digits_aux:nNNN {#1} + \c_true_bool \c_true_bool \c_false_bool + } +\cs_new:Npn \int_get_digits:n #1 + { + \int_get_sign_and_digits_aux:nNNN {#1} + \c_true_bool \c_false_bool \c_true_bool + } +\cs_new:Npn \int_get_sign_and_digits_aux:nNNN #1#2#3#4 + { + \tl_if_head_eq_charcode:fNTF {#1} - + { + \bool_if:NTF #2 + { + \int_get_sign_and_digits_aux:oNNN + { \use_none:n #1 } \c_false_bool #3#4 + } + { + \int_get_sign_and_digits_aux:oNNN + { \use_none:n #1 } \c_true_bool #3#4 + } + } + { + \tl_if_head_eq_charcode:fNTF {#1} + + { \int_get_sign_and_digits_aux:oNNN { \use_none:n #1 } #2#3#4 } + { + \bool_if:NT #3 { \bool_if:NF #2 - } + \bool_if:NT #4 {#1} + } + } + } +\cs_generate_variant:Nn \int_get_sign_and_digits_aux:nNNN { o } +\cs_new:Npn \int_from_alph:n #1 + { + \int_eval:n + { + \int_get_sign:n {#1} + \exp_args:Nf \int_from_alph_aux:n { \int_get_digits:n {#1} } + } + } +\cs_new:Npn \int_from_alph_aux:n #1 + { \int_from_alph_aux:nN { 0 } #1 \q_nil } +\cs_new:Npn \int_from_alph_aux:nN #1#2 + { + \quark_if_nil:NTF #2 + {#1} + { + \exp_args:Nf \int_from_alph_aux:nN + { \int_eval:n { #1 * 26 + \int_from_alph_aux:N #2 } } + } + } +\cs_new:Npn \int_from_alph_aux:N #1 + { \int_eval:n { `#1 - \int_compare:nNnTF { `#1 } < { 91 } { 64 } { 96 } } } +\cs_new:Npn \int_from_base:nn #1#2 + { + \int_eval:n + { + \int_get_sign:n {#1} + \exp_args:Nf \int_from_base_aux:nn + { \int_get_digits:n {#1} } {#2} + } + } +\cs_new:Npn \int_from_base_aux:nn #1#2 + { \int_from_base_aux:nnN { 0 } { #2 } #1 \q_nil } +\cs_new:Npn \int_from_base_aux:nnN #1#2#3 + { + \quark_if_nil:NTF #3 + {#1} + { + \exp_args:Nf \int_from_base_aux:nnN + { \int_eval:n { #1 * #2 + \int_from_base_aux:N #3 } } + {#2} + } + } +\cs_new:Npn \int_from_base_aux:N #1 + { + \int_compare:nNnTF { `#1 } < { 58 } + {#1} + { + \int_eval:n + { `#1 - \int_compare:nNnTF { `#1 } < { 91 } { 55 } { 87 } } + } + } +\cs_new:Npn \int_from_binary:n #1 + { \int_from_base:nn {#1} \c_two } +\cs_new:Npn \int_from_hexadecimal:n #1 + { \int_from_base:nn {#1} \c_sixteen } +\cs_new:Npn \int_from_octal:n #1 + { \int_from_base:nn {#1} \c_eight } +\int_const:cn { c_int_from_roman_i_int } { 1 } +\int_const:cn { c_int_from_roman_v_int } { 5 } +\int_const:cn { c_int_from_roman_x_int } { 10 } +\int_const:cn { c_int_from_roman_l_int } { 50 } +\int_const:cn { c_int_from_roman_c_int } { 100 } +\int_const:cn { c_int_from_roman_d_int } { 500 } +\int_const:cn { c_int_from_roman_m_int } { 1000 } +\int_const:cn { c_int_from_roman_I_int } { 1 } +\int_const:cn { c_int_from_roman_V_int } { 5 } +\int_const:cn { c_int_from_roman_X_int } { 10 } +\int_const:cn { c_int_from_roman_L_int } { 50 } +\int_const:cn { c_int_from_roman_C_int } { 100 } +\int_const:cn { c_int_from_roman_D_int } { 500 } +\int_const:cn { c_int_from_roman_M_int } { 1000 } +\cs_new_nopar:Npn \int_from_roman:n #1 + { + \tl_if_blank:nF {#1} + { + \exp_after:wN \int_from_roman_end:w + \int_value:w \int_eval:w + \int_from_roman_aux:NN #1 Q \q_stop + } + } +\cs_new_nopar:Npn \int_from_roman_aux:NN #1#2 + { + \str_if_eq:nnTF {#1} { Q } + {#1#2} + { + \str_if_eq:nnTF {#2} { Q } + { + \cs_if_exist:cF { c_int_from_roman_ #1 _int } + { \int_from_roman_clean_up:w } + + + \use:c { c_int_from_roman_ #1 _int } + #2 + } + { + \cs_if_exist:cF { c_int_from_roman_ #1 _int } + { \int_from_roman_clean_up:w } + \cs_if_exist:cF { c_int_from_roman_ #2 _int } + { \int_from_roman_clean_up:w } + \int_compare:nNnTF + { \use:c { c_int_from_roman_ #1 _int } } + < + { \use:c { c_int_from_roman_ #2 _int } } + { + + \use:c { c_int_from_roman_ #2 _int } + - \use:c { c_int_from_roman_ #1 _int } + \int_from_roman_aux:NN + } + { + + \use:c { c_int_from_roman_ #1 _int } + \int_from_roman_aux:NN #2 + } + } + } + } +\cs_new_nopar:Npn \int_from_roman_end:w #1 Q #2 \q_stop + { \tl_if_empty:nTF {#2} {#1} {#2} } +\cs_new_nopar:Npn \int_from_roman_clean_up:w #1 Q { + 0 Q -1 } +\cs_new_eq:NN \int_show:N \kernel_register_show:N +\cs_new_eq:NN \int_show:c \kernel_register_show:c +\int_const:Nn \c_one { 1 } +\int_const:Nn \c_two { 2 } +\int_const:Nn \c_three { 3 } +\int_const:Nn \c_four { 4 } +\int_const:Nn \c_five { 5 } +\int_const:Nn \c_eight { 8 } +\int_const:Nn \c_nine { 9 } +\int_const:Nn \c_ten { 10 } +\int_const:Nn \c_eleven { 11 } +\int_const:Nn \c_thirteen { 13 } +\int_const:Nn \c_fourteen { 14 } +\int_const:Nn \c_fifteen { 15 } +\int_const:Nn \c_thirty_two { 32 } +\int_const:Nn \c_two_hundred_fifty_five { 255 } +\int_const:Nn \c_two_hundred_fifty_six { 256 } +\int_const:Nn \c_one_hundred { 100 } +\int_const:Nn \c_one_thousand { 1000 } +\int_const:Nn \c_ten_thousand { 10000 } +\int_const:Nn \c_max_int { 2 147 483 647 } +\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 \g_seq_nesting_depth_int +\int_new:N \g_tl_inline_level_int +\cs_new_eq:NN \int_convert_from_base_ten:nn \int_to_base:nn +\cs_new_eq:NN \int_convert_to_symbols:nnn \int_to_symbols:nnn +\cs_new_eq:NN \int_convert_to_base_ten:nn \int_from_base:nn +\cs_new_nopar:Npn \int_to_symbol:n + { + \mode_if_math:TF + { \int_to_symbol_math:n } + { \int_to_symbol_text:n } + } +\cs_new:Npn \int_to_symbol_math:n #1 + { + \int_to_symbols:nnn {#1} { 9 } + { + { 1 } { * } + { 2 } { \dagger } + { 3 } { \ddagger } + { 4 } { \mathsection } + { 5 } { \mathparagraph } + { 6 } { \| } + { 7 } { ** } + { 8 } { \dagger \dagger } + { 9 } { \ddagger \ddagger } + } + } +\cs_new:Npn \int_to_symbol_text:n #1 + { + \int_to_symbols:nnn {#1} { 9 } + { + { 1 } { \textasteriskcentered } + { 2 } { \textdagger } + { 3 } { \textdaggerdbl } + { 4 } { \textsection } + { 5 } { \textparagraph } + { 6 } { \textbardbl } + { 7 } { \textasteriskcentered \textasteriskcentered } + { 8 } { \textdagger \textdagger } + { 9 } { \textdaggerdbl \textdaggerdbl } + } + } +%% +%% +%% End of file `l3int.sty'. diff --git a/Master/texmf-dist/tex/latex/l3kernel/l3io.sty b/Master/texmf-dist/tex/latex/l3kernel/l3io.sty new file mode 100644 index 00000000000..7239fbae288 --- /dev/null +++ b/Master/texmf-dist/tex/latex/l3kernel/l3io.sty @@ -0,0 +1,430 @@ +%% +%% This is file `l3io.sty', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% l3io.dtx (with options: `package') +%% +%% EXPERIMENTAL CODE +%% +%% Do not distribute this file without also distributing the +%% source files specified above. +%% +%% Do not distribute a modified version of this file. +%% +%% File: l3io.dtx Copyright (C) 1990-2011 The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +\RequirePackage{l3names} +\GetIdInfo$Id: l3io.dtx 2478 2011-06-19 21:34:23Z joseph $ + {L3 Experimental input-output operations} +\ProvidesExplPackage + {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +\package_check_loaded_expl: +\cs_new_eq:NN \if_eof:w \tex_ifeof:D +\cs_new_eq:NN \c_iow_term_stream \c_sixteen +\cs_new_eq:NN \c_ior_term_stream \c_sixteen +\cs_new_eq:NN \c_iow_log_stream \c_minus_one +\cs_new_eq:NN \c_ior_log_stream \c_minus_one +\tl_const:Nn \c_iow_streams_tl + { + \c_zero + \c_one + \c_two + \c_three + \c_four + \c_five + \c_six + \c_seven + \c_eight + \c_nine + \c_ten + \c_eleven + \c_twelve + \c_thirteen + \c_fourteen + \c_fifteen + } +\cs_new_eq:NN \c_ior_streams_tl \c_iow_streams_tl +\prop_new:N \g_iow_streams_prop +\prop_new:N \g_ior_streams_prop +\prop_put:Nnn \g_iow_streams_prop { 0 } { LaTeX2e~reserved } +\prop_put:Nnn \g_iow_streams_prop { 1 } { LaTeX2e~reserved } +\prop_put:Nnn \g_iow_streams_prop { 2 } { LaTeX2e~reserved } +\prop_put:Nnn \g_ior_streams_prop { 0 } { LaTeX2e~reserved } +\int_new:N \l_iow_stream_int +\cs_new_eq:NN \l_ior_stream_int \l_iow_stream_int +\cs_set_eq:NN \iow_raw_new:N \newwrite +\cs_set_eq:NN \ior_raw_new:N \newread +\cs_generate_variant:Nn \ior_raw_new:N { c } +\cs_generate_variant:Nn \iow_raw_new:N { c } +\cs_new_protected_nopar:Npn \ior_open:Nn #1#2 + { + \ior_close:N #1 + \int_set:Nn \l_ior_stream_int \c_sixteen + \tl_map_function:NN \c_ior_streams_tl \ior_alloc_read:n + \int_compare:nNnTF \l_ior_stream_int = \c_sixteen + { \msg_kernel_error:nn { ior } { streams-exhausted } } + { + \ior_stream_alloc:N #1 + \prop_gput:NVn \g_ior_streams_prop \l_ior_stream_int {#2} + \tex_openin:D #1#2 \scan_stop: + } + } +\cs_new_protected_nopar:Npn \iow_open:Nn #1#2 + { + \iow_close:N #1 + \int_set:Nn \l_iow_stream_int \c_sixteen + \tl_map_function:NN \c_iow_streams_tl \iow_alloc_write:n + \int_compare:nNnTF \l_iow_stream_int = \c_sixteen + { \msg_kernel_error:nn { iow } { streams-exhausted } } + { + \iow_stream_alloc:N #1 + \prop_gput:NVn \g_iow_streams_prop \l_iow_stream_int {#2} + \tex_immediate:D \tex_openout:D #1#2 \scan_stop: + } + } +\cs_generate_variant:Nn \ior_open:Nn { c } +\cs_generate_variant:Nn \iow_open:Nn { c } +\cs_new_protected_nopar:Npn \iow_alloc_write:n #1 + { + \prop_if_in:NnF \g_iow_streams_prop {#1} + { + \int_set:Nn \l_iow_stream_int {#1} + \tl_map_break: + } + } +\cs_new_protected_nopar:Npn \ior_alloc_read:n #1 + { + \prop_if_in:NnF \g_iow_streams_prop {#1} + { + \int_set:Nn \l_ior_stream_int {#1} + \tl_map_break: + } + } +\cs_new_protected_nopar:Npn \iow_stream_alloc:N #1 + { + \cs_if_exist:cTF { g_iow_ \int_use:N \l_iow_stream_int _stream } + { \cs_gset_eq:Nc #1 { g_iow_ \int_use:N \l_iow_stream_int _stream } } + { + \iow_stream_alloc_aux: + \int_compare:nNnT \l_iow_stream_int = \c_sixteen + { + \iow_raw_new:N \g_iow_tmp_stream + \int_set:Nn \l_iow_stream_int { \g_iow_tmp_stream } + \cs_gset_eq:cN + { g_iow_ \int_use:N \l_iow_stream_int _stream } + \g_iow_tmp_stream + } + \cs_gset_eq:Nc #1 { g_iow_ \int_use:N \l_iow_stream_int _stream } + } + } +\cs_new_protected_nopar:Npn \iow_stream_alloc_aux: + { + \int_incr:N \l_iow_stream_int + \int_compare:nNnT \l_iow_stream_int < \c_sixteen + { + \cs_if_exist:cTF { g_iow_ \int_use:N \l_iow_stream_int _stream } + { + \prop_if_in:NVT \g_iow_streams_prop \l_iow_stream_int + { \iow_stream_alloc_aux: } + } + { \iow_stream_alloc_aux: } + } + } +\cs_new_protected_nopar:Npn \ior_stream_alloc:N #1 + { + \cs_if_exist:cTF { g_ior_ \int_use:N \l_ior_stream_int _stream } + { \cs_gset_eq:Nc #1 { g_ior_ \int_use:N \l_ior_stream_int _stream } } + { + \ior_stream_alloc_aux: + \int_compare:nNnT \l_ior_stream_int = \c_sixteen + { + \ior_raw_new:N \g_ior_tmp_stream + \int_set:Nn \l_ior_stream_int { \g_ior_tmp_stream } + \cs_gset_eq:cN + { g_ior_ \int_use:N \l_iow_stream_int _stream } + \g_ior_tmp_stream + } + \cs_gset_eq:Nc #1 { g_ior_ \int_use:N \l_ior_stream_int _stream } + } + } +\cs_new_protected_nopar:Npn \ior_stream_alloc_aux: + { + \int_incr:N \l_ior_stream_int + \int_compare:nNnT \l_ior_stream_int < \c_sixteen + { + \cs_if_exist:cTF { g_ior_ \int_use:N \l_ior_stream_int _stream } + { + \prop_if_in:NVT \g_ior_streams_prop \l_ior_stream_int + { \ior_stream_alloc_aux: } + } + { \ior_stream_alloc_aux: } + } + } +\cs_new_protected_nopar:Npn \ior_close:N #1 + { + \cs_if_exist:NT #1 + { + \int_compare:nNnF #1 = \c_minus_one + { + \tex_closein:D #1 + \prop_gdel:NV \g_ior_streams_prop #1 + \cs_undefine:N #1 + } + } + } +\cs_new_protected_nopar:Npn \iow_close:N #1 + { + \cs_if_exist:NT #1 + { + \int_compare:nNnF #1 = \c_minus_one + { + \tex_immediate:D \tex_closeout:D #1 + \prop_gdel:NV \g_iow_streams_prop #1 + \cs_undefine:N #1 + } + } + } +\cs_generate_variant:Nn \ior_close:N { c } +\cs_generate_variant:Nn \iow_close:N { c } +\cs_new_protected_nopar:Npn \ior_list_streams: + { + \prop_if_empty:NTF \g_ior_streams_prop + { + \iow_term:x { No~input~streams~are~open } + \tl_show:n { } + } + { + \iow_term:x { The~following~input~streams~are~in~use: } + \tl_set:Nx \l_prop_show_tl + { \prop_map_function:NN \g_ior_streams_prop \ior_show_aux:nn } + \etex_showtokens:D \exp_after:wN \exp_after:wN \exp_after:wN + { \exp_after:wN \prop_show_aux:w \l_prop_show_tl } + } + } +\cs_new:Npn \ior_show_aux:nn #1#2 + { + \iow_newline: > \c_space_tl \c_space_tl + #1 \iow_char:N + \c_space_tl \c_space_tl => \c_space_tl \c_space_tl + \exp_not:n {#2} + } +\cs_new_protected_nopar:Npn \iow_list_streams: + { + \prop_if_empty:NTF \g_iow_streams_prop + { + \iow_term:x { No~output~streams~are~open } + \tl_show:n { } + } + { + \iow_term:x { The~following~output~streams~are~in~use: } + \tl_set:Nx \l_prop_show_tl + { \prop_map_function:NN \g_iow_streams_prop \iow_show_aux:nn } + \etex_showtokens:D \exp_after:wN \exp_after:wN \exp_after:wN + { \exp_after:wN \prop_show_aux:w \l_prop_show_tl } + } + } +\cs_new_eq:NN \iow_show_aux:nn \ior_show_aux:nn +\msg_kernel_new:nnnn { iow } { streams-exhausted } + { Output~streams~exhausted } + { + TeX~can~only~open~up~to~16~output~streams~at~one~time.\\ + All~16 are currently~in~use,~and~something~wanted~to~open + another~one. + } +\msg_kernel_new:nnnn { ior } { streams-exhausted } + { Input~streams~exhausted } + { + TeX~can~only~open~up~to~16~input~streams~at~one~time.\\ + All~16 are currently~in~use,~and~something~wanted~to~open + another~one. + } +\cs_new_eq:NN \iow_shipout_x:Nn \tex_write:D +\cs_generate_variant:Nn \iow_shipout_x:Nn { Nx } +\cs_new_protected_nopar:Npn \iow_shipout:Nn #1#2 + { \iow_shipout_x:Nn #1 { \exp_not:n {#2} } } +\cs_generate_variant:Nn \iow_shipout:Nn { Nx } +\cs_new_protected_nopar:Npn \iow_now:Nx { \tex_immediate:D \iow_shipout_x:Nn } +\cs_new_protected_nopar:Npn \iow_now:Nn #1#2 + { \iow_now:Nx #1 { \exp_not:n {#2} } } +\cs_set_protected_nopar:Npn \iow_log:x { \iow_now:Nx \c_iow_log_stream } +\cs_new_protected_nopar:Npn \iow_log:n { \iow_now:Nn \c_iow_log_stream } +\cs_set_protected_nopar:Npn \iow_term:x { \iow_now:Nx \c_iow_term_stream } +\cs_new_protected_nopar:Npn \iow_term:n { \iow_now:Nn \c_iow_term_stream } +\cs_new_protected_nopar:Npn \iow_now_when_avail:Nn #1 + { \cs_if_free:NTF #1 { \use_none:n } { \iow_now:Nn #1 } } +\cs_new_protected_nopar:Npn \iow_now_when_avail:Nx #1 + { \cs_if_free:NTF #1 { \use_none:n } { \iow_now:Nx #1 } } +\int_new:N \l_iow_line_length_int +\int_set:Nn \l_iow_line_length_int { 78 } +\int_new:N \l_iow_target_length_int +\int_new:N \l_iow_current_line_int +\int_new:N \l_iow_current_word_int +\tl_new:N \l_iow_current_line_tl +\tl_new:N \l_iow_current_word_tl +\tl_new:N \l_iow_wrap_tl +\tl_new:N \l_iow_wrapped_tl +\quark_new:N \q_iow_stop +\bool_new:N \l_iow_line_start_bool +\cs_new_protected:Npn \iow_wrap:xnnnN #1#2#3#4#5 + { + \group_begin: + \int_set:Nn \l_iow_target_length_int { \l_iow_line_length_int - ( #3 ) } + \int_zero:N \l_iow_current_line_int + \tl_clear:N \l_iow_current_line_tl + \tl_clear:N \l_iow_wrap_tl + \bool_set_true:N \l_iow_line_start_bool + \cs_set:Npx \\ { \c_space_tl \iow_newline: \c_space_tl } + \cs_set_eq:NN \ \c_space_tl + #4 + \protected@edef \l_iow_wrap_tl {#1} + \cs_set:Npn \\ { \iow_newline: #2 } + \use:x + { + \exp_not:N \iow_wrap_loop:w + \tl_to_str:N \l_iow_wrap_tl \c_space_tl + \exp_not:N \q_iow_stop \c_space_tl + } + \exp_args:NNo \group_end: + #5 \l_iow_wrapped_tl + } +\cs_new_protected:Npn \iow_wrap_loop:w #1 ~ % + { + \tl_set:Nn \l_iow_current_word_tl {#1} + \tl_if_eq:NNTF \l_iow_current_word_tl \iow_newline: + { \iow_wrap_newline: } + { + \tl_if_eq:NNTF \l_iow_current_word_tl \q_iow_stop + { \iow_wrap_end: } + { \iow_wrap_word: } + } + } +\cs_new_protected_nopar:Npn \iow_wrap_word: + { + \int_set:Nn \l_iow_current_word_int + { \str_length_skip_spaces:N \l_iow_current_word_tl } + \int_add:Nn \l_iow_current_line_int { \l_iow_current_word_int } + \int_compare:nNnTF \l_iow_current_line_int + < \l_iow_target_length_int + { \iow_wrap_word_fits: } + { \iow_wrap_word_newline: } + \iow_wrap_loop:w + } +\cs_new_protected_nopar:Npn \iow_wrap_word_fits: + { + \bool_if:NTF \l_iow_line_start_bool + { + \bool_set_false:N \l_iow_line_start_bool + \tl_set_eq:NN \l_iow_current_line_tl \l_iow_current_word_tl + } + { + \tl_put_right:Nx \l_iow_current_line_tl + { ~ \l_iow_current_word_tl } + \int_incr:N \l_iow_current_line_int + } + } +\cs_new_protected_nopar:Npn \iow_wrap_word_newline: + { + \tl_put_right:Nx \l_iow_wrapped_tl + { \l_iow_current_line_tl \\ } + \int_set_eq:NN \l_iow_current_line_int \l_iow_current_word_int + \tl_set_eq:NN \l_iow_current_line_tl \l_iow_current_word_tl + } +\cs_new_protected_nopar:Npn \iow_wrap_newline: + { + \tl_put_right:Nx \l_iow_wrapped_tl + { \l_iow_current_line_tl \\ } + \int_zero:N \l_iow_current_line_int + \tl_clear:N \l_iow_current_line_tl + \bool_set_true:N \l_iow_line_start_bool + \iow_wrap_loop:w + } +\cs_new_protected_nopar:Npn \iow_wrap_end: + { + \tl_put_right:Nx \l_iow_wrapped_tl + { \l_iow_current_line_tl } + } +\cs_new_nopar:Npn \str_length_skip_spaces:N + { \exp_args:No \str_length_skip_spaces:n } +\cs_new:Npn \str_length_skip_spaces:n #1 + { + \int_value:w \int_eval:w + \exp_after:wN \str_length_loop:NNNNNNNNN \tl_to_str:n {#1} + {X8}{X7}{X6}{X5}{X4}{X3}{X2}{X1}{X0} \q_stop + \int_eval_end: + } +\cs_new:Npn \str_length_loop:NNNNNNNNN #1#2#3#4#5#6#7#8#9 + { + \if_catcode:w X #9 + \exp_after:wN \use_none_delimit_by_q_stop:w + \else: + 9 + + \exp_after:wN \str_length_loop:NNNNNNNNN + \fi: + } +\cs_new_nopar:Npn \iow_newline: { ^^J } +\cs_new_eq:NN \iow_char:N \cs_to_str:N +\prg_new_conditional:Nnn \ior_if_eof:N { p , T , F , TF } + { + \cs_if_exist:NTF #1 + { + \if_eof:w #1 + \prg_return_true: + \else: + \prg_return_false: + \fi: + } + { \prg_return_true: } + } +\cs_new_protected_nopar:Npn \ior_to:NN #1#2 + { \tex_read:D #1 to #2 } +\cs_new_protected_nopar:Npn \ior_gto:NN #1#2 + { \pref_global:D \tex_read:D #1 to #2 } +\cs_new_protected_nopar:Npn \ior_str_to:NN #1#2 + { \etex_readline:D #1 to #2 } +\cs_new_protected_nopar:Npn \ior_str_gto:NN #1#2 + { \pref_global:D \etex_readline:D #1 to #2 } +\cs_new_protected:Npn \iow_now_buffer_safe:Nn #1#2 + { \iow_wrap:xnnnN { \exp_not:n {#2} } { } \c_zero { } \iow_now:Nn #1 } +\cs_new_protected:Npn \iow_now_buffer_safe:Nx #1#2 + { \iow_wrap:xnnnN {#2} { } \c_zero { } \iow_now:Nn #1 } +\cs_new_eq:NN \ior_new:N \use_none:n +\cs_new_eq:NN \ior_new:c \use_none:n +\cs_new_eq:NN \iow_new:N \use_none:n +\cs_new_eq:NN \iow_new:c \use_none:n +\cs_new_eq:NN \ior_open_streams: \ior_list_streams: +\cs_new_eq:NN \iow_open_streams: \iow_list_streams: +%% +%% +%% End of file `l3io.sty'. diff --git a/Master/texmf-dist/tex/latex/l3kernel/l3keys.sty b/Master/texmf-dist/tex/latex/l3kernel/l3keys.sty new file mode 100644 index 00000000000..b12add10c9c --- /dev/null +++ b/Master/texmf-dist/tex/latex/l3kernel/l3keys.sty @@ -0,0 +1,475 @@ +%% +%% This is file `l3keys.sty', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% l3keys.dtx (with options: `package') +%% +%% EXPERIMENTAL CODE +%% +%% Do not distribute this file without also distributing the +%% source files specified above. +%% +%% Do not distribute a modified version of this file. +%% +%% File: l3keys.dtx Copyright (C) 2009-2011 The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +\RequirePackage{l3names} +\GetIdInfo$Id: l3keys.dtx 2478 2011-06-19 21:34:23Z joseph $ + {L3 Experimental key-value interfaces} +\ProvidesExplPackage + {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +\package_check_loaded_expl: +\tl_const:Nn \c_keys_code_root_tl { key~code~>~ } +\tl_const:Nn \c_keys_vars_root_tl { key~var~>~ } +\tl_const:Nn \c_keys_props_root_tl { key~prop~>~ } +\tl_const:Nn \c_keys_value_forbidden_tl { forbidden } +\tl_const:Nn \c_keys_value_required_tl { required } +\int_new:N \l_keys_choice_int +\tl_new:N \l_keys_choices_tl +\tl_new:N \l_keys_key_tl +\tl_new:N \l_keys_module_tl +\bool_new:N \l_keys_no_value_bool +\tl_new:N \l_keys_path_tl +\tl_new:N \l_keys_property_tl +\tl_new:N \l_keys_value_tl +\cs_new_protected:Npn \keys_define:nn + { \keys_define_aux:onn \l_keys_module_tl } +\cs_new_protected:Npn \keys_define_aux:nnn #1#2#3 + { + \tl_set:Nx \l_keys_module_tl { \tl_to_str:n {#2} } + \keyval_parse:NNn \keys_define_elt:n \keys_define_elt:nn {#3} + \tl_set:Nn \l_keys_module_tl {#1} + } +\cs_generate_variant:Nn \keys_define_aux:nnn { o } +\cs_new_protected_nopar:Npn \keys_define_elt:n #1 + { + \bool_set_true:N \l_keys_no_value_bool + \keys_define_elt_aux:nn {#1} { } + } +\cs_new_protected:Npn \keys_define_elt:nn #1#2 + { + \bool_set_false:N \l_keys_no_value_bool + \keys_define_elt_aux:nn {#1} {#2} + } +\cs_new_protected:Npn \keys_define_elt_aux:nn #1#2 { + \keys_property_find:n {#1} + \cs_if_exist:cTF { \c_keys_props_root_tl \l_keys_property_tl } + { \keys_define_key:n {#2} } + { + \msg_kernel_error:nnxx { keys } { property-unknown } + { \l_keys_property_tl } { \l_keys_path_tl } + } +} +\cs_new_protected_nopar:Npn \keys_property_find:n #1 + { + \tl_set:Nx \l_keys_path_tl { \l_keys_module_tl / } + \tl_if_in:nnTF {#1} { . } + { \keys_property_find_aux:w #1 \q_stop } + { \msg_kernel_error:nnx { keys } { key-no-property } {#1} } + } +\cs_new_protected_nopar:Npn \keys_property_find_aux:w #1 . #2 \q_stop + { + \tl_set:Nx \l_keys_path_tl { \l_keys_path_tl \tl_to_str:n {#1} } + \tl_if_in:nnTF {#2} { . } + { + \tl_set:Nx \l_keys_path_tl { \l_keys_path_tl . } + \keys_property_find_aux:w #2 \q_stop + } + { \tl_set:Nn \l_keys_property_tl { . #2 } } + } +\cs_new_protected:Npn \keys_define_key:n #1 + { + \bool_if:NTF \l_keys_no_value_bool + { + \exp_after:wN \keys_define_key_aux:w + \l_keys_property_tl \q_stop + { \use:c { \c_keys_props_root_tl \l_keys_property_tl } } + { + \msg_kernel_error:nnxx { keys } + { property-requires-value } { \l_keys_property_tl } + { \l_keys_path_tl } + } + } + { \use:c { \c_keys_props_root_tl \l_keys_property_tl } {#1} } + } +\cs_new_protected:Npn \keys_define_key_aux:w #1 : #2 \q_stop + { \tl_if_empty:nTF {#2} } +\cs_new_nopar:Npn \keys_bool_set:NN #1#2 + { + \cs_if_exist:NF #1 { \bool_new:N #1 } + \keys_choice_make: + \keys_cmd_set:nx { \l_keys_path_tl / true } + { \exp_not:c { bool_ #2 set_true:N } \exp_not:N #1 } + \keys_cmd_set:nx { \l_keys_path_tl / false } + { \exp_not:c { bool_ #2 set_false:N } \exp_not:N #1 } + \keys_cmd_set:nn { \l_keys_path_tl / unknown } + { + \msg_kernel_error:nnx { keys } { boolean-values-only } + { \l_keys_key_tl } + } + \keys_default_set:n { true } + } +\cs_new_protected_nopar:Npn \keys_choice_make: + { + \keys_cmd_set:nn { \l_keys_path_tl } + { \keys_choice_find:n {##1} } + \keys_cmd_set:nn { \l_keys_path_tl / unknown } + { + \msg_kernel_error:nnxx { keys } { choice-unknown } + { \l_keys_path_tl } {##1} + } + } +\cs_new_protected:Npn \keys_choices_generate:n #1 + { + \cs_if_exist:cTF + { \c_keys_vars_root_tl \l_keys_path_tl .choice~code } + { + \keys_choice_make: + \int_zero:N \l_keys_choice_int + \clist_map_function:nN {#1} \keys_choices_generate_aux:n + } + { + \msg_kernel_error:nnx { keys } + { generate-choices-before-code } { \l_keys_path_tl } + } + } +\cs_new_protected_nopar:Npn \keys_choices_generate_aux:n #1 + { + \keys_cmd_set:nx { \l_keys_path_tl / #1 } + { + \exp_not:n { \tl_set:Nn \l_keys_choice_tl } {#1} + \exp_not:n { \int_set:Nn \l_keys_choice_int } + { \int_use:N \l_keys_choice_int } + \exp_not:v + { \c_keys_vars_root_tl \l_keys_path_tl .choice~code } + } + \int_incr:N \l_keys_choice_int + } +\cs_new_protected:Npn \keys_choice_code_store:x #1 + { + \cs_if_exist:cF + { \c_keys_vars_root_tl \l_keys_path_tl .choice~code } + { + \tl_new:c + { \c_keys_vars_root_tl \l_keys_path_tl .choice~code } + } + \tl_set:cx { \c_keys_vars_root_tl \l_keys_path_tl .choice~code } + {#1} + } +\cs_new_protected:Npn \keys_cmd_set:nn #1#2 + { + \keys_cmd_set_aux:n {#1} + \cs_set:cpn { \c_keys_code_root_tl #1 } ##1 {#2} + } +\cs_new_protected:Npn \keys_cmd_set:nx #1#2 + { + \keys_cmd_set_aux:n {#1} + \cs_set:cpx { \c_keys_code_root_tl #1 } ##1 {#2} + } +\cs_new_protected_nopar:Npn \keys_cmd_set_aux:n #1 + { + \tl_clear_new:c { \c_keys_vars_root_tl #1 .default } + \tl_set:cn { \c_keys_vars_root_tl #1 .default } { \q_no_value } + \tl_clear_new:c { \c_keys_vars_root_tl #1 .req } + } +\cs_new_protected:Npn \keys_default_set:n #1 + { \tl_set:cn { \c_keys_vars_root_tl \l_keys_path_tl .default } {#1} } +\cs_generate_variant:Nn \keys_default_set:n { V } +\cs_new_protected_nopar:Npn \keys_meta_make:n #1 + { + \exp_args:NNo \keys_cmd_set:nn \l_keys_path_tl + { \exp_after:wN \keys_set:nn \exp_after:wN { \l_keys_module_tl } {#1} } + } +\cs_new_protected_nopar:Npn \keys_meta_make:x #1 + { + \keys_cmd_set:nx { \l_keys_path_tl } + { \exp_not:N \keys_set:nn { \l_keys_module_tl } {#1} } + } +\cs_new_protected_nopar:Npn \keys_value_requirement:n #1 + { + \tl_set_eq:cc + { \c_keys_vars_root_tl \l_keys_path_tl .req } + { c_keys_value_ #1 _tl } + } +\cs_new_protected_nopar:Npn \keys_variable_set:NnNN #1#2#3#4 + { + \cs_if_exist:NF #1 { \use:c { #2 _new:N } #1 } + \keys_cmd_set:nx { \l_keys_path_tl } + { \exp_not:c { #2 _ #3 set:N #4 } \exp_not:N #1 {##1} } + } +\cs_new_protected_nopar:Npn \keys_variable_set:NnN #1#2#3 + { \keys_variable_set:NnNN #1 {#2} { } #3 } +\cs_generate_variant:Nn \keys_variable_set:NnNN { c } +\cs_generate_variant:Nn \keys_variable_set:NnN { c } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .bool_set:N } #1 + { \keys_bool_set:NN #1 { } } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .bool_gset:N } #1 + { \keys_bool_set:NN #1 g } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .choice: } + { \keys_choice_make: } +\cs_new_protected:cpn { \c_keys_props_root_tl .code:n } #1 + { \keys_cmd_set:nn { \l_keys_path_tl } {#1} } +\cs_new_protected:cpn { \c_keys_props_root_tl .code:x } #1 + { \keys_cmd_set:nx { \l_keys_path_tl } {#1} } +\cs_new_protected:cpn { \c_keys_props_root_tl .choice_code:n } #1 + { \keys_choice_code_store:x { \exp_not:n {#1} } } +\cs_new_protected:cpn { \c_keys_props_root_tl .choice_code:x } #1 + { \keys_choice_code_store:x {#1} } +\cs_new_protected:cpn { \c_keys_props_root_tl .default:n } #1 + { \keys_default_set:n {#1} } +\cs_new_protected:cpn { \c_keys_props_root_tl .default:V } #1 + { \keys_default_set:V #1 } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .dim_set:N } #1 + { \keys_variable_set:NnN #1 { dim } n } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .dim_set:c } #1 + { \keys_variable_set:cnN {#1} { dim } n } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .dim_gset:N } #1 + { \keys_variable_set:NnNN #1 { dim } g n } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .dim_gset:c } #1 + { \keys_variable_set:cnNN {#1} { dim } g n } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .fp_set:N } #1 + { \keys_variable_set:NnN #1 { fp } n } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .fp_set:c } #1 + { \keys_variable_set:cnN {#1} { fp } n } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .fp_gset:N } #1 + { \keys_variable_set:NnNN #1 { fp } g n } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .fp_gset:c } #1 + { \keys_variable_set:cnNN {#1} { fp } g n } +\cs_new_protected:cpn { \c_keys_props_root_tl .generate_choices:n } #1 + { \keys_choices_generate:n {#1} } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .int_set:N } #1 + { \keys_variable_set:NnN #1 { int } n } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .int_set:c } #1 + { \keys_variable_set:cnN {#1} { int } n } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .int_gset:N } #1 + { \keys_variable_set:NnNN #1 { int } g n } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .int_gset:c } #1 + { \keys_variable_set:cnNN {#1} { int } g n } +\cs_new_protected:cpn { \c_keys_props_root_tl .meta:n } #1 + { \keys_meta_make:n {#1} } +\cs_new_protected:cpn { \c_keys_props_root_tl .meta:x } #1 + { \keys_meta_make:x {#1} } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .skip_set:N } #1 + { \keys_variable_set:NnN #1 { skip } n } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .skip_set:c } #1 + { \keys_variable_set:cnN {#1} { skip } n } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .skip_gset:N } #1 + { \keys_variable_set:NnNN #1 { skip } g n } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .skip_gset:c } #1 + { \keys_variable_set:cnNN {#1} { skip } g n } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .tl_set:N } #1 + { \keys_variable_set:NnN #1 { tl } n } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .tl_set:c } #1 + { \keys_variable_set:cnN {#1} { tl } n } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .tl_set_x:N } #1 + { \keys_variable_set:NnN #1 { tl } x } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .tl_set_x:c } #1 + { \keys_variable_set:cnN {#1} { tl } x } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .tl_gset:N } #1 + { \keys_variable_set:NnNN #1 { tl } g n } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .tl_gset:c } #1 + { \keys_variable_set:cnNN {#1} { tl } g n } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .tl_gset_x:N } #1 + { \keys_variable_set:NnNN #1 { tl } g x } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .tl_gset_x:c } #1 + { \keys_variable_set:cnNN {#1} { tl } g x } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .value_forbidden: } + { \keys_value_requirement:n { forbidden } } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .value_required: } + { \keys_value_requirement:n { required } } +\cs_new_protected:Npn \keys_set:nn + { \keys_set_aux:onn { \l_keys_module_tl } } +\cs_new_protected:Npn \keys_set_aux:nnn #1#2#3 + { + \tl_set:Nn \l_keys_module_tl {#2} + \keyval_parse:NNn \keys_set_elt:n \keys_set_elt:nn {#3} + \tl_set:Nn \l_keys_module_tl {#1} + } +\cs_generate_variant:Nn \keys_set:nn { nV , nv , no } +\cs_generate_variant:Nn \keys_set_aux:nnn { o } +\cs_new_protected_nopar:Npn \keys_set_elt:n #1 + { + \bool_set_true:N \l_keys_no_value_bool + \keys_set_elt_aux:nn {#1} { } + } +\cs_new_protected:Npn \keys_set_elt:nn #1#2 + { + \bool_set_false:N \l_keys_no_value_bool + \keys_set_elt_aux:nn {#1} {#2} + } +\cs_new_protected:Npn \keys_set_elt_aux:nn #1#2 + { + \tl_set:Nx \l_keys_key_tl { \tl_to_str:n {#1} } + \tl_set:Nx \l_keys_path_tl { \l_keys_module_tl / \l_keys_key_tl } + \keys_value_or_default:n {#2} + \bool_if:nTF + { + \keys_if_value_p:n { required } && + \l_keys_no_value_bool + } + { + \msg_kernel_error:nnx { keys } { value-required } + { \l_keys_path_tl } + } + { + \bool_if:nTF + { + \keys_if_value_p:n { forbidden } && + ! \l_keys_no_value_bool + } + { + \msg_kernel_error:nnxx { keys } { value-forbidden } + { \l_keys_path_tl } { \l_keys_value_tl } + } + { \keys_execute: } + } + } +\cs_new_protected:Npn \keys_value_or_default:n #1 + { + \tl_set:Nn \l_keys_value_tl {#1} + \bool_if:NT \l_keys_no_value_bool + { + \quark_if_no_value:cF { \c_keys_vars_root_tl \l_keys_path_tl .default } + { + \tl_set_eq:Nc \l_keys_value_tl + { \c_keys_vars_root_tl \l_keys_path_tl .default } + } + } + } +\prg_new_conditional:Npnn \keys_if_value:n #1 { p } + { + \tl_if_eq:ccTF { c_keys_value_ #1 _tl } + { \c_keys_vars_root_tl \l_keys_path_tl .req } + { \prg_return_true: } + { \prg_return_false: } + } +\cs_new_nopar:Npn \keys_execute: + { \keys_execute:nn { \l_keys_path_tl } { \keys_execute_unknown: } } +\cs_new_nopar:Npn \keys_execute_unknown: + { + \keys_execute:nn { \l_keys_module_tl / unknown } + { + \msg_kernel_error:nnxx { keys } { key-unknown } + { \l_keys_path_tl } { \l_keys_module_tl } + } + } +\cs_new_nopar:Npn \keys_execute:nn #1#2 + { + \cs_if_exist:cTF { \c_keys_code_root_tl #1 } + { + \exp_args:Nno \use:c { \c_keys_code_root_tl #1 } + \l_keys_value_tl + } + {#2} + } +\cs_new_nopar:Npn \keys_choice_find:n #1 + { + \keys_execute:nn { \l_keys_path_tl / \tl_to_str:n {#1} } + { \keys_execute:nn { \l_keys_path_tl / unknown } { } } + } +\prg_new_conditional:Npnn \keys_if_exist:nn #1#2 { p , T , F , TF } + { + \cs_if_exist:cTF { \c_keys_code_root_tl #1 / #2 } + { \prg_return_true:} + { \prg_return_false:} + } +\cs_new_nopar:Npn \keys_show:nn #1#2 + { \cs_show:c { \c_keys_code_root_tl #1 / \tl_to_str:n {#2} } } +\msg_kernel_new:nnnn { keys } { boolean-values-only } + { Key~'#1'~accepts~boolean~values~only. } + { The~key~'#1'~only~accepts~the~values~'true'~and~'false'. } +\msg_kernel_new:nnnn { keys } { choice-unknown } + { Choice~'#2'~unknown~for~key~'#1'. } + { + The~key~'#1'~takes~a~limited~number~of~values.\\ + The~input~given,~'#2',~is~not~on~the~list~accepted. + } +\msg_kernel_new:nnnn { keys } { generate-choices-before-code } + { No~code~available~to~generate~choices~for~key~'#1'. } + { + \c_msg_coding_error_text_tl + Before~using~.generate_choices:n~the~code~should~be~defined~ + with~'.choice_code:n'~or~'.choice_code:x'. + } +\msg_kernel_new:nnnn { keys } { key-no-property } + { No~property~given~in~definition~of~key~'#1'. } + { + \c_msg_coding_error_text_tl + Inside~\keys_define:nn each~key~name + needs~a~property: \\ + ~ ~ #1 .<property> \\ + LaTeX~did~not~find~a~'.'~to~indicate~the~start~of~a~property. + } +\msg_kernel_new:nnnn { keys } { key-unknown } + { The~key~'#1'~is~unknown~and~is~being~ignored. } + { + The~module~'#2'~does~not~have~a~key~called~#1'.\\ + Check~that~you~have~spelled~the~key~name~correctly. + } +\msg_kernel_new:nnnn { keys } { option-unknown } + { Unknown~option~'#1'~for~package~#2. } + { + LaTeX~has~been~asked~to~set~an~option~called~'#1'~ + but~the~#2~package~has~not~created~an~option~with~this~name. + } +\msg_kernel_new:nnnn { keys } { property-requires-value } + { The~property~'#1'~requires~a~value. } + { + \c_msg_coding_error_text_tl + LaTeX~was~asked~to~set~property~'#2'~for~key~'#1'.\\ + No~value~was~given~for~the~property,~and~one~is~required. + } +\msg_kernel_new:nnnn { keys } { property-unknown } + { The~key~property~'#1'~is~unknown. } + { + \c_msg_coding_error_text_tl + LaTeX~has~been~asked~to~set~the~property~'#1'~for~key~'#2':~ + this~property~is~not~defined. + } +\msg_kernel_new:nnnn { keys } { value-forbidden } + { The~key~'#1'~does~not~taken~a~value. } + { + The~key~'#1'~should~be~given~without~a~value.\\ + LaTeX~will~ignore~the~given~value~'#2'. + } +\msg_kernel_new:nnnn { keys } { value-required } + { The~key~'#1'~requires~a~value. } + { + The~key~'#1'~must~have~a~value.\\ + No~value~was~present:~the~key~will~be~ignored. + } +%% +%% +%% End of file `l3keys.sty'. diff --git a/Master/texmf-dist/tex/latex/l3kernel/l3keyval.sty b/Master/texmf-dist/tex/latex/l3kernel/l3keyval.sty new file mode 100644 index 00000000000..c42867b5b48 --- /dev/null +++ b/Master/texmf-dist/tex/latex/l3kernel/l3keyval.sty @@ -0,0 +1,177 @@ +%% +%% This is file `l3keyval.sty', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% l3keyval.dtx (with options: `package') +%% +%% EXPERIMENTAL CODE +%% +%% Do not distribute this file without also distributing the +%% source files specified above. +%% +%% Do not distribute a modified version of this file. +%% +%% File: l3keyval.dtx Copyright (C) 2006-2011 The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +\RequirePackage{l3names} +\GetIdInfo$Id: l3keyval.dtx 2478 2011-06-19 21:34:23Z joseph $ + {L3 Experimental key-value parsing} + %\section{Parsing key--value lists} + %\begin{function}{\keyval_parse:NNn} +\ProvidesExplPackage + {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +\package_check_loaded_expl: +\int_new:N \g_keyval_level_int +\tl_new:N \l_keyval_key_tl +\tl_new:N \l_keyval_value_tl +\tl_new:N \l_keyval_sanitise_tl +\tl_new:N \l_keyval_parse_tl +\group_begin: + \char_set_catcode_active:n { `\= } + \char_set_catcode_active:n { `\, } + \char_set_lccode:nn { `\8 } { `\= } + \char_set_lccode:nn { `\9 } { `\, } +\tl_to_lowercase:n + { + \group_end: + \cs_new_protected:Npn \keyval_parse:n #1 + { + \group_begin: + \tl_clear:N \l_keyval_sanitise_tl + \tl_set:Nn \l_keyval_sanitise_tl {#1} + \tl_replace_all_in:Nnn \l_keyval_sanitise_tl { = } { 8 } + \tl_replace_all_in:Nnn \l_keyval_sanitise_tl { , } { 9 } + \tl_clear:N \l_keyval_parse_tl + \exp_after:wN \keyval_parse_elt:w \exp_after:wN + \q_no_value \l_keyval_sanitise_tl 9 \q_nil 9 + \exp_after:wN \group_end: + \l_keyval_parse_tl + } + } +\cs_new_protected:Npn \keyval_parse_elt:w #1 , + { + \tl_if_blank:oTF { \use_none:n #1 } + { \keyval_parse_elt:w \q_no_value } + { + \quark_if_nil:oF { \use_ii:nn #1 } + { + \keyval_split_key_value:w #1 = = \q_stop + \keyval_parse_elt:w \q_no_value + } + } + } +\cs_new_protected:Npn \keyval_split_key_value:w #1 = #2 \q_stop + { + \keyval_split_key:w #1 \q_stop + \str_if_eq:nnTF {#2} { = } + { + \tl_put_right:Nx \l_keyval_parse_tl + { + \exp_not:c { keyval_key_no_value_elt_ \int_use:N \g_keyval_level_int :n } + { \exp_not:o \l_keyval_key_tl } + } + } + { + \keyval_split_key_value_aux:wTF #2 \q_no_value \q_stop + { \keyval_split_value:w \q_nil #2 } + { \msg_kernel_error:nn { keyval } { misplaced-equals-sign } } + } + } +\cs_new:Npn \keyval_split_key_value_aux:wTF #1 = #2#3 \q_stop + { \tl_if_head_eq_meaning:nNTF {#3} \q_no_value } +\group_begin: + \char_set_catcode_math_toggle:n { `\Q } + \cs_new_protected:Npn \keyval_split_key:w #1 \q_stop + { + \exp_args:NNf \tl_set:Nn \l_keyval_key_tl + { + \exp_after:wN \keyval_remove_spaces:w \exp_after:wN + \exp_not:N \use_none:n #1 Q ~ Q + } + \tl_set:Nx \l_keyval_key_tl + { \exp_after:wN \keyval_split_key_aux:w \l_keyval_key_tl \q_stop } + } + \cs_gset:Npn \keyval_split_key_aux:w #1 \q_stop { \exp_not:n {#1} } + \cs_gset:Npn \keyval_remove_spaces:w #1 ~ Q { \keyval_remove_spaces_aux:w #1 Q } + \cs_gset:Npn \keyval_remove_spaces_aux:w #1 Q #2 {#1} +\group_end: +\cs_new_protected:Npn \keyval_split_value:w #1 = = + { + \tl_put_right:Nx \l_keyval_parse_tl + { + \exp_not:c { keyval_key_value_elt_ \int_use:N \g_keyval_level_int :nn } + { \exp_not:o \l_keyval_key_tl } + } + \tl_set:Nx \l_keyval_value_tl { \exp_not:o { \use_none:nnn #1 \q_nil \q_nil } } + \tl_if_empty:NTF \l_keyval_value_tl + { \tl_put_right:Nn \l_keyval_parse_tl { { } } } + { + \quark_if_nil:NTF \l_keyval_value_tl + { + \tl_put_right:Nx \l_keyval_parse_tl + { { \exp_not:o { \use_ii:nnn #1 \q_nil } } } + } + { \keyval_split_value_aux:w #1 \q_stop } + } + } +\group_begin: + \char_set_catcode_math_toggle:n { `\Q } + \cs_new_protected:Npn \keyval_split_value_aux:w \q_nil #1 \q_stop + { + \exp_args:NNf \tl_set:Nn \l_keyval_value_tl + { \keyval_remove_spaces:w \exp_not:N #1 Q ~ Q } + \tl_put_right:Nx \l_keyval_parse_tl { { \exp_not:o \l_keyval_value_tl } } + } +\group_end: +\cs_new_protected:Npn \keyval_parse:NNn #1#2#3 + { + \int_gincr:N \g_keyval_level_int + \cs_gset_eq:cN { keyval_key_no_value_elt_ \int_use:N \g_keyval_level_int :n } #1 + \cs_gset_eq:cN { keyval_key_value_elt_ \int_use:N \g_keyval_level_int :nn } #2 + \keyval_parse:n {#3} + \int_gdecr:N \g_keyval_level_int + } +\msg_kernel_new:nnnn { keyval } { misplaced-equals-sign } + { Misplaced~equals~sign~in~key-value~input~\msg_line_number: } + { + LaTeX~is~attempting~to~parse~some~key-value~input~but~found~ + two~equals~signs~not~separated~by~a~comma. + } +\cs_new_eq:NN \KV_process_space_removal_sanitize:NNn \keyval_parse:NNn +\cs_new_eq:NN \KV_process_space_removal_no_sanitize:NNn \keyval_parse:NNn +\cs_new_eq:NN \KV_process_no_space_removal_no_sanitize:NNn \keyval_parse:NNn +%% +%% +%% End of file `l3keyval.sty'. diff --git a/Master/texmf-dist/tex/latex/l3kernel/l3luatex.sty b/Master/texmf-dist/tex/latex/l3kernel/l3luatex.sty new file mode 100644 index 00000000000..b7e63c89882 --- /dev/null +++ b/Master/texmf-dist/tex/latex/l3kernel/l3luatex.sty @@ -0,0 +1,160 @@ +%% +%% This is file `l3luatex.sty', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% l3luatex.dtx (with options: `package') +%% +%% EXPERIMENTAL CODE +%% +%% Do not distribute this file without also distributing the +%% source files specified above. +%% +%% Do not distribute a modified version of this file. +%% +%% File: l3luatex.dtx Copyright (C) 2010,2011 The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +\RequirePackage{l3names} +\GetIdInfo$Id: l3luatex.dtx 2478 2011-06-19 21:34:23Z joseph $ + {L3 Experimental LuaTeX-specific functions} +\ProvidesExplPackage + {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +\package_check_loaded_expl: +\luatex_if_engine:TF + { + \cs_new_eq:NN \lua_now:x \luatex_directlua:D + \cs_new_eq:NN \lua_shipout_x:n \luatex_latelua:D + } + { + \cs_new:Npn \lua_now:x #1 { \lua_wrong_engine: } + \cs_new_protected:Npn \lua_shipout_x:n #1 { \lua_wrong_engine: } + } +\cs_new:Npn \lua_now:n #1 + { \lua_now:x { \exp_not:n {#1} } } +\cs_generate_variant:Nn \lua_shipout_x:n { x } +\cs_new_protected:Npn \lua_shipout:n #1 + { \lua_shipout_x:n { \exp_not:n {#1} } } +\cs_generate_variant:Nn \lua_shipout:n { x } +\group_begin: +\char_set_catcode_letter:N\! +\char_set_catcode_letter:N\ % +\cs_gset:Npn\lua_wrong_engine:{% +\LuaTeX engine not in use!% +}% +\group_end:% +\int_new:N \g_cctab_allocate_int +\int_set:Nn \g_cctab_allocate_int { -1 } +\int_new:N \g_cctab_stack_int +\seq_new:N \g_cctab_stack_seq +\cs_new_protected_nopar:Npn \cctab_new:N #1 + { + \cs_if_free:NTF #1 + { + \int_gadd:Nn \g_cctab_allocate_int { 2 } + \int_compare:nNnTF + { \g_cctab_allocate_int } < { \c_max_register_int + 1 } + { + \pref_global:D \tex_mathchardef:D #1 \g_cctab_allocate_int + \luatex_initcatcodetable:D #1 + } + { \msg_kernel_fatal:nnx { alloc } { out-of-registers } { cctab } } + } + { + \msg_kernel_error:nnx { code } { variable-already-defined } + { \token_to_str:N #1 } + } + } +\luatex_if_engine:F + { \cs_set_protected_nopar:Npn \cctab_new:N #1 { \lua_wrong_engine: } } +\luatex_if_engine:T + { + \cs_set_protected_nopar:Npn \cctab_new:N #1 + { + \newcatcodetable #1 + \luatex_initcatcodetable:D #1 + } + } +\cs_new_protected_nopar:Npn \cctab_begin:N #1 + { + \seq_gpush:Nx \g_cctab_stack_seq { \tex_the:D \luatex_catcodetable:D } + \luatex_catcodetable:D #1 + \int_gadd:Nn \g_cctab_stack_int { 2 } + \int_compare:nNnT { \g_cctab_stack_int } > { 268 435 453 } + { \msg_kernel_error:nn { code } { cctab-stack-full } } + \luatex_savecatcodetable:D \g_cctab_stack_int + \luatex_catcodetable:D \g_cctab_stack_int + } +\cs_new_protected_nopar:Npn \cctab_end: + { + \int_gsub:Nn \g_cctab_stack_int { 2 } + \seq_gpop:NN \g_cctab_stack_seq \l_cctab_tmp_tl + \quark_if_no_value:NT \l_cctab_tmp_tl + { \tl_set:Nn \l_cctab_tmp_tl { 0 } } + \luatex_catcodetable:D \l_cctab_tmp_tl \scan_stop: + } +\luatex_if_engine:F + { + \cs_set_protected_nopar:Npn \cctab_begin:N #1 { \lua_wrong_engine: } + \cs_set_protected_nopar:Npn \cctab_end: { \lua_wrong_engine: } + } +\luatex_if_engine:T + { + \cs_set_protected_nopar:Npn \cctab_begin:N #1 { \BeginCatcodeRegime #1 } + \cs_set_protected_nopar:Npn \cctab_end: { \EndCatcodeRegime } + } +\tl_new:N \l_cctab_tmp_tl +\cs_new_protected:Npn \cctab_gset:Nn #1#2 + { + \group_begin: + #2 + \luatex_savecatcodetable:D #1 + \group_end: + } +\luatex_if_engine:F + { \cs_set_protected_nopar:Npn \cctab_gset:Nn #1#2 { \lua_wrong_engine: } } +\luatex_if_engine:T + { + \cctab_new:N \c_code_cctab + \cctab_gset:Nn \c_code_cctab { } + } +\luatex_if_engine:T + { + \cs_new_eq:NN \c_document_cctab \CatcodeTableLaTeX + \cs_new_eq:NN \c_initex_cctab \CatcodeTableIniTeX + \cs_new_eq:NN \c_other_cctab \CatcodeTableOther + \cs_new_eq:NN \c_string_cctab \CatcodeTableString + } +%% +%% +%% End of file `l3luatex.sty'. diff --git a/Master/texmf-dist/tex/latex/l3kernel/l3msg.sty b/Master/texmf-dist/tex/latex/l3kernel/l3msg.sty new file mode 100644 index 00000000000..bf1d732514f --- /dev/null +++ b/Master/texmf-dist/tex/latex/l3kernel/l3msg.sty @@ -0,0 +1,574 @@ +%% +%% This is file `l3msg.sty', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% l3msg.dtx (with options: `package') +%% +%% EXPERIMENTAL CODE +%% +%% Do not distribute this file without also distributing the +%% source files specified above. +%% +%% Do not distribute a modified version of this file. +%% +%% File: l3msg.dtx Copyright (C) 2009-2011 The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +\RequirePackage{l3names} +\GetIdInfo$Id: l3msg.dtx 2478 2011-06-19 21:34:23Z joseph $ + {L3 Experimental messages} +\ProvidesExplPackage + {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +\package_check_loaded_expl: +\tl_new:N \l_msg_tmp_tl +\tl_const:Nn \c_msg_text_prefix_tl { msg~text~>~ } +\tl_const:Nn \c_msg_more_text_prefix_tl { msg~extra~text~>~ } +\cs_new_protected:Npn \msg_new:nnnn #1#2 + { + \cs_if_exist:cT { \c_msg_text_prefix_tl #1 / #2 } + { + \msg_kernel_error:nn { msg } { message-already-defined } + {#1} {#2} + } + \msg_set:nnnn {#1} {#2} + } +\cs_new_protected:Npn \msg_new:nnn #1#2#3 + { \msg_new:nnnn {#1} {#2} {#3} { } } +\cs_new_protected:Npn \msg_set:nnnn #1#2#3#4 + { + \cs_set:cpn { \c_msg_text_prefix_tl #1 / #2 } + ##1##2##3##4 {#3} + \cs_set:cpn { \c_msg_more_text_prefix_tl #1 / #2 } + ##1##2##3##4 {#4} + } +\cs_new_protected:Npn \msg_set:nnn #1#2#3 + { \msg_set:nnnn {#1} {#2} {#3} { } } +\tl_const:Nn \c_msg_coding_error_text_tl + { + This~is~a~coding~error. + \\ \\ + } +\tl_const:Nn \c_msg_continue_text_tl + { Type~<return>~to~continue } +\tl_const:Nn \c_msg_critical_text_tl + { Reading~the~current~file~will~stop } +\tl_const:Nn \c_msg_fatal_text_tl + { This~is~a~fatal~error:~LaTeX~will~abort } +\tl_const:Nn \c_msg_help_text_tl + { For~immediate~help~type~H~<return> } +\tl_const:Nn \c_msg_no_info_text_tl + { + LaTeX~does~not~know~anything~more~about~this~error,~sorry. + \c_msg_return_text_tl + } +\tl_const:Nn \c_msg_on_line_text_tl { on~line } +\tl_const:Nn \c_msg_return_text_tl + { + \\ \\ + Try~typing~<return>~to~proceed. + \\ + If~that~doesn't~work,~type~X~<return>~to~quit. + } +\tl_const:Nn \c_msg_trouble_text_tl + { + \\ \\ + More~errors~will~almost~certainly~follow: \\ + the~LaTeX~run~should~be~aborted. + } +\cs_new_nopar:Npn \msg_newline: { ^^J } +\cs_new_nopar:Npn \msg_two_newlines: { ^^J ^^J } +\cs_new_nopar:Npn \msg_line_number: { \int_use:N \tex_inputlineno:D } +\cs_set_nopar:Npn \msg_line_context: + { + \c_msg_on_line_text_tl + \c_space_tl + \msg_line_number: + } +\char_set_catcode_letter:N \. +\tl_new:N + \c_msg_hide_tl.......................................................... +\tl_const:Nn \c_msg_hide_tl + { \c_msg_hide_tl.......................................................... } +\char_set_catcode_other:N \. +\cs_new_protected:Npn \msg_interrupt:xxx #1#2#3 + { + \group_begin: + \tl_if_empty:nTF {#3} + { \msg_interrupt_no_details:xx {#1} {#2} } + { \msg_interrupt_details:xxx {#1} {#2} {#3} } + \msg_interrupt_aux: + \group_end: + } +\cs_new_protected:Npn \msg_interrupt_no_details:xx #1#2 + { + \iow_wrap:xnnnN + { \\ \c_msg_no_info_text_tl } + { |~ } { 2 } { } \msg_interrupt_more_text:n + \iow_wrap:xnnnN { #1 \\ \\ #2 \\ \\ \c_msg_continue_text_tl } + { ! ~ } { 2 } {} \msg_interrupt_text:n + } +\cs_new_protected:Npn \msg_interrupt_details:xxx #1#2#3 + { + \iow_wrap:xnnnN + { \\ #3 } + { |~ } { 2 } { } \msg_interrupt_more_text:n + \iow_wrap:xnnnN { #1 \\ \\ #2 \\ \\ \c_msg_help_text_tl } + { ! ~ } { 2 } { } \msg_interrupt_text:n + } +\cs_new_protected:Npn \msg_interrupt_text:n #1 + { \tl_set:Nn \l_msg_text_tl {#1} } +\cs_new_protected:Npn \msg_interrupt_more_text:n #1 + { + \protected@edef \l_msg_tmp_tl + { + |''''''''''''''''''''''''''''''''''''''''''''''' + #1 + \msg_newline: + |............................................... + } + \tex_errhelp:D \exp_after:wN { \l_msg_tmp_tl } + } +\group_begin: % { + \char_set_lccode:w `\} = `\ \scan_stop: + \char_set_lccode:w `\& = `\! \scan_stop: + \char_set_catcode_active:N \& +\tl_to_lowercase:n + { + \group_end: + \cs_new_protected:Npn \msg_interrupt_aux: + { + \iow_term:x + { + \iow_newline: + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + \iow_newline: + ! + } + \tl_put_right:No \l_msg_text_tl { \c_msg_hide_tl } + \cs_set_protected_nopar:Npx & + { \tex_errmessage:D { \exp_not:o { \l_msg_text_tl } } } + & + } + } +\cs_new_protected:Npn \msg_log:x #1 + { + \iow_log:x { ................................................. } + \iow_wrap:xnnnN { . ~ #1} { . ~ } { 2 } { } + \iow_log:x + \iow_log:x { ................................................. } + } +\cs_new_protected:Npn \msg_term:x #1 + { + \iow_term:x { ************************************************* } + \iow_wrap:xnnnN { * ~ #1} { * ~ } { 2 } { } + \iow_term:x + \iow_term:x { ************************************************* } + } +\int_set:Nn \tex_errorcontextlines:D { -1 } +\cs_new_nopar:Npn \msg_fatal_text:n #1 { Fatal~#1~error } +\cs_new_nopar:Npn \msg_critical_text:n #1 { Critical~#1~error } +\cs_new_nopar:Npn \msg_error_text:n #1 { #1~error } +\cs_new_nopar:Npn \msg_warning_text:n #1 { #1~warning } +\cs_new_nopar:Npn \msg_info_text:n #1 { #1~info } +\cs_new_nopar:Npn \msg_see_documentation_text:n #1 + { \\ \\ See~the~#1~documentation~for~further~information. } +\prop_new:N \l_msg_redirect_classes_prop +\prop_new:N \l_msg_redirect_names_prop +\cs_new_protected_nopar:Npn \msg_class_set:nn #1#2 + { + \prop_clear_new:c { l_msg_redirect_ #1 _prop } + \cs_set_protected:cpn { msg_ #1 :nnxxxx } ##1##2##3##4##5##6 + { \msg_use:nnnnxxxx {#1} {#2} {##1} {##2} {##3} {##4} {##5} {##6} } + \cs_set_protected:cpx { msg_ #1 :nnxxx } ##1##2##3##4##5 + { \exp_not:c { msg_ #1 :nnxxxx } {##1} {##2} {##3} {##4} {##5} { } } + \cs_set_protected:cpx { msg_ #1 :nnxx } ##1##2##3##4 + { \exp_not:c { msg_ #1 :nnxxxx } {##1} {##2} {##3} {##4} { } { } } + \cs_set_protected:cpx { msg_ #1 :nnx } ##1##2##3 + { \exp_not:c { msg_ #1 :nnxxxx } {##1} {##2} {##3} { } { } { } } + \cs_set_protected:cpx { msg_ #1 :nn } ##1##2 + { \exp_not:c { msg_ #1 :nnxxxx } {##1} {##2} { } { } { } { } } + } +\prg_set_conditional:Npnn \msg_if_more_text:N #1 { p , T , F , TF } + { + \cs_if_eq:NNTF #1 \msg_no_more_text:xxxx + { \prg_return_false: } + { \prg_return_true: } + } +\cs_new:Npn \msg_no_more_text:xxxx #1#2#3#4 { } +\cs_generate_variant:Nn \msg_if_more_text_p:N { c } +\cs_generate_variant:Nn \msg_if_more_text:NT { c } +\cs_generate_variant:Nn \msg_if_more_text:NF { c } +\cs_generate_variant:Nn \msg_if_more_text:NTF { c } +\msg_class_set:nn { fatal } + { + \msg_interrupt:xxx + { \msg_fatal_text:n {#1} : ~ "#2" } + { + \use:c { \c_msg_text_prefix_tl #1 / #2 } {#3} {#4} {#5} {#6} + \msg_see_documentation_text:n {#1} + } + { \c_msg_fatal_text_tl } + \tex_end:D + } +\msg_class_set:nn { critical } + { + \msg_interrupt:xxx + { \msg_critical_text:n {#1} : ~ "#2" } + { + \use:c { \c_msg_text_prefix_tl #1 / #2 } {#3} {#4} {#5} {#6} + \msg_see_documentation_text:n {#1} + } + { \c_msg_critical_text_tl } + \tex_endinput:D + } +\msg_class_set:nn { error } + { + \msg_if_more_text:cTF { \c_msg_more_text_prefix_tl #1 / #2 } + { + \msg_interrupt:xxx + { \msg_error_text:n {#1} : ~ "#2" } + { + \use:c { \c_msg_text_prefix_tl #1 / #2 } {#3} {#4} {#5} {#6} + \msg_see_documentation_text:n {#1} + } + { \use:c { \c_msg_more_text_prefix_tl #1 / #2 } {#3} {#4} {#5} {#6} } + } + { + \msg_interrupt:xxx + { \msg_error_text:n {#1} : ~ "#2" } + { + \use:c { \c_msg_text_prefix_tl #1 / #2 } {#3} {#4} {#5} {#6} + \msg_see_documentation_text:n {#1} + } + { } + } + } +\msg_class_set:nn { warning } + { + \msg_term:x + { + \msg_warning_text:n {#1} : ~ "#2" \\ \\ + \use:c { \c_msg_text_prefix_tl #1 / #2 } {#3} {#4} {#5} {#6} + } + } +\msg_class_set:nn { info } + { + \msg_log:x + { + \msg_info_text:n {#1} : ~ "#2" \\ \\ + \use:c { \c_msg_text_prefix_tl #1 / #2 } {#3} {#4} {#5} {#6} + } + } +\msg_class_set:nn { log } + { + \msg_log:x + { \use:c { \c_msg_text_prefix_tl #1 / #2 } {#3} {#4} {#5} {#6} } + } +\msg_class_set:nn { none } { } +\seq_new:N \l_msg_redirect_classes_seq +\tl_new:N \l_msg_class_tl +\tl_new:N \l_msg_current_class_tl +\tl_new:N \l_msg_current_module_tl +\cs_new_protected:Npn \msg_use:nnnnxxxx #1#2#3#4#5#6#7#8 + { + \cs_set_protected_nopar:Npx \msg_use_code: + { + \seq_clear:N \exp_not:N \l_msg_redirect_classes_seq + \exp_not:n {#2} + } + \cs_set_protected:Npx \msg_use_loop:n ##1 + { + \seq_if_in:NnTF \exp_not:n \l_msg_redirect_classes_seq {#1} + { \msg_kernel_error:nn { msg } { message-loop } {#1} } + { + \seq_put_right:Nn \exp_not:N \l_msg_redirect_classes_seq {#1} + \exp_not:N \cs_if_exist:cTF { msg_ ##1 :nnxxxx } + { + \exp_not:N \use:c { msg_ ##1 :nnxxxx } + \exp_not:n { {#3} {#4} {#5} {#6} {#7} {#8} } + } + { + \msg_kernel_error:nnx { msg } { message-class-unknown } {##1} + } + } + } + \cs_if_exist:cTF { \c_msg_text_prefix_tl #3 / #4 } + { \msg_use_aux:nnn {#1} {#3} {#4} } + { \msg_kernel_error:nnxx { msg } { message-unknown } {#3} {#4} } + } +\cs_new_protected_nopar:Npn \msg_use_aux:nnn #1#2#3 + { + \tl_set:Nn \l_msg_current_class_tl {#1} + \tl_set:Nn \l_msg_current_module_tl {#2} + \prop_if_in:NnTF \l_msg_redirect_names_prop { // #2 / #3 / } + { \msg_use_loop_check:nn { names } { // #2 / #3 / } } + { \msg_use_aux:nn {#1} {#2} } + } +\cs_new_protected_nopar:Npn \msg_use_aux:nn #1#2 + { + \prop_if_in:cnTF { l_msg_redirect_ #1 _prop } {#2} + { \msg_use_loop_check:nn {#1} {#2} } + { + \prop_if_in:cnTF { l_msg_redirect_ #1 _prop } { * } + { \msg_use_loop_check:nn {#1} { * } } + { \msg_use_code: } + } + } +\cs_new_protected:Npn \msg_use_loop_check:nn #1#2 + { + \prop_get:cnN { l_msg_redirect_ #1 _prop } {#2} \l_msg_class_tl + \tl_if_eq:NNTF \l_msg_current_class_tl \l_msg_class_tl + { + { \msg_use_code: } + { \msg_use_loop:o \l_msg_class_tl } + } + } +\cs_new_protected_nopar:Npn \msg_use_code: { } +\cs_new_protected:Npn \msg_use_loop:n #1 { } +\cs_generate_variant:Nn \msg_use_loop:n { o } +\cs_new_protected_nopar:Npn \msg_redirect_class:nn #1#2 + { \prop_put:cnn { l_msg_redirect_ #1 _prop } { * } {#2} } +\cs_new_protected_nopar:Npn \msg_redirect_module:nnn #1#2#3 + { \prop_put:cnn { l_msg_redirect_ #2 _prop } {#1} {#3} } +\cs_new_protected_nopar:Npn \msg_redirect_name:nnn #1#2#3 + { \prop_put:Nnn \l_msg_redirect_names_prop { // #1 / #2 / } {#3} } +\cs_new_protected_nopar:Npn \msg_kernel_new:nnnn #1#2 + { \msg_new:nnnn { LaTeX } { #1 / #2 } } +\cs_new_protected_nopar:Npn \msg_kernel_new:nnn #1#2 + { \msg_new:nnn { LaTeX } { #1 / #2 } } +\cs_new_protected_nopar:Npn \msg_kernel_set:nnnn #1#2 + { \msg_set:nnnn { LaTeX } { #1 / #2 } } +\cs_new_protected_nopar:Npn \msg_kernel_set:nnn #1#2 + { \msg_set:nnn { LaTeX } { #1 / #2 } } +\cs_new_protected:Npn \msg_kernel_fatal:nnxxxx #1#2#3#4#5#6 + { + \msg_interrupt:xxx + { \msg_fatal_text:n { LaTeX } : ~ "#1 / #2" } + { + \use:c { \c_msg_text_prefix_tl LaTeX / #1 / #2 } + {#3} {#4} {#5} {#6} + \msg_see_documentation_text:n { LaTeX3 } + } + { \c_msg_fatal_text_tl } + \tex_end:D + } +\cs_new_protected:Npn \msg_kernel_fatal:nnxxx #1#2#3#4#5 + {\msg_kernel_fatal:nnxxxx {#1} {#2} {#3} {#4} {#5} { } } +\cs_new_protected:Npn \msg_kernel_fatal:nnxx #1#2#3#4 + { \msg_kernel_fatal:nnxxxx {#1} {#2} {#3} {#4} { } { } } +\cs_new_protected:Npn \msg_kernel_fatal:nnx #1#2#3 + { \msg_kernel_fatal:nnxxxx {#1} {#2} {#3} { } { } { } } +\cs_new_protected:Npn \msg_kernel_fatal:nn #1#2 + { \msg_kernel_fatal:nnxxxx {#1} {#2} { } { } { } { } } +\cs_new_protected:Npn \msg_kernel_error:nnxxxx #1#2#3#4#5#6 + { + \msg_if_more_text:cTF { \c_msg_more_text_prefix_tl LaTeX / #1 / #2 } + { + \msg_interrupt:xxx + { \msg_error_text:n { LaTeX } : ~ " #1 / #2 " } + { + \use:c { \c_msg_text_prefix_tl LaTeX / #1 / #2 } + {#3} {#4} {#5} {#6} + \msg_see_documentation_text:n { LaTeX3 } + } + { + \use:c { \c_msg_more_text_prefix_tl LaTeX / #1 / #2 } + {#3} {#4} {#5} {#6} + } + } + { + \msg_interrupt:xxx + { \msg_error_text:n { LaTeX } : ~ " #1 / #2 " } + { + \use:c { \c_msg_text_prefix_tl LaTeX / #1 / #2 } + {#3} {#4} {#5} {#6} + \msg_see_documentation_text:n { LaTeX3 } + } + { } + } + } +\cs_new_protected:Npn \msg_kernel_error:nnxxx #1#2#3#4#5 + {\msg_kernel_error:nnxxxx {#1} {#2} {#3} {#4} {#5} { } } +\cs_set_protected:Npn \msg_kernel_error:nnxx #1#2#3#4 + { \msg_kernel_error:nnxxxx {#1} {#2} {#3} {#4} { } { } } +\cs_set_protected:Npn \msg_kernel_error:nnx #1#2#3 + { \msg_kernel_error:nnxxxx {#1} {#2} {#3} { } { } { } } +\cs_set_protected:Npn \msg_kernel_error:nn #1#2 + { \msg_kernel_error:nnxxxx {#1} {#2} { } { } { } { } } +\prop_new:N \l_msg_redirect_kernel_warning_prop +\cs_new_protected:Npn \msg_kernel_warning:nnxxxx #1#2#3#4#5#6 + { + \msg_use:nnnnxxxx { warning } + { + \msg_term:x + { + \msg_warning_text:n { LaTeX } : ~ " #1 / #2 " \\ \\ + \use:c { \c_msg_text_prefix_tl LaTeX / #1 / #2 } + {#3} {#4} {#5} {#6} + } + } + { LaTeX } { #1 / #2 } {#3} {#4} {#5} {#6} + } +\cs_new_protected:Npn \msg_kernel_warning:nnxxx #1#2#3#4#5 + { \msg_kernel_warning:nnxxxx {#1} {#2} {#3} {#4} {#5} { } } +\cs_new_protected:Npn \msg_kernel_warning:nnxx #1#2#3#4 + { \msg_kernel_warning:nnxxxx {#1} {#2} {#3} {#4} { } { } } +\cs_new_protected:Npn \msg_kernel_warning:nnx #1#2#3 + { \msg_kernel_warning:nnxxxx {#1} {#2} {#3} { } { } { } } +\cs_new_protected:Npn \msg_kernel_warning:nn #1#2 + { \msg_kernel_warning:nnxxxx {#1} {#2} { } { } { } { } } +\prop_new:N \l_msg_redirect_kernel_info_prop +\cs_new_protected:Npn \msg_kernel_info:nnxxxx #1#2#3#4#5#6 + { + \msg_use:nnnnxxxx { info } + { + \msg_log:x + { + \msg_info_text:n { LaTeX } : ~ " #1 / #2 " \\ \\ + \use:c { \c_msg_text_prefix_tl LaTeX / #1 / #2 } + {#3} {#4} {#5} {#6} + } + } + { LaTeX } { #1 / #2 } {#3} {#4} {#5} {#6} + } +\cs_new_protected:Npn \msg_kernel_info:nnxxx #1#2#3#4#5 + { \msg_kernel_info:nnxxxx {#1} {#2} {#3} {#4} {#5} { } } +\cs_new_protected:Npn \msg_kernel_info:nnxx #1#2#3#4 + { \msg_kernel_info:nnxxxx {#1} {#2} {#3} {#4} { } { } } +\cs_new_protected:Npn \msg_kernel_info:nnx #1#2#3 + { \msg_kernel_info:nnxxxx {#1} {#2} {#3} { } { } { } } +\cs_new_protected:Npn \msg_kernel_info:nn #1#2 + { \msg_kernel_info:nnxxxx {#1} {#2} { } { } { } { } } +\msg_kernel_new:nnnn { msg } { message-already-defined } + { Message~'#2'~for~module~'#1'~already~defined. } + { + \c_msg_coding_error_text_tl + LaTeX~was~asked~to~define~a~new~message~called~'#2' + by~the~module~'#1'~module:\\ + this~message~already~exists. + \c_msg_return_text_tl + } +\msg_kernel_new:nnnn { msg } { message-unknown } + { Unknown~message~'#2'~for~module~'#1'. } + { + \c_msg_coding_error_text_tl + LaTeX~was~asked~to~display~a~message~called~'#2'\\ + by~the~module~'#1'~module:~this~message~does~not~exist. + \c_msg_return_text_tl + } +\msg_kernel_new:nnnn { msg } { message-class-unknown } + { Unknown~message~class~'#1'. } + { + LaTeX~has~been~asked~to~redirect~messages~to~a~class~'#1':\\ + this~was~never~defined. + \c_msg_return_text_tl + } +\msg_kernel_new:nnnn { msg } { redirect-loop } + { Message~redirection~loop~for~message~class~'#1'. } + { + LaTeX~has~been~asked~to~redirect~messages~in~an~infinite~loop.\\ + The~original~message~here~has~been~lost. + \c_msg_return_text_tl + } +\msg_kernel_new:nnnn { kernel } { bad-number-of-arguments } + { Function~'#1'~cannot~be~defined~with~#2~arguments. } + { + \c_msg_coding_error_text_tl + LaTeX~has~been~asked~to~define~a~function~'#1'~with~ + #2~arguments. \\ + TeX~allows~between~0~and~9~arguments~for~a~single~function. + } +\msg_kernel_new:nnnn { kernel } { command-already-defined } + { Control~sequence~#1~already~defined. } + { + \c_msg_coding_error_text_tl + LaTeX~has~been~asked~to~create~a~new~control~sequence~'#1'~ + but~this~name~has~already~been~used~elsewhere. \\ \\ + The~current~meaning~is:\\ + \ \ #2 + } +\msg_kernel_new:nnnn { kernel } { command-not-defined } + { Control~sequence~#1~undefined. } + { + \c_msg_coding_error_text_tl + LaTeX~has~been~asked~to~use~a~command~#1,~but~this~has~not~ + been~defined~yet. + } +\msg_kernel_new:nnnn { kernel } { variable-not-defined } + { Variable~#1~undefined. } + { + \c_msg_coding_error_text_tl + LaTeX~has~been~asked~to~show~a~variable~#1,~but~this~has~not~ + been~defined~yet. + } +\msg_kernel_new:nnnn { seq } { empty-sequence } + { Empty~sequence~#1. } + { + \c_msg_coding_error_text_tl + LaTeX~has~been~asked~to~recover~an~entry~from~a~sequence~that~ + has~no~content:~that~cannot~happen! + } +\cs_set_protected:Npn \msg_kernel_bug:x #1 + { + \msg_interrupt:xxx { \c_msg_kernel_bug_text_tl } + { + #1 + \msg_see_documentation_text:n { LaTeX3 } + } + { \c_msg_kernel_bug_more_text_tl } + } +\tl_const:Nn \c_msg_kernel_bug_text_tl + { This~is~a~LaTeX~bug:~check~coding! } +\tl_const:Nn \c_msg_kernel_bug_more_text_tl + { + There~is~a~coding~bug~somewhere~around~here. \\ + This~probably~needs~examining~by~an~expert. + \c_msg_return_text_tl + } +\cs_new_eq:NN \msg_class_new:nn \msg_class_set:nn +\cs_new_eq:NN \msg_trace:nnxxxx \msg_log:nnxxxx +\cs_new_eq:NN \msg_trace:nnxxx \msg_log:nnxxx +\cs_new_eq:NN \msg_trace:nnxx \msg_log:nnxx +\cs_new_eq:NN \msg_trace:nnx \msg_log:nnx +\cs_new_eq:NN \msg_trace:nn \msg_log:nn +\cs_new_protected:Npn \msg_generic_new:nnn #1#2#3 { \deprecated } +\cs_new_protected:Npn \msg_generic_new:nn #1#2 { \deprecated } +\cs_new_protected:Npn \msg_generic_set:nnn #1#2#3 { \deprecated } +\cs_new_protected:Npn \msg_generic_set:nn #1#2 { \deprecated } +\cs_new_protected:Npn \msg_direct_interrupt:xxxxx #1#2#3#4#5 { \deprecated } +\cs_new_protected:Npn \msg_direct_log:xx #1#2 { \deprecated } +\cs_new_protected:Npn \msg_direct_term:xx #1#2 { \deprecated } +%% +%% +%% End of file `l3msg.sty'. diff --git a/Master/texmf-dist/tex/latex/l3kernel/l3names.sty b/Master/texmf-dist/tex/latex/l3kernel/l3names.sty new file mode 100644 index 00000000000..a504049d1ed --- /dev/null +++ b/Master/texmf-dist/tex/latex/l3kernel/l3names.sty @@ -0,0 +1,489 @@ +%% +%% This is file `l3names.sty', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% l3names.dtx (with options: `package') +%% +%% EXPERIMENTAL CODE +%% +%% Do not distribute this file without also distributing the +%% source files specified above. +%% +%% Do not distribute a modified version of this file. +%% +%% File: l3names.dtx Copyright (C) 1990-2011 The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +\RequirePackage{l3bootstrap} +\GetIdInfo$Id: l3names.dtx 2478 2011-06-19 21:34:23Z joseph $ + {L3 Experimental namespace for primitives} +\ProvidesExplPackage + {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +\let \tex_global:D \global +\let \tex_let:D \let +\begingroup + \long \def \name_primitive:NN #1#2 + { + \tex_global:D \tex_let:D #2 #1 + } + \name_primitive:NN \ \tex_space:D + \name_primitive:NN \/ \tex_italiccor:D + \name_primitive:NN \- \tex_hyphen:D + \name_primitive:NN \let \tex_let:D + \name_primitive:NN \def \tex_def:D + \name_primitive:NN \edef \tex_edef:D + \name_primitive:NN \gdef \tex_gdef:D + \name_primitive:NN \xdef \tex_xdef:D + \name_primitive:NN \chardef \tex_chardef:D + \name_primitive:NN \countdef \tex_countdef:D + \name_primitive:NN \dimendef \tex_dimendef:D + \name_primitive:NN \skipdef \tex_skipdef:D + \name_primitive:NN \muskipdef \tex_muskipdef:D + \name_primitive:NN \mathchardef \tex_mathchardef:D + \name_primitive:NN \toksdef \tex_toksdef:D + \name_primitive:NN \futurelet \tex_futurelet:D + \name_primitive:NN \advance \tex_advance:D + \name_primitive:NN \divide \tex_divide:D + \name_primitive:NN \multiply \tex_multiply:D + \name_primitive:NN \font \tex_font:D + \name_primitive:NN \fam \tex_fam:D + \name_primitive:NN \global \tex_global:D + \name_primitive:NN \long \tex_long:D + \name_primitive:NN \outer \tex_outer:D + \name_primitive:NN \setlanguage \tex_setlanguage:D + \name_primitive:NN \globaldefs \tex_globaldefs:D + \name_primitive:NN \afterassignment \tex_afterassignment:D + \name_primitive:NN \aftergroup \tex_aftergroup:D + \name_primitive:NN \expandafter \tex_expandafter:D + \name_primitive:NN \noexpand \tex_noexpand:D + \name_primitive:NN \begingroup \tex_begingroup:D + \name_primitive:NN \endgroup \tex_endgroup:D + \name_primitive:NN \halign \tex_halign:D + \name_primitive:NN \valign \tex_valign:D + \name_primitive:NN \cr \tex_cr:D + \name_primitive:NN \crcr \tex_crcr:D + \name_primitive:NN \noalign \tex_noalign:D + \name_primitive:NN \omit \tex_omit:D + \name_primitive:NN \span \tex_span:D + \name_primitive:NN \tabskip \tex_tabskip:D + \name_primitive:NN \everycr \tex_everycr:D + \name_primitive:NN \if \tex_if:D + \name_primitive:NN \ifcase \tex_ifcase:D + \name_primitive:NN \ifcat \tex_ifcat:D + \name_primitive:NN \ifnum \tex_ifnum:D + \name_primitive:NN \ifodd \tex_ifodd:D + \name_primitive:NN \ifdim \tex_ifdim:D + \name_primitive:NN \ifeof \tex_ifeof:D + \name_primitive:NN \ifhbox \tex_ifhbox:D + \name_primitive:NN \ifvbox \tex_ifvbox:D + \name_primitive:NN \ifvoid \tex_ifvoid:D + \name_primitive:NN \ifx \tex_ifx:D + \name_primitive:NN \iffalse \tex_iffalse:D + \name_primitive:NN \iftrue \tex_iftrue:D + \name_primitive:NN \ifhmode \tex_ifhmode:D + \name_primitive:NN \ifmmode \tex_ifmmode:D + \name_primitive:NN \ifvmode \tex_ifvmode:D + \name_primitive:NN \ifinner \tex_ifinner:D + \name_primitive:NN \else \tex_else:D + \name_primitive:NN \fi \tex_fi:D + \name_primitive:NN \or \tex_or:D + \name_primitive:NN \immediate \tex_immediate:D + \name_primitive:NN \closeout \tex_closeout:D + \name_primitive:NN \openin \tex_openin:D + \name_primitive:NN \openout \tex_openout:D + \name_primitive:NN \read \tex_read:D + \name_primitive:NN \write \tex_write:D + \name_primitive:NN \closein \tex_closein:D + \name_primitive:NN \newlinechar \tex_newlinechar:D + \name_primitive:NN \input \tex_input:D + \name_primitive:NN \endinput \tex_endinput:D + \name_primitive:NN \inputlineno \tex_inputlineno:D + \name_primitive:NN \errmessage \tex_errmessage:D + \name_primitive:NN \message \tex_message:D + \name_primitive:NN \show \tex_show:D + \name_primitive:NN \showthe \tex_showthe:D + \name_primitive:NN \showbox \tex_showbox:D + \name_primitive:NN \showlists \tex_showlists:D + \name_primitive:NN \errhelp \tex_errhelp:D + \name_primitive:NN \errorcontextlines \tex_errorcontextlines:D + \name_primitive:NN \tracingcommands \tex_tracingcommands:D + \name_primitive:NN \tracinglostchars \tex_tracinglostchars:D + \name_primitive:NN \tracingmacros \tex_tracingmacros:D + \name_primitive:NN \tracingonline \tex_tracingonline:D + \name_primitive:NN \tracingoutput \tex_tracingoutput:D + \name_primitive:NN \tracingpages \tex_tracingpages:D + \name_primitive:NN \tracingparagraphs \tex_tracingparagraphs:D + \name_primitive:NN \tracingrestores \tex_tracingrestores:D + \name_primitive:NN \tracingstats \tex_tracingstats:D + \name_primitive:NN \pausing \tex_pausing:D + \name_primitive:NN \showboxbreadth \tex_showboxbreadth:D + \name_primitive:NN \showboxdepth \tex_showboxdepth:D + \name_primitive:NN \batchmode \tex_batchmode:D + \name_primitive:NN \errorstopmode \tex_errorstopmode:D + \name_primitive:NN \nonstopmode \tex_nonstopmode:D + \name_primitive:NN \scrollmode \tex_scrollmode:D + \name_primitive:NN \end \tex_end:D + \name_primitive:NN \csname \tex_csname:D + \name_primitive:NN \endcsname \tex_endcsname:D + \name_primitive:NN \ignorespaces \tex_ignorespaces:D + \name_primitive:NN \relax \tex_relax:D + \name_primitive:NN \the \tex_the:D + \name_primitive:NN \mag \tex_mag:D + \name_primitive:NN \language \tex_language:D + \name_primitive:NN \mark \tex_mark:D + \name_primitive:NN \topmark \tex_topmark:D + \name_primitive:NN \firstmark \tex_firstmark:D + \name_primitive:NN \botmark \tex_botmark:D + \name_primitive:NN \splitfirstmark \tex_splitfirstmark:D + \name_primitive:NN \splitbotmark \tex_splitbotmark:D + \name_primitive:NN \fontname \tex_fontname:D + \name_primitive:NN \escapechar \tex_escapechar:D + \name_primitive:NN \endlinechar \tex_endlinechar:D + \name_primitive:NN \mathchoice \tex_mathchoice:D + \name_primitive:NN \delimiter \tex_delimiter:D + \name_primitive:NN \mathaccent \tex_mathaccent:D + \name_primitive:NN \mathchar \tex_mathchar:D + \name_primitive:NN \mskip \tex_mskip:D + \name_primitive:NN \radical \tex_radical:D + \name_primitive:NN \vcenter \tex_vcenter:D + \name_primitive:NN \mkern \tex_mkern:D + \name_primitive:NN \above \tex_above:D + \name_primitive:NN \abovewithdelims \tex_abovewithdelims:D + \name_primitive:NN \atop \tex_atop:D + \name_primitive:NN \atopwithdelims \tex_atopwithdelims:D + \name_primitive:NN \over \tex_over:D + \name_primitive:NN \overwithdelims \tex_overwithdelims:D + \name_primitive:NN \displaystyle \tex_displaystyle:D + \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 + \name_primitive:NN \abovedisplayskip \tex_abovedisplayskip:D + \name_primitive:NN \belowdisplayshortskip \tex_belowdisplayshortskip:D + \name_primitive:NN \belowdisplayskip \tex_belowdisplayskip:D + \name_primitive:NN \displaywidowpenalty \tex_displaywidowpenalty:D + \name_primitive:NN \displayindent \tex_displayindent:D + \name_primitive:NN \displaywidth \tex_displaywidth:D + \name_primitive:NN \everydisplay \tex_everydisplay:D + \name_primitive:NN \predisplaysize \tex_predisplaysize:D + \name_primitive:NN \predisplaypenalty \tex_predisplaypenalty:D + \name_primitive:NN \postdisplaypenalty \tex_postdisplaypenalty:D + \name_primitive:NN \mathbin \tex_mathbin:D + \name_primitive:NN \mathclose \tex_mathclose:D + \name_primitive:NN \mathinner \tex_mathinner:D + \name_primitive:NN \mathop \tex_mathop:D + \name_primitive:NN \displaylimits \tex_displaylimits:D + \name_primitive:NN \limits \tex_limits:D + \name_primitive:NN \nolimits \tex_nolimits:D + \name_primitive:NN \mathopen \tex_mathopen:D + \name_primitive:NN \mathord \tex_mathord:D + \name_primitive:NN \mathpunct \tex_mathpunct:D + \name_primitive:NN \mathrel \tex_mathrel:D + \name_primitive:NN \overline \tex_overline:D + \name_primitive:NN \underline \tex_underline:D + \name_primitive:NN \left \tex_left:D + \name_primitive:NN \right \tex_right:D + \name_primitive:NN \binoppenalty \tex_binoppenalty:D + \name_primitive:NN \relpenalty \tex_relpenalty:D + \name_primitive:NN \delimitershortfall \tex_delimitershortfall:D + \name_primitive:NN \delimiterfactor \tex_delimiterfactor:D + \name_primitive:NN \nulldelimiterspace \tex_nulldelimiterspace:D + \name_primitive:NN \everymath \tex_everymath:D + \name_primitive:NN \mathsurround \tex_mathsurround:D + \name_primitive:NN \medmuskip \tex_medmuskip:D + \name_primitive:NN \thinmuskip \tex_thinmuskip:D + \name_primitive:NN \thickmuskip \tex_thickmuskip:D + \name_primitive:NN \scriptspace \tex_scriptspace:D + \name_primitive:NN \noboundary \tex_noboundary:D + \name_primitive:NN \accent \tex_accent:D + \name_primitive:NN \char \tex_char:D + \name_primitive:NN \discretionary \tex_discretionary:D + \name_primitive:NN \hfil \tex_hfil:D + \name_primitive:NN \hfilneg \tex_hfilneg:D + \name_primitive:NN \hfill \tex_hfill:D + \name_primitive:NN \hskip \tex_hskip:D + \name_primitive:NN \hss \tex_hss:D + \name_primitive:NN \vfil \tex_vfil:D + \name_primitive:NN \vfilneg \tex_vfilneg:D + \name_primitive:NN \vfill \tex_vfill:D + \name_primitive:NN \vskip \tex_vskip:D + \name_primitive:NN \vss \tex_vss:D + \name_primitive:NN \unskip \tex_unskip:D + \name_primitive:NN \kern \tex_kern:D + \name_primitive:NN \unkern \tex_unkern:D + \name_primitive:NN \hrule \tex_hrule:D + \name_primitive:NN \vrule \tex_vrule:D + \name_primitive:NN \leaders \tex_leaders:D + \name_primitive:NN \cleaders \tex_cleaders:D + \name_primitive:NN \xleaders \tex_xleaders:D + \name_primitive:NN \lastkern \tex_lastkern:D + \name_primitive:NN \lastskip \tex_lastskip:D + \name_primitive:NN \indent \tex_indent:D + \name_primitive:NN \par \tex_par:D + \name_primitive:NN \noindent \tex_noindent:D + \name_primitive:NN \vadjust \tex_vadjust:D + \name_primitive:NN \baselineskip \tex_baselineskip:D + \name_primitive:NN \lineskip \tex_lineskip:D + \name_primitive:NN \lineskiplimit \tex_lineskiplimit:D + \name_primitive:NN \clubpenalty \tex_clubpenalty:D + \name_primitive:NN \widowpenalty \tex_widowpenalty:D + \name_primitive:NN \exhyphenpenalty \tex_exhyphenpenalty:D + \name_primitive:NN \hyphenpenalty \tex_hyphenpenalty:D + \name_primitive:NN \linepenalty \tex_linepenalty:D + \name_primitive:NN \doublehyphendemerits \tex_doublehyphendemerits:D + \name_primitive:NN \finalhyphendemerits \tex_finalhyphendemerits:D + \name_primitive:NN \adjdemerits \tex_adjdemerits:D + \name_primitive:NN \hangafter \tex_hangafter:D + \name_primitive:NN \hangindent \tex_hangindent:D + \name_primitive:NN \parshape \tex_parshape:D + \name_primitive:NN \hsize \tex_hsize:D + \name_primitive:NN \lefthyphenmin \tex_lefthyphenmin:D + \name_primitive:NN \righthyphenmin \tex_righthyphenmin:D + \name_primitive:NN \leftskip \tex_leftskip:D + \name_primitive:NN \rightskip \tex_rightskip:D + \name_primitive:NN \looseness \tex_looseness:D + \name_primitive:NN \parskip \tex_parskip:D + \name_primitive:NN \parindent \tex_parindent:D + \name_primitive:NN \uchyph \tex_uchyph:D + \name_primitive:NN \emergencystretch \tex_emergencystretch:D + \name_primitive:NN \pretolerance \tex_pretolerance:D + \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 + \name_primitive:NN \shipout \tex_shipout:D + \name_primitive:NN \vsize \tex_vsize:D + \name_primitive:NN \interlinepenalty \tex_interlinepenalty:D + \name_primitive:NN \brokenpenalty \tex_brokenpenalty:D + \name_primitive:NN \topskip \tex_topskip:D + \name_primitive:NN \maxdeadcycles \tex_maxdeadcycles:D + \name_primitive:NN \maxdepth \tex_maxdepth:D + \name_primitive:NN \output \tex_output:D + \name_primitive:NN \deadcycles \tex_deadcycles:D + \name_primitive:NN \pagedepth \tex_pagedepth:D + \name_primitive:NN \pagestretch \tex_pagestretch:D + \name_primitive:NN \pagefilstretch \tex_pagefilstretch:D + \name_primitive:NN \pagefillstretch \tex_pagefillstretch:D + \name_primitive:NN \pagefilllstretch \tex_pagefilllstretch:D + \name_primitive:NN \pageshrink \tex_pageshrink:D + \name_primitive:NN \pagegoal \tex_pagegoal:D + \name_primitive:NN \pagetotal \tex_pagetotal:D + \name_primitive:NN \outputpenalty \tex_outputpenalty:D + \name_primitive:NN \hoffset \tex_hoffset:D + \name_primitive:NN \voffset \tex_voffset:D + \name_primitive:NN \insert \tex_insert:D + \name_primitive:NN \holdinginserts \tex_holdinginserts:D + \name_primitive:NN \floatingpenalty \tex_floatingpenalty:D + \name_primitive:NN \insertpenalties \tex_insertpenalties:D + \name_primitive:NN \lower \tex_lower:D + \name_primitive:NN \moveleft \tex_moveleft:D + \name_primitive:NN \moveright \tex_moveright:D + \name_primitive:NN \raise \tex_raise:D + \name_primitive:NN \copy \tex_copy:D + \name_primitive:NN \lastbox \tex_lastbox:D + \name_primitive:NN \vsplit \tex_vsplit:D + \name_primitive:NN \unhbox \tex_unhbox:D + \name_primitive:NN \unhcopy \tex_unhcopy:D + \name_primitive:NN \unvbox \tex_unvbox:D + \name_primitive:NN \unvcopy \tex_unvcopy:D + \name_primitive:NN \setbox \tex_setbox:D + \name_primitive:NN \hbox \tex_hbox:D + \name_primitive:NN \vbox \tex_vbox:D + \name_primitive:NN \vtop \tex_vtop:D + \name_primitive:NN \prevdepth \tex_prevdepth:D + \name_primitive:NN \badness \tex_badness:D + \name_primitive:NN \hbadness \tex_hbadness:D + \name_primitive:NN \vbadness \tex_vbadness:D + \name_primitive:NN \hfuzz \tex_hfuzz:D + \name_primitive:NN \vfuzz \tex_vfuzz:D + \name_primitive:NN \overfullrule \tex_overfullrule:D + \name_primitive:NN \boxmaxdepth \tex_boxmaxdepth:D + \name_primitive:NN \splitmaxdepth \tex_splitmaxdepth:D + \name_primitive:NN \splittopskip \tex_splittopskip:D + \name_primitive:NN \everyhbox \tex_everyhbox:D + \name_primitive:NN \everyvbox \tex_everyvbox:D + \name_primitive:NN \nullfont \tex_nullfont:D + \name_primitive:NN \textfont \tex_textfont:D + \name_primitive:NN \scriptfont \tex_scriptfont:D + \name_primitive:NN \scriptscriptfont \tex_scriptscriptfont:D + \name_primitive:NN \fontdimen \tex_fontdimen:D + \name_primitive:NN \hyphenchar \tex_hyphenchar:D + \name_primitive:NN \skewchar \tex_skewchar:D + \name_primitive:NN \defaulthyphenchar \tex_defaulthyphenchar:D + \name_primitive:NN \defaultskewchar \tex_defaultskewchar:D + \name_primitive:NN \number \tex_number:D + \name_primitive:NN \romannumeral \tex_romannumeral:D + \name_primitive:NN \string \tex_string:D + \name_primitive:NN \lowercase \tex_lowercase:D + \name_primitive:NN \uppercase \tex_uppercase:D + \name_primitive:NN \meaning \tex_meaning:D + \name_primitive:NN \penalty \tex_penalty:D + \name_primitive:NN \unpenalty \tex_unpenalty:D + \name_primitive:NN \lastpenalty \tex_lastpenalty:D + \name_primitive:NN \special \tex_special:D + \name_primitive:NN \dump \tex_dump:D + \name_primitive:NN \patterns \tex_patterns:D + \name_primitive:NN \hyphenation \tex_hyphenation:D + \name_primitive:NN \time \tex_time:D + \name_primitive:NN \day \tex_day:D + \name_primitive:NN \month \tex_month:D + \name_primitive:NN \year \tex_year:D + \name_primitive:NN \jobname \tex_jobname:D + \name_primitive:NN \everyjob \tex_everyjob:D + \name_primitive:NN \count \tex_count:D + \name_primitive:NN \dimen \tex_dimen:D + \name_primitive:NN \skip \tex_skip:D + \name_primitive:NN \toks \tex_toks:D + \name_primitive:NN \muskip \tex_muskip:D + \name_primitive:NN \box \tex_box:D + \name_primitive:NN \wd \tex_wd:D + \name_primitive:NN \ht \tex_ht:D + \name_primitive:NN \dp \tex_dp:D + \name_primitive:NN \catcode \tex_catcode:D + \name_primitive:NN \delcode \tex_delcode:D + \name_primitive:NN \sfcode \tex_sfcode:D + \name_primitive:NN \lccode \tex_lccode:D + \name_primitive:NN \uccode \tex_uccode:D + \name_primitive:NN \mathcode \tex_mathcode:D + \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 + \name_primitive:NN \pdfcreationdate \pdftex_pdfcreationdate:D + \name_primitive:NN \pdfcolorstack \pdftex_pdfcolorstack:D + \name_primitive:NN \pdfcompresslevel \pdftex_pdfcompresslevel:D + \name_primitive:NN \pdfdecimaldigits \pdftex_pdfdecimaldigits:D + \name_primitive:NN \pdfhorigin \pdftex_pdfhorigin:D + \name_primitive:NN \pdfinfo \pdftex_pdfinfo:D + \name_primitive:NN \pdfliteral \pdftex_pdfliteral:D + \name_primitive:NN \pdfminorversion \pdftex_pdfminorversion:D + \name_primitive:NN \pdfobjcompresslevel \pdftex_pdfobjcompresslevel:D + \name_primitive:NN \pdfoutput \pdftex_pdfoutput:D + \name_primitive:NN \pdfrestore \pdftex_pdfrestore:D + \name_primitive:NN \pdfsave \pdftex_pdfsave:D + \name_primitive:NN \pdfsetmatrix \pdftex_pdfsetmatrix:D + \name_primitive:NN \pdfpkresolution \pdftex_pdfpkresolution:D + \name_primitive:NN \pdftexrevision \pdftex_pdftextrevision:D + \name_primitive:NN \pdfvorigin \pdftex_pdfvorigin:D + \name_primitive:NN \pdfstrcmp \pdftex_strcmp:D + \name_primitive:NN \XeTeXversion \xetex_XeTeXversion:D + \name_primitive:NN \catcodetable \luatex_catcodetable:D + \name_primitive:NN \directlua \luatex_directlua:D + \name_primitive:NN \initcatcodetable \luatex_initcatcodetable:D + \name_primitive:NN \latelua \luatex_latelua:D + \name_primitive:NN \luatexversion \luatex_luatexversion:D + \name_primitive:NN \savecatcodetable \luatex_savecatcodetable:D +\tex_endgroup:D +\tex_let:D \tex_end:D \@@end +\tex_let:D \tex_everydisplay:D \frozen@everydisplay +\tex_let:D \tex_everymath:D \frozen@everymath +\tex_let:D \tex_hyphen:D \@@hyph +\tex_let:D \tex_input:D \@@input +\tex_let:D \tex_italic_correction:D \@@italiccorr +\tex_let:D \tex_underline:D \@@underline +\tex_let:D \luatex_catcodetable:D \luatexcatcodetable +\tex_let:D \luatex_initcatcodetable:D \luatexinitcatcodetable +\tex_let:D \luatex_latelua:D \luatexlatelua +\tex_let:D \luatex_savecatcodetable:D \luatexsavecatcodetable +%% +%% +%% End of file `l3names.sty'. diff --git a/Master/texmf-dist/tex/latex/l3kernel/l3prg.sty b/Master/texmf-dist/tex/latex/l3kernel/l3prg.sty new file mode 100644 index 00000000000..4a20c040547 --- /dev/null +++ b/Master/texmf-dist/tex/latex/l3kernel/l3prg.sty @@ -0,0 +1,563 @@ +%% +%% This is file `l3prg.sty', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% l3prg.dtx (with options: `package') +%% +%% EXPERIMENTAL CODE +%% +%% Do not distribute this file without also distributing the +%% source files specified above. +%% +%% Do not distribute a modified version of this file. +%% +%% File: l3prg.dtx Copyright (C) 2005-2011 The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +\RequirePackage{l3names} +\GetIdInfo$Id: l3prg.dtx 2495 2011-07-06 16:57:08Z bruno $ + {L3 Experimental control structures} +%% +\ProvidesExplPackage + {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +\package_check_loaded_expl: +\cs_new_protected_nopar:Npn \bool_new:N #1 { \cs_new_eq:NN #1 \c_false_bool } +\cs_generate_variant:Nn \bool_new:N { c } +\cs_new_protected_nopar:Npn \bool_set_true:N #1 + { \cs_set_eq:NN #1 \c_true_bool } +\cs_new_protected_nopar:Npn \bool_set_false:N #1 + { \cs_set_eq:NN #1 \c_false_bool } +\cs_new_protected_nopar:Npn \bool_gset_true:N #1 + { \cs_gset_eq:NN #1 \c_true_bool } +\cs_new_protected_nopar:Npn \bool_gset_false:N #1 + { \cs_gset_eq:NN #1 \c_false_bool } +\cs_generate_variant:Nn \bool_set_true:N { c } +\cs_generate_variant:Nn \bool_set_false:N { c } +\cs_generate_variant:Nn \bool_gset_true:N { c } +\cs_generate_variant:Nn \bool_gset_false:N { c } +\cs_new_eq:NN \bool_set_eq:NN \cs_set_eq:NN +\cs_new_eq:NN \bool_set_eq:Nc \cs_set_eq:Nc +\cs_new_eq:NN \bool_set_eq:cN \cs_set_eq:cN +\cs_new_eq:NN \bool_set_eq:cc \cs_set_eq:cc +\cs_new_eq:NN \bool_gset_eq:NN \cs_gset_eq:NN +\cs_new_eq:NN \bool_gset_eq:Nc \cs_gset_eq:Nc +\cs_new_eq:NN \bool_gset_eq:cN \cs_gset_eq:cN +\cs_new_eq:NN \bool_gset_eq:cc \cs_gset_eq:cc +\cs_new:Npn \bool_set:Nn #1#2 + { \tex_chardef:D #1 = \bool_if_p:n {#2} } +\cs_new:Npn \bool_gset:Nn #1#2 + { \tex_global:D \tex_chardef:D #1 = \bool_if_p:n {#2} } +\cs_generate_variant:Nn \bool_set:Nn { c } +\cs_generate_variant:Nn \bool_gset:Nn { c } +\prg_new_conditional:Npnn \bool_if:N #1 { p , T , F , TF } + { + \if_bool:N #1 + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +\cs_generate_variant:Nn \bool_if_p:N { c } +\cs_generate_variant:Nn \bool_if:NT { c } +\cs_generate_variant:Nn \bool_if:NF { c } +\cs_generate_variant:Nn \bool_if:NTF { c } +\bool_new:N \l_tmpa_bool +\bool_new:N \g_tmpa_bool +\prg_new_conditional:Npnn \bool_if:n #1 { T , F , TF } + { + \if_predicate:w \bool_if_p:n {#1} + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +\cs_new:Npn \bool_if_p:n #1 + { + \group_align_safe_begin: + \bool_get_next:N ( #1 ) S + } +\cs_new:Npn \bool_get_next:N #1 + { + \use:c + { + bool_ + \if_meaning:w !#1 ! \else: \if_meaning:w (#1 ( \else: p \fi: \fi: + :w + } + #1 + } +\cs_new:Npn \bool_get_not_next:N #1 + { + \use:c + { + bool_not_ + \if_meaning:w !#1 ! \else: \if_meaning:w (#1 ( \else: p \fi: \fi: + :w + } + #1 + } +\cs_new:Npn \bool_get_next:NN #1#2 { \bool_get_next:N #2 } +\cs_new:Npn \bool_get_not_next:NN #1#2 { \bool_get_not_next:N #2 } +\cs_new:cpn { bool_!:w } #1#2 + { + \if_meaning:w ( #2 + \exp_after:wN \bool_Not:w + \else: + \if_meaning:w ! #2 + \exp_after:wN \exp_after:wN \exp_after:wN \bool_get_next:NN + \else: + \exp_after:wN \exp_after:wN \exp_after:wN \bool_Not:N + \fi: + \fi: + #2 + } +\cs_new:cpn { bool_not_!:w } #1#2 + { + \if_meaning:w ( #2 + \exp_after:wN \bool_not_Not:w + \else: + \if_meaning:w ! #2 + \exp_after:wN \exp_after:wN \exp_after:wN \bool_get_not_next:NN + \else: + \exp_after:wN \exp_after:wN \exp_after:wN \bool_not_Not:N + \fi: + \fi: + #2 + } +\cs_new:Npn \bool_Not:w { \exp_after:wN \int_value:w \bool_get_not_next:N } +\cs_new:Npn \bool_not_Not:w { \exp_after:wN \int_value:w \bool_get_next:N } +\cs_new:Npn \bool_Not:N #1 + { + \exp_after:wN \bool_p:w + \if_meaning:w #1 \c_true_bool + \c_false_bool + \else: + \c_true_bool + \fi: + } +\cs_new:Npn \bool_not_Not:N #1 + { + \exp_after:wN \bool_p:w + \if_meaning:w #1 \c_true_bool + \c_true_bool + \else: + \c_false_bool + \fi: + } +\cs_new:cpn { bool_(:w } #1 + { \exp_after:wN \bool_cleanup:N \int_value:w \bool_get_next:N } +\cs_new:cpn { bool_not_(:w } #1 + { \exp_after:wN \bool_not_cleanup:N \int_value:w \bool_get_next:N } +\cs_new:cpn { bool_p:w } { \exp_after:wN \bool_cleanup:N \int_value:w } +\cs_new:cpn { bool_not_p:w } {\exp_after:wN \bool_not_cleanup:N \int_value:w } +\cs_new:Npn \bool_cleanup:N #1 + { + \exp_after:wN \bool_choose:NN \exp_after:wN #1 + \int_to_roman:w - `\q + } +\cs_new:Npn \bool_not_cleanup:N #1 + { + \exp_after:wN \bool_not_choose:NN \exp_after:wN #1 + \int_to_roman:w - `\q + } +\cs_new_nopar:Npn \bool_choose:NN #1#2 { \use:c { bool_ #2 _ #1 :w } } +\cs_new_nopar:Npn \bool_not_choose:NN #1#2 { \use:c { bool_not_ #2 _ #1 :w } } +\cs_new_nopar:cpn { bool_&_1:w } & { \bool_get_next:N } +\cs_new_nopar:cpn { bool_|_0:w } | { \bool_get_next:N } +\cs_new_nopar:cpn { bool_not_&_0:w } & { \bool_get_next:N } +\cs_new_nopar:cpn { bool_not_|_1:w } | { \bool_get_next:N } +\cs_new_nopar:cpn { bool_)_0:w } { \c_false_bool } +\cs_new_nopar:cpn { bool_)_1:w } { \c_true_bool } +\cs_new_nopar:cpn { bool_not_)_0:w } { \c_true_bool } +\cs_new_nopar:cpn { bool_not_)_1:w } { \c_false_bool } +\cs_new_nopar:cpn { bool_S_0:w } { \group_align_safe_end: \c_false_bool } +\cs_new_nopar:cpn { bool_S_1:w } { \group_align_safe_end: \c_true_bool } +\cs_new_nopar:cpn { bool_&_0:w } & { \bool_eval_skip_to_end:Nw \c_false_bool } +\cs_new_nopar:cpn { bool_|_1:w } | { \bool_eval_skip_to_end:Nw \c_true_bool } +\cs_new_nopar:cpn { bool_not_&_1:w } & + { \bool_eval_skip_to_end:Nw \c_false_bool } +\cs_new_nopar:cpn { bool_not_|_0:w } | + { \bool_eval_skip_to_end:Nw \c_true_bool } +%% ( +\cs_new:Npn \bool_eval_skip_to_end:Nw #1#2 ) + { + \bool_eval_skip_to_end_aux:Nw #1#2 ( % ) + \q_no_value \q_stop + {#2} + } +\cs_new:Npn \bool_eval_skip_to_end_aux:Nw #1#2 ( #3#4 \q_stop #5 % ) + { + \quark_if_no_value:NTF #3 + {#1} + { \bool_eval_skip_to_end_aux_ii:Nw #1 #5 } + } +\cs_new:Npn \bool_eval_skip_to_end_aux_ii:Nw #1#2 ( #3 ) + { % ( + \bool_eval_skip_to_end:Nw #1#3 ) + } +\cs_new:Npn \bool_not_p:n #1 { \bool_if_p:n { ! ( #1 ) } } +\cs_new:Npn \bool_xor_p:nn #1#2 + { + \int_compare:nNnTF { \bool_if_p:n {#1} } = { \bool_if_p:n {#2} } + \c_false_bool + \c_true_bool + } +\cs_new:Npn \bool_while_do:Nn #1#2 + { \bool_if:NT #1 { #2 \bool_while_do:Nn #1 {#2} } } +\cs_new:Npn \bool_until_do:Nn #1#2 + { \bool_if:NF #1 { #2 \bool_until_do:Nn #1 {#2} } } +\cs_generate_variant:Nn \bool_while_do:Nn { c } +\cs_generate_variant:Nn \bool_until_do:Nn { c } +\cs_new:Npn \bool_do_while:Nn #1#2 + { #2 \bool_if:NT #1 { \bool_do_while:Nn #1 {#2} } } +\cs_new:Npn \bool_do_until:Nn #1#2 + { #2 \bool_if:NF #1 { \bool_do_until:Nn #1 {#2} } } +\cs_generate_variant:Nn \bool_do_while:Nn { c } +\cs_generate_variant:Nn \bool_do_until:Nn { c } +\cs_new:Npn \bool_while_do:nn #1#2 + { + \bool_if:nT {#1} + { + #2 + \bool_while_do:nn {#1} {#2} + } + } +\cs_new:Npn \bool_do_while:nn #1#2 + { + #2 + \bool_if:nT {#1} { \bool_do_while:nn {#1} {#2} } + } +\cs_new:Npn \bool_until_do:nn #1#2 + { + \bool_if:nF {#1} + { + #2 + \bool_until_do:nn {#1} {#2} + } + } +\cs_new:Npn \bool_do_until:nn #1#2 + { + #2 + \bool_if:nF {#1} { \bool_do_until:nn {#1} {#2} } + } +\cs_new_eq:NN \prg_case_end:nw \use_i_delimit_by_q_recursion_stop:nw +\cs_new:Npn \prg_case_int:nnn #1 + { \exp_args:Nf \prg_case_int_aux:nnn { \int_eval:n {#1} } } +\cs_new:Npn \prg_case_int_aux:nnn #1 #2 #3 + { \prg_case_int_aux:nw {#1} #2 {#1} {#3} \q_recursion_stop } +\cs_new:Npn \prg_case_int_aux:nw #1#2#3 + { + \int_compare:nNnTF {#1} = {#2} + { \prg_case_end:nw {#3} } + { \prg_case_int_aux:nw {#1} } + } +\cs_new:Npn \prg_case_dim:nnn #1 + { \exp_args:Nf \prg_case_dim_aux:nnn { \dim_eval:n {#1} } } +\cs_new:Npn \prg_case_dim_aux:nnn #1 #2 #3 + { \prg_case_dim_aux:nw {#1} #2 {#1} {#3} \q_recursion_stop } +\cs_new:Npn \prg_case_dim_aux:nw #1#2#3 + { + \dim_compare:nNnTF {#1} = {#2} + { \prg_case_end:nw {#3} } + { \prg_case_dim_aux:nw {#1} } + } +\cs_new:Npn \prg_case_str:nnn #1#2#3 + { \prg_case_str_aux:nw {#1} #2 {#1} {#3} \q_recursion_stop } +\cs_new:Npn \prg_case_str_aux:nw #1#2#3 + { + \str_if_eq:nnTF {#1} {#2} + { \prg_case_end:nw {#3} } + { \prg_case_str_aux:nw {#1} } + } +\cs_generate_variant:Nn \prg_case_str:nnn { o } +\cs_new:Npn \prg_case_str:xxn #1#2#3 + { \prg_case_str_x_aux:nw {#1} #2 {#1} {#3} \q_recursion_stop } +\cs_new:Npn \prg_case_str_x_aux:nw #1#2#3 + { + \str_if_eq:xxTF {#1} {#2} + { \prg_case_end:nw {#3} } + { \prg_case_str_aux:nw {#1} } + } +\cs_new:Npn \prg_case_tl:Nnn #1#2#3 + { \prg_case_tl_aux:Nw #1 #2 #1 {#3} \q_recursion_stop } +\cs_new:Npn \prg_case_tl_aux:Nw #1#2#3 + { + \tl_if_eq:NNTF #1 #2 + { \prg_case_end:nw {#3} } + { \prg_case_tl_aux:Nw #1 } + } +\cs_generate_variant:Nn \prg_case_tl:Nnn { c } +\cs_new_nopar:Npn \prg_replicate:nn #1 + { + \int_to_roman:w + \exp_after:wN \prg_replicate_first_aux:N + \int_value:w \int_eval:w #1 \int_eval_end: + \cs_end: + } +\cs_new_nopar:Npn \prg_replicate_aux:N #1 + { \cs:w prg_replicate_#1 :n \prg_replicate_aux:N } +\cs_new_nopar:Npn \prg_replicate_first_aux:N #1 + { \cs:w prg_replicate_first_ #1 :n \prg_replicate_aux:N } +\cs_new_nopar:Npn \prg_replicate_ :n #1 { \cs_end: } +\cs_new:cpn { prg_replicate_0:n } #1 { \cs_end: {#1#1#1#1#1#1#1#1#1#1} } +\cs_new:cpn { prg_replicate_1:n } #1 { \cs_end: {#1#1#1#1#1#1#1#1#1#1} #1 } +\cs_new:cpn { prg_replicate_2:n } #1 { \cs_end: {#1#1#1#1#1#1#1#1#1#1} #1#1 } +\cs_new:cpn { prg_replicate_3:n } #1 + { \cs_end: {#1#1#1#1#1#1#1#1#1#1} #1#1#1 } +\cs_new:cpn { prg_replicate_4:n } #1 + { \cs_end: {#1#1#1#1#1#1#1#1#1#1} #1#1#1#1 } +\cs_new:cpn { prg_replicate_5:n } #1 + { \cs_end: {#1#1#1#1#1#1#1#1#1#1} #1#1#1#1#1 } +\cs_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 } +\cs_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 } +\cs_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 } +\cs_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 } +\cs_new:cpn { prg_replicate_first_-:n } #1 { \c_zero \negative_replication } +\cs_new:cpn { prg_replicate_first_0:n } #1 { \c_zero } +\cs_new:cpn { prg_replicate_first_1:n } #1 { \c_zero #1 } +\cs_new:cpn { prg_replicate_first_2:n } #1 { \c_zero #1#1 } +\cs_new:cpn { prg_replicate_first_3:n } #1 { \c_zero #1#1#1 } +\cs_new:cpn { prg_replicate_first_4:n } #1 { \c_zero #1#1#1#1 } +\cs_new:cpn { prg_replicate_first_5:n } #1 { \c_zero #1#1#1#1#1 } +\cs_new:cpn { prg_replicate_first_6:n } #1 { \c_zero #1#1#1#1#1#1 } +\cs_new:cpn { prg_replicate_first_7:n } #1 { \c_zero #1#1#1#1#1#1#1 } +\cs_new:cpn { prg_replicate_first_8:n } #1 { \c_zero #1#1#1#1#1#1#1#1 } +\cs_new:cpn { prg_replicate_first_9:n } #1 { \c_zero #1#1#1#1#1#1#1#1#1 } +\cs_new:Npn \prg_stepwise_function:nnnN #1#2 + { + \int_compare:nNnTF {#2} > { 0 } + { \exp_args:Nf \prg_stepwise_function_incr:nnnN } + { \exp_args:Nf \prg_stepwise_function_decr:nnnN } + { \int_eval:n {#1} } {#2} + } +\cs_new:Npn \prg_stepwise_function_incr:nnnN #1#2#3#4 + { + \int_compare:nNnF {#1} > {#3} + { + #4 {#1} + \exp_args:Nf \prg_stepwise_function_incr:nnnN + { \int_eval:n { #1 + #2 } } {#2} {#3} #4 + } + } +\cs_new:Npn \prg_stepwise_function_decr:nnnN #1#2#3#4 + { + \int_compare:nNnF {#1} < {#3} + { + #4 {#1} + \exp_args:Nf \prg_stepwise_function_decr:nnnN + { \int_eval:n { #1 + #2 } } {#2} {#3} #4 + } + } +\int_new:N \g_prg_stepwise_level_int +\cs_new_protected:Npn \prg_stepwise_inline:nnnn #1#2#3#4 + { + \int_gincr:N \g_prg_stepwise_level_int + \cs_gset_nopar:cpn + { g_prg_stepwise_ \int_use:N \g_prg_stepwise_level_int :n } + ##1 {#4} + \int_compare:nNnTF {#2} > { 0 } + { \exp_args:Ncf \prg_stepwise_inline_incr:Nnnn } + { \exp_args:Ncf \prg_stepwise_inline_decr:Nnnn } + { g_prg_stepwise_ \int_use:N \g_prg_stepwise_level_int :n } + { \int_eval:n {#1} } {#2} {#3} + \int_gdecr:N \g_prg_stepwise_level_int + } +\cs_new_protected:Npn \prg_stepwise_inline_incr:Nnnn #1#2#3#4 + { + \int_compare:nNnF {#2} > {#4} + { + #1 {#2} + \exp_args:NNf \prg_stepwise_inline_incr:Nnnn #1 + { \int_eval:n { #2 + #3 } } {#3} {#4} + } + } +\cs_new_protected:Npn \prg_stepwise_inline_decr:Nnnn #1#2#3#4 + { + \int_compare:nNnF {#2} < {#4} + { + #1 {#2} + \exp_args:NNf \prg_stepwise_inline_decr:Nnnn #1 + { \int_eval:n { #2 + #3 } } {#3} {#4} + } + } +\cs_new_protected:Npn \prg_stepwise_variable:nnnNn #1#2#3#4#5 + { + \prg_stepwise_inline:nnnn {#1} {#2} {#3} + { + \tl_set:Nn #4 {##1} + #5 + } + } +\prg_new_conditional:Npnn \mode_if_vertical: { p , T , F , TF } + { \if_mode_vertical: \prg_return_true: \else: \prg_return_false: \fi: } +\prg_new_conditional:Npnn \mode_if_horizontal: { p , T , F , TF } + { \if_mode_horizontal: \prg_return_true: \else: \prg_return_false: \fi: } +\prg_new_conditional:Npnn \mode_if_inner: { p , T , F , TF } + { \if_mode_inner: \prg_return_true: \else: \prg_return_false: \fi: } +\prg_new_conditional:Npnn \mode_if_math: { p , T , F , TF } + { + \scan_align_safe_stop: + \if_mode_math: \prg_return_true: \else: \prg_return_false: \fi: + } +\cs_new_nopar:Npn \group_align_safe_begin: + { \if_false: { \fi: \if_int_compare:w `} = \c_zero \fi: } +\cs_new_nopar:Npn \group_align_safe_end: + { \if_int_compare:w `{ = \c_zero } \fi: } +\cs_new_nopar:Npn \scan_align_safe_stop: + { + \int_compare:nNnT \etex_currentgrouptype:D = \c_six + { + \int_compare:nNnF \etex_lastnodetype:D = \c_zero + { \int_compare:nNnF \etex_lastnodetype:D = \c_seven { \scan_stop: } } + } + } +\group_begin: + \tex_lccode:D `\& = `\g \scan_stop: + \tex_catcode:D `\& = \c_twelve +\tl_to_lowercase:n + { + \group_end: + \cs_new_nopar:Npn \prg_variable_get_scope:N #1 + { + \exp_last_unbraced:Nf \prg_variable_get_scope_aux:w + { \cs_to_str:N #1 \exp_stop_f: \q_stop } + } + \cs_new_nopar:Npn \prg_variable_get_scope_aux:w #1#2 \q_stop + { \token_if_eq_meaning:NNT & #1 { g } } + } +\group_begin: + \tex_lccode:D `\& = `\_ \scan_stop: + \tex_catcode:D `\& = \c_twelve +\tl_to_lowercase:n + { + \group_end: + \cs_new_nopar:Npn \prg_variable_get_type:N #1 + { + \exp_after:wN \prg_variable_get_type_aux:w + \token_to_str:N #1 & a \q_stop + } + \cs_new_nopar:Npn \prg_variable_get_type_aux:w #1 & #2#3 \q_stop + { + \token_if_eq_meaning:NNTF a #2 + {#1} + { \prg_variable_get_type_aux:w #2#3 \q_stop } + } + } +\cs_new_protected_nopar:Npn \prg_define_quicksort:nnn #1#2#3 { + \cs_set:cpx{#1_quicksort:n}##1{ + \exp_not:c{#1_quicksort_start_partition:w} ##1 + \exp_not:n{#2\q_nil#3\q_stop} + } + \cs_set:cpx{#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 + } + \cs_set: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}{}{} + } + \cs_set:cpx {#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}{}{} + } + \cs_set: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} + } + \cs_set:cpx {#1_quicksort_do_partition_i_braced:nnnn} ##1##2##3##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} + } + \cs_set: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} + } + \cs_set:cpx {#1_quicksort_do_partition_ii_braced:nnnn} ##1##2##3##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} + } + \cs_set:cpx {#1_quicksort_partition_less_i:nnnn} ##1##2##3##4{ + \exp_not:c{#1_quicksort_do_partition_i:nnnw}{##1}{##2}{{##4}##3}} + \cs_set:cpx {#1_quicksort_partition_less_ii:nnnn} ##1##2##3##4{ + \exp_not:c{#1_quicksort_do_partition_ii:nnnw}{##1}{##2}{##3{##4}}} + \cs_set:cpx {#1_quicksort_partition_greater_i:nnnn} ##1##2##3##4{ + \exp_not:c{#1_quicksort_do_partition_i:nnnw}{##1}{{##4}##2}{##3}} + \cs_set:cpx {#1_quicksort_partition_greater_ii:nnnn} ##1##2##3##4{ + \exp_not:c{#1_quicksort_do_partition_ii:nnnw}{##1}{##2{##4}}{##3}} + \cs_set:cpx {#1_quicksort_partition_less_i_braced:nnnn} ##1##2##3##4{ + \exp_not:c{#1_quicksort_do_partition_i_braced:nnnn}{##1}{##2}{{##4}##3}} + \cs_set:cpx {#1_quicksort_partition_less_ii_braced:nnnn} ##1##2##3##4{ + \exp_not:c{#1_quicksort_do_partition_ii_braced:nnnn}{##1}{##2}{##3{##4}}} + \cs_set:cpx {#1_quicksort_partition_greater_i_braced:nnnn} ##1##2##3##4{ + \exp_not:c{#1_quicksort_do_partition_i_braced:nnnn}{##1}{{##4}##2}{##3}} + \cs_set:cpx {#1_quicksort_partition_greater_ii_braced:nnnn} ##1##2##3##4{ + \exp_not:c{#1_quicksort_do_partition_ii_braced:nnnn}{##1}{##2{##4}}{##3}} + \cs_set: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} + } +} +\prg_define_quicksort:nnn {prg}{}{} +\cs_set:Npn \prg_quicksort_function:n {\ERROR} +\cs_set:Npn \prg_quicksort_compare:nnTF {\ERROR} +\cs_new_protected:Npn \prg_new_map_functions:Nn #1#2 { \deprectiated } +\cs_new_protected:Npn \prg_set_map_functions:Nn #1#2 { \deprectiated } +%% +%% +%% End of file `l3prg.sty'. diff --git a/Master/texmf-dist/tex/latex/l3kernel/l3prop.sty b/Master/texmf-dist/tex/latex/l3kernel/l3prop.sty new file mode 100644 index 00000000000..5d2a1ff69d0 --- /dev/null +++ b/Master/texmf-dist/tex/latex/l3kernel/l3prop.sty @@ -0,0 +1,333 @@ +%% +%% This is file `l3prop.sty', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% l3prop.dtx (with options: `package') +%% +%% EXPERIMENTAL CODE +%% +%% Do not distribute this file without also distributing the +%% source files specified above. +%% +%% Do not distribute a modified version of this file. +%% +%% File: l3prop.dtx Copyright (C) 1990-2011 The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +\RequirePackage{l3names} +\GetIdInfo$Id: l3prop.dtx 2478 2011-06-19 21:34:23Z joseph $ + {L3 Experimental property lists} +\ProvidesExplPackage + {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +\package_check_loaded_expl: +\quark_new:N \q_prop +\tl_const:Nn \c_empty_prop { \q_prop } +\cs_new_protected:Npn \prop_new:N #1 { \cs_new_eq:NN #1 \c_empty_prop } +\cs_new_protected:Npn \prop_new:c #1 { \cs_new_eq:cN {#1} \c_empty_prop } +\cs_new_protected:Npn \prop_clear:N #1 { \cs_set_eq:NN #1 \c_empty_prop } +\cs_new_protected:Npn \prop_clear:c #1 { \cs_set_eq:cN {#1} \c_empty_prop } +\cs_new_protected:Npn \prop_gclear:N #1 { \cs_gset_eq:NN #1 \c_empty_prop } +\cs_new_protected:Npn \prop_gclear:c #1 { \cs_gset_eq:cN {#1} \c_empty_prop } +\cs_new_protected:Npn \prop_clear_new:N #1 + { \cs_if_exist:NTF #1 { \prop_clear:N #1 } { \prop_new:N #1 } } +\cs_generate_variant:Nn \prop_clear_new:N {c} +\cs_new_protected:Npn \prop_gclear_new:N #1 + { \cs_if_exist:NTF #1 { \prop_gclear:N #1 } { \prop_new:N #1 } } +\cs_new_eq:NN \prop_gclear_new:c \prop_gclear:c +\cs_new_eq:NN \prop_set_eq:NN \tl_set_eq:NN +\cs_new_eq:NN \prop_set_eq:Nc \tl_set_eq:Nc +\cs_new_eq:NN \prop_set_eq:cN \tl_set_eq:cN +\cs_new_eq:NN \prop_set_eq:cc \tl_set_eq:cc +\cs_new_eq:NN \prop_gset_eq:NN \tl_gset_eq:NN +\cs_new_eq:NN \prop_gset_eq:Nc \tl_gset_eq:Nc +\cs_new_eq:NN \prop_gset_eq:cN \tl_gset_eq:cN +\cs_new_eq:NN \prop_gset_eq:cc \tl_gset_eq:cc +\cs_set_protected:Npn \prop_split:NnTF #1#2 + { \exp_args:NNo \prop_split_aux:NnTF #1 { \tl_to_str:n {#2} } } +\cs_new_protected:Npn \prop_split_aux:NnTF #1#2 + { + \cs_set_protected:Npn \prop_split_aux:w + ##1 \q_prop #2 \q_prop ##2 ##3 ##4 \q_mark ##5 \q_stop + { \prop_split_aux:nnnn ##3 { {##1 \q_prop } {##2} {##4} } } + \exp_after:wN \prop_split_aux:w #1 \q_mark + \q_prop #2 \q_prop { } { ? \use_ii:nn { } } \q_mark \q_stop + } +\cs_new:Npn \prop_split_aux:nnnn #1#2#3#4 { #3 #2 } +\cs_new_protected:Npn \prop_split_aux:w { } +\cs_set_protected:Npn \prop_split:Nnn #1#2#3 + { + \prop_split:NnTF #1 {#2} + {#3} + { \exp_args:Nno \use:n {#3} {#1} { \q_no_value } { } } + } +\cs_new_protected:Npn \prop_del:Nn #1#2 + { \prop_split:NnTF #1 {#2} { \prop_del_aux:NNnnn \tl_set:Nn #1 } { } } +\cs_new_protected:Npn \prop_gdel:Nn #1#2 + { \prop_split:NnTF #1 {#2} { \prop_del_aux:NNnnn \tl_gset:Nn #1 } { } } +\cs_new_protected:Npn \prop_del_aux:NNnnn #1#2#3#4#5 + { #1 #2 { #3 #5 } } +\cs_generate_variant:Nn \prop_del:Nn { NV } +\cs_generate_variant:Nn \prop_del:Nn { c , cV } +\cs_generate_variant:Nn \prop_gdel:Nn { NV } +\cs_generate_variant:Nn \prop_gdel:Nn { c , cV } +\cs_new_protected:Npn \prop_get:NnN #1#2#3 + { + \prop_split:NnTF #1 {#2} + { \prop_get_aux:Nnnn #3 } + { \tl_set:Nn #3 { \q_no_value } } + } +\cs_new_protected:Npn \prop_get_aux:Nnnn #1#2#3#4 + { \tl_set:Nn #1 {#3} } +\cs_generate_variant:Nn \prop_get:NnN { NV , No } +\cs_generate_variant:Nn \prop_get:NnN { c , cV , co } +\cs_new_protected:Npn \prop_pop:NnN #1#2#3 + { + \prop_split:NnTF #1 {#2} + { \prop_pop_aux:NNNnnn \tl_set:Nn #1 #3 } + { \tl_set:Nn #3 { \q_no_value } } + } +\cs_new_protected:Npn \prop_gpop:NnN #1#2#3 + { + \prop_split:NnTF #1 {#2} + { \prop_pop_aux:NNNnnn \tl_gset:Nn #1 #3 } + { \tl_set:Nn #3 { \q_no_value } } + } +\cs_new_protected:Npn \prop_pop_aux:NNNnnn #1#2#3#4#5#6 + { + \tl_set:Nn #3 {#5} + #1 #2 { #4 #6 } + } +\cs_generate_variant:Nn \prop_pop:NnN { No } +\cs_generate_variant:Nn \prop_pop:NnN { c , co } +\cs_generate_variant:Nn \prop_gpop:NnN { No } +\cs_generate_variant:Nn \prop_gpop:NnN { c , co } +\cs_new_protected:Npn \prop_put:Nnn { \prop_put_aux:NNnn \tl_set:Nx } +\cs_new_protected:Npn \prop_gput:Nnn { \prop_put_aux:NNnn \tl_gset:Nx } +\cs_new_protected:Npn \prop_put_aux:NNnn #1#2#3#4 + { + \prop_split:Nnn #2 {#3} { \prop_put_aux:NNnnnnn #1 #2 {#3} {#4} } + } +\cs_new_protected:Npn \prop_put_aux:NNnnnnn #1#2#3#4#5#6#7 + { + #1 #2 + { + \exp_not:n { #5 #7 } + \tl_to_str:n {#3} \exp_not:n { \q_prop {#4} \q_prop } + } + } +\cs_generate_variant:Nn \prop_put:Nnn + { NnV , Nno , Nnx , NV , NVV , No , Noo } +\cs_generate_variant:Nn \prop_put:Nnn + { c , cnV , cno , cnx , cV , cVV , co , coo } +\cs_generate_variant:Nn \prop_gput:Nnn + { NnV , Nno , Nnx , NV , NVV , No , Noo } +\cs_generate_variant:Nn \prop_gput:Nnn + { c , cnV , cno , cnx , cV , cVV , co , coo } +\cs_new_protected_nopar:Npn \prop_put_if_new:Nnn + { \prop_put_if_new_aux:NNnn \tl_put_right:Nx } +\cs_new_protected_nopar:Npn \prop_gput_if_new:Nnn + { \prop_put_if_new_aux:NNnn \tl_gput_right:Nx } +\cs_new_protected:Npn \prop_put_if_new_aux:NNnn #1#2#3#4 + { + \prop_split:NnTF #2 {#3} + { \use_none:nnn } + { + #1 #2 + { \tl_to_str:n {#3} \exp_not:n { \q_prop {#4} \q_prop } } + } + } +\cs_generate_variant:Nn \prop_put_if_new:Nnn { c } +\cs_generate_variant:Nn \prop_gput_if_new:Nnn { c } +\prg_new_conditional:Npnn \prop_if_empty:N #1 { p, T , F , TF } + { + \if_meaning:w #1 \c_empty_prop + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +\cs_generate_variant:Nn \prop_if_empty_p:N {c} +\cs_generate_variant:Nn \prop_if_empty:NTF {c} +\cs_generate_variant:Nn \prop_if_empty:NT {c} +\cs_generate_variant:Nn \prop_if_empty:NF {c} +\prg_new_conditional:Npnn \prop_if_in:Nn #1#2 { p , T , F , TF } + { + \exp_last_unbraced:Noo \prop_if_in_aux:nwn + { \tl_to_str:n {#2} } #1 + A \q_prop { } \q_stop + } +\cs_new:Npn \prop_if_in_aux:nwn #1 \q_prop #2 \q_prop #3 + { + \if_catcode:w A #2 + \prg_return_false: + \exp_after:wN \use_none_delimit_by_q_stop:w + \fi: + \str_if_eq:nnT {#1} {#2} + { + \prg_return_true: + \use_none_delimit_by_q_stop:w + } + \prop_if_in_aux:nwn {#1} + } +\cs_generate_variant:Nn \prop_if_in_p:Nn { NV , No } +\cs_generate_variant:Nn \prop_if_in_p:Nn { c , cV , co } +\cs_generate_variant:Nn \prop_if_in:NnT { NV , No } +\cs_generate_variant:Nn \prop_if_in:NnT { c , cV , co } +\cs_generate_variant:Nn \prop_if_in:NnF { NV , No } +\cs_generate_variant:Nn \prop_if_in:NnF { c , cV , co } +\cs_generate_variant:Nn \prop_if_in:NnTF { NV , No } +\cs_generate_variant:Nn \prop_if_in:NnTF { c , cV , co } +\cs_new_nopar:Npn \prop_map_function:NN #1#2 + { + \exp_last_unbraced:NNo \prop_map_function_aux:Nwn #2 + #1 A \q_prop { } \q_recursion_stop + } +\cs_new:Npn \prop_map_function_aux:Nwn #1 \q_prop #2 \q_prop #3 + { + \if_catcode:w A #2 + \exp_after:wN \prop_map_break: + \fi: + #1 {#2} {#3} + \prop_map_function_aux:Nwn #1 + } +\cs_generate_variant:Nn \prop_map_function:NN { Nc } +\cs_generate_variant:Nn \prop_map_function:NN { c , cc } +\int_new:N \g_prop_map_inline_int +\cs_new_protected:Npn \prop_map_inline:Nn #1#2 + { + \int_gincr:N \g_prop_map_inline_int + \cs_gset:cpn { prop_map_inline_ \int_use:N \g_prop_map_inline_int :nn } + ##1##2 {#2} + \prop_map_function:Nc #1 + { prop_map_inline_ \int_use:N \g_prop_map_inline_int :nn } + \int_gdecr:N \g_prop_map_inline_int + } +\cs_generate_variant:Nn \prop_map_inline:Nn { c } +\cs_new_eq:NN \prop_map_break: \use_none_delimit_by_q_recursion_stop:w +\cs_new_eq:NN \prop_map_break:n \use_i_delimit_by_q_recursion_stop:nw +\tl_new:N \l_prop_show_tl +\cs_new_protected_nopar:Npn \prop_show:N #1 + { + \prop_if_empty:NTF #1 + { + \iow_term:x { Property~list~\token_to_str:N #1 \c_space_tl is~empty } + \tl_show:n { } + } + { + \iow_term:x + { + Property~list~\token_to_str:N #1 \c_space_tl + contains~the~pairs~(without~outer~braces): + } + \tl_set:Nx \l_prop_show_tl + { \prop_map_function:NN #1 \prop_show_aux:nn } + \tl_show:n \exp_after:wN \exp_after:wN \exp_after:wN + { \exp_after:wN \prop_show_aux:w \l_prop_show_tl } + } + } +\cs_new:Npn \prop_show_aux:nn #1#2 + { + \iow_newline: > \c_space_tl \c_space_tl + \iow_char:N \{ #1 \iow_char:N \} + \c_space_tl \c_space_tl => \c_space_tl \c_space_tl + \iow_char:N \{ \exp_not:n {#2} \iow_char:N \} + } +\cs_new:Npn \prop_show_aux:w #1 > ~ { } +\cs_generate_variant:Nn \prop_show:N { c } +\prg_new_protected_conditional:Npnn \prop_get:NnN #1#2#3 { T , F , TF } + { + \prop_split:NnTF #1 {#2} + { \prop_get_aux_true:Nnnn #3 } + { \prg_return_false: } + } +\cs_new_protected:Npn \prop_get_aux_true:Nnnn #1#2#3#4 + { + \tl_set:Nn #1 {#3} + \prg_return_true: + } +\prg_new_protected_conditional:Npnn \prop_pop:NnN #1#2#3 {T,F,TF} + { + \prop_split:NnTF #1 {#2} + { \prop_pop_aux_true:NNNnnn \tl_set:Nn #1 #3 } + { \prg_return_false: } + } +\prg_new_protected_conditional:Npnn \prop_gpop:NnN #1#2#3 {T,F,TF} + { + \prop_split:NnTF #1 {#2} + { \prop_pop_aux_true:NNNnnn \tl_gset:Nn #1 #3 } + { \prg_return_false: } + } +\cs_new_protected:Npn \prop_pop_aux_true:NNNnnn #1#2#3#4#5#6 + { + \tl_set:Nn #3 {#5} + #1 #2 { #4 #6 } + \prg_return_true: + } +\cs_new:Npn \prop_map_tokens:Nn #1#2 + { + \exp_last_unbraced:Nno \prop_map_tokens_aux:nwn {#2} #1 + A \q_prop { } \q_recursion_stop + } +\cs_new:Npn \prop_map_tokens_aux:nwn #1 \q_prop #2 \q_prop #3 + { + \if_catcode:w A #2 + \exp_after:wN \prop_map_break: + \fi: + \use:n {#1} {#2} {#3} + \prop_map_tokens_aux:nwn {#1} + } +\cs_new:Npn \prop_get:Nn #1 #2 + { \prop_map_tokens:Nn #1 { \prop_get_aux:nnn {#2} } } +\cs_new:Npn \prop_get_aux:nnn #1 #2 #3 + { \str_if_eq:nnT {#1} {#2} { \prop_map_break:n {#3} } } +\cs_new_eq:NN \prop_display:N \prop_show:N +\cs_new_eq:NN \prop_display:c \prop_show:c +\cs_new_protected:Npn \prop_gget:NnN #1#2#3 + { \prop_split:Nnn #1 {#2} { \prop_gget_aux:Nnnn #3 } } +\cs_new_protected:Npn \prop_gget_aux:Nnnn #1#2#3#4 + { \tl_gset:Nn #1 {#3} } +\cs_generate_variant:Nn \prop_gget:NnN { NV } +\cs_generate_variant:Nn \prop_gget:NnN { c , cV } +\cs_new_eq:NN \prop_get_gdel:NnN \prop_gpop:NnN +\cs_generate_variant:Nn \prop_if_in:NnT { cc } +\cs_generate_variant:Nn \prop_if_in:NnF { cc } +\cs_generate_variant:Nn \prop_if_in:NnTF { cc } +\cs_generate_variant:Nn \prop_gput:Nnn { ccx } +\prg_new_eq_conditional:NNn \prop_if_eq:NN \tl_if_eq:NN { p , T , F , TF } +\prg_new_eq_conditional:NNn \prop_if_eq:cN \tl_if_eq:cN { p , T , F , TF } +\prg_new_eq_conditional:NNn \prop_if_eq:Nc \tl_if_eq:Nc { p , T , F , TF } +\prg_new_eq_conditional:NNn \prop_if_eq:cc \tl_if_eq:cc { p , T , F , TF } +%% +%% +%% End of file `l3prop.sty'. diff --git a/Master/texmf-dist/tex/latex/l3kernel/l3quark.sty b/Master/texmf-dist/tex/latex/l3kernel/l3quark.sty new file mode 100644 index 00000000000..35a8ca8f8e7 --- /dev/null +++ b/Master/texmf-dist/tex/latex/l3kernel/l3quark.sty @@ -0,0 +1,154 @@ +%% +%% This is file `l3quark.sty', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% l3quark.dtx (with options: `package') +%% +%% EXPERIMENTAL CODE +%% +%% Do not distribute this file without also distributing the +%% source files specified above. +%% +%% Do not distribute a modified version of this file. +%% +%% File: l3quark.dtx Copyright (C) 1990-2011 The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +\RequirePackage{l3names} +\GetIdInfo$Id: l3quark.dtx 2478 2011-06-19 21:34:23Z joseph $ + {L3 Experimental quarks} +\ProvidesExplPackage + {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +\package_check_loaded_expl: +\cs_new_protected_nopar:Npn \quark_new:N #1 { \tl_const:Nn #1 {#1} } +\quark_new:N \q_nil +\quark_new:N \q_mark +\quark_new:N \q_no_value +\quark_new:N \q_stop +\quark_new:N \q_recursion_tail +\quark_new:N \q_recursion_stop +\cs_new:Npn \quark_if_recursion_tail_stop:N #1 + { + \if_meaning:w #1 \q_recursion_tail + \exp_after:wN \use_none_delimit_by_q_recursion_stop:w + \fi: + } +\cs_new:Npn \quark_if_recursion_tail_stop_do:Nn #1#2 + { + \if_meaning:w #1 \q_recursion_tail + \exp_after:wN \use_i_delimit_by_q_recursion_stop:nw + \else: + \exp_after:wN \use_none:n + \fi: + {#2} + } +\cs_new:Npn \quark_if_recursion_tail_stop:n #1 + { + \if_catcode:w + A + \etex_detokenize:D \exp_after:wN + { + \quark_if_recursion_tail_aux:w #1 \q_recursion_stop + \q_recursion_tail \q_recursion_stop \q_stop + } + A + \exp_after:wN \use_none_delimit_by_q_recursion_stop:w + \fi: + } +\cs_new:Npn \quark_if_recursion_tail_stop_do:nn #1#2 + { + \if_catcode:w + A + \etex_detokenize:D \exp_after:wN + { + \quark_if_recursion_tail_aux:w #1 \q_recursion_stop + \q_recursion_tail \q_recursion_stop \q_stop + } + A + \exp_after:wN \use_i_delimit_by_q_recursion_stop:nw + \else: + \exp_after:wN \use_none:n + \fi: + {#2} + } +\cs_new:Npn \quark_if_recursion_tail_aux:w + #1 \q_recursion_tail #2 \q_recursion_stop #3 \q_stop + { #1 #2 } +\cs_generate_variant:Nn \quark_if_recursion_tail_stop:n { o } +\cs_generate_variant:Nn \quark_if_recursion_tail_stop_do:nn { o } +\prg_new_conditional:Nnn \quark_if_nil:N { p, T , F , TF } + { + \if_meaning:w \q_nil #1 + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +\prg_new_conditional:Nnn \quark_if_no_value:N { p, T , F , TF } + { + \if_meaning:w \q_no_value #1 + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +\cs_generate_variant:Nn \quark_if_no_value_p:N { c } +\cs_generate_variant:Nn \quark_if_no_value:NT { c } +\cs_generate_variant:Nn \quark_if_no_value:NF { c } +\cs_generate_variant:Nn \quark_if_no_value:NTF { c } +\prg_new_conditional:Nnn \quark_if_nil:n { p, T , F , TF } + { + \if_int_compare:w \pdftex_strcmp:D + { \exp_not:N \q_nil } { \exp_not:n {#1} } = \c_zero + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +\prg_new_conditional:Nnn \quark_if_no_value:n { p, T , F , TF } + { + \if_int_compare:w \pdftex_strcmp:D + { \exp_not:N \q_no_value } { \exp_not:n {#1} } = \c_zero + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +\cs_generate_variant:Nn \quark_if_nil_p:n { V , o } +\cs_generate_variant:Nn \quark_if_nil:nTF { V , o } +\cs_generate_variant:Nn \quark_if_nil:nT { V , o } +\cs_generate_variant:Nn \quark_if_nil:nF { V , o } +%% +%% +%% End of file `l3quark.sty'. diff --git a/Master/texmf-dist/tex/latex/l3kernel/l3seq.sty b/Master/texmf-dist/tex/latex/l3kernel/l3seq.sty new file mode 100644 index 00000000000..13136da4828 --- /dev/null +++ b/Master/texmf-dist/tex/latex/l3kernel/l3seq.sty @@ -0,0 +1,531 @@ +%% +%% This is file `l3seq.sty', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% l3seq.dtx (with options: `package') +%% +%% EXPERIMENTAL CODE +%% +%% Do not distribute this file without also distributing the +%% source files specified above. +%% +%% Do not distribute a modified version of this file. +%% +%% File: l3seq.dtx Copyright (C) 1990-2011 The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +\RequirePackage{l3names} +\GetIdInfo$Id: l3seq.dtx 2478 2011-06-19 21:34:23Z joseph $ + {L3 Experimental sequences and stacks} +\ProvidesExplPackage + {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +\package_check_loaded_expl: +\cs_new:Npn \seq_item:n + { + \seq_use_error: + \use_none:n + } +\tl_new:N \l_seq_tmpa_tl +\tl_new:N \l_seq_tmpb_tl +\cs_new_eq:NN \seq_new:N \tl_new:N +\cs_new_eq:NN \seq_new:c \tl_new:c +\cs_new_eq:NN \seq_clear:N \tl_clear:N +\cs_new_eq:NN \seq_clear:c \tl_clear:c +\cs_new_eq:NN \seq_gclear:N \tl_gclear:N +\cs_new_eq:NN \seq_gclear:c \tl_gclear:c +\cs_new_eq:NN \seq_clear_new:N \tl_clear_new:N +\cs_new_eq:NN \seq_clear_new:c \tl_clear_new:c +\cs_new_eq:NN \seq_gclear_new:N \tl_gclear_new:N +\cs_new_eq:NN \seq_gclear_new:c \tl_gclear_new:c +\cs_new_eq:NN \seq_set_eq:NN \tl_set_eq:NN +\cs_new_eq:NN \seq_set_eq:Nc \tl_set_eq:Nc +\cs_new_eq:NN \seq_set_eq:cN \tl_set_eq:cN +\cs_new_eq:NN \seq_set_eq:cc \tl_set_eq:cc +\cs_new_eq:NN \seq_gset_eq:NN \tl_gset_eq:NN +\cs_new_eq:NN \seq_gset_eq:Nc \tl_gset_eq:Nc +\cs_new_eq:NN \seq_gset_eq:cN \tl_gset_eq:cN +\cs_new_eq:NN \seq_gset_eq:cc \tl_gset_eq:cc +\cs_new_protected_nopar:Npn \seq_concat:NNN #1#2#3 + { \tl_set:Nx #1 { \exp_not:o {#2} \exp_not:o {#3} } } +\cs_new_protected_nopar:Npn \seq_gconcat:NNN #1#2#3 + { \tl_gset:Nx #1 { \exp_not:o {#2} \exp_not:o {#3} } } +\cs_generate_variant:Nn \seq_concat:NNN { ccc } +\cs_generate_variant:Nn \seq_gconcat:NNN { ccc } +\cs_new_protected:Npn \seq_put_left:Nn #1#2 + { \tl_put_left:Nn #1 { \seq_item:n {#2} } } +\cs_new_protected:Npn \seq_put_right:Nn #1#2 + { \tl_put_right:Nn #1 { \seq_item:n {#2} } } +\cs_generate_variant:Nn \seq_put_left:Nn { NV , Nv , No , Nx } +\cs_generate_variant:Nn \seq_put_left:Nn { c , cV , cv , co , cx } +\cs_generate_variant:Nn \seq_put_right:Nn { NV , Nv , No , Nx } +\cs_generate_variant:Nn \seq_put_right:Nn { c , cV , cv , co , cx } +\cs_new_protected:Npn \seq_gput_left:Nn #1#2 + { \tl_gput_left:Nn #1 { \seq_item:n {#2} } } +\cs_new_protected:Npn \seq_gput_right:Nn #1#2 + { \tl_gput_right:Nn #1 { \seq_item:n {#2} } } +\cs_generate_variant:Nn \seq_gput_left:Nn { NV , Nv , No , Nx } +\cs_generate_variant:Nn \seq_gput_left:Nn { c , cV , cv , co , cx } +\cs_generate_variant:Nn \seq_gput_right:Nn { NV , Nv , No , Nx } +\cs_generate_variant:Nn \seq_gput_right:Nn { c , cV , cv , co , cx } +\seq_new:N \l_seq_remove_seq +\cs_new_protected:Npn \seq_remove_duplicates:N + { \seq_remove_duplicates_aux:NN \seq_set_eq:NN } +\cs_new_protected:Npn \seq_gremove_duplicates:N + { \seq_remove_duplicates_aux:NN \seq_gset_eq:NN } +\cs_new_protected:Npn \seq_remove_duplicates_aux:NN #1#2 + { + \seq_clear:N \l_seq_remove_seq + \seq_map_inline:Nn #2 + { + \seq_if_in:NnF \l_seq_remove_seq {##1} + { \seq_put_right:Nn \l_seq_remove_seq {##1} } + } + #1 #2 \l_seq_remove_seq + } +\cs_generate_variant:Nn \seq_remove_duplicates:N { c } +\cs_generate_variant:Nn \seq_gremove_duplicates:N { c } +\cs_new_protected:Npn \seq_remove_all:Nn + { \seq_remove_all_aux:NNn \tl_set:Nx } +\cs_new_protected:Npn \seq_gremove_all:Nn + { \seq_remove_all_aux:NNn \tl_gset:Nx } +\cs_new_protected:Npn \seq_remove_all_aux:NNn #1#2#3 + { + \seq_push_item_def:n + { + \str_if_eq:nnT {##1} {#3} + { + \if_false: { \fi: } + \tl_set:Nn \l_seq_tmpb_tl {##1} + #1 #2 + { \if_false: } \fi: + \exp_not:o {#2} + \tl_if_eq:NNT \l_seq_tmpa_tl \l_seq_tmpb_tl + { \use_none:nn } + } + \exp_not:n { \seq_item:n {##1} } + } + \tl_set:Nn \l_seq_tmpa_tl {#3} + #1 #2 {#2} + \seq_pop_item_def: + } +\cs_generate_variant:Nn \seq_remove_all:Nn { c } +\cs_generate_variant:Nn \seq_gremove_all:Nn { c } +\prg_new_eq_conditional:NNn \seq_if_empty:N \tl_if_empty:N + { p , T , F , TF } +\prg_new_eq_conditional:NNn \seq_if_empty:c \tl_if_empty:c + { p , T , F , TF } +\prg_new_protected_conditional:Npnn \seq_if_in:Nn #1#2 + { T , F , TF } + { + \group_begin: + \tl_set:Nn \l_seq_tmpa_tl {#2} + \cs_set_protected:Npn \seq_item:n ##1 + { + \tl_set:Nn \l_seq_tmpb_tl {##1} + \if_meaning:w \l_seq_tmpa_tl \l_seq_tmpb_tl + \exp_after:wN \seq_if_in_aux: + \fi: + } + #1 + \seq_break:n { \prg_return_false: } + \seq_break_point:n { \group_end: } + } +\cs_new_nopar:Npn \seq_if_in_aux: { \seq_break:n { \prg_return_true: } } +\cs_generate_variant:Nn \seq_if_in:NnT { NV , Nv , No , Nx } +\cs_generate_variant:Nn \seq_if_in:NnT { c , cV , cv , co , cx } +\cs_generate_variant:Nn \seq_if_in:NnF { NV , Nv , No , Nx } +\cs_generate_variant:Nn \seq_if_in:NnF { c , cV , cv , co , cx } +\cs_generate_variant:Nn \seq_if_in:NnTF { NV , Nv , No , Nx } +\cs_generate_variant:Nn \seq_if_in:NnTF { c , cV , cv , co , cx } +\cs_new_protected_nopar:Npn \seq_get_left:NN #1#2 + { + \seq_if_empty_err_break:N #1 + \exp_after:wN \seq_get_left_aux:NnwN #1 \q_stop #2 + \seq_break_point:n { } + } +\cs_new_protected:Npn \seq_get_left_aux:NnwN \seq_item:n #1#2 \q_stop #3 + { \tl_set:Nn #3 {#1} } +\cs_generate_variant:Nn \seq_get_left:NN { c } +\cs_new_protected_nopar:Npn \seq_pop_left:NN + { \seq_pop_left_aux:NNN \tl_set:Nn } +\cs_new_protected_nopar:Npn \seq_gpop_left:NN + { \seq_pop_left_aux:NNN \tl_gset:Nn } +\cs_new_protected_nopar:Npn \seq_pop_left_aux:NNN #1#2#3 + { + \seq_if_empty_err_break:N #2 + \exp_after:wN \seq_pop_left_aux:NnwNNN #2 \q_stop #1#2#3 + \seq_break_point:n { } + } +\cs_new_protected:Npn \seq_pop_left_aux:NnwNNN \seq_item:n #1#2 \q_stop #3#4#5 + { + #3 #4 {#2} + \tl_set:Nn #5 {#1} + } +\cs_generate_variant:Nn \seq_pop_left:NN { c } +\cs_generate_variant:Nn \seq_gpop_left:NN { c } +\cs_new_protected_nopar:Npn \seq_get_right:NN #1#2 + { + \seq_if_empty_err_break:N #1 + \seq_get_right_aux:NN #1#2 + \seq_break_point:n { } + } +\cs_new_protected_nopar:Npn \seq_get_right_aux:NN #1#2 + { + \seq_push_item_def:n { } + \exp_after:wN \exp_after:wN \exp_after:wN \seq_get_right_loop:nn + \exp_after:wN \use_none:n #1 + { \tl_set:Nn #2 } + { } + { + \seq_pop_item_def: + \seq_break: + } +} +\cs_new:Npn \seq_get_right_loop:nn #1#2 + { + #2 {#1} + \seq_get_right_loop:nn + } +\cs_generate_variant:Nn \seq_get_right:NN { c } +\cs_new_protected_nopar:Npn \seq_pop_right:NN + { \seq_pop_right_aux:NNN \tl_set:Nx } +\cs_new_protected_nopar:Npn \seq_gpop_right:NN + { \seq_pop_right_aux:NNN \tl_gset:Nx } +\cs_new_protected_nopar:Npn \seq_pop_right_aux:NNN #1#2#3 + { + \seq_if_empty_err_break:N #2 + \seq_pop_right_aux_ii:NNN #1 #2 #3 + \seq_break_point:n { } + } +\cs_new_protected_nopar:Npn \seq_pop_right_aux_ii:NNN #1#2#3 + { + \seq_push_item_def:n { \exp_not:n { \seq_item:n {##1} } } + #1 #2 { \if_false: } \fi: + \exp_after:wN \exp_after:wN \exp_after:wN \seq_get_right_loop:nn + \exp_after:wN \use_none:n #2 + { + \if_false: { \fi: } + \tl_set:Nn #3 + } + { } + { + \seq_pop_item_def: + \seq_break: + } + } +\cs_generate_variant:Nn \seq_pop_right:NN { c } +\cs_generate_variant:Nn \seq_gpop_right:NN { c } +\cs_new:Npn \seq_break: #1 \seq_break_point:n #2 {#2} +\cs_new:Npn \seq_break:n #1#2 \seq_break_point:n #3 { #3 #1 } +\cs_new_eq:NN \seq_map_break: \seq_break: +\cs_new_eq:NN \seq_map_break:n \seq_break:n +\cs_new_eq:NN \seq_break_point:n \use:n +\cs_new_protected_nopar:Npn \seq_if_empty_err_break:N #1 + { + \if_meaning:w #1 \c_empty_tl + \msg_kernel_error:nnx { seq } { empty-sequence } { \token_to_str:N #1 } + \exp_after:wN \seq_break: + \fi: + } +\cs_new:Npn \seq_map_function:NN #1#2 + { + \exp_after:wN \seq_map_function_aux:NNn \exp_after:wN #2 #1 + { ? \seq_map_break: } { } + \seq_break_point:n { } + } +\cs_new:Npn \seq_map_function_aux:NNn #1#2#3 + { + \use_none:n #2 + #1 {#3} + \seq_map_function_aux:NNn #1 + } +\cs_generate_variant:Nn \seq_map_function:NN { c } +\cs_new_protected:Npn \seq_push_item_def:n + { + \seq_push_item_def_aux: + \cs_gset:Npn \seq_item:n ##1 + } +\cs_new_protected:Npn \seq_push_item_def:x + { + \seq_push_item_def_aux: + \cs_gset:Npx \seq_item:n ##1 + } +\cs_new_protected:Npn \seq_push_item_def_aux: + { + \cs_gset_eq:cN { seq_item_ \int_use:N \g_seq_nesting_depth_int :n } + \seq_item:n + \int_gincr:N \g_seq_nesting_depth_int + } +\cs_new_protected_nopar:Npn \seq_pop_item_def: + { + \int_gdecr:N \g_seq_nesting_depth_int + \cs_gset_eq:Nc \seq_item:n + { seq_item_ \int_use:N \g_seq_nesting_depth_int :n } + } +\cs_new_protected:Npn \seq_map_inline:Nn #1#2 + { + \seq_push_item_def:n {#2} + #1 + \seq_break_point:n { \seq_pop_item_def: } + } +\cs_generate_variant:Nn \seq_map_inline:Nn { c } +\cs_new_protected:Npn \seq_map_variable:NNn #1#2#3 + { + \seq_push_item_def:x + { + \tl_set:Nn \exp_not:N #2 {##1} + \exp_not:n {#3} + } + #1 + \seq_break_point:n { \seq_pop_item_def: } + } +\cs_generate_variant:Nn \seq_map_variable:NNn { Nc } +\cs_generate_variant:Nn \seq_map_variable:NNn { c , cc } +\cs_new_eq:NN \seq_push:Nn \seq_put_left:Nn +\cs_new_eq:NN \seq_push:NV \seq_put_left:NV +\cs_new_eq:NN \seq_push:Nv \seq_put_left:Nv +\cs_new_eq:NN \seq_push:No \seq_put_left:No +\cs_new_eq:NN \seq_push:Nx \seq_put_left:Nx +\cs_new_eq:NN \seq_push:cn \seq_put_left:cn +\cs_new_eq:NN \seq_push:cV \seq_put_left:cV +\cs_new_eq:NN \seq_push:cv \seq_put_left:cv +\cs_new_eq:NN \seq_push:co \seq_put_left:co +\cs_new_eq:NN \seq_push:cx \seq_put_left:cx +\cs_new_eq:NN \seq_gpush:Nn \seq_gput_left:Nn +\cs_new_eq:NN \seq_gpush:NV \seq_gput_left:NV +\cs_new_eq:NN \seq_gpush:Nv \seq_gput_left:Nv +\cs_new_eq:NN \seq_gpush:No \seq_gput_left:No +\cs_new_eq:NN \seq_gpush:Nx \seq_gput_left:Nx +\cs_new_eq:NN \seq_gpush:cn \seq_gput_left:cn +\cs_new_eq:NN \seq_gpush:cV \seq_gput_left:cV +\cs_new_eq:NN \seq_gpush:cv \seq_gput_left:cv +\cs_new_eq:NN \seq_gpush:co \seq_gput_left:co +\cs_new_eq:NN \seq_gpush:cx \seq_gput_left:cx +\cs_new_eq:NN \seq_get:NN \seq_get_left:NN +\cs_new_eq:NN \seq_get:cN \seq_get_left:cN +\cs_new_eq:NN \seq_pop:NN \seq_pop_left:NN +\cs_new_eq:NN \seq_pop:cN \seq_pop_left:cN +\cs_new_eq:NN \seq_gpop:NN \seq_gpop_left:NN +\cs_new_eq:NN \seq_gpop:cN \seq_gpop_left:cN +\tl_new:N \l_seq_show_tl +\cs_new_protected_nopar:Npn \seq_show:N #1 + { + \seq_if_empty:NTF #1 + { + \iow_term:x { Sequence~\token_to_str:N #1 \c_space_tl is~empty } + \tl_show:n { } + } + { + \iow_term:x + { + Sequence~\token_to_str:N #1 \c_space_tl + contains~the~items~(without~outer~braces): + } + \tl_set:Nx \l_seq_show_tl + { \seq_map_function:NN #1 \seq_show_aux:n } + \etex_showtokens:D \exp_after:wN \exp_after:wN \exp_after:wN + { \exp_after:wN \seq_show_aux:w \l_seq_show_tl } + } + } +\cs_new:Npn \seq_show_aux:n #1 + { + \iow_newline: > \c_space_tl \c_space_tl + \iow_char:N \{ \exp_not:n {#1} \iow_char:N \} + } +\cs_new:Npn \seq_show_aux:w #1 > ~ { } +\cs_generate_variant:Nn \seq_show:N { c } +\cs_new_nopar:Npn \seq_if_empty_break_return_false:N #1 + { + \if_meaning:w #1 \c_empty_tl + \prg_return_false: + \exp_after:wN \seq_break: + \fi: + } +\prg_new_protected_conditional:Npnn \seq_get_left:NN #1 #2 { T , F , TF } + { + \seq_if_empty_break_return_false:N #1 + \exp_after:wN \seq_get_left_aux:Nw #1 \q_stop #2 + \prg_return_true: + \seq_break: + \seq_break_point:n { } + } +\prg_new_protected_conditional:Npnn \seq_get_right:NN #1#2 { T , F , TF } + { + \seq_if_empty_break_return_false:N #1 + \seq_get_right_aux:NN #1#2 + \prg_return_true: \seq_break: + \seq_break_point:n { } + } +\cs_generate_variant:Nn \seq_get_left:NNT { c } +\cs_generate_variant:Nn \seq_get_left:NNF { c } +\cs_generate_variant:Nn \seq_get_left:NNTF { c } +\cs_generate_variant:Nn \seq_get_right:NNT { c } +\cs_generate_variant:Nn \seq_get_right:NNF { c } +\cs_generate_variant:Nn \seq_get_right:NNTF { c } +\prg_new_protected_conditional:Npnn \seq_pop_left:NN #1#2 { T , F , TF } + { + \seq_if_empty_break_return_false:N #1 + \exp_after:wN \seq_pop_left_aux:NnwNNN #1 \q_stop \tl_set:Nn #1#2 + \prg_return_true: \seq_break: + \seq_break_point:n { } + } +\prg_new_protected_conditional:Npnn \seq_gpop_left:NN #1#2 { T , F , TF } + { + \seq_if_empty_break_return_false:N #1 + \exp_after:wN \seq_pop_left_aux:NnwNNN #1 \q_stop \tl_gset:Nn #1#2 + \prg_return_true: \seq_break: + \seq_break_point:n { } + } +\prg_new_protected_conditional:Npnn \seq_pop_right:NN #1#2 { T , F , TF } + { + \seq_if_empty_break_return_false:N #1 + \seq_pop_right_aux_ii:NNN \tl_set:Nx #1 #2 + \prg_return_true: \seq_break: + \seq_break_point:n { } + } +\prg_new_protected_conditional:Npnn \seq_gpop_right:NN #1#2 { T , F , TF } + { + \seq_if_empty_break_return_false:N #1 + \seq_pop_right_aux_ii:NNN \tl_gset:Nx #1 #2 + \prg_return_true: \seq_break: + \seq_break_point:n { } + } +\cs_generate_variant:Nn \seq_pop_left:NNT { c } +\cs_generate_variant:Nn \seq_pop_left:NNF { c } +\cs_generate_variant:Nn \seq_pop_left:NNTF { c } +\cs_generate_variant:Nn \seq_gpop_left:NNT { c } +\cs_generate_variant:Nn \seq_gpop_left:NNF { c } +\cs_generate_variant:Nn \seq_gpop_left:NNTF { c } +\cs_generate_variant:Nn \seq_pop_right:NNT { c } +\cs_generate_variant:Nn \seq_pop_right:NNF { c } +\cs_generate_variant:Nn \seq_pop_right:NNTF { c } +\cs_generate_variant:Nn \seq_gpop_right:NNT { c } +\cs_generate_variant:Nn \seq_gpop_right:NNF { c } +\cs_generate_variant:Nn \seq_gpop_right:NNTF { c } +\cs_new:Npn \seq_length:N #1 + { + \int_eval:n + { + 0 + \seq_map_function:NN #1 \seq_length_aux:n + } + } +\cs_new:Npn \seq_length_aux:n #1 { +1 } +\cs_generate_variant:Nn \seq_length:N { c } +\cs_new_nopar:Npn \seq_item:Nn #1#2 + { + \exp_last_unbraced:Nfo \seq_item_aux:nnn + { + \int_eval:n + { + \int_compare:nNnT {#2} < \c_zero + { \seq_length:N #1 + } + #2 + } + } + #1 + { ? \seq_break: } + { } + \seq_break_point:n { } + } +\cs_new_nopar:Npn \seq_item_aux:nnn #1#2#3 + { + \use_none:n #2 + \int_compare:nNnTF {#1} = \c_zero + { \seq_break:n {#3} } + { \exp_args:Nf \seq_item_aux:nnn { #1 - 1 } } + } +\cs_generate_variant:Nn \seq_item:Nn { c } +\cs_new_nopar:Npn \seq_use:N #1 { \seq_map_function:NN #1 \use:n } +\cs_generate_variant:Nn \seq_use:N { c } +\cs_new_nopar:Npn \seq_mapthread_function:NNN #1#2#3 + { + \exp_after:wN \seq_mapthread_function_aux:NN + \exp_after:wN #3 + \exp_after:wN #1 + #2 + { ? \seq_break: } { } + \seq_break_point:n { } + } +\cs_new_nopar:Npn \seq_mapthread_function_aux:NN #1#2 + { + \exp_after:wN \seq_mapthread_function_aux:Nnnwnn + \exp_after:wN #1 + #2 + { ? \seq_break: } { } + \q_stop + } +\cs_new:Npn \seq_mapthread_function_aux:Nnnwnn #1#2#3#4 \q_stop #5#6 + { + \use_none:n #2 + \use_none:n #5 + #1 {#3} {#6} + \seq_mapthread_function_aux:Nnnwnn #1 #4 \q_stop + } +\cs_generate_variant:Nn \seq_mapthread_function:NNN { Nc } +\cs_generate_variant:Nn \seq_mapthread_function:NNN { c , cc } +\cs_new_protected:Npn \seq_set_from_clist:NN #1#2 + { + \tl_set:Nx #1 + { \clist_map_function:NN #2 \seq_wrap_item:n } + } +\cs_new_protected:Npn \seq_set_from_clist:Nn #1#2 + { + \tl_set:Nx #1 + { \clist_map_function:nN {#2} \seq_wrap_item:n } + } +\cs_new_protected:Npn \seq_gset_from_clist:NN #1#2 + { + \tl_gset:Nx #1 + { \clist_map_function:NN #2 \seq_wrap_item:n } + } +\cs_new_protected:Npn \seq_gset_from_clist:Nn #1#2 + { + \tl_gset:Nx #1 + { \clist_map_function:nN {#2} \seq_wrap_item:n } + } +\cs_new:Npn \seq_wrap_item:n #1 { \exp_not:n { \seq_item:n {#1} } } +\cs_generate_variant:Nn \seq_set_from_clist:NN { Nc } +\cs_generate_variant:Nn \seq_set_from_clist:NN { c , cc } +\cs_generate_variant:Nn \seq_set_from_clist:Nn { c } +\cs_generate_variant:Nn \seq_gset_from_clist:NN { Nc } +\cs_generate_variant:Nn \seq_gset_from_clist:NN { c , cc } +\cs_generate_variant:Nn \seq_gset_from_clist:Nn { c } +\cs_new_eq:NN \seq_top:NN \seq_get_left:NN +\cs_new_eq:NN \seq_top:cN \seq_get_left:cN +\cs_new_eq:NN \seq_display:N \seq_show:N +\cs_new_eq:NN \seq_display:c \seq_show:c +%% +%% +%% End of file `l3seq.sty'. diff --git a/Master/texmf-dist/tex/latex/l3kernel/l3skip.sty b/Master/texmf-dist/tex/latex/l3kernel/l3skip.sty new file mode 100644 index 00000000000..ae4a46fc805 --- /dev/null +++ b/Master/texmf-dist/tex/latex/l3kernel/l3skip.sty @@ -0,0 +1,332 @@ +%% +%% This is file `l3skip.sty', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% l3skip.dtx (with options: `package') +%% +%% EXPERIMENTAL CODE +%% +%% Do not distribute this file without also distributing the +%% source files specified above. +%% +%% Do not distribute a modified version of this file. +%% +%% File: l3skip.dtx Copyright (C) 2004-2011 Frank Mittelbach, The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +\RequirePackage{l3names} +\GetIdInfo$Id: l3skip.dtx 2478 2011-06-19 21:34:23Z joseph $ + {L3 Experimental dimensions and skips} +\ProvidesExplPackage + {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +\package_check_loaded_expl: +\cs_new_eq:NN \if_dim:w \tex_ifdim:D +\cs_new_eq:NN \dim_eval:w \etex_dimexpr:D +\cs_new_eq:NN \dim_eval_end: \tex_relax:D +\cs_new_protected_nopar:Npn \dim_new:N #1 + { + \chk_if_free_cs:N #1 + \newdimen #1 + } +\cs_generate_variant:Nn \dim_new:N { c } +\cs_new_protected_nopar:Npn \dim_zero:N #1 { #1 \c_zero_dim } +\cs_new_protected_nopar:Npn \dim_gzero:N { \pref_global:D \dim_zero:N } +\cs_generate_variant:Nn \dim_zero:N { c } +\cs_generate_variant:Nn \dim_gzero:N { c } +\cs_new_protected_nopar:Npn \dim_set:Nn #1#2 + { #1 ~ \dim_eval:w #2 \dim_eval_end: } +\cs_new_protected_nopar:Npn \dim_gset:Nn { \pref_global:D \dim_set:Nn } +\cs_generate_variant:Nn \dim_set:Nn { c } +\cs_generate_variant:Nn \dim_gset:Nn { c } +\cs_new_protected_nopar:Npn \dim_set_eq:NN #1#2 { #1 = #2 } +\cs_generate_variant:Nn \dim_set_eq:NN { c } +\cs_generate_variant:Nn \dim_set_eq:NN { Nc , cc } +\cs_new_protected_nopar:Npn \dim_gset_eq:NN #1#2 { \pref_global:D #1 = #2 } +\cs_generate_variant:Nn \dim_gset_eq:NN { c } +\cs_generate_variant:Nn \dim_gset_eq:NN { Nc , cc } +\cs_new_protected_nopar:Npn \dim_set_max:Nn #1#2 + { \dim_compare:nNnT {#1} < {#2} { \dim_set:Nn #1 {#2} } } +\cs_new_protected_nopar:Npn \dim_gset_max:Nn #1#2 + { \dim_compare:nNnT {#1} < {#2} { \dim_gset:Nn #1 {#2} } } +\cs_new_protected_nopar:Npn \dim_set_min:Nn #1#2 + { \dim_compare:nNnT {#1} > {#2} { \dim_set:Nn #1 {#2} } } +\cs_new_protected_nopar:Npn \dim_gset_min:Nn #1#2 + { \dim_compare:nNnT {#1} > {#2} { \dim_gset:Nn #1 {#2} } } +\cs_generate_variant:Nn \dim_set_max:Nn { c } +\cs_generate_variant:Nn \dim_gset_max:Nn { c } +\cs_generate_variant:Nn \dim_set_min:Nn { c } +\cs_generate_variant:Nn \dim_gset_min:Nn { c } +\cs_new_protected_nopar:Npn \dim_add:Nn #1#2 + { \tex_advance:D #1 by \dim_eval:w #2 \dim_eval_end: } +\cs_new_protected_nopar:Npn \dim_gadd:Nn { \pref_global:D \dim_add:Nn } +\cs_generate_variant:Nn \dim_add:Nn { c } +\cs_generate_variant:Nn \dim_gadd:Nn { c } +\cs_new_protected_nopar:Npn \dim_sub:Nn #1#2 + { \tex_advance:D #1 by - \dim_eval:w #2 \dim_eval_end: } +\cs_new_protected_nopar:Npn \dim_gsub:Nn { \pref_global:D \dim_sub:Nn } +\cs_generate_variant:Nn \dim_sub:Nn { c } +\cs_generate_variant:Nn \dim_gsub:Nn { c } +\cs_new_nopar:Npn \dim_ratio:nn #1#2 + { \dim_ratio_aux:n {#1} / \dim_ratio_aux:n {#2} } +\cs_new_nopar:Npn \dim_ratio_aux:n #1 + { \exp_after:wN \int_value:w \dim_eval:w #1 \dim_eval_end: } +\prg_new_conditional:Npnn \dim_compare:nNn #1#2#3 { p , T , F , TF } + { + \if_dim:w \dim_eval:w #1 #2 \dim_eval:w #3 \dim_eval_end: + \prg_return_true: \else: \prg_return_false: \fi: + } +\prg_new_conditional:Npnn \dim_compare:n #1 { p , T , F , TF } + { + \exp_after:wN \dim_compare_aux:wNN \dim_use:N \dim_eval:w #1 + \dim_eval_end: + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +\exp_args:Nno \use:nn + { \cs_new:Npn \dim_compare_aux:wNN #1 } + { \tl_to_str:n { pt } } + #2 #3 + { + \use:c + { + dim_compare_ #2 + \if_meaning:w = #3 = \fi: + :nw + } + { #1 pt } #3 + } +\cs_new:cpn { dim_compare_<:nw } #1 { \if_dim:w #1 < \dim_eval:w } +\cs_new:cpn { dim_compare_=:nw } #1 { \if_dim:w #1 = \dim_eval:w } +\cs_new:cpn { dim_compare_>:nw } #1 { \if_dim:w #1 > \dim_eval:w } +\cs_new:cpn {dim_compare_==:nw} #1#2 { \if_dim:w #1 = \dim_eval:w } +\cs_new:cpn {dim_compare_<=:nw} #1#2 {\reverse_if:N \if_dim:w #1 > \dim_eval:w} +\cs_new:cpn {dim_compare_!=:nw} #1#2 {\reverse_if:N \if_dim:w #1 = \dim_eval:w} +\cs_new:cpn {dim_compare_>=:nw} #1#2 {\reverse_if:N \if_dim:w #1 < \dim_eval:w} +\cs_set:Npn \dim_while_do:nn #1#2 + { + \dim_compare:nT {#1} + { + #2 + \dim_while_do:nn {#1} {#2} + } + } +\cs_set:Npn \dim_until_do:nn #1#2 + { + \dim_compare:nF {#1} + { + #2 + \dim_until_do:nn {#1} {#2} + } + } +\cs_set:Npn \dim_do_while:nn #1#2 + { + #2 + \dim_compare:nT {#1} + { \dim_do_while:nNnn {#1} {#2} } + } +\cs_set:Npn \dim_do_until:nn #1#2 + { + #2 + \dim_compare:nF {#1} + { \dim_do_until:nn {#1} {#2} } + } +\cs_set:Npn \dim_while_do:nNnn #1#2#3#4 + { + \dim_compare:nNnT {#1} #2 {#3} + { + #4 + \dim_while_do:nNnn {#1} #2 {#3} {#4} + } + } +\cs_set:Npn \dim_until_do:nNnn #1#2#3#4 + { + \dim_compare:nNnF {#1} #2 {#3} + { + #4 + \dim_until_do:nNnn {#1} #2 {#3} {#4} + } + } +\cs_set:Npn \dim_do_while:nNnn #1#2#3#4 + { + #4 + \dim_compare:nNnT {#1} #2 {#3} + { \dim_do_while:nNnn {#1} #2 {#3} {#4} } + } +\cs_set:Npn \dim_do_until:nNnn #1#2#3#4 + { + #4 + \dim_compare:nNnF {#1} #2 {#3} + { \dim_do_until:nNnn {#1} #2 {#3} {#4} } + } +\cs_new_nopar:Npn \dim_eval:n #1 + { \dim_use:N \dim_eval:w #1 \dim_eval_end: } +\cs_new_eq:NN \dim_use:N \tex_the:D +\cs_generate_variant:Nn \dim_use:N { c } +\cs_new_eq:NN \dim_show:N \kernel_register_show:N +\cs_generate_variant:Nn \dim_show:N { c } +\cs_new_eq:NN \c_zero_dim \z@ +\cs_new_eq:NN \c_max_dim \maxdimen +\dim_new:N \l_tmpa_dim +\dim_new:N \l_tmpb_dim +\dim_new:N \l_tmpc_dim +\dim_new:N \g_tmpa_dim +\dim_new:N \g_tmpb_dim +\cs_new_protected_nopar:Npn \skip_new:N #1 + { + \chk_if_free_cs:N #1 + \newskip #1 + } +\cs_generate_variant:Nn \skip_new:N { c } +\cs_new_protected_nopar:Npn \skip_zero:N #1 { #1 \c_zero_skip } +\cs_new_protected_nopar:Npn \skip_gzero:N { \pref_global:D \skip_zero:N } +\cs_generate_variant:Nn \skip_zero:N { c } +\cs_generate_variant:Nn \skip_gzero:N { c } +\cs_new_protected_nopar:Npn \skip_set:Nn #1#2 + { #1 ~ \etex_glueexpr:D #2 \scan_stop: } +\cs_new_protected_nopar:Npn \skip_gset:Nn { \pref_global:D \skip_set:Nn } +\cs_generate_variant:Nn \skip_set:Nn { c } +\cs_generate_variant:Nn \skip_gset:Nn { c } +\cs_new_protected_nopar:Npn \skip_set_eq:NN #1#2 { #1 = #2 } +\cs_generate_variant:Nn \skip_set_eq:NN { c } +\cs_generate_variant:Nn \skip_set_eq:NN { Nc , cc } +\cs_new_protected_nopar:Npn \skip_gset_eq:NN #1#2 { \pref_global:D #1 = #2 } +\cs_generate_variant:Nn \skip_gset_eq:NN { c } +\cs_generate_variant:Nn \skip_gset_eq:NN { Nc , cc } +\cs_new_protected_nopar:Npn \skip_add:Nn #1#2 + { \tex_advance:D #1 by \etex_glueexpr:D #2 \scan_stop: } +\cs_new_protected_nopar:Npn \skip_gadd:Nn { \pref_global:D \skip_add:Nn } +\cs_generate_variant:Nn \skip_add:Nn { c } +\cs_generate_variant:Nn \skip_gadd:Nn { c } +\cs_new_protected_nopar:Npn \skip_sub:Nn #1#2 + { \tex_advance:D #1 by - \etex_glueexpr:D #2 \scan_stop: } +\cs_new_protected_nopar:Npn \skip_gsub:Nn { \pref_global:D \skip_sub:Nn } +\cs_generate_variant:Nn \skip_sub:Nn { c } +\cs_generate_variant:Nn \skip_gsub:Nn { c } +\prg_new_conditional:Npnn \skip_if_eq:nn #1#2 { p , T , F , TF } + { + \if_int_compare:w + \pdftex_strcmp:D { \skip_eval:n { #1 } } { \skip_eval:n { #2 } } + = \c_zero + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +\prg_new_conditional:Npnn \skip_if_infinite_glue:n #1 { p , T , F , TF } + { + \bool_if:nTF + { + \int_compare_p:nNn { \etex_gluestretchorder:D #1 } > \c_zero || + \int_compare_p:nNn { \etex_glueshrinkorder:D #1 } > \c_zero + } + { \prg_return_true: } + { \prg_return_false: } + } +\cs_new_nopar:Npn \skip_eval:n #1 + { \skip_use:N \etex_glueexpr:D #1 \scan_stop: } +\cs_new_eq:NN \skip_use:N \tex_the:D +\cs_generate_variant:Nn \skip_use:N { c } +\cs_new_eq:NN \skip_horizontal:N \tex_hskip:D +\cs_new_nopar:Npn \skip_horizontal:n #1 + { \skip_horizontal:N \etex_glueexpr:D #1 \scan_stop: } +\cs_new_eq:NN \skip_vertical:N \tex_vskip:D +\cs_new_nopar:Npn \skip_vertical:n #1 + { \skip_vertical:N \etex_glueexpr:D #1 \scan_stop: } +\cs_generate_variant:Nn \skip_horizontal:N { c } +\cs_generate_variant:Nn \skip_vertical:N { c } +\cs_new_eq:NN \skip_show:N \kernel_register_show:N +\cs_generate_variant:Nn \skip_show:N { c } +\cs_new_eq:NN \c_zero_skip \c_zero_dim +\cs_new_eq:NN \c_max_skip \c_max_dim +\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 +\cs_new_protected_nopar:Npn \muskip_new:N #1 + { + \chk_if_free_cs:N #1 + \newmuskip #1 + } +\cs_generate_variant:Nn \muskip_new:N { c } +\cs_new_protected_nopar:Npn \muskip_zero:N #1 + { #1 \c_zero_muskip } +\cs_new_protected_nopar:Npn \muskip_gzero:N { \pref_global:D \muskip_zero:N } +\cs_generate_variant:Nn \muskip_zero:N { c } +\cs_generate_variant:Nn \muskip_gzero:N { c } +\cs_new_protected_nopar:Npn \muskip_set:Nn #1#2 + { #1 ~ \etex_muexpr:D #2 \scan_stop: } +\cs_new_protected_nopar:Npn \muskip_gset:Nn { \pref_global:D \muskip_set:Nn } +\cs_generate_variant:Nn \muskip_set:Nn { c } +\cs_generate_variant:Nn \muskip_gset:Nn { c } +\cs_new_protected_nopar:Npn \muskip_set_eq:NN #1#2 { #1 = #2 } +\cs_generate_variant:Nn \muskip_set_eq:NN { c } +\cs_generate_variant:Nn \muskip_set_eq:NN { Nc , cc } +\cs_new_protected_nopar:Npn \muskip_gset_eq:NN #1#2 { \pref_global:D #1 = #2 } +\cs_generate_variant:Nn \muskip_gset_eq:NN { c } +\cs_generate_variant:Nn \muskip_gset_eq:NN { Nc , cc } +\cs_new_protected_nopar:Npn \muskip_add:Nn #1#2 + { \tex_advance:D #1 by \etex_muexpr:D #2 \scan_stop: } +\cs_new_protected_nopar:Npn \muskip_gadd:Nn { \pref_global:D \muskip_add:Nn } +\cs_generate_variant:Nn \muskip_add:Nn { c } +\cs_generate_variant:Nn \muskip_gadd:Nn { c } +\cs_new_protected_nopar:Npn \muskip_sub:Nn #1#2 + { \tex_advance:D #1 by - \etex_muexpr:D #2 \scan_stop: } +\cs_new_protected_nopar:Npn \muskip_gsub:Nn { \pref_global:D \muskip_sub:Nn } +\cs_generate_variant:Nn \muskip_sub:Nn { c } +\cs_generate_variant:Nn \muskip_gsub:Nn { c } +\cs_new_nopar:Npn \muskip_eval:n #1 + { \muskip_use:N \etex_muexpr:D #1 \scan_stop: } +\cs_new_eq:NN \muskip_use:N \tex_the:D +\cs_generate_variant:Nn \muskip_use:N { c } +\cs_new_eq:NN \muskip_show:N \kernel_register_show:N +\cs_generate_variant:Nn \muskip_show:N { c } +\cs_new_nopar:Npn \skip_split_finite_else_action:nnNN #1#2#3#4 + { + \skip_if_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 of file `l3skip.sty'. diff --git a/Master/texmf-dist/tex/latex/l3kernel/l3tl.sty b/Master/texmf-dist/tex/latex/l3kernel/l3tl.sty new file mode 100644 index 00000000000..34238f643f0 --- /dev/null +++ b/Master/texmf-dist/tex/latex/l3kernel/l3tl.sty @@ -0,0 +1,628 @@ +%% +%% This is file `l3tl.sty', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% l3tl.dtx (with options: `package') +%% +%% EXPERIMENTAL CODE +%% +%% Do not distribute this file without also distributing the +%% source files specified above. +%% +%% Do not distribute a modified version of this file. +%% +%% File: l3tl.dtx Copyright (C) 1990-2011 The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +\RequirePackage{l3names} +\GetIdInfo$Id: l3tl.dtx 2498 2011-07-09 17:51:47Z joseph $ + {L3 Experimental token lists} +\ProvidesExplPackage + {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +\package_check_loaded_expl: +\cs_new_protected_nopar:Npn \tl_new:N #1 + { + \chk_if_free_cs:N #1 + \cs_gset_eq:NN #1 \c_empty_tl + } +\cs_generate_variant:Nn \tl_new:N { c } +\cs_new_protected:Npn \tl_const:Nn #1#2 + { + \chk_if_free_cs:N #1 + \cs_gset_nopar:Npx #1 { \exp_not:n {#2} } + } +\cs_new_protected:Npn \tl_const:Nx #1#2 + { + \chk_if_free_cs:N #1 + \cs_gset_nopar:Npx #1 {#2} + } +\cs_generate_variant:Nn \tl_const:Nn { c } +\cs_generate_variant:Nn \tl_const:Nx { c } +\cs_new_protected_nopar:Npn \tl_clear:N #1 + { \tl_set_eq:NN #1 \c_empty_tl } +\cs_new_protected_nopar:Npn \tl_gclear:N #1 + { \tl_gset_eq:NN #1 \c_empty_tl } +\cs_generate_variant:Nn \tl_clear:N { c } +\cs_generate_variant:Nn \tl_gclear:N { c } +\cs_new_protected_nopar:Npn \tl_clear_new:N #1 + { \cs_if_exist:NTF #1 { \tl_clear:N #1 } { \tl_new:N #1 } } +\cs_new_protected_nopar:Npn \tl_gclear_new:N #1 + { \cs_if_exist:NTF #1 { \tl_gclear:N #1 } { \tl_new:N #1 } } +\cs_generate_variant:Nn \tl_clear_new:N { c } +\cs_generate_variant:Nn \tl_gclear_new:N { c } +\cs_new_eq:NN \tl_set_eq:NN \cs_set_eq:NN +\cs_new_eq:NN \tl_set_eq:cN \cs_set_eq:cN +\cs_new_eq:NN \tl_set_eq:Nc \cs_set_eq:Nc +\cs_new_eq:NN \tl_set_eq:cc \cs_set_eq:cc +\cs_new_eq:NN \tl_gset_eq:NN \cs_gset_eq:NN +\cs_new_eq:NN \tl_gset_eq:cN \cs_gset_eq:cN +\cs_new_eq:NN \tl_gset_eq:Nc \cs_gset_eq:Nc +\cs_new_eq:NN \tl_gset_eq:cc \cs_gset_eq:cc +\cs_new_protected:Npn \tl_set:Nn #1#2 + { \cs_set_nopar:Npx #1 { \exp_not:n {#2} } } +\cs_new_protected:Npn \tl_set:No #1#2 + { \cs_set_nopar:Npx #1 { \exp_not:o {#2} } } +\cs_new_protected:Npn \tl_set:Nx #1#2 + { \cs_set_nopar:Npx #1 {#2} } +\cs_new_protected:Npn \tl_gset:Nn #1#2 + { \cs_gset_nopar:Npx #1 { \exp_not:n {#2} } } +\cs_new_protected:Npn \tl_gset:No #1#2 + { \cs_gset_nopar:Npx #1 { \exp_not:o {#2} } } +\cs_new_protected:Npn \tl_gset:Nx #1#2 + { \cs_gset_nopar:Npx #1 {#2} } +\cs_generate_variant:Nn \tl_set:Nn { NV , Nv , Nf } +\cs_generate_variant:Nn \tl_set:Nx { c } +\cs_generate_variant:Nn \tl_set:Nn { c, co , cV , cv , cf } +\cs_generate_variant:Nn \tl_gset:Nn { NV , Nv , Nf } +\cs_generate_variant:Nn \tl_gset:Nx { c } +\cs_generate_variant:Nn \tl_gset:Nn { c, co , cV , cv , cf } +\cs_new_protected:Npn \tl_put_left:Nn #1#2 + { \cs_set_nopar:Npx #1 { \exp_not:n {#2} \exp_not:o #1 } } +\cs_new_protected:Npn \tl_put_left:NV #1#2 + { \cs_set_nopar:Npx #1 { \exp_not:V #2 \exp_not:o #1 } } +\cs_new_protected:Npn \tl_put_left:No #1#2 + { \cs_set_nopar:Npx #1 { \exp_not:o {#2} \exp_not:o #1 } } +\cs_new_protected:Npn \tl_put_left:Nx #1#2 + { \cs_set_nopar:Npx #1 { #2 \exp_not:o #1 } } +\cs_new_protected:Npn \tl_gput_left:Nn #1#2 + { \cs_gset_nopar:Npx #1 { \exp_not:n {#2} \exp_not:o #1 } } +\cs_new_protected:Npn \tl_gput_left:NV #1#2 + { \cs_gset_nopar:Npx #1 { \exp_not:V #2 \exp_not:o #1 } } +\cs_new_protected:Npn \tl_gput_left:No #1#2 + { \cs_gset_nopar:Npx #1 { \exp_not:o {#2} \exp_not:o #1 } } +\cs_new_protected:Npn \tl_gput_left:Nx #1#2 + { \cs_gset_nopar:Npx #1 { #2 \exp_not:o {#1} } } +\cs_generate_variant:Nn \tl_put_left:Nn { c } +\cs_generate_variant:Nn \tl_put_left:NV { c } +\cs_generate_variant:Nn \tl_put_left:No { c } +\cs_generate_variant:Nn \tl_put_left:Nx { c } +\cs_generate_variant:Nn \tl_gput_left:Nn { c } +\cs_generate_variant:Nn \tl_gput_left:NV { c } +\cs_generate_variant:Nn \tl_gput_left:No { c } +\cs_generate_variant:Nn \tl_gput_left:Nx { c } +\cs_new_protected:Npn \tl_put_right:Nn #1#2 + { \cs_set_nopar:Npx #1 { \exp_not:o #1 \exp_not:n {#2} } } +\cs_new_protected:Npn \tl_put_right:NV #1#2 + { \cs_set_nopar:Npx #1 { \exp_not:o #1 \exp_not:V #2 } } +\cs_new_protected:Npn \tl_put_right:No #1#2 + { \cs_set_nopar:Npx #1 { \exp_not:o #1 \exp_not:o {#2} } } +\cs_new_protected:Npn \tl_put_right:Nx #1#2 + { \cs_set_nopar:Npx #1 { \exp_not:o #1 #2 } } +\cs_new_protected:Npn \tl_gput_right:Nn #1#2 + { \cs_gset_nopar:Npx #1 { \exp_not:o #1 \exp_not:n {#2} } } +\cs_new_protected:Npn \tl_gput_right:NV #1#2 + { \cs_gset_nopar:Npx #1 { \exp_not:o #1 \exp_not:V #2 } } +\cs_new_protected:Npn \tl_gput_right:No #1#2 + { \cs_gset_nopar:Npx #1 { \exp_not:o #1 \exp_not:o {#2} } } +\cs_new_protected:Npn \tl_gput_right:Nx #1#2 + { \cs_gset_nopar:Npx #1 { \exp_not:o {#1} #2 } } +\cs_generate_variant:Nn \tl_put_right:Nn { c } +\cs_generate_variant:Nn \tl_put_right:NV { c } +\cs_generate_variant:Nn \tl_put_right:No { c } +\cs_generate_variant:Nn \tl_put_right:Nx { c } +\cs_generate_variant:Nn \tl_gput_right:Nn { c } +\cs_generate_variant:Nn \tl_gput_right:NV { c } +\cs_generate_variant:Nn \tl_gput_right:No { c } +\cs_generate_variant:Nn \tl_gput_right:Nx { c } +\group_begin: + \tex_lccode:D `\A = `\@ \scan_stop: + \tex_lccode:D `\B = `\@ \scan_stop: + \tex_catcode:D `\A = 8 \scan_stop: + \tex_catcode:D `\B = 3 \scan_stop: +\tex_lowercase:D + { + \group_end: + \tl_const:Nn \c_tl_rescan_marker_tl { A B } + } +\tl_new:N \l_tl_rescan_tl +\cs_new_protected_nopar:Npn \tl_set_rescan:Nnn + { \tl_set_rescan_aux:NNnn \tl_set:Nn } +\cs_new_protected_nopar:Npn \tl_gset_rescan:Nnn + { \tl_set_rescan_aux:NNnn \tl_gset:Nn } +\cs_new_protected:Npn \tl_set_rescan_aux:NNnn #1#2#3#4 + { + \group_begin: + \exp_args:No \etex_everyeof:D { \c_tl_rescan_marker_tl } + \tex_endlinechar:D \c_minus_one + #3 + \tl_clear:N \l_tl_rescan_tl + \exp_after:wN \tl_rescan_aux:w \etex_scantokens:D {#4} + \exp_args:NNNo \group_end: + #1 #2 \l_tl_rescan_tl + } +\cs_new_nopar:Npx \tl_rescan_aux:w + { + \cs_set_protected:Npn \exp_not:N \tl_rescan_aux:w ##1 + \c_tl_rescan_marker_tl + { \tl_set:Nn \exp_not:N \l_tl_rescan_tl {##1} } + } +\tl_rescan_aux:w +\cs_generate_variant:Nn \tl_set_rescan:Nnn { Nno } +\cs_generate_variant:Nn \tl_set_rescan:Nnn { c , cno } +\cs_generate_variant:Nn \tl_gset_rescan:Nnn { Nno } +\cs_generate_variant:Nn \tl_gset_rescan:Nnn { c , cno } +\cs_new_protected_nopar:Npn \tl_set_rescan:Nnx + { \tl_set_rescan_aux:NNnx \tl_set:Nn } +\cs_new_protected_nopar:Npn \tl_gset_rescan:Nnx + { \tl_set_rescan_aux:NNnx \tl_gset:Nn } +\cs_new_protected_nopar:Npn \tl_set_rescan_aux:NNnx #1#2#3#4 + { + \group_begin: + \etex_everyeof:D { \exp_not:N } + \tex_endlinechar:D \c_minus_one + #3 + \tl_set:Nx \l_tl_rescan_tl { \etex_scantokens:D {#4} } + \exp_args:NNNo \group_end: + #1 #2 \l_tl_rescan_tl + } +\cs_generate_variant:Nn \tl_set_rescan:Nnx { c } +\cs_generate_variant:Nn \tl_gset_rescan:Nnx { c } +\cs_new_protected:Npn \tl_rescan:nn #1#2 + { + \group_begin: + \exp_args:No \etex_everyeof:D { \c_tl_rescan_marker_tl } + \tex_endlinechar:D \c_minus_one + #1 + \exp_after:wN \tl_rescan_aux:w \etex_scantokens:D {#2} + \exp_args:No \group_end: + \l_tl_rescan_tl + } +\cs_new_eq:NN \tl_to_lowercase:n \tex_lowercase:D +\cs_new_eq:NN \tl_to_uppercase:n \tex_uppercase:D +\tl_new:N \l_tl_replace_tl +\cs_new_protected_nopar:Npn \tl_replace_once:Nnn + { \tl_replace_once_aux:NNnn \tl_set_eq:NN } +\cs_new_protected_nopar:Npn \tl_greplace_once:Nnn + { \tl_replace_once_aux:NNnn \tl_gset_eq:NN } +\cs_new_protected:Npn \tl_replace_once_aux:NNnn #1#2#3#4 + { + \cs_set_protected:Npx \tl_tmp:w ##1 #3 ##2 \q_stop + { + \exp_not:N \quark_if_no_value:nF {##2} + { + \tl_set:No \exp_not:N \l_tl_replace_tl { ##1 \exp_not:n{#4} } + \exp_not:n + { + \cs_set_protected:Npn \tl_tmp:w ##1 \q_nil #3 \q_no_value + { \tl_put_right:No \l_tl_replace_tl {##1} } + } + \exp_not:n { \tl_tmp:w \prg_do_nothing: } ##2 + \exp_not:n { #1 #2 \l_tl_replace_tl } + } + } + \exp_after:wN \tl_tmp:w \exp_after:wN \prg_do_nothing: + #2 \q_nil #3 \q_no_value \q_stop + } +\cs_generate_variant:Nn \tl_replace_once:Nnn { c } +\cs_generate_variant:Nn \tl_greplace_once:Nnn { c } +\cs_new_protected_nopar:Npn \tl_replace_all:Nnn + { \tl_replace_all_aux:NNnn \tl_set_eq:NN } +\cs_new_protected_nopar:Npn \tl_greplace_all:Nnn + { \tl_replace_all_aux:NNnn \tl_gset_eq:NN } +\cs_new_protected:Npn \tl_replace_all_aux:NNnn #1#2#3#4 + { + \tl_clear:N \l_tl_replace_tl + \cs_set_protected:Npx \tl_tmp:w ##1 #3 ##2 \q_stop + { + \exp_not:N \quark_if_no_value:nTF {##2} + { + \exp_not:n + { + \cs_set_protected:Npn \tl_tmp:w ##1 \q_nil ##2 \q_stop + { \tl_put_right:No \l_tl_replace_tl {##1} } + } + \exp_not:N \tl_tmp:w ##1 \exp_not:N \q_stop + } + { + \exp_not:n { \tl_put_right:No \l_tl_replace_tl } + { ##1 \exp_not:n{#4} } + \exp_not:n { \tl_tmp:w \prg_do_nothing: } ##2 \exp_not:N \q_stop + } + } + \exp_after:wN \tl_tmp:w \exp_after:wN \prg_do_nothing: + #2 \q_nil #3 \q_no_value \q_stop + #1 #2 \l_tl_replace_tl + } +\cs_generate_variant:Nn \tl_replace_all:Nnn { c } +\cs_generate_variant:Nn \tl_greplace_all:Nnn { c } +\cs_new_protected_nopar:Npn \tl_remove_once:Nn #1#2 + { \tl_replace_once:Nnn #1 {#2} { } } +\cs_new_protected_nopar:Npn \tl_gremove_once:Nn #1#2 + { \tl_greplace_once:Nnn #1 {#2} { } } +\cs_generate_variant:Nn \tl_remove_once:Nn { c } +\cs_generate_variant:Nn \tl_gremove_once:Nn { c } +\cs_new_protected_nopar:Npn \tl_remove_all:Nn #1#2 + { \tl_replace_all:Nnn #1 {#2} { } } +\cs_new_protected_nopar:Npn \tl_gremove_all:Nn #1#2 + { \tl_greplace_all:Nnn #1 {#2} { } } +\cs_generate_variant:Nn \tl_remove_all:Nn { c } +\cs_generate_variant:Nn \tl_gremove_all:Nn { c } +\prg_new_conditional:Npnn \tl_if_blank:n #1 { p , T , F , TF } + { \tl_if_empty_return:o { \use_none:n #1 ? } } +\cs_generate_variant:Nn \tl_if_blank_p:n { V } +\cs_generate_variant:Nn \tl_if_blank:nT { V } +\cs_generate_variant:Nn \tl_if_blank:nF { V } +\cs_generate_variant:Nn \tl_if_blank:nTF { V } +\cs_generate_variant:Nn \tl_if_blank_p:n { o } +\cs_generate_variant:Nn \tl_if_blank:nT { o } +\cs_generate_variant:Nn \tl_if_blank:nF { o } +\cs_generate_variant:Nn \tl_if_blank:nTF { o } +\prg_set_conditional:Npnn \tl_if_empty:N #1 { p , T , F , TF } + { + \if_meaning:w #1 \c_empty_tl + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +\cs_generate_variant:Nn \tl_if_empty_p:N { c } +\cs_generate_variant:Nn \tl_if_empty:NT { c } +\cs_generate_variant:Nn \tl_if_empty:NF { c } +\cs_generate_variant:Nn \tl_if_empty:NTF { c } +\prg_new_conditional:Npnn \tl_if_empty:n #1 { p,TF,T,F} { + \exp_after:wN \if_meaning:w \exp_after:wN \q_nil \tl_to_str:n {#1} \q_nil + \prg_return_true: + \else: + \prg_return_false: + \fi: +} +\cs_generate_variant:Nn \tl_if_empty_p:n { V } +\cs_generate_variant:Nn \tl_if_empty:nTF { V } +\cs_generate_variant:Nn \tl_if_empty:nT { V } +\cs_generate_variant:Nn \tl_if_empty:nF { V } +\cs_new:Npn \tl_if_empty_return:o #1 { + \exp_after:wN \if_meaning:w \exp_after:wN \q_nil + \tl_to_str:n \exp_after:wN {#1} \q_nil + \prg_return_true: + \else: + \prg_return_false: + \fi: +} +\prg_new_conditional:Npnn \tl_if_empty:o #1 { p,TF,T,F} + { \tl_if_empty_return:o {#1} } +\prg_new_conditional:Npnn \tl_if_eq:NN #1#2 { p , T , F , TF } + { + \if_meaning:w #1 #2 + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +\cs_generate_variant:Nn \tl_if_eq_p:NN { Nc , c , cc } +\cs_generate_variant:Nn \tl_if_eq:NNTF { Nc , c , cc } +\cs_generate_variant:Nn \tl_if_eq:NNT { Nc , c , cc } +\cs_generate_variant:Nn \tl_if_eq:NNF { Nc , c , cc } +\prg_new_protected_conditional:Npnn \tl_if_eq:nn #1#2 { T , F , TF } + { + \group_begin: + \tl_set:Nn \l_tl_tmpa_tl {#1} + \tl_set:Nn \l_tl_tmpb_tl {#2} + \if_meaning:w \l_tl_tmpa_tl \l_tl_tmpb_tl + \group_end: + \prg_return_true: + \else: + \group_end: + \prg_return_false: + \fi: + } +\tl_new:N \l_tl_tmpa_tl +\tl_new:N \l_tl_tmpb_tl +\cs_new_protected_nopar:Npn \tl_if_in:NnT { \exp_args:No \tl_if_in:nnT } +\cs_new_protected_nopar:Npn \tl_if_in:NnF { \exp_args:No \tl_if_in:nnF } +\cs_new_protected_nopar:Npn \tl_if_in:NnTF { \exp_args:No \tl_if_in:nnTF } +\cs_generate_variant:Nn \tl_if_in:NnT { c } +\cs_generate_variant:Nn \tl_if_in:NnF { c } +\cs_generate_variant:Nn \tl_if_in:NnTF { c } +\prg_new_protected_conditional:Npnn \tl_if_in:nn #1#2 { T , F , TF } + { + \cs_set:Npn \tl_tmp:w ##1 #2 { } + \tl_if_empty:oTF { \tl_tmp:w #1 {} {} #2 } + { \prg_return_false: } { \prg_return_true: } + } +\cs_generate_variant:Nn \tl_if_in:nnT { V } +\cs_generate_variant:Nn \tl_if_in:nnF { V } +\cs_generate_variant:Nn \tl_if_in:nnTF { V } +\cs_generate_variant:Nn \tl_if_in:nnT { o } +\cs_generate_variant:Nn \tl_if_in:nnF { o } +\cs_generate_variant:Nn \tl_if_in:nnTF { o } +\cs_generate_variant:Nn \tl_if_in:nnT { no } +\cs_generate_variant:Nn \tl_if_in:nnF { no } +\cs_generate_variant:Nn \tl_if_in:nnTF { no } +\prg_new_conditional:Npnn \tl_if_single:n #1 { p , T , F , TF } + { + \tl_if_blank:nTF {#1} + { \tl_if_empty:nTF {#1} { \prg_return_false: } { \prg_return_true: } } + { \tl_if_single_aux:n {#1} } + } +\prg_new_conditional:Npnn \tl_if_single:N #1 { p , T , F , TF } + { + \tl_if_blank:oTF #1 + { \tl_if_empty:NTF #1 { \prg_return_false: } { \prg_return_true: } } + { \exp_args:No \tl_if_single_aux:n {#1} } + } +\cs_new:Npn \tl_if_single_aux:n #1 + { \tl_if_empty_return:o { \use_none:n #1 } } +\cs_new:Npn \tl_map_function:nN #1#2 + { \tl_map_function_aux:Nn #2 #1 \q_recursion_tail \q_recursion_stop } +\cs_new_nopar:Npn \tl_map_function:NN #1#2 + { + \exp_after:wN \tl_map_function_aux:Nn + \exp_after:wN #2 #1 \q_recursion_tail \q_recursion_stop + } +\cs_new:Npn \tl_map_function_aux:Nn #1#2 + { + \quark_if_recursion_tail_stop:n {#2} + #1 {#2} \tl_map_function_aux:Nn #1 + } +\cs_generate_variant:Nn \tl_map_function:NN { c } +\cs_new_protected:Npn \tl_map_inline:nn #1#2 + { + \int_gincr:N \g_tl_inline_level_int + \cs_gset:cpn { tl_map_inline_ \int_use:N \g_tl_inline_level_int :n } + ##1 {#2} + \exp_args:Nc \tl_map_function_aux:Nn + { tl_map_inline_ \int_use:N \g_tl_inline_level_int :n } + #1 \q_recursion_tail \q_recursion_stop + \int_gdecr:N \g_tl_inline_level_int + } +\cs_new_protected:Npn \tl_map_inline:Nn #1#2 + { + \int_gincr:N \g_tl_inline_level_int + \cs_gset:cpn { tl_map_inline_ \int_use:N \g_tl_inline_level_int :n } + ##1 {#2} + \exp_last_unbraced:NcV \tl_map_function_aux:Nn + { tl_map_inline_ \int_use:N \g_tl_inline_level_int :n } + #1 \q_recursion_tail\q_recursion_stop + \int_gdecr:N \g_tl_inline_level_int + } +\cs_generate_variant:Nn \tl_map_inline:Nn { c } +\cs_new_protected:Npn \tl_map_variable:nNn #1#2#3 + { \tl_map_variable_aux:Nnn #2 {#3} #1 \q_recursion_tail \q_recursion_stop } +\cs_new_protected_nopar:Npn \tl_map_variable:NNn + { \exp_args:No \tl_map_variable:nNn } +\cs_new_protected:Npn \tl_map_variable_aux:Nnn #1#2#3 + { + \tl_set:Nn #1 {#3} + \quark_if_recursion_tail_stop:N #1 + #2 \tl_map_variable_aux:Nnn #1 {#2} + } +\cs_generate_variant:Nn \tl_map_variable:NNn { c } +\cs_new_eq:NN \tl_map_break: \use_none_delimit_by_q_recursion_stop:w +\cs_new_eq:NN \tl_to_str:n \etex_detokenize:D +\cs_new_nopar:Npn \tl_to_str:N #1 { \etex_detokenize:D \exp_after:wN {#1} } +\cs_generate_variant:Nn \tl_to_str:N { c } +\cs_new_eq:NN \tl_use:N \prg_do_nothing: +\cs_new_nopar:Npn \tl_use:c #1 + { + \if_cs_exist:w #1 \cs_end: + \cs:w #1 \exp_after:wN \cs_end: + \else: + \exp_after:wN \tl_error_message: + \fi: + } +\group_begin: +\tex_catcode:D `\! = 11 \scan_stop: +\tex_catcode:D `\ = 11\scan_stop:% +\cs_gset_nopar:Npn\tl_error_message:{\undefined variable name!}% +\group_end:% +\cs_new:Npn \tl_length:n #1 + { + \int_eval:n + { 0 \tl_map_function:nN {#1} \tl_length_aux:n } + } +\cs_new_nopar:Npn \tl_length:N #1 + { + \int_eval:n + { 0 \tl_map_function:NN #1 \tl_length_aux:n } + } +\cs_new:Npn \tl_length_aux:n #1 { + 1 } +\cs_generate_variant:Nn \tl_length:n { V , o } +\cs_generate_variant:Nn \tl_length:N { c } +\cs_new:Npn \tl_reverse:n #1 + { \tl_reverse_aux:nN { } #1 \q_recursion_tail \q_recursion_stop } +\cs_new:Npn \tl_reverse_aux:nN #1#2 + { + \quark_if_recursion_tail_stop_do:nn {#2} {#1} + \tl_reverse_aux:nN { #2 #1 } + } +\cs_generate_variant:Nn \tl_reverse:n {V,o} +\cs_new_protected_nopar:Npn \tl_reverse:N #1 + { \tl_set:Nf #1 { \tl_reverse:o { #1 \exp_stop_f: } } } +\cs_generate_variant:Nn \tl_reverse:N { c } +\cs_new:Npn \tl_trim_spaces:n #1 + { + \etex_unexpanded:D \exp_after:wN \exp_after:wN \exp_after:wN + { \tl_trim_spaces_exp:n {#1} } + } +\cs_new_protected:Npn \tl_trim_spaces:N #1 + { \tl_set:Nx #1 { \exp_after:wN \tl_trim_spaces:n \exp_after:wN {#1} } } +\cs_new_protected:Npn \tl_gtrim_spaces:N #1 + { \tl_gset:Nx #1 { \exp_after:wN \tl_trim_spaces:n \exp_after:wN {#1} } } +\group_begin: + \tex_catcode:D `\Q = 3 \scan_stop: + \cs_new:Npn \tl_trim_spaces_exp:n #1 + { \tex_romannumeral:D - `0 \tl_trim_spaces_aux_i:w \exp_not:N #1 Q ~ Q } + \cs_new:Npn \tl_trim_spaces_aux_i:w #1 ~ Q { \tl_trim_spaces_aux_ii:w #1 Q } + \cs_new:Npn \tl_trim_spaces_aux_ii:w #1 Q #2 {#1} +\group_end: +\cs_generate_variant:Nn \tl_trim_spaces:N { c } +\cs_generate_variant:Nn \tl_gtrim_spaces:N { c } +\cs_new:Npn \tl_head:n #1 { \tl_head:w #1 \q_stop } +\cs_new:Npn \tl_tail:n #1 { \tl_tail:w #1 \q_stop } +\cs_new:Npn \tl_head:w #1#2 \q_stop {#1} +\cs_new:Npn \tl_tail:w #1#2 \q_stop {#2} +\cs_generate_variant:Nn \tl_head:n { V , v , f } +\cs_generate_variant:Nn \tl_tail:n { V , v , f } +\prg_new_conditional:Npnn \tl_if_head_eq_meaning:nN #1#2 { p , T , F , TF } + { + \exp_after:wN \if_meaning:w \tl_head:w #1 \q_stop #2 + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +\prg_new_conditional:Npnn \tl_if_head_eq_charcode:nN #1#2 { p , T , F , TF } + { + \exp_after:wN \if:w + \exp_after:wN \exp_not:N \tl_head:w #1 \q_stop \exp_not:N #2 + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +\cs_generate_variant:Nn \tl_if_head_eq_charcode_p:nN { f } +\cs_generate_variant:Nn \tl_if_head_eq_charcode:nNTF { f } +\cs_generate_variant:Nn \tl_if_head_eq_charcode:nNT { f } +\cs_generate_variant:Nn \tl_if_head_eq_charcode:nNF { f } +\prg_new_conditional:Npnn \tl_if_head_eq_catcode:nN #1#2 { p , T , F , TF } + { + \exp_after:wN \if_catcode:w \exp_after:wN \exp_not:N + \tl_head:w #1 \q_stop \exp_not:N #2 + \prg_return_true: \else: \prg_return_false: \fi: + } +\cs_new_protected:Npn \tl_show:N #1 { \cs_show:N #1 } +\cs_generate_variant:Nn \tl_show:N { c } +\cs_new_eq:NN \tl_show:n \etex_showtokens:D +\tl_const:Nx \c_job_name_tl { \tex_jobname:D } +\tl_const:Nn \c_empty_tl { } +\tl_const:Nn \c_space_tl { ~ } +\tl_new:N \g_tmpa_tl +\tl_new:N \g_tmpb_tl +\tl_new:N \l_tmpa_tl +\tl_new:N \l_tmpb_tl +\cs_new:Npn \tl_if_single_item:nTF #1 + { \str_if_eq:onTF { \use_ii:nn #1 {?} ? } {??} } +\cs_new:Npn \tl_if_single_item:nT #1 + { \str_if_eq:onT { \use_ii:nn #1 {?} ? } {??} } +\cs_new:Npn \tl_if_single_item:nF #1 + { \str_if_eq:onF { \use_ii:nn #1 {?} ? } {??} } +\cs_new:Npn \tl_if_single_item_p:n #1 + { \str_if_eq_p:on { \use_ii:nn #1 {?} ? } {??} } +\prg_new_conditional:Npnn \tl_if_head_begin_group:n #1 { p , T , F , TF } + { + \exp_after:wN \use_none:n + \exp_after:wN { + \exp_after:wN { + \token_to_str:N #1 . + } + \prg_return_true: \exp_after:wN \use_none:nn \token_to_str:N + } + \prg_return_false: + } +\prg_new_conditional:Npnn \tl_if_head_eq_space:n #1 { p , T , F , TF } + { + \if_false: { \fi: + \tl_if_head_eq_space_aux:w \prg_do_nothing: #1 ? ~ } + } +\cs_new:Npn \tl_if_head_eq_space_aux:w #1 ~ % + { + \tl_if_empty_return:o { #1 } + \exp_after:wN \use_none:n \exp_after:wN { \if_false: } \fi: + } +\prg_new_conditional:Npnn \tl_if_single_token:n #1 { p , T , F , TF } + { + \tl_if_head_eq_space:nTF {#1} + { + \str_if_eq:nnTF {#1} {~} + \prg_return_true: \prg_return_false: + } + { + \str_if_eq:onTF { \use_none:n #1 ? } {?} + { + \tl_if_head_begin_group:nTF {#1} + \prg_return_false: \prg_return_true: + } + \prg_return_false: + } + } +\cs_new_protected:Npn \tl_new:Nn #1#2 + { + \tl_new:N #1 + \tl_gset:Nn #1 {#2} + } +\cs_generate_variant:Nn \tl_new:Nn { c } +\cs_generate_variant:Nn \tl_new:Nn { Nx } +\cs_new_protected_nopar:Npn \tl_gset:Nc + { \pref_global:D \tl_set:Nc } +\cs_new_protected_nopar:Npn \tl_set:Nc #1#2 + { \tl_set:No #1 { \cs:w #2 \cs_end: } } +\cs_new_eq:NN \tl_replace_in:Nnn \tl_replace_once:Nnn +\cs_new_eq:NN \tl_replace_in:cnn \tl_replace_once:cnn +\cs_new_eq:NN \tl_greplace_in:Nnn \tl_greplace_once:Nnn +\cs_new_eq:NN \tl_greplace_in:cnn \tl_greplace_once:cnn +\cs_new_eq:NN \tl_replace_all_in:Nnn \tl_replace_all:Nnn +\cs_new_eq:NN \tl_replace_all_in:cnn \tl_replace_all:cnn +\cs_new_eq:NN \tl_greplace_all_in:Nnn \tl_greplace_all:Nnn +\cs_new_eq:NN \tl_greplace_all_in:cnn \tl_greplace_all:cnn +\cs_new_eq:NN \tl_remove_in:Nn \tl_remove_once:Nn +\cs_new_eq:NN \tl_remove_in:cn \tl_remove_once:cn +\cs_new_eq:NN \tl_gremove_in:Nn \tl_gremove_once:Nn +\cs_new_eq:NN \tl_gremove_in:cn \tl_gremove_once:cn +\cs_new_eq:NN \tl_remove_all_in:Nn \tl_remove_all:Nn +\cs_new_eq:NN \tl_remove_all_in:cn \tl_remove_all:cn +\cs_new_eq:NN \tl_gremove_all_in:Nn \tl_gremove_all:Nn +\cs_new_eq:NN \tl_gremove_all_in:cn \tl_gremove_all:cn +\cs_new_eq:NN \tl_elt_count:n \tl_length:n +\cs_new_eq:NN \tl_elt_count:V \tl_length:V +\cs_new_eq:NN \tl_elt_count:o \tl_length:o +\cs_new_eq:NN \tl_elt_count:N \tl_length:N +\cs_new_eq:NN \tl_elt_count:c \tl_length:c +\cs_new_eq:NN \tl_head_i:n \tl_head:n +\cs_new_eq:NN \tl_head_i:w \tl_head:w +\cs_new:Npn \tl_head_iii:n #1 { \tl_head_iii:w #1 \q_stop } +\cs_generate_variant:Nn \tl_head_iii:n { f } +\cs_new:Npn \tl_head_iii:w #1#2#3#4 \q_stop {#1#2#3} +%% +%% +%% End of file `l3tl.sty'. diff --git a/Master/texmf-dist/tex/latex/l3kernel/l3token.sty b/Master/texmf-dist/tex/latex/l3kernel/l3token.sty new file mode 100644 index 00000000000..c4ca0549b2f --- /dev/null +++ b/Master/texmf-dist/tex/latex/l3kernel/l3token.sty @@ -0,0 +1,739 @@ +%% +%% This is file `l3token.sty', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% l3token.dtx (with options: `package') +%% +%% EXPERIMENTAL CODE +%% +%% Do not distribute this file without also distributing the +%% source files specified above. +%% +%% Do not distribute a modified version of this file. +%% +%% File: l3token.dtx Copyright (C) 2005-2011 The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +\RequirePackage{l3names} +\GetIdInfo$Id: l3token.dtx 2491 2011-07-02 11:49:37Z joseph $ + {L3 Experimental token manipulation} +%% \begin{function}[EXP,pTF]{\token_if_protected_long_macro:N} +\ProvidesExplPackage + {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +\package_check_loaded_expl: +\cs_new_protected_nopar:Npn \char_set_catcode:nn #1#2 + { \tex_catcode:D #1 = \int_eval:w #2 \int_eval_end: } +\cs_new_nopar:Npn \char_value_catcode:n #1 + { \tex_the:D \tex_catcode:D \int_eval:w #1\int_eval_end: } +\cs_new_nopar:Npn \char_show_value_catcode:n #1 + { \tex_showthe:D \tex_catcode:D \int_eval:w #1 \int_eval_end: } +\cs_new_protected_nopar:Npn \char_set_catcode_escape:N #1 + { \char_set_catcode:nn { `#1 } \c_zero } +\cs_new_protected_nopar:Npn \char_set_catcode_group_begin:N #1 + { \char_set_catcode:nn { `#1 } \c_one } +\cs_new_protected_nopar:Npn \char_set_catcode_group_end:N #1 + { \char_set_catcode:nn { `#1 } \c_two } +\cs_new_protected_nopar:Npn \char_set_catcode_math_toggle:N #1 + { \char_set_catcode:nn { `#1 } \c_three } +\cs_new_protected_nopar:Npn \char_set_catcode_alignment:N #1 + { \char_set_catcode:nn { `#1 } \c_four } +\cs_new_protected_nopar:Npn \char_set_catcode_end_line:N #1 + { \char_set_catcode:nn { `#1 } \c_five } +\cs_new_protected_nopar:Npn \char_set_catcode_parameter:N #1 + { \char_set_catcode:nn { `#1 } \c_six } +\cs_new_protected_nopar:Npn \char_set_catcode_math_superscript:N #1 + { \char_set_catcode:nn { `#1 } \c_seven } +\cs_new_protected_nopar:Npn \char_set_catcode_math_subscript:N #1 + { \char_set_catcode:nn { `#1 } \c_eight } +\cs_new_protected_nopar:Npn \char_set_catcode_ignore:N #1 + { \char_set_catcode:nn { `#1 } \c_nine } +\cs_new_protected_nopar:Npn \char_set_catcode_space:N #1 + { \char_set_catcode:nn { `#1 } \c_ten } +\cs_new_protected_nopar:Npn \char_set_catcode_letter:N #1 + { \char_set_catcode:nn { `#1 } \c_eleven } +\cs_new_protected_nopar:Npn \char_set_catcode_other:N #1 + { \char_set_catcode:nn { `#1 } \c_twelve } +\cs_new_protected_nopar:Npn \char_set_catcode_active:N #1 + { \char_set_catcode:nn { `#1 } \c_thirteen } +\cs_new_protected_nopar:Npn \char_set_catcode_comment:N #1 + { \char_set_catcode:nn { `#1 } \c_fourteen } +\cs_new_protected_nopar:Npn \char_set_catcode_invalid:N #1 + { \char_set_catcode:nn { `#1 } \c_fifteen } +\cs_new_protected_nopar:Npn \char_set_catcode_escape:n #1 + { \char_set_catcode:nn {#1} \c_zero } +\cs_new_protected_nopar:Npn \char_set_catcode_group_begin:n #1 + { \char_set_catcode:nn {#1} \c_one } +\cs_new_protected_nopar:Npn \char_set_catcode_group_end:n #1 + { \char_set_catcode:nn {#1} \c_two } +\cs_new_protected_nopar:Npn \char_set_catcode_math_toggle:n #1 + { \char_set_catcode:nn {#1} \c_three } +\cs_new_protected_nopar:Npn \char_set_catcode_alignment:n #1 + { \char_set_catcode:nn {#1} \c_four } +\cs_new_protected_nopar:Npn \char_set_catcode_end_line:n #1 + { \char_set_catcode:nn {#1} \c_five } +\cs_new_protected_nopar:Npn \char_set_catcode_parameter:n #1 + { \char_set_catcode:nn {#1} \c_six } +\cs_new_protected_nopar:Npn \char_set_catcode_math_superscript:n #1 + { \char_set_catcode:nn {#1} \c_seven } +\cs_new_protected_nopar:Npn \char_set_catcode_math_subscript:n #1 + { \char_set_catcode:nn {#1} \c_eight } +\cs_new_protected_nopar:Npn \char_set_catcode_ignore:n #1 + { \char_set_catcode:nn {#1} \c_nine } +\cs_new_protected_nopar:Npn \char_set_catcode_space:n #1 + { \char_set_catcode:nn {#1} \c_ten } +\cs_new_protected_nopar:Npn \char_set_catcode_letter:n #1 + { \char_set_catcode:nn {#1} \c_eleven } +\cs_new_protected_nopar:Npn \char_set_catcode_other:n #1 + { \char_set_catcode:nn {#1} \c_twelve } +\cs_new_protected_nopar:Npn \char_set_catcode_active:n #1 + { \char_set_catcode:nn {#1} \c_thirteen } +\cs_new_protected_nopar:Npn \char_set_catcode_comment:n #1 + { \char_set_catcode:nn {#1} \c_fourteen } +\cs_new_protected_nopar:Npn \char_set_catcode_invalid:n #1 + { \char_set_catcode:nn {#1} \c_fifteen } +\cs_new_protected_nopar:Npn \char_set_mathcode:nn #1#2 + { \tex_mathcode:D #1 = \int_eval:w #2 \int_eval_end: } +\cs_new_nopar:Npn \char_value_mathcode:n #1 + { \tex_the:D \tex_mathcode:D \int_eval:w #1\int_eval_end: } +\cs_new_nopar:Npn \char_show_value_mathcode:n #1 + { \tex_showthe:D \tex_mathcode:D \int_eval:w #1 \int_eval_end: } +\cs_new_protected_nopar:Npn \char_set_lccode:nn #1#2 + { \tex_lccode:D #1 = \int_eval:w #2 \int_eval_end: } +\cs_new_nopar:Npn \char_value_lccode:n #1 + { \tex_the:D \tex_lccode:D \int_eval:w #1\int_eval_end: } +\cs_new_nopar:Npn \char_show_value_lccode:n #1 + { \tex_showthe:D \tex_lccode:D \int_eval:w #1 \int_eval_end: } +\cs_new_protected_nopar:Npn \char_set_uccode:nn #1#2 + { \tex_uccode:D #1 = \int_eval:w #2 \int_eval_end: } +\cs_new_nopar:Npn \char_value_uccode:n #1 + { \tex_the:D \tex_uccode:D \int_eval:w #1\int_eval_end: } +\cs_new_nopar:Npn \char_show_value_uccode:n #1 + { \tex_showthe:D \tex_uccode:D \int_eval:w #1 \int_eval_end: } +\cs_new_protected_nopar:Npn \char_set_sfcode:nn #1#2 + { \tex_sfcode:D #1 = \int_eval:w #2 \int_eval_end: } +\cs_new_nopar:Npn \char_value_sfcode:n #1 + { \tex_the:D \tex_sfcode:D \int_eval:w #1\int_eval_end: } +\cs_new_nopar:Npn \char_show_value_sfcode:n #1 + { \tex_showthe:D \tex_sfcode:D \int_eval:w #1 \int_eval_end: } +\cs_new_protected_nopar:Npn \token_new:Nn #1#2 { \cs_new_eq:NN #1 #2 } +\cs_new_eq:NN \c_group_begin_token { +\cs_new_eq:NN \c_group_end_token } +\group_begin: + \char_set_catcode_math_toggle:N \* + \token_new:Nn \c_math_toggle_token { * } + \char_set_catcode_alignment:N \* + \token_new:Nn \c_alignment_token { * } + \token_new:Nn \c_parameter_token { # } + \token_new:Nn \c_math_superscript_token { ^ } + \char_set_catcode_math_subscript:N \* + \token_new:Nn \c_math_subscript_token { * } + \token_new:Nn \c_space_token { ~ } + \token_new:Nn \c_catcode_letter_token { a } + \token_new:Nn \c_catcode_other_token { 1 } +\group_end: +\group_begin: + \char_set_catcode_active:N \* + \cs_new_nopar:Npn \c_catcode_active_tl { \exp_not:N * } +\group_end: +\prg_new_conditional:Npnn \token_if_group_begin:N #1 { p , T , F , TF } + { + \if_catcode:w \exp_not:N #1 \c_group_begin_token + \prg_return_true: \else: \prg_return_false: \fi: + } +\prg_new_conditional:Npnn \token_if_group_end:N #1 { p , T , F , TF } + { + \if_catcode:w \exp_not:N #1 \c_group_end_token + \prg_return_true: \else: \prg_return_false: \fi: + } +\prg_new_conditional:Npnn \token_if_math_toggle:N #1 { p , T , F , TF } + { + \if_catcode:w \exp_not:N #1 \c_math_toggle_token + \prg_return_true: \else: \prg_return_false: \fi: + } +\prg_new_conditional:Npnn \token_if_alignment:N #1 { p , T , F , TF } + { + \if_catcode:w \exp_not:N #1 \c_alignment_token + \prg_return_true: \else: \prg_return_false: \fi: + } +\group_begin: +\cs_set_eq:NN \c_parameter_token \scan_stop: +\prg_new_conditional:Npnn \token_if_parameter:N #1 { p , T , F , TF } + { + \if_catcode:w \exp_not:N #1 \c_parameter_token + \prg_return_true: \else: \prg_return_false: \fi: + } +\group_end: +\prg_new_conditional:Npnn \token_if_math_superscript:N #1 { p , T , F , TF } + { + \if_catcode:w \exp_not:N #1 \c_math_superscript_token + \prg_return_true: \else: \prg_return_false: \fi: + } +\prg_new_conditional:Npnn \token_if_math_subscript:N #1 { p , T , F , TF } + { + \if_catcode:w \exp_not:N #1 \c_math_subscript_token + \prg_return_true: \else: \prg_return_false: \fi: + } +\prg_new_conditional:Npnn \token_if_space:N #1 { p , T , F , TF } + { + \if_catcode:w \exp_not:N #1 \c_space_token + \prg_return_true: \else: \prg_return_false: \fi: + } +\prg_new_conditional:Npnn \token_if_letter:N #1 { p , T , F , TF } + { + \if_catcode:w \exp_not:N #1 \c_catcode_letter_token + \prg_return_true: \else: \prg_return_false: \fi: + } +\prg_new_conditional:Npnn \token_if_other:N #1 { p , T , F , TF } + { + \if_catcode:w \exp_not:N #1 \c_catcode_other_token + \prg_return_true: \else: \prg_return_false: \fi: + } +\prg_new_conditional:Npnn \token_if_active:N #1 { p , T , F , TF } + { + \if_catcode:w \exp_not:N #1 \c_catcode_active_tl + \prg_return_true: \else: \prg_return_false: \fi: + } +\prg_new_conditional:Npnn \token_if_eq_meaning:NN #1#2 { p , T , F , TF } + { + \if_meaning:w #1 #2 + \prg_return_true: \else: \prg_return_false: \fi: + } +\prg_new_conditional:Npnn \token_if_eq_catcode:NN #1#2 { p , T , F , TF } + { + \if_catcode:w \exp_not:N #1 \exp_not:N #2 + \prg_return_true: \else: \prg_return_false: \fi: + } +\prg_new_conditional:Npnn \token_if_eq_charcode:NN #1#2 { p , T , F , TF } + { + \if_charcode:w \exp_not:N #1 \exp_not:N #2 + \prg_return_true: \else: \prg_return_false: \fi: + } +\group_begin: +\char_set_catcode_other:N \M +\char_set_catcode_other:N \A +\char_set_lccode:nn { `\; } { `\: } +\char_set_lccode:nn { `\T } { `\T } +\char_set_lccode:nn { `\F } { `\F } +\tl_to_lowercase:n + { + \group_end: + \prg_new_conditional:Npnn \token_if_macro:N #1 { p , T , F , TF } + { + \exp_after:wN \token_if_macro_p_aux:w + \token_to_meaning:N #1 MA; \q_stop + } + \cs_new_nopar:Npn \token_if_macro_p_aux:w #1 MA #2 ; #3 \q_stop + { + \if_int_compare:w \pdftex_strcmp:D { #2 } { cro } = \c_zero + \prg_return_true: + \else: + \prg_return_false: + \fi: + } + } +\prg_new_conditional:Npnn \token_if_cs:N #1 { p , T , F , TF } + { + \if_catcode:w \exp_not:N #1 \scan_stop: + \prg_return_true: \else: \prg_return_false: \fi: + } +\prg_new_conditional:Npnn \token_if_expandable:N #1 { p , T , F , TF } + { + \cs_if_exist:NTF #1 + { + \exp_after:wN \if_meaning:w \exp_not:N #1 #1 + \prg_return_false: \else: \prg_return_true: \fi: + } + { \prg_return_false: } + } +\group_begin: + \char_set_lccode:nn { `\T } { `\T } + \char_set_lccode:nn { `\F } { `\F } + \char_set_lccode:nn { `\X } { `\n } + \char_set_lccode:nn { `\Y } { `\t } + \char_set_lccode:nn { `\Z } { `\d } + \char_set_lccode:nn { `\? } { `\\ } + \tl_map_inline:nn { \X \Y \Z \M \C \H \A \R \O \U \S \K \I \P \L \G \P \E } + { \char_set_catcode:nn { `#1 } \c_twelve } +\tl_to_lowercase:n + { + \group_end: + \prg_new_conditional:Npnn \token_if_chardef:N #1 { p , T , F , TF } + { + \exp_after:wN \token_if_chardef_aux:w + \token_to_meaning:N #1 ?CHAR" \q_stop + } + \cs_new_nopar:Npn \token_if_chardef_aux:w #1 ?CHAR" #2 \q_stop + { \tl_if_empty:nTF {#1} { \prg_return_true: } { \prg_return_false: } } + \prg_new_conditional:Npnn \token_if_mathchardef:N #1 { p , T , F , TF } + { + \exp_after:wN \token_if_mathchardef_aux:w + \token_to_meaning:N #1 ?MAYHCHAR" \q_stop + } + \cs_new_nopar:Npn \token_if_mathchardef_aux:w #1 ?MAYHCHAR" #2 \q_stop + { \tl_if_empty:nTF {#1} { \prg_return_true: } { \prg_return_false: } } + \prg_new_conditional:Npnn \token_if_int_register:N #1 { p , T , F , TF } + { + \if_meaning:w \tex_countdef:D #1 + \prg_return_false: + \else: + \exp_after:wN \token_if_int_register_aux:w + \token_to_meaning:N #1 ?COUXY \q_stop + \fi: + } + \cs_new_nopar:Npn \token_if_int_register_aux:w #1 ?COUXY #2 \q_stop + { \tl_if_empty:nTF {#1} { \prg_return_true: } { \prg_return_false: } } + \prg_new_conditional:Npnn \token_if_skip_register:N #1 { p , T , F , TF } + { + \if_meaning:w \tex_skipdef:D #1 + \prg_return_false: + \else: + \exp_after:wN \token_if_skip_register_aux:w + \token_to_meaning:N #1?SKIP\q_stop + \fi: + } + \cs_new_nopar:Npn \token_if_skip_register_aux:w #1 ?SKIP #2 \q_stop + { \tl_if_empty:nTF {#1} { \prg_return_true: } { \prg_return_false: } } + \prg_new_conditional:Npnn \token_if_dim_register:N #1 { p , T , F , TF } + { + \if_meaning:w \tex_dimendef:D #1 + \c_false_bool + \else: + \exp_after:wN \token_if_dim_register_aux:w + \token_to_meaning:N #1 ?ZIMEX \q_stop + \fi: + } + \cs_new_nopar:Npn \token_if_dim_register_aux:w #1 ?ZIMEX #2 \q_stop + { \tl_if_empty:nTF {#1} { \prg_return_true: } { \prg_return_false: } } + \prg_new_conditional:Npnn \token_if_toks_register:N #1 { p , T , F , TF } + { + \if_meaning:w \tex_toksdef:D #1 + \prg_return_false: + \else: + \exp_after:wN \token_if_toks_register_aux:w + \token_to_meaning:N #1 ?YOKS \q_stop + \fi: + } + \cs_new_nopar:Npn \token_if_toks_register_aux:w #1 ?YOKS #2 \q_stop + { \tl_if_empty:nTF {#1} { \prg_return_true: } { \prg_return_false: } } + \prg_new_conditional:Npnn \token_if_protected_macro:N #1 + { p , T , F , TF } + { + \exp_after:wN \token_if_protected_macro_aux:w + \token_to_meaning:N #1 ?PROYECYEZ~MACRO \q_stop + } + \cs_new_nopar:Npn \token_if_protected_macro_aux:w + #1 ?PROYECYEZ~MACRO #2 \q_stop + { \tl_if_empty:nTF {#1} { \prg_return_true: } { \prg_return_false: } } + \prg_new_conditional:Npnn \token_if_long_macro:N #1 { p , T , F , TF } + { + \exp_after:wN \token_if_long_macro_aux:w + \token_to_meaning:N #1 ?LOXG~MACRO \q_stop + } + \cs_new_nopar:Npn \token_if_long_macro_aux:w #1 ?LOXG~MACRO #2 \q_stop + { \tl_if_empty:nTF {#1} { \prg_return_true: } { \prg_return_false: } } + \prg_new_conditional:Npnn \token_if_protected_long_macro:N #1 + { p , T , F , TF } + { + \exp_after:wN \token_if_protected_long_macro_aux:w + \token_to_meaning:N #1 ?PROYECYEZ?LOXG~MACRO \q_stop + } + \cs_new_nopar:Npn \token_if_protected_long_macro_aux:w + #1 ?PROYECYEZ?LOXG~MACRO #2 \q_stop + { \tl_if_empty:nTF {#1} { \prg_return_true: } { \prg_return_false: } } + } +\tex_chardef:D \c_token_A_int = `A ~ % +\group_begin: +\char_set_catcode_other:N \; +\char_set_lccode:nn { `\; } { `\: } +\char_set_lccode:nn { `\T } { `\T } +\char_set_lccode:nn { `\F } { `\F } +\tl_to_lowercase:n { + \group_end: + \prg_new_conditional:Npnn \token_if_primitive:N #1 { p , T , F , TF } + { + \token_if_macro:NTF #1 + \prg_return_false: + { + \exp_after:wN \token_if_primitive_aux:NNw + \token_to_meaning:N #1 ; ; ; \q_stop #1 + } + } + \cs_new_nopar:Npn \token_if_primitive_aux:NNw #1#2 #3 ; #4 \q_stop + { + \tl_if_empty:oTF { \token_if_primitive_aux_space:w #3 ~ } + { \token_if_primitive_aux_loop:N #3 ; \q_stop } + { \token_if_primitive_aux_nullfont:N } + } +} +\cs_new_nopar:Npn \token_if_primitive_aux_space:w #1 ~ { } +\cs_new:Npn \token_if_primitive_aux_nullfont:N #1 + { + \if_meaning:w \tex_nullfont:D #1 + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +\cs_new_nopar:Npn \token_if_primitive_aux_loop:N #1 + { + \if_num:w `#1 < \c_token_A_int % + \exp_after:wN \token_if_primitive_auxii:Nw + \exp_after:wN #1 + \else: + \exp_after:wN \token_if_primitive_aux_loop:N + \fi: + } +\cs_new_nopar:Npn \token_if_primitive_auxii:Nw #1 #2 \q_stop + { + \if:w : #1 + \exp_after:wN \token_if_primitive_aux_undefined:N + \else: + \prg_return_false: + \exp_after:wN \use_none:n + \fi: + } +\cs_new:Npn \token_if_primitive_aux_undefined:N #1 + { + \if_cs_exist:N #1 + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +\cs_new_eq:NN \l_peek_token ? +\cs_new_eq:NN \g_peek_token ? +\cs_new_eq:NN \l_peek_search_token ? +\cs_new_nopar:Npn \l_peek_search_tl { } +\cs_new_nopar:Npn \peek_true:w { } +\cs_new_nopar:Npn \peek_true_aux:w { } +\cs_new_nopar:Npn \peek_false:w { } +\cs_new:Npn \peek_tmp:w { } +\cs_new_protected_nopar:Npn \peek_after:Nw + { \tex_futurelet:D \l_peek_token } +\cs_new_protected_nopar:Npn \peek_gafter:Nw + { \pref_global:D \tex_futurelet:D \g_peek_token } +\cs_new_protected:Npn \peek_true_remove:w + { + \group_align_safe_end: + \tex_afterassignment:D \peek_true_aux:w + \cs_set_eq:NN \peek_tmp:w + } +\cs_new_protected:Npn \peek_token_generic:NNTF #1#2#3#4 + { + \cs_set_eq:NN \l_peek_search_token #2 + \tl_set:Nn \l_peek_search_tl {#2} + \cs_set_nopar:Npx \peek_true:w + { + \exp_not:N \group_align_safe_end: + \exp_not:n {#3} + } + \cs_set_nopar:Npx \peek_false:w + { + \exp_not:N \group_align_safe_end: + \exp_not:n {#4} + } + \group_align_safe_begin: + \peek_after:Nw #1 + } +\cs_new_protected:Npn \peek_token_generic:NNT #1#2#3 + { \peek_token_generic:NNTF #1 #2 {#3} { } } +\cs_new_protected:Npn \peek_token_generic:NNF #1#2#3 + { \peek_token_generic:NNTF #1 #2 { } {#3} } +\cs_new_protected:Npn \peek_token_remove_generic:NNTF #1#2#3#4 + { + \cs_set_eq:NN \l_peek_search_token #2 + \tl_set:Nn \l_peek_search_tl {#2} + \cs_set_eq:NN \peek_true:w \peek_true_remove:w + \cs_set_nopar:Npx \peek_true_aux:w { \exp_not:n {#3} } + \cs_set_nopar:Npx \peek_false:w + { + \exp_not:N \group_align_safe_end: + \exp_not:n {#4} + } + \group_align_safe_begin: + \peek_after:Nw #1 + } +\cs_new_protected:Npn \peek_token_remove_generic:NNT #1#2#3 + { \peek_token_remove_generic:NNTF #1 #2 {#3} { } } +\cs_new_protected:Npn \peek_token_remove_generic:NNF #1#2#3 + { \peek_token_remove_generic:NNTF #1 #2 { } {#3} } +\cs_new_nopar:Npn \peek_execute_branches_catcode: + { + \if_catcode:w + \exp_not:N \l_peek_token \exp_not:N \l_peek_search_token + \exp_after:wN \peek_true:w + \else: + \exp_after:wN \peek_false:w + \fi: + } +\cs_new_nopar:Npn \peek_execute_branches_meaning: + { + \if_meaning:w \l_peek_token \l_peek_search_token + \exp_after:wN \peek_true:w + \else: + \exp_after:wN \peek_false:w + \fi: + } +\cs_new_nopar:Npn \peek_execute_branches_charcode: + { + \bool_if:nTF + { + \token_if_eq_catcode_p:NN \l_peek_token \c_group_begin_token + || \token_if_eq_catcode_p:NN \l_peek_token \c_group_end_token + || \token_if_eq_meaning_p:NN \l_peek_token \c_space_token + } + { \peek_false:w } + { + \exp_after:wN \peek_execute_branches_charcode_aux:NN + \l_peek_search_tl + } + } +\cs_new:Npn \peek_execute_branches_charcode_aux:NN #1#2 + { + \if:w \exp_not:N #1 \exp_not:N #2 + \exp_after:wN \peek_true:w + \else: + \exp_after:wN \peek_false:w + \fi: + #2 + } +\cs_new_protected_nopar:Npn \peek_ignore_spaces_execute_branches: + { + \token_if_eq_meaning:NNTF \l_peek_token \c_space_token + { + \tex_afterassignment:D \peek_ignore_spaces_execute_branches_aux: + \cs_set_eq:NN \peek_tmp:w + } + { \peek_execute_branches: } + } +\cs_new_protected_nopar:Npn \peek_ignore_spaces_execute_branches_aux: + { \peek_after:Nw \peek_ignore_spaces_execute_branches: } +\group_begin: + \cs_set_nopar:Npn \peek_def:nnnn #1#2#3#4 + { + \peek_def_aux:nnnnn {#1} {#2} {#3} {#4} { TF } + \peek_def_aux:nnnnn {#1} {#2} {#3} {#4} { T } + \peek_def_aux:nnnnn {#1} {#2} {#3} {#4} { F } + } + \cs_set_nopar:Npn \peek_def_aux:nnnnn #1#2#3#4#5 + { + \cs_gset_nopar:cpx { #1 #5 } + { + \tl_if_empty:nF {#2} + { \exp_not:n { \cs_set_eq:NN \peek_execute_branches: #2 } } + \exp_not:c { #3 #5 } + \exp_not:n {#4} + } + } + \peek_def:nnnn { peek_catcode:N } + { } + { peek_token_generic:NN } + { \peek_execute_branches_catcode: } + \peek_def:nnnn { peek_catcode_ignore_spaces:N } + { \peek_execute_branches_catcode: } + { peek_token_generic:NN } + { \peek_ignore_spaces_execute_branches: } + \peek_def:nnnn { peek_catcode_remove:N } + { } + { peek_token_remove_generic:NN } + { \peek_execute_branches_catcode: } + \peek_def:nnnn { peek_catcode_remove_ignore_spaces:N } + { \peek_execute_branches_catcode: } + { peek_token_remove_generic:NN } + { \peek_ignore_spaces_execute_branches: } + \peek_def:nnnn { peek_charcode:N } + { } + { peek_token_generic:NN } + { \peek_execute_branches_charcode: } + \peek_def:nnnn { peek_charcode_ignore_spaces:N } + { \peek_execute_branches_charcode: } + { peek_token_generic:NN } + { \peek_ignore_spaces_execute_branches: } + \peek_def:nnnn { peek_charcode_remove:N } + { } + { peek_token_remove_generic:NN } + { \peek_execute_branches_charcode: } + \peek_def:nnnn { peek_charcode_remove_ignore_spaces:N } + { \peek_execute_branches_charcode: } + { peek_token_remove_generic:NN } + { \peek_ignore_spaces_execute_branches: } + \peek_def:nnnn { peek_meaning:N } + { } + { peek_token_generic:NN } + { \peek_execute_branches_meaning: } + \peek_def:nnnn { peek_meaning_ignore_spaces:N } + { \peek_execute_branches_meaning: } + { peek_token_generic:NN } + { \peek_ignore_spaces_execute_branches: } + \peek_def:nnnn { peek_meaning_remove:N } + { } + { peek_token_remove_generic:NN } + { \peek_execute_branches_meaning: } + \peek_def:nnnn { peek_meaning_remove_ignore_spaces:N } + { \peek_execute_branches_meaning: } + { peek_token_remove_generic:NN } + { \peek_ignore_spaces_execute_branches: } +\group_end: +\exp_args:Nno \use:nn + { \cs_new_nopar:Npn \token_get_prefix_arg_replacement_aux:wN #1 } + { \tl_to_str:n { macro : } #2 -> #3 \q_stop #4 } + { #4 {#1} {#2} {#3} } +\cs_new:Npn \token_get_prefix_spec:N #1 + { + \token_if_macro:NTF #1 + { + \exp_after:wN \token_get_prefix_arg_replacement_aux:wN + \token_to_meaning:N #1 \q_stop \use_i:nnn + } + { \scan_stop: } + } +\cs_new:Npn \token_get_arg_spec:N #1 + { + \token_if_macro:NTF #1 + { + \exp_after:wN \token_get_prefix_arg_replacement_aux:wN + \token_to_meaning:N #1 \q_stop \use_ii:nnn + } + { \scan_stop: } + } +\cs_new:Npn \token_get_replacement_spec:N #1 + { + \token_if_macro:NTF #1 + { + \exp_after:wN \token_get_prefix_arg_replacement_aux:wN + \token_to_meaning:N #1 \q_stop \use_iii:nnn + } + { \scan_stop: } + } +\group_begin: + \char_set_catcode_active:N \^^@ + \cs_set:Npn \char_tmp:NN #1#2 + { + \cs_new:Npn #1 ##1 + { + \char_set_catcode_active:n { `##1 } + \group_begin: + \char_set_lccode:nn { `\^^@ } { `##1 } + \tl_to_lowercase:n { \group_end: #2 ^^@ } + } + } + \char_tmp:NN \char_active_set:Npn \cs_set:Npn + \char_tmp:NN \char_active_set:Npx \cs_set:Npx + \char_tmp:NN \char_active_gset:Npn \cs_gset:Npn + \char_tmp:NN \char_active_gset:Npx \cs_gset:Npx + \char_tmp:NN \char_active_set_eq:NN \cs_set_eq:NN + \char_tmp:NN \char_active_gset_eq:NN \cs_gset_eq:NN +\group_end: +\cs_new_eq:NN \char_set_catcode:w \tex_catcode:D +\cs_new_eq:NN \char_set_mathcode:w \tex_mathcode:D +\cs_new_eq:NN \char_set_lccode:w \tex_lccode:D +\cs_new_eq:NN \char_set_uccode:w \tex_uccode:D +\cs_new_eq:NN \char_set_sfcode:w \tex_sfcode:D +\cs_new_nopar:Npn \char_value_catcode:w { \tex_the:D \char_set_catcode:w } +\cs_new_nopar:Npn \char_show_value_catcode:w + { \tex_showthe:D \char_set_catcode:w } +\cs_new_nopar:Npn \char_value_mathcode:w { \tex_the:D \char_set_mathcode:w } +\cs_new_nopar:Npn \char_show_value_mathcode:w + { \tex_showthe:D \char_set_mathcode:w } +\cs_new_nopar:Npn \char_value_lccode:w { \tex_the:D \char_set_lccode:w } +\cs_new_nopar:Npn \char_show_value_lccode:w + { \tex_showthe:D \char_set_lccode:w } +\cs_new_nopar:Npn \char_value_uccode:w { \tex_the:D \char_set_uccode:w } +\cs_new_nopar:Npn \char_show_value_uccode:w + { \tex_showthe:D \char_set_uccode:w } +\cs_new_nopar:Npn \char_value_sfcode:w { \tex_the:D \char_set_sfcode:w } +\cs_new_nopar:Npn \char_show_value_sfcode:w + { \tex_showthe:D \char_set_sfcode:w } +\cs_new_eq:NN \peek_after:NN \peek_after:Nw +\cs_new_eq:NN \peek_gafter:NN \peek_gafter:Nw +\cs_new_eq:NN \c_alignment_tab_token \c_alignment_token +\cs_new_eq:NN \c_math_shift_token \c_math_toggle_token +\cs_new_eq:NN \c_letter_token \c_catcode_letter_token +\cs_new_eq:NN \c_other_char_token \c_catcode_other_token +\cs_new_eq:NN \c_active_char_token \c_catcode_active_tl +\cs_new_eq:NN \char_make_escape:N \char_set_catcode_escape:N +\cs_new_eq:NN \char_make_begin_group:N \char_set_catcode_group_begin:N +\cs_new_eq:NN \char_make_end_group:N \char_set_catcode_group_end:N +\cs_new_eq:NN \char_make_math_shift:N \char_set_catcode_math_toggle:N +\cs_new_eq:NN \char_make_alignment_tab:N \char_set_catcode_alignment:N +\cs_new_eq:NN \char_make_end_line:N \char_set_catcode_end_line:N +\cs_new_eq:NN \char_make_parameter:N \char_set_catcode_parameter:N +\cs_new_eq:NN \char_make_math_superscript:N + \char_set_catcode_math_superscript:N +\cs_new_eq:NN \char_make_math_subscript:N + \char_set_catcode_math_subscript:N +\cs_new_eq:NN \char_make_ignore:N \char_set_catcode_ignore:N +\cs_new_eq:NN \char_make_space:N \char_set_catcode_space:N +\cs_new_eq:NN \char_make_letter:N \char_set_catcode_letter:N +\cs_new_eq:NN \char_make_other:N \char_set_catcode_other:N +\cs_new_eq:NN \char_make_active:N \char_set_catcode_active:N +\cs_new_eq:NN \char_make_comment:N \char_set_catcode_comment:N +\cs_new_eq:NN \char_make_invalid:N \char_set_catcode_invalid:N +\cs_new_eq:NN \char_make_escape:n \char_set_catcode_escape:n +\cs_new_eq:NN \char_make_begin_group:n \char_set_catcode_group_begin:n +\cs_new_eq:NN \char_make_end_group:n \char_set_catcode_group_end:n +\cs_new_eq:NN \char_make_math_shift:n \char_set_catcode_math_toggle:n +\cs_new_eq:NN \char_make_alignment_tab:n \char_set_catcode_alignment:n +\cs_new_eq:NN \char_make_end_line:n \char_set_catcode_end_line:n +\cs_new_eq:NN \char_make_parameter:n \char_set_catcode_parameter:n +\cs_new_eq:NN \char_make_math_superscript:n + \char_set_catcode_math_superscript:n +\cs_new_eq:NN \char_make_math_subscript:n + \char_set_catcode_math_subscript:n +\cs_new_eq:NN \char_make_ignore:n \char_set_catcode_ignore:n +\cs_new_eq:NN \char_make_space:n \char_set_catcode_space:n +\cs_new_eq:NN \char_make_letter:n \char_set_catcode_letter:n +\cs_new_eq:NN \char_make_other:n \char_set_catcode_other:n +\cs_new_eq:NN \char_make_active:n \char_set_catcode_active:n +\cs_new_eq:NN \char_make_comment:n \char_set_catcode_comment:n +\cs_new_eq:NN \char_make_invalid:n \char_set_catcode_invalid:n +\cs_new_eq:NN \token_if_alignment_tab_p:N \token_if_alignment_p:N +\cs_new_eq:NN \token_if_alignment_tab:NT \token_if_alignment:NT +\cs_new_eq:NN \token_if_alignment_tab:NF \token_if_alignment:NF +\cs_new_eq:NN \token_if_alignment_tab:NTF \token_if_alignment:NTF +\cs_new_eq:NN \token_if_math_shift_p:N \token_if_math_toggle_p:N +\cs_new_eq:NN \token_if_math_shift:NT \token_if_math_toggle:NT +\cs_new_eq:NN \token_if_math_shift:NF \token_if_math_toggle:NF +\cs_new_eq:NN \token_if_math_shift:NTF \token_if_math_toggle:NTF +\cs_new_eq:NN \token_if_other_char_p:N \token_if_other_p:N +\cs_new_eq:NN \token_if_other_char:NT \token_if_other:NT +\cs_new_eq:NN \token_if_other_char:NF \token_if_other:NF +\cs_new_eq:NN \token_if_other_char:NTF \token_if_other:NTF +\cs_new_eq:NN \token_if_active_char_p:N \token_if_active_p:N +\cs_new_eq:NN \token_if_active_char:NT \token_if_active:NT +\cs_new_eq:NN \token_if_active_char:NF \token_if_active:NF +\cs_new_eq:NN \token_if_active_char:NTF \token_if_active:NTF +%% +%% +%% End of file `l3token.sty'. diff --git a/Master/texmf-dist/tex/latex/l3kernel/l3toks.sty b/Master/texmf-dist/tex/latex/l3kernel/l3toks.sty new file mode 100644 index 00000000000..1b1ab880687 --- /dev/null +++ b/Master/texmf-dist/tex/latex/l3kernel/l3toks.sty @@ -0,0 +1,163 @@ +%% +%% This is file `l3toks.sty', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% l3toks.dtx (with options: `package') +%% +%% EXPERIMENTAL CODE +%% +%% Do not distribute this file without also distributing the +%% source files specified above. +%% +%% Do not distribute a modified version of this file. +%% +%% File: l3toks.dtx Copyright (C) 1990-2011 The 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/svnroot/experimental/trunk/ +%% +%% 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +\RequirePackage{l3names} +\GetIdInfo$Id: l3toks.dtx 2478 2011-06-19 21:34:23Z joseph $ + {L3 Experimental token registers} +\ProvidesExplPackage + {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +\package_check_loaded_expl: +\cs_new_protected_nopar:Npn \toks_new:N #1 { + \chk_if_free_cs:N #1 + \newtoks #1 +} +\cs_generate_variant:Nn \toks_new:N {c} +\cs_new_eq:NN \toks_use:N \tex_the:D +\cs_generate_variant:Nn \toks_use:N {c} +\cs_new_eq:NN \toks_set:Nn \prg_do_nothing: +\cs_new_protected:Npn \toks_set:NV #1#2 { + #1 \exp_after:wN { \int_to_roman:w -`0 \exp_eval_register:N #2 } +} +\cs_new_protected:Npn \toks_set:Nv #1#2 { + #1 \exp_after:wN { \int_to_roman:w -`0 \exp_eval_register:c {#2} } +} +\cs_new_protected:Npn \toks_set:No #1#2 { #1 \exp_after:wN {#2} } +\cs_new_protected:Npn \toks_set:Nf #1#2 { + #1 \exp_after:wN { \int_to_roman:w -`0#2 } +} +\cs_generate_variant:Nn \toks_set:Nn {Nx,cn,cV,cv,co,cx,cf} +\cs_new_eq:NN \toks_gset:Nn \pref_global:D +\cs_generate_variant:Nn \toks_gset:Nn {NV,No,Nx,cn,cV,co,cx} +\cs_new_eq:NN \toks_set_eq:NN \prg_do_nothing: +\cs_new_eq:NN \toks_gset_eq:NN \pref_global:D +\cs_generate_variant:Nn \toks_set_eq:NN {Nc,cN,cc} +\cs_generate_variant:Nn \toks_gset_eq:NN {Nc,cN,cc} +\cs_new_protected_nopar:Npn \toks_clear:N #1 { + #1\c_empty_toks +} +\cs_new_protected_nopar:Npn \toks_gclear:N { + \pref_global:D + \toks_clear:N +} +\cs_generate_variant:Nn \toks_clear:N {c} +\cs_generate_variant:Nn \toks_gclear:N {c} +\cs_new_protected_nopar:Npn \toks_use_clear:N #1 { + \exp_last_unbraced:NNV \toks_clear:N #1 #1 +} +\cs_new_protected_nopar:Npn \toks_use_gclear:N { + \pref_global:D + \toks_use_clear:N +} +\cs_generate_variant:Nn \toks_use_clear:N {c} +\cs_generate_variant:Nn \toks_use_gclear:N {c} +\cs_new_eq:NN \toks_show:N \kernel_register_show:N +\cs_generate_variant:Nn \toks_show:N {c} +\cs_new_protected_nopar:Npn \toks_put_left:Nn #1 { + \exp_after:wN \toks_put_left_aux:w \exp_after:wN \q_nil + \toks_use:N #1 \q_stop #1 +} +\cs_generate_variant:Nn \toks_put_left:Nn {NV,No,Nx,cn,co,cV} +\cs_new_protected_nopar:Npn \toks_gput_left:Nn { + \pref_global:D + \toks_put_left:Nn +} +\cs_generate_variant:Nn \toks_gput_left:Nn {NV,No,Nx,cn,cV,co} +\cs_new:Npn \toks_put_left_aux:w #1\q_stop #2#3 { + #2 \exp_after:wN { \use_i:nn {#3} #1 } +} +\cs_new_protected:Npn \toks_put_right:Nn #1#2 { + #1 \exp_after:wN { \toks_use:N #1 #2 } +} +\cs_new_protected_nopar:Npn \toks_gput_right:Nn { + \pref_global:D + \toks_put_right:Nn +} +\cs_new_protected:Npn \toks_put_right:NV #1#2 { + #1 \exp_after:wN \exp_after:wN \exp_after:wN { + \exp_after:wN \toks_use:N \exp_after:wN #1 + \int_to_roman:w -`0 \exp_eval_register:N #2 + } +} +\cs_new_protected:Npn \toks_put_right:No #1#2 { + #1 \exp_after:wN \exp_after:wN \exp_after:wN { + \exp_after:wN \toks_use:N \exp_after:wN #1 #2 + } +} +\cs_generate_variant:Nn \toks_put_right:Nn {Nx,cn,cV,co} +\cs_generate_variant:Nn \toks_gput_right:Nn {NV,No,Nx,cn,cV,co} +\cs_new_protected:Npn \toks_put_right:Nf #1#2 { + #1 \exp_after:wN \exp_after:wN \exp_after:wN { + \exp_after:wN \toks_use:N \exp_after:wN #1 \int_to_roman:w -`0#2 + } +} +\prg_new_conditional:Nnn \toks_if_empty:N {p,TF,T,F} { + \tl_if_empty:VTF #1 {\prg_return_true:} {\prg_return_false:} +} +\cs_generate_variant:Nn \toks_if_empty_p:N {c} +\cs_generate_variant:Nn \toks_if_empty:NTF {c} +\cs_generate_variant:Nn \toks_if_empty:NT {c} +\cs_generate_variant:Nn \toks_if_empty:NF {c} +\prg_new_conditional:Nnn \toks_if_eq:NN {p,TF,T,F} { + \str_if_eq:xxTF {\toks_use:N #1} {\toks_use:N #2} + {\prg_return_true:} {\prg_return_false:} +} +\cs_generate_variant:Nn \toks_if_eq_p:NN {Nc,c,cc} +\cs_generate_variant:Nn \toks_if_eq:NNTF {Nc,c,cc} +\cs_generate_variant:Nn \toks_if_eq:NNT {Nc,c,cc} +\cs_generate_variant:Nn \toks_if_eq:NNF {Nc,c,cc} +\tex_toksdef:D \l_tmpa_toks = 255\scan_stop: +\toks_new:N \l_tmpb_toks +\toks_new:N \l_tmpc_toks +\toks_new:N \g_tmpa_toks +\toks_new:N \g_tmpb_toks +\toks_new:N \g_tmpc_toks +\toks_new:N \c_empty_toks +\toks_new:N \l_tl_replace_toks + +%% +%% +%% End of file `l3toks.sty'. |