diff options
Diffstat (limited to 'macros/latex/required/l3kernel/l3skip.dtx')
-rw-r--r-- | macros/latex/required/l3kernel/l3skip.dtx | 2600 |
1 files changed, 2600 insertions, 0 deletions
diff --git a/macros/latex/required/l3kernel/l3skip.dtx b/macros/latex/required/l3kernel/l3skip.dtx new file mode 100644 index 0000000000..a3d9256223 --- /dev/null +++ b/macros/latex/required/l3kernel/l3skip.dtx @@ -0,0 +1,2600 @@ +% \iffalse meta-comment +% +%% File: l3skip.dtx +% +% Copyright (C) 2004-2011 Frank Mittelbach, The LaTeX Project +% (C) 2012-2024 The LaTeX 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 +% +% https://www.latex-project.org/lppl.txt +% +% This file is part of the "l3kernel bundle" (The Work in LPPL) +% and all files in that bundle must be distributed together. +% +% ----------------------------------------------------------------------- +% +% The development version of the bundle can be found at +% +% https://github.com/latex3/latex3 +% +% for those people who are interested. +% +%<*driver> +\documentclass[full,kernel]{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{^^A +% The \pkg{l3skip} module\\ Dimensions and skips^^A +% } +% +% \author{^^A +% The \LaTeX{} Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% +% \date{Released 2024-04-11} +% +% \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. +% +% Many functions take +% \emph{dimension expressions} (\enquote{\meta{dim expr}}) or +% \emph{skip expressions} (\enquote{\meta{skip expr}}) as arguments. +% +% +% \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} +% is initially equal to $0$\,pt. +% \end{function} +% +% \begin{function}[added = 2012-03-05]{\dim_const:Nn, \dim_const:cn} +% \begin{syntax} +% \cs{dim_const:Nn} \meta{dimension} \Arg{dim expr} +% \end{syntax} +% Creates a new constant \meta{dimension} or raises an error if the +% name is already taken. The value of the \meta{dimension} is set +% globally to the \meta{dim expr}. +% \end{function} +% +% \begin{function}{\dim_zero:N, \dim_zero:c, \dim_gzero:N, \dim_gzero:c} +% \begin{syntax} +% \cs{dim_zero:N} \meta{dimension} +% \end{syntax} +% Sets \meta{dimension} to $0$\,pt. +% \end{function} +% +% \begin{function}[added = 2012-01-07] +% {\dim_zero_new:N, \dim_zero_new:c, \dim_gzero_new:N, \dim_gzero_new:c} +% \begin{syntax} +% \cs{dim_zero_new:N} \meta{dimension} +% \end{syntax} +% Ensures that the \meta{dimension} exists globally by applying +% \cs{dim_new:N} if necessary, then applies +% \cs[index=dim_zero:N]{dim_(g)zero:N} to leave +% the \meta{dimension} set to zero. +% \end{function} +% +% \begin{function}[EXP, pTF, added=2012-03-03]{\dim_if_exist:N, \dim_if_exist:c} +% \begin{syntax} +% \cs{dim_if_exist_p:N} \meta{dimension} +% \cs{dim_if_exist:NTF} \meta{dimension} \Arg{true code} \Arg{false code} +% \end{syntax} +% Tests whether the \meta{dimension} is currently defined. This does +% not check that the \meta{dimension} really is a dimension variable. +% \end{function} +% +% \section{Setting \texttt{dim} variables} +% +% \begin{function}[updated = 2011-10-22] +% {\dim_add:Nn, \dim_add:cn, \dim_gadd:Nn, \dim_gadd:cn} +% \begin{syntax} +% \cs{dim_add:Nn} \meta{dimension} \Arg{dim expr} +% \end{syntax} +% Adds the result of the \meta{dim expr} to the current +% content of the \meta{dimension}. +% \end{function} +% +% \begin{function}[updated = 2011-10-22] +% {\dim_set:Nn, \dim_set:cn, \dim_gset:Nn, \dim_gset:cn} +% \begin{syntax} +% \cs{dim_set:Nn} \meta{dimension} \Arg{dim expr} +% \end{syntax} +% Sets \meta{dimension} to the value of \meta{dim expr}, which +% must evaluate to a length with units. +% \end{function} +% +% \begin{function} +% { +% \dim_set_eq:NN, \dim_set_eq:cN, \dim_set_eq:Nc, \dim_set_eq:cc, +% \dim_gset_eq:NN, \dim_gset_eq:cN, \dim_gset_eq:Nc, \dim_gset_eq:cc +% } +% \begin{syntax} +% \cs{dim_set_eq:NN} \meta{dimension_1} \meta{dimension_2} +% \end{syntax} +% Sets the content of \meta{dimension_1} equal to that of +% \meta{dimension_2}. +% \end{function} +% +% \begin{function}[updated = 2011-10-22] +% {\dim_sub:Nn, \dim_sub:cn, \dim_gsub:Nn, \dim_gsub:cn} +% \begin{syntax} +% \cs{dim_sub:Nn} \meta{dimension} \Arg{dim expr} +% \end{syntax} +% Subtracts the result of the \meta{dim expr} from the +% current content of the \meta{dimension}. +% \end{function} +% +% \section{Utilities for dimension calculations} +% +% \begin{function}[updated = 2012-09-26, EXP]{\dim_abs:n} +% \begin{syntax} +% \cs{dim_abs:n} \Arg{dim expr} +% \end{syntax} +% Converts the \meta{dim expr} to its absolute value, leaving the result +% in the input stream as a \meta{dimension denotation}. +% \end{function} +% +% \begin{function}[added = 2012-09-09, updated = 2012-09-26, EXP] +% {\dim_max:nn, \dim_min:nn} +% \begin{syntax} +% \cs{dim_max:nn} \Arg{dim expr_1} \Arg{dim expr_2} +% \cs{dim_min:nn} \Arg{dim expr_1} \Arg{dim expr_2} +% \end{syntax} +% Evaluates the two \meta{dim exprs} and leaves either the +% maximum or minimum value in the input stream as appropriate, as a +% \meta{dimension denotation}. +% \end{function} +% +% \begin{function}[updated = 2011-10-22, rEXP]{\dim_ratio:nn} +% \begin{syntax} +% \cs{dim_ratio:nn} \Arg{dim expr_1} \Arg{dim expr_2} +% \end{syntax} +% Parses the two \meta{dim exprs} and converts the ratio of +% the two to a form suitable for use inside a \meta{dim expr}. +% 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 ratio expression +% between two integers, with all distances converted to scaled points. +% Thus +% \begin{verbatim} +% \tl_set:Ne \l_my_tl { \dim_ratio:nn { 5 pt } { 10 pt } } +% \tl_show:N \l_my_tl +% \end{verbatim} +% displays |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{dim expr_1} \meta{relation} \Arg{dim expr_2} \\ +% \cs{dim_compare:nNnTF} +% ~~\Arg{dim expr_1} \meta{relation} \Arg{dim expr_2} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% This function first evaluates each of the \meta{dim exprs} +% 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} +% This function is less flexible than \cs{dim_compare:nTF} but around +% $5$~times faster. +% \end{function} +% +% \begin{function}[updated = 2013-01-13, EXP, pTF]{\dim_compare:n} +% \begin{syntax} +% \cs{dim_compare_p:n} \\ +% ~~\{ \\ +% ~~~~\meta{dim expr_1} \meta{relation_1} \\ +% ~~~~\ldots{} \\ +% ~~~~\meta{dim expr_N} \meta{relation_N} \\ +% ~~~~\meta{dim expr_{N+1}} \\ +% ~~\} \\ +% \cs{dim_compare:nTF} +% ~~\{ \\ +% ~~~~\meta{dim expr_1} \meta{relation_1} \\ +% ~~~~\ldots{} \\ +% ~~~~\meta{dim expr_N} \meta{relation_N} \\ +% ~~~~\meta{dim expr_{N+1}} \\ +% ~~\} \\ +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% This function evaluates the \meta{dim exprs} as +% described for \cs{dim_eval:n} and compares consecutive result using +% the corresponding \meta{relation}, namely it compares +% \meta{dim expr_1} and \meta{dim expr_2} using the \meta{relation_1}, +% then \meta{dim expr_2} and \meta{dim expr_3} using the +% \meta{relation_2}, until finally comparing \meta{dim expr_N} and +% \meta{dim expr_{N+1}} using the \meta{relation_N}. The test yields +% \texttt{true} if all comparisons are \texttt{true}. Each +% \meta{dim expr} is evaluated only once, and the +% evaluation is lazy, in the sense that if one comparison is +% \texttt{false}, then no other \meta{dim expr} is +% evaluated and no other comparison is performed. The +% \meta{relations} can be any of the following: +% \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} +% This function is more flexible than \cs{dim_compare:nNnTF} but +% around $5$~times slower. +% \end{function} +% +% \begin{function}[added = 2013-07-24, EXP, noTF]{\dim_case:nn} +% \begin{syntax} +% \cs{dim_case:nnTF} \Arg{test dim expr} \\ +% ~~|{| \\ +% ~~~~\Arg{dim expr case_1} \Arg{code case_1} \\ +% ~~~~\Arg{dim expr case_2} \Arg{code case_2} \\ +% ~~~~\ldots \\ +% ~~~~\Arg{dim expr case_n} \Arg{code case_n} \\ +% ~~|}| \\ +% ~~\Arg{true code} +% ~~\Arg{false code} +% \end{syntax} +% This function evaluates the \meta{test dim expr} and +% compares this in turn to each of the +% \meta{dim expr cases}. If the two are equal then the +% associated \meta{code} is left in the input stream +% and other cases are discarded. If any of the +% cases are matched, the \meta{true code} is also inserted into the +% input stream (after the code for the appropriate case), while if none +% match then the \meta{false code} is inserted. The function +% \cs{dim_case:nn}, which does nothing if there is no match, is also +% available. For example +% \begin{verbatim} +% \dim_set:Nn \l_tmpa_dim { 5 pt } +% \dim_case:nnF +% { 2 \l_tmpa_dim } +% { +% { 5 pt } { Small } +% { 4 pt + 6 pt } { Medium } +% { - 10 pt } { Negative } +% } +% { No idea! } +% \end{verbatim} +% leaves \enquote{\texttt{Medium}} in the input stream. +% \end{function} +% +% \section{Dimension expression loops} +% +% \begin{function}[rEXP]{\dim_do_until:nNnn} +% \begin{syntax} +% \cs{dim_do_until:nNnn} \Arg{dim expr_1} \meta{relation} \Arg{dim expr_2} \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{dim exprs} as described for \cs{dim_compare:nNnTF}. +% If the test is \texttt{false} then the \meta{code} is inserted +% into the input stream again and a loop occurs until the +% \meta{relation} is \texttt{true}. +% \end{function} +% +% \begin{function}[rEXP]{\dim_do_while:nNnn} +% \begin{syntax} +% \cs{dim_do_while:nNnn} \Arg{dim expr_1} \meta{relation} \Arg{dim expr_2} \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{dim exprs} as described for \cs{dim_compare:nNnTF}. +% If the test is \texttt{true} then the \meta{code} is inserted +% into the input stream again and a loop occurs until the +% \meta{relation} is \texttt{false}. +% \end{function} +% +% \begin{function}[rEXP]{\dim_until_do:nNnn} +% \begin{syntax} +% \cs{dim_until_do:nNnn} \Arg{dim expr_1} \meta{relation} \Arg{dim expr_2} \Arg{code} +% \end{syntax} +% Evaluates the relationship between the two \meta{dim exprs} +% 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 is repeated, and a loop occurs until the test is +% \texttt{true}. +% \end{function} +% +% \begin{function}[rEXP]{\dim_while_do:nNnn} +% \begin{syntax} +% \cs{dim_while_do:nNnn} \Arg{dim expr_1} \meta{relation} \Arg{dim expr_2} \Arg{code} +% \end{syntax} +% Evaluates the relationship between the two \meta{dim exprs} +% 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 is repeated, and a loop occurs until the test is +% \texttt{false}. +% \end{function} +% +% \begin{function}[updated = 2013-01-13, rEXP]{\dim_do_until:nn} +% \begin{syntax} +% \cs{dim_do_until:nn} \Arg{dimension relation} \Arg{code} +% \end{syntax} +% Places the \meta{code} in the input stream for \TeX{} to process, and +% then evaluates the \meta{dimension relation} +% as described for \cs{dim_compare:nTF}. +% If the test is \texttt{false} then the \meta{code} is inserted +% into the input stream again and a loop occurs until the +% \meta{relation} is \texttt{true}. +% \end{function} +% +% \begin{function}[updated = 2013-01-13, rEXP]{\dim_do_while:nn} +% \begin{syntax} +% \cs{dim_do_while:nn} \Arg{dimension relation} \Arg{code} +% \end{syntax} +% Places the \meta{code} in the input stream for \TeX{} to process, and +% then evaluates the \meta{dimension relation} +% as described for \cs{dim_compare:nTF}. +% If the test is \texttt{true} then the \meta{code} is inserted +% into the input stream again and a loop occurs until the +% \meta{relation} is \texttt{false}. +% \end{function} +% +% \begin{function}[updated = 2013-01-13, rEXP]{\dim_until_do:nn} +% \begin{syntax} +% \cs{dim_until_do:nn} \Arg{dimension relation} \Arg{code} +% \end{syntax} +% Evaluates the \meta{dimension relation} +% 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 is repeated, and a loop occurs until the test is +% \texttt{true}. +% \end{function} +% +% \begin{function}[updated = 2013-01-13, rEXP]{\dim_while_do:nn} +% \begin{syntax} +% \cs{dim_while_do:nn} \Arg{dimension relation} \Arg{code} +% \end{syntax} +% Evaluates the \meta{dimension relation} +% 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 is repeated, and a loop occurs until the test is +% \texttt{false}. +% \end{function} +% +% \section{Dimension step functions} +% +% \begin{function}[added = 2018-02-18, rEXP] +% {\dim_step_function:nnnN} +% \begin{syntax} +% \cs{dim_step_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 dimension 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}). The \meta{step} must +% be non-zero. If the \meta{step} is positive, the loop stops when +% the \meta{value} becomes larger than the \meta{final value}. If the +% \meta{step} is negative, the loop stops when the \meta{value} +% becomes smaller than the \meta{final value}. The \meta{function} +% should absorb one argument. +% \end{function} +% +% \begin{function}[added = 2018-02-18] +% {\dim_step_inline:nnnn} +% \begin{syntax} +% \cs{dim_step_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 dimension expressions. +% Then for each \meta{value} from the \meta{initial value} to the +% \meta{final value} in turn (using \meta{step} between each +% \meta{value}), the \meta{code} is inserted into the input stream +% with |#1| replaced by the current \meta{value}. Thus the +% \meta{code} should define a function of one argument~(|#1|). +% \end{function} +% +% \begin{function}[added = 2018-02-18] +% {\dim_step_variable:nnnNn} +% \begin{syntax} +% \cs{dim_step_variable:nnnNn} \\ +% ~~\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 dimension expressions. +% Then for each \meta{value} from the \meta{initial value} to the +% \meta{final value} in turn (using \meta{step} between each +% \meta{value}), 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{Using \texttt{dim} expressions and variables} +% +% \begin{function}[updated = 2011-10-22, EXP]{\dim_eval:n} +% \begin{syntax} +% \cs{dim_eval:n} \Arg{dim expr} +% \end{syntax} +% Evaluates the \meta{dim expr}, 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 is +% expressed in points (\texttt{pt}), and requires suitable +% termination if used in a \TeX{}-style assignment as it is \emph{not} +% an \meta{internal dimension}. +% \end{function} +% +% \begin{function}[EXP, added = 2018-11-03]{\dim_sign:n} +% \begin{syntax} +% \cs{dim_sign:n} \Arg{dim expr} +% \end{syntax} +% Evaluates the \meta{dim expr} then leaves $1$ or $0$ or $-1$ in the +% input stream according to the sign of the result. +% \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 is 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 \tn{the}: this is one of +% several \LaTeX3 names for this primitive. +% \end{texnote} +% \end{function} +% +% \begin{function}[added = 2014-07-15, EXP]{\dim_to_decimal:n} +% \begin{syntax} +% \cs{dim_to_decimal:n} \Arg{dim expr} +% \end{syntax} +% Evaluates the \meta{dim expr}, and leaves the result, +% expressed in points (\texttt{pt}) in the input stream, with \emph{no +% units}. The result is rounded by \TeX{} to at most five decimal +% places. If the decimal part of the result is zero, it is omitted, +% together with the decimal marker. +% +% For example +% \begin{verbatim} +% \dim_to_decimal:n { 1bp } +% \end{verbatim} +% leaves |1.00374| in the input stream, \emph{i.e.}~the magnitude of +% one \enquote{big point} when converted to (\TeX{}) points. +% \end{function} +% +% \begin{function}[added = 2014-07-15, updated = 2023-05-20, EXP] +% {\dim_to_decimal_in_bp:n} +% \begin{syntax} +% \cs{dim_to_decimal_in_bp:n} \Arg{dim expr} +% \end{syntax} +% Evaluates the \meta{dim expr}, and leaves the result, +% expressed in big points (\texttt{bp}) in the input stream, with \emph{no +% units}. The result is rounded by \TeX{} to at most five decimal +% places. If the decimal part of the result is zero, it is omitted, +% together with the decimal marker. +% +% For example +% \begin{verbatim} +% \dim_to_decimal_in_bp:n { 1pt } +% \end{verbatim} +% leaves |0.99628| in the input stream, \emph{i.e.}~the magnitude of +% one (\TeX{}) point when converted to big points. +% \begin{texnote} +% The implementation of this function is re-entrant: the result of +% \begin{verbatim} +% \dim_compare:nNnTF +% { <x>bp } = +% { \dim_to_decimal_in_bp:n { <x>bp } bp } +% \end{verbatim} +% will be logically \texttt{true}. The decimal representations may +% differ provided they produce the same \TeX{} dimension. +% \end{texnote} +% \end{function} +% +% \begin{function}[added = 2023-05-20, EXP] +% { +% \dim_to_decimal_in_cc:n , +% \dim_to_decimal_in_cm:n , +% \dim_to_decimal_in_dd:n , +% \dim_to_decimal_in_in:n , +% \dim_to_decimal_in_mm:n , +% \dim_to_decimal_in_pc:n +% } +% \begin{syntax} +% \cs{dim_to_decimal_in_cm:n} \Arg{dim expr} +% \end{syntax} +% Evaluates the \meta{dim expr}, and leaves the result, +% expressed with the appropriate scaling in the input stream, with +% \emph{no units}. If the decimal part of the result is zero, it is omitted, +% together with the decimal marker. The precisions of the result is limited +% to a maximum of five decimal places with trailing zeros omitted. +% +% The maximum \TeX{} allowable dimension value (available as +% \tn{maxdimen} in plain \TeX{} and \LaTeX{} and \cs{c_max_dim} in +% \pkg{expl3}) can only be expressed exactly in the units +% \texttt{pt}, \texttt{bp} and \texttt{sp}. The maximum allowable +% input values to five decimal places are\\ +% \begin{center} +% \begin{tabular}{@{}>{$}r<{$}@{\,}l@{}} +% 1276.00215 & cc \\ +% 575.83174 & cm \\ +% 15312.02584 & dd \\ +% 226.70540 & in \\ +% 5758.31742 & mm \\ +% 1365.33333 & pc \\ +% \end{tabular} +% \end{center} +% (Note that these are not all equal, but rather any larger value will overflow +% due to the way \TeX{} converts to \texttt{sp}.) +% Values given to five decimal places larger that these will result in \TeX{} +% errors; the behavior if additional decimal places are given depends on the +% \TeX{} internals and thus larger values are \emph{not} supported by +% \pkg{expl3}. +% \begin{texnote} +% The implementation of these functions is re-entrant: the result of +% \begin{verbatim} +% \dim_compare:nNnTF +% { <x><unit> } = +% { \dim_to_decimal_in_<unit>:n { <x><unit> } <unit> } +% \end{verbatim} +% will be logically \texttt{true}. The decimal representations may +% differ provided they produce the same \TeX{} dimension. +% \end{texnote} +% \end{function} +% +% \begin{function}[added = 2015-05-18, EXP]{\dim_to_decimal_in_sp:n} +% \begin{syntax} +% \cs{dim_to_decimal_in_sp:n} \Arg{dim expr} +% \end{syntax} +% Evaluates the \meta{dim expr}, and leaves the result, +% expressed in scaled points (\texttt{sp}) in the input stream, with \emph{no +% units}. The result is necessarily an integer. +% \end{function} +% +% \begin{function}[added = 2014-07-15, updated = 2023-05-20, EXP] +% {\dim_to_decimal_in_unit:nn} +% \begin{syntax} +% \cs{dim_to_decimal_in_unit:nn} \Arg{dim expr_1} \Arg{dim expr_2} +% \end{syntax} +% Evaluates the \meta{dim exprs}, and leaves the value of +% \meta{dim expr_1}, expressed in a unit given by \meta{dim expr_2}, in +% the input stream. If the decimal part of the result +% is zero, it is omitted, together with the decimal marker. +% The precisions of the result is limited +% to a maximum of five decimal places with trailing zeros omitted. +% +% For example +% \begin{verbatim} +% \dim_to_decimal_in_unit:nn { 1bp } { 1mm } +% \end{verbatim} +% leaves |0.35278| in the input stream, \emph{i.e.}~the magnitude of +% one big point when expressed in millimetres. The conversions do +% \emph{not} guarantee that \TeX{} would yield identical results +% for the direct input in an equality test, thus for instance +% \begin{verbatim} +% \dim_compare:nNnTF +% { 1bp } = +% { \dim_to_decimal_in_unit:nn { 1bp } { 1mm } mm } +% \end{verbatim} +% will take the \texttt{false} branch. +% \end{function} +% +% \begin{function}[EXP, added = 2012-05-08, tested = m3fp-convert002] +% {\dim_to_fp:n} +% \begin{syntax} +% \cs{dim_to_fp:n} \Arg{dim expr} +% \end{syntax} +% Expands to an internal floating point number equal to the value of +% the \meta{dim expr} in \texttt{pt}. Since dimension expressions are +% evaluated much faster than their floating point equivalent, +% \cs{dim_to_fp:n} can be used to speed up parts of a computation +% where a low precision and a smaller range are acceptable. +% \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} +% +% \begin{function}[added = 2011-11-22, updated = 2015-08-07]{\dim_show:n} +% \begin{syntax} +% \cs{dim_show:n} \Arg{dim expr} +% \end{syntax} +% Displays the result of evaluating the \meta{dim expr} +% on the terminal. +% \end{function} +% +% \begin{function}[added = 2014-08-22, updated = 2015-08-03]{\dim_log:N, \dim_log:c} +% \begin{syntax} +% \cs{dim_log:N} \meta{dimension} +% \end{syntax} +% Writes the value of the \meta{dimension} in the log file. +% \end{function} +% +% \begin{function}[added = 2014-08-22, updated = 2015-08-07]{\dim_log:n} +% \begin{syntax} +% \cs{dim_log:n} \Arg{dim expr} +% \end{syntax} +% Writes the result of evaluating the \meta{dim expr} +% in the log file. +% \end{function} +% +% \section{Constant dimensions} +% +% \begin{variable}{\c_max_dim} +% The maximum value that can be stored as a dimension. This can also +% be used as a component of a skip. +% \end{variable} +% +% \begin{variable}{\c_zero_dim} +% A zero length as a dimension. This can also be used as a component +% of a skip. +% \end{variable} +% +% \section{Scratch dimensions} +% +% \begin{variable}{\l_tmpa_dim, \l_tmpb_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} +% is initially equal to $0$\,pt. +% \end{function} +% +% \begin{function}[added = 2012-03-05]{\skip_const:Nn, \skip_const:cn} +% \begin{syntax} +% \cs{skip_const:Nn} \meta{skip} \Arg{skip expr} +% \end{syntax} +% Creates a new constant \meta{skip} or raises an error if the +% name is already taken. The value of the \meta{skip} is set +% globally to the \meta{skip expr}. +% \end{function} +% +% \begin{function}{\skip_zero:N, \skip_zero:c, \skip_gzero:N, \skip_gzero:c} +% \begin{syntax} +% \cs{skip_zero:N} \meta{skip} +% \end{syntax} +% Sets \meta{skip} to $0$\,pt. +% \end{function} +% +% \begin{function}[added = 2012-01-07] +% {\skip_zero_new:N, \skip_zero_new:c, \skip_gzero_new:N, \skip_gzero_new:c} +% \begin{syntax} +% \cs{skip_zero_new:N} \meta{skip} +% \end{syntax} +% Ensures that the \meta{skip} exists globally by applying +% \cs{skip_new:N} if necessary, then applies +% \cs[index=skip_zero:N]{skip_(g)zero:N} to leave +% the \meta{skip} set to zero. +% \end{function} +% +% \begin{function}[EXP, pTF, added=2012-03-03] +% {\skip_if_exist:N, \skip_if_exist:c} +% \begin{syntax} +% \cs{skip_if_exist_p:N} \meta{skip} +% \cs{skip_if_exist:NTF} \meta{skip} \Arg{true code} \Arg{false code} +% \end{syntax} +% Tests whether the \meta{skip} is currently defined. This does not +% check that the \meta{skip} really is a skip variable. +% \end{function} +% +% \section{Setting \texttt{skip} variables} +% +% \begin{function}[updated = 2011-10-22] +% {\skip_add:Nn, \skip_add:cn, \skip_gadd:Nn, \skip_gadd:cn} +% \begin{syntax} +% \cs{skip_add:Nn} \meta{skip} \Arg{skip expr} +% \end{syntax} +% Adds the result of the \meta{skip expr} to the current +% content of the \meta{skip}. +% \end{function} +% +% \begin{function}[updated = 2011-10-22] +% {\skip_set:Nn, \skip_set:cn, \skip_gset:Nn, \skip_gset:cn} +% \begin{syntax} +% \cs{skip_set:Nn} \meta{skip} \Arg{skip expr} +% \end{syntax} +% Sets \meta{skip} to the value of \meta{skip expr}, which +% must evaluate to a length with units and may include a rubber +% component (for example |1 cm plus 0.5 cm|. +% \end{function} +% +% \begin{function} +% { +% \skip_set_eq:NN, \skip_set_eq:cN, \skip_set_eq:Nc, \skip_set_eq:cc, +% \skip_gset_eq:NN, \skip_gset_eq:cN, \skip_gset_eq:Nc, \skip_gset_eq:cc +% } +% \begin{syntax} +% \cs{skip_set_eq:NN} \meta{skip_1} \meta{skip_2} +% \end{syntax} +% Sets the content of \meta{skip_1} equal to that of \meta{skip_2}. +% \end{function} +% +% \begin{function}[updated = 2011-10-22] +% {\skip_sub:Nn, \skip_sub:cn, \skip_gsub:Nn, \skip_gsub:cn} +% \begin{syntax} +% \cs{skip_sub:Nn} \meta{skip} \Arg{skip expr} +% \end{syntax} +% Subtracts the result of the \meta{skip expr} from the +% current content of the \meta{skip}. +% \end{function} +% +% \section{Skip expression conditionals} +% +% \begin{function}[EXP,pTF]{\skip_if_eq:nn} +% \begin{syntax} +% \cs{skip_if_eq_p:nn} \Arg{skip expr_1} \Arg{skip expr_2} +% \cs{skip_if_eq:nnTF} +% ~~\Arg{skip expr_1} \Arg{skip expr_2} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% This function first evaluates each of the +% \meta{skip exprs} 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. +% \end{function} +% +% \begin{function}[EXP, pTF, added = 2012-03-05]{\skip_if_finite:n} +% \begin{syntax} +% \cs{skip_if_finite_p:n} \Arg{skip expr} +% \cs{skip_if_finite:nTF} \Arg{skip expr} \Arg{true code} \Arg{false code} +% \end{syntax} +% Evaluates the \meta{skip expr} as described for \cs{skip_eval:n}, +% and then tests if all of its components are finite. +% \end{function} +% +% \section{Using \texttt{skip} expressions and variables} +% +% \begin{function}[updated = 2011-10-22, EXP]{\skip_eval:n} +% \begin{syntax} +% \cs{skip_eval:n} \Arg{skip expr} +% \end{syntax} +% Evaluates the \meta{skip expr}, 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 is expressed in points (\texttt{pt}), +% and requires 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 is raised if the variable does +% not exist or if it is invalid. Can be omitted in places where a +% \meta{dimension} or \meta{skip} is required (such as in the argument of +% \cs{skip_eval:n}). +% \begin{texnote} +% \cs{skip_use:N} is the \TeX{} primitive \tn{the}: this is one of +% several \LaTeX3 names for this primitive. +% \end{texnote} +% \end{function} +% +% \section{Viewing \texttt{skip} variables} +% +% \begin{function}[updated = 2015-08-03]{\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} +% +% \begin{function}[added = 2011-11-22, updated = 2015-08-07]{\skip_show:n} +% \begin{syntax} +% \cs{skip_show:n} \Arg{skip expr} +% \end{syntax} +% Displays the result of evaluating the \meta{skip expr} +% on the terminal. +% \end{function} +% +% \begin{function}[added = 2014-08-22, updated = 2015-08-03]{\skip_log:N, \skip_log:c} +% \begin{syntax} +% \cs{skip_log:N} \meta{skip} +% \end{syntax} +% Writes the value of the \meta{skip} in the log file. +% \end{function} +% +% \begin{function}[added = 2014-08-22, updated = 2015-08-07]{\skip_log:n} +% \begin{syntax} +% \cs{skip_log:n} \Arg{skip expr} +% \end{syntax} +% Writes the result of evaluating the \meta{skip expr} +% in the log file. +% \end{function} +% +% \section{Constant skips} +% +% \begin{variable}[updated = 2012-11-02]{\c_max_skip} +% The maximum value that can be stored as a skip (equal to +% \cs{c_max_dim} in length), with no stretch nor shrink component. +% \end{variable} +% +% \begin{variable}[updated = 2012-11-01]{\c_zero_skip} +% A zero length as a skip, with no stretch nor shrink component. +% \end{variable} +% +% \section{Scratch skips} +% +% \begin{variable}{\l_tmpa_skip, \l_tmpb_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{Inserting skips into the output} +% +% \begin{function}[updated = 2011-10-22] +% {\skip_horizontal:N, \skip_horizontal:c, \skip_horizontal:n} +% \begin{syntax} +% \cs{skip_horizontal:N} \meta{skip} +% \cs{skip_horizontal:n} \Arg{skip expr} +% \end{syntax} +% Inserts a horizontal \meta{skip} into the current list. +% The argument can also be a \meta{dim}. +% \begin{texnote} +% \cs{skip_horizontal:N} is the \TeX{} primitive \tn{hskip}. +% \end{texnote} +% \end{function} +% +% \begin{function}[updated = 2011-10-22] +% {\skip_vertical:N, \skip_vertical:c, \skip_vertical:n} +% \begin{syntax} +% \cs{skip_vertical:N} \meta{skip} +% \cs{skip_vertical:n} \Arg{skip expr} +% \end{syntax} +% Inserts a vertical \meta{skip} into the current list. +% The argument can also be a \meta{dim}. +% \begin{texnote} +% \cs{skip_vertical:N} is the \TeX{} primitive \tn{vskip}. +% \end{texnote} +% \end{function} +% +% \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} +% is initially equal to $0$\,mu. +% \end{function} +% +% \begin{function}[added = 2012-03-05]{\muskip_const:Nn, \muskip_const:cn} +% \begin{syntax} +% \cs{muskip_const:Nn} \meta{muskip} \Arg{muskip expr} +% \end{syntax} +% Creates a new constant \meta{muskip} or raises an error if the +% name is already taken. The value of the \meta{muskip} is set +% globally to the \meta{muskip expr}. +% \end{function} +% +% \begin{function} +% {\muskip_zero:N, \muskip_zero:c, \muskip_gzero:N, \muskip_gzero:c} +% \begin{syntax} +% \cs{skip_zero:N} \meta{muskip} +% \end{syntax} +% Sets \meta{muskip} to $0$\,mu. +% \end{function} +% +% \begin{function}[added = 2012-01-07] +% { +% \muskip_zero_new:N, \muskip_zero_new:c, +% \muskip_gzero_new:N, \muskip_gzero_new:c +% } +% \begin{syntax} +% \cs{muskip_zero_new:N} \meta{muskip} +% \end{syntax} +% Ensures that the \meta{muskip} exists globally by applying +% \cs{muskip_new:N} if necessary, then applies +% \cs[index=muskip_zero:N]{muskip_(g)zero:N} +% to leave the \meta{muskip} set to zero. +% \end{function} +% +% \begin{function}[EXP, pTF, added=2012-03-03] +% {\muskip_if_exist:N, \muskip_if_exist:c} +% \begin{syntax} +% \cs{muskip_if_exist_p:N} \meta{muskip} +% \cs{muskip_if_exist:NTF} \meta{muskip} \Arg{true code} \Arg{false code} +% \end{syntax} +% Tests whether the \meta{muskip} is currently defined. This does not +% check that the \meta{muskip} really is a muskip variable. +% \end{function} +% +% \section{Setting \texttt{muskip} variables} +% +% \begin{function}[updated = 2011-10-22] +% {\muskip_add:Nn, \muskip_add:cn, \muskip_gadd:Nn, \muskip_gadd:cn} +% \begin{syntax} +% \cs{muskip_add:Nn} \meta{muskip} \Arg{muskip expr} +% \end{syntax} +% Adds the result of the \meta{muskip expr} to the current +% content of the \meta{muskip}. +% \end{function} +% +% \begin{function}[updated = 2011-10-22] +% {\muskip_set:Nn, \muskip_set:cn, \muskip_gset:Nn, \muskip_gset:cn} +% \begin{syntax} +% \cs{muskip_set:Nn} \meta{muskip} \Arg{muskip expr} +% \end{syntax} +% Sets \meta{muskip} to the value of \meta{muskip expr}, which +% must evaluate to a math length with units and may include a rubber +% component (for example |1 mu plus 0.5 mu|. +% \end{function} +% +% \begin{function} +% { +% \muskip_set_eq:NN, \muskip_set_eq:cN, +% \muskip_set_eq:Nc, \muskip_set_eq:cc, +% \muskip_gset_eq:NN, \muskip_gset_eq:cN, +% \muskip_gset_eq:Nc, \muskip_gset_eq:cc +% } +% \begin{syntax} +% \cs{muskip_set_eq:NN} \meta{muskip_1} \meta{muskip_2} +% \end{syntax} +% Sets the content of \meta{muskip_1} equal to that of +% \meta{muskip_2}. +% \end{function} +% +% \begin{function}[updated = 2011-10-22] +% {\muskip_sub:Nn, \muskip_sub:cn, \muskip_gsub:Nn, \muskip_gsub:cn} +% \begin{syntax} +% \cs{muskip_sub:Nn} \meta{muskip} \Arg{muskip expr} +% \end{syntax} +% Subtracts the result of the \meta{muskip expr} from the +% current content of the \meta{muskip}. +% \end{function} +% +% \section{Using \texttt{muskip} expressions and variables} +% +% \begin{function}[updated = 2011-10-22, EXP]{\muskip_eval:n} +% \begin{syntax} +% \cs{muskip_eval:n} \Arg{muskip expr} +% \end{syntax} +% Evaluates the \meta{muskip expr}, 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 is expressed in \texttt{mu}, +% and requires 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 is 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 \tn{the}: this is one of +% several \LaTeX3 names for this primitive. +% \end{texnote} +% \end{function} +% +% \section{Viewing \texttt{muskip} variables} +% +% \begin{function}[updated = 2015-08-03]{\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} +% +% \begin{function}[added = 2011-11-22, updated = 2015-08-07]{\muskip_show:n} +% \begin{syntax} +% \cs{muskip_show:n} \Arg{muskip expr} +% \end{syntax} +% Displays the result of evaluating the \meta{muskip expr} +% on the terminal. +% \end{function} +% +% \begin{function}[added = 2014-08-22, updated = 2015-08-03]{\muskip_log:N, \muskip_log:c} +% \begin{syntax} +% \cs{muskip_log:N} \meta{muskip} +% \end{syntax} +% Writes the value of the \meta{muskip} in the log file. +% \end{function} +% +% \begin{function}[added = 2014-08-22, updated = 2015-08-07]{\muskip_log:n} +% \begin{syntax} +% \cs{muskip_log:n} \Arg{muskip expr} +% \end{syntax} +% Writes the result of evaluating the \meta{muskip expr} +% in the log file. +% \end{function} +% +% \section{Constant muskips} +% +% \begin{variable}{\c_max_muskip} +% The maximum value that can be stored as a muskip, with no stretch +% nor shrink component. +% \end{variable} +% +% \begin{variable}{\c_zero_muskip} +% A zero length as a muskip, with no stretch nor shrink component. +% \end{variable} +% +% \section{Scratch muskips} +% +% \begin{variable}{\l_tmpa_muskip, \l_tmpb_muskip} +% Scratch muskip 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_muskip, \g_tmpb_muskip} +% Scratch muskip 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{Primitive conditional} +% +% \begin{function}[EXP]{\if_dim:w} +% \begin{syntax} +% \cs{if_dim:w} \meta{dimen_1} \meta{relation} \meta{dimen_2} +% ~~\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 \tn{ifdim}. +% \end{texnote} +% \end{function} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{l3skip} implementation} +% +% \begin{macrocode} +%<*package> +% \end{macrocode} +% +% \begin{macrocode} +%<@@=dim> +% \end{macrocode} +% +% \subsection{Length primitives renamed} +% +% \begin{macro}{\if_dim:w} +% \begin{macro}{\@@_eval:w} +% \begin{macro}{\@@_eval_end:} +% Primitives renamed. +% \begin{macrocode} +\cs_new_eq:NN \if_dim:w \tex_ifdim:D +\cs_new_eq:NN \@@_eval:w \tex_dimexpr:D +\cs_new_eq:NN \@@_eval_end: \tex_relax:D +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Internal auxiliaries} +% +% \begin{variable}{\s_@@_mark,\s_@@_stop} +% Internal scan marks. +% \begin{macrocode} +\scan_new:N \s_@@_mark +\scan_new:N \s_@@_stop +% \end{macrocode} +% \end{variable} +% +% \begin{macro}[EXP]{\@@_use_none_delimit_by_s_stop:w} +% Functions to gobble up to a scan mark. +% \begin{macrocode} +\cs_new:Npn \@@_use_none_delimit_by_s_stop:w #1 \s_@@_stop { } +% \end{macrocode} +% \end{macro} +% +% \subsection{Creating and initialising \texttt{dim} variables} +% +% \begin{macro}{\dim_new:N, \dim_new:c} +% Allocating \meta{dim} registers \ldots +% \begin{macrocode} +\cs_new_protected:Npn \dim_new:N #1 + { + \__kernel_chk_if_free_cs:N #1 + \cs:w newdimen \cs_end: #1 + } +\cs_generate_variant:Nn \dim_new:N { c } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\dim_const:Nn, \dim_const:cn} +% Contrarily to integer constants, we cannot avoid using a register, +% even for constants. We cannot use \cs{dim_gset:Nn} because +% debugging code would complain that the constant is not a global +% variable. Since \cs{dim_const:Nn} does not need to be fast, use +% \cs{dim_eval:n} to avoid needing a debugging patch that wraps the +% expression in checking code. +% \begin{macrocode} +\cs_new_protected:Npn \dim_const:Nn #1#2 + { + \dim_new:N #1 + \tex_global:D #1 = \dim_eval:n {#2} \scan_stop: + } +\cs_generate_variant:Nn \dim_const:Nn { 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. Using \cs{c_zero_skip} deals with the +% case where the variable passed is incorrectly a skip (for example a +% \LaTeXe{} length). Besides, these functions are then simply copied +% for \cs{skip_zero:N} and related functions. +% \begin{macrocode} +\cs_new_protected:Npn \dim_zero:N #1 { #1 = \c_zero_skip } +\cs_new_protected:Npn \dim_gzero:N #1 + { \tex_global:D #1 = \c_zero_skip } +\cs_generate_variant:Nn \dim_zero:N { c } +\cs_generate_variant:Nn \dim_gzero:N { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro} +% {\dim_zero_new:N, \dim_zero_new:c, \dim_gzero_new:N, \dim_gzero_new:c} +% Create a register if needed, otherwise clear it. +% \begin{macrocode} +\cs_new_protected:Npn \dim_zero_new:N #1 + { \dim_if_exist:NTF #1 { \dim_zero:N #1 } { \dim_new:N #1 } } +\cs_new_protected:Npn \dim_gzero_new:N #1 + { \dim_if_exist:NTF #1 { \dim_gzero:N #1 } { \dim_new:N #1 } } +\cs_generate_variant:Nn \dim_zero_new:N { c } +\cs_generate_variant:Nn \dim_gzero_new:N { c } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[pTF]{\dim_if_exist:N, \dim_if_exist:c} +% Copies of the \texttt{cs} functions defined in \pkg{l3basics}. +% \begin{macrocode} +\prg_new_eq_conditional:NNn \dim_if_exist:N \cs_if_exist:N + { TF , T , F , p } +\prg_new_eq_conditional:NNn \dim_if_exist:c \cs_if_exist:c + { TF , T , F , p } +% \end{macrocode} +% \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 but when debugging we want both to +% check that the variable is correctly local/global and to wrap the +% expression in some code. The \cs{scan_stop:} deals with the case +% where the variable passed is a skip (for example a \LaTeXe{} +% length). +% \begin{macrocode} +\cs_new_protected:Npn \dim_set:Nn #1#2 + { #1 = \@@_eval:w #2 \@@_eval_end: \scan_stop: } +\cs_new_protected:Npn \dim_gset:Nn #1#2 + { \tex_global:D #1 = \@@_eval:w #2 \@@_eval_end: \scan_stop: } +\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, with a \cs{scan_stop:} to deal with the case +% where |#1| is (incorrectly) a skip. +% \begin{macrocode} +\cs_new_protected:Npn \dim_set_eq:NN #1#2 + { #1 = #2 \scan_stop: } +\cs_generate_variant:Nn \dim_set_eq:NN { c , Nc , cc } +\cs_new_protected:Npn \dim_gset_eq:NN #1#2 + { \tex_global:D #1 = #2 \scan_stop: } +\cs_generate_variant:Nn \dim_gset_eq:NN { c , Nc , cc } +% \end{macrocode} +% \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 would slow things down just to detect nonsensical +% cases such as passing |\dimen 123| as the first argument. +% Using \cs{scan_stop:} deals with skip variables. Since +% debugging checks that the variable is correctly local/global, the +% global versions cannot be defined as \cs{tex_global:D} followed by +% the local versions. +% \begin{macrocode} +\cs_new_protected:Npn \dim_add:Nn #1#2 + { \tex_advance:D #1 \@@_eval:w #2 \@@_eval_end: \scan_stop: } +\cs_new_protected:Npn \dim_gadd:Nn #1#2 + { + \tex_global:D \tex_advance:D #1 + \@@_eval:w #2 \@@_eval_end: \scan_stop: + } +\cs_generate_variant:Nn \dim_add:Nn { c } +\cs_generate_variant:Nn \dim_gadd:Nn { c } +\cs_new_protected:Npn \dim_sub:Nn #1#2 + { \tex_advance:D #1 - \@@_eval:w #2 \@@_eval_end: \scan_stop: } +\cs_new_protected:Npn \dim_gsub:Nn #1#2 + { + \tex_global:D \tex_advance:D #1 + -\@@_eval:w #2 \@@_eval_end: \scan_stop: + } +\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}[EXP]{\dim_abs:n} +% \begin{macro}[EXP]{\@@_abs:N} +% \UnitTested +% \begin{macro}[EXP]{\dim_max:nn} +% \begin{macro}[EXP]{\dim_min:nn} +% \begin{macro}[EXP]{\@@_maxmin:wwN} +% \UnitTested +% \UnitTested +% Functions for $\min$, $\max$, and absolute value with only one evaluation. +% The absolute value is evaluated by removing a leading~|-| if present. +% \begin{macrocode} +\cs_new:Npn \dim_abs:n #1 + { + \exp_after:wN \@@_abs:N + \dim_use:N \@@_eval:w #1 \@@_eval_end: + } +\cs_new:Npn \@@_abs:N #1 + { \if_meaning:w - #1 \else: \exp_after:wN #1 \fi: } +\cs_new:Npn \dim_max:nn #1#2 + { + \dim_use:N \@@_eval:w \exp_after:wN \@@_maxmin:wwN + \dim_use:N \@@_eval:w #1 \exp_after:wN ; + \dim_use:N \@@_eval:w #2 ; + > + \@@_eval_end: + } +\cs_new:Npn \dim_min:nn #1#2 + { + \dim_use:N \@@_eval:w \exp_after:wN \@@_maxmin:wwN + \dim_use:N \@@_eval:w #1 \exp_after:wN ; + \dim_use:N \@@_eval:w #2 ; + < + \@@_eval_end: + } +\cs_new:Npn \@@_maxmin:wwN #1 ; #2 ; #3 + { + \if_dim:w #1 #3 #2 ~ + #1 + \else: + #2 + \fi: + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\dim_ratio:nn} +% \begin{macro}{\@@_ratio:n} +% With dimension expressions, something like |10 pt * ( 5 pt / 10 pt )| does +% 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:Npn \dim_ratio:nn #1#2 + { \@@_ratio:n {#1} / \@@_ratio:n {#2} } +\cs_new:Npn \@@_ratio:n #1 + { \int_value:w \@@_eval:w (#1) \@@_eval_end: } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Dimension expression conditionals} +% +% \begin{macro}[pTF, EXP]{\dim_compare:nNn} +% Simple comparison. +% \begin{macrocode} +\prg_new_conditional:Npnn \dim_compare:nNn #1#2#3 { p , T , F , TF } + { + \if_dim:w \@@_eval:w #1 #2 \@@_eval:w #3 \@@_eval_end: + \prg_return_true: \else: \prg_return_false: \fi: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[pTF, EXP]{\dim_compare:n} +% \begin{macro}[EXP]{\@@_compare:w, \@@_compare:wNN} +% \begin{macro}[EXP] +% { +% \@@_compare_=:w, +% \@@_compare_!:w, +% \@@_compare_<:w, +% \@@_compare_>:w +% } +% \begin{macro}{\@@_compare_error:} +% This code is adapted from the \cs{int_compare:nTF} function. First +% make sure that there is at least one relation operator, by +% evaluating a dimension expression with a trailing +% \cs{@@_compare_error:}. Just like for integers, the looping +% auxiliary \cs{@@_compare:wNN} closes a primitive conditional and +% opens a new one. It is actually easier to grab a dimension operand +% than an integer one, because once evaluated, dimensions all end with +% \texttt{pt} (with category other). Thus we do not need specific +% auxiliaries for the three \enquote{simple} relations |<|, |=|, +% and~|>|. +% \begin{macrocode} +\prg_new_conditional:Npnn \dim_compare:n #1 { p , T , F , TF } + { + \exp_after:wN \@@_compare:w + \dim_use:N \@@_eval:w #1 \@@_compare_error: + } +\cs_new:Npn \@@_compare:w #1 \@@_compare_error: + { + \exp_after:wN \if_false: \exp:w \exp_end_continue_f:w + \@@_compare:wNN #1 ? { = \@@_compare_end:w \else: } \s_@@_stop + } +\exp_args:Nno \use:nn + { \cs_new:Npn \@@_compare:wNN #1 } { \tl_to_str:n {pt} #2#3 } + { + \if_meaning:w = #3 + \use:c { @@_compare_#2:w } + \fi: + #1 pt \exp_stop_f: + \prg_return_false: + \exp_after:wN \@@_use_none_delimit_by_s_stop:w + \fi: + \reverse_if:N \if_dim:w #1 pt #2 + \exp_after:wN \@@_compare:wNN + \dim_use:N \@@_eval:w #3 + } +\cs_new:cpn { @@_compare_ ! :w } + #1 \reverse_if:N #2 ! #3 = { #1 #2 = #3 } +\cs_new:cpn { @@_compare_ = :w } + #1 \@@_eval:w = { #1 \@@_eval:w } +\cs_new:cpn { @@_compare_ < :w } + #1 \reverse_if:N #2 < #3 = { #1 #2 > #3 } +\cs_new:cpn { @@_compare_ > :w } + #1 \reverse_if:N #2 > #3 = { #1 #2 < #3 } +\cs_new:Npn \@@_compare_end:w #1 \prg_return_false: #2 \s_@@_stop + { #1 \prg_return_false: \else: \prg_return_true: \fi: } +\cs_new_protected:Npn \@@_compare_error: + { + \if_int_compare:w \c_zero_int \c_zero_int \fi: + = + \@@_compare_error: + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}[EXP, noTF]{\dim_case:nn} +% \begin{macro}{\@@_case:nnTF} +% \begin{macro}{\@@_case:nw, \@@_case_end:nw} +% For dimension cases, the first task to fully expand the check +% condition. The over all idea is then much the same as for +% \cs{str_case:nnTF} as described in \pkg{l3basics}. +% \begin{macrocode} +\cs_new:Npn \dim_case:nnTF #1 + { + \exp:w + \exp_args:Nf \@@_case:nnTF { \dim_eval:n {#1} } + } +\cs_new:Npn \dim_case:nnT #1#2#3 + { + \exp:w + \exp_args:Nf \@@_case:nnTF { \dim_eval:n {#1} } {#2} {#3} { } + } +\cs_new:Npn \dim_case:nnF #1#2 + { + \exp:w + \exp_args:Nf \@@_case:nnTF { \dim_eval:n {#1} } {#2} { } + } +\cs_new:Npn \dim_case:nn #1#2 + { + \exp:w + \exp_args:Nf \@@_case:nnTF { \dim_eval:n {#1} } {#2} { } { } + } +\cs_new:Npn \@@_case:nnTF #1#2#3#4 + { \@@_case:nw {#1} #2 {#1} { } \s_@@_mark {#3} \s_@@_mark {#4} \s_@@_stop } +\cs_new:Npn \@@_case:nw #1#2#3 + { + \dim_compare:nNnTF {#1} = {#2} + { \@@_case_end:nw {#3} } + { \@@_case:nw {#1} } + } +\cs_new:Npn \@@_case_end:nw #1#2#3 \s_@@_mark #4#5 \s_@@_stop + { \exp_end: #1 #4 } +% \end{macrocode} +% \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_new:Npn \dim_while_do:nn #1#2 + { + \dim_compare:nT {#1} + { + #2 + \dim_while_do:nn {#1} {#2} + } + } +\cs_new:Npn \dim_until_do:nn #1#2 + { + \dim_compare:nF {#1} + { + #2 + \dim_until_do:nn {#1} {#2} + } + } +\cs_new:Npn \dim_do_while:nn #1#2 + { + #2 + \dim_compare:nT {#1} + { \dim_do_while:nn {#1} {#2} } + } +\cs_new: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_new: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_new: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_new: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_new: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{Dimension step functions} +% +% \begin{macro}{\dim_step_function:nnnN} +% \begin{macro}{\@@_step:wwwN, \@@_step:NnnnN} +% Before all else, evaluate the initial value, step, and final value. +% Repeating a function by steps first needs a check on the direction +% of the steps. After that, do the function for the start value then +% step and loop around. It would be more symmetrical to test for a +% step size of zero before checking the sign, but we optimize for the +% most frequent case (positive step). +% \begin{macrocode} +\cs_new:Npn \dim_step_function:nnnN #1#2#3 + { + \exp_after:wN \@@_step:wwwN + \tex_the:D \@@_eval:w #1 \exp_after:wN ; + \tex_the:D \@@_eval:w #2 \exp_after:wN ; + \tex_the:D \@@_eval:w #3 ; + } +\cs_new:Npn \@@_step:wwwN #1; #2; #3; #4 + { + \dim_compare:nNnTF {#2} > \c_zero_dim + { \@@_step:NnnnN > } + { + \dim_compare:nNnTF {#2} = \c_zero_dim + { + \msg_expandable_error:nnn { kernel } { zero-step } {#4} + \use_none:nnnn + } + { \@@_step:NnnnN < } + } + {#1} {#2} {#3} #4 + } +\cs_new:Npn \@@_step:NnnnN #1#2#3#4#5 + { + \dim_compare:nNnF {#2} #1 {#4} + { + #5 {#2} + \exp_args:NNf \@@_step:NnnnN + #1 { \dim_eval:n { #2 + #3 } } {#3} {#4} #5 + } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\dim_step_inline:nnnn} +% \begin{macro}{\dim_step_variable:nnnNn} +% \begin{macro}{\@@_step:NNnnnn} +% The approach here is to build a function, with a global integer +% required to make the nesting safe (as seen in other in line +% functions), and map that function using \cs{dim_step_function:nnnN}. +% We put a \cs{prg_break_point:Nn} so that \texttt{map_break} +% functions from other modules correctly decrement \cs{g__kernel_prg_map_int} +% before looking for their own break point. The first argument is +% \cs{scan_stop:}, so that no breaking function recognizes this break +% point as its own. +% \begin{macrocode} +\cs_new_protected:Npn \dim_step_inline:nnnn + { + \int_gincr:N \g__kernel_prg_map_int + \exp_args:NNc \@@_step:NNnnnn + \cs_gset_protected:Npn + { @@_map_ \int_use:N \g__kernel_prg_map_int :w } + } +\cs_new_protected:Npn \dim_step_variable:nnnNn #1#2#3#4#5 + { + \int_gincr:N \g__kernel_prg_map_int + \exp_args:NNc \@@_step:NNnnnn + \cs_gset_protected:Npe + { @@_map_ \int_use:N \g__kernel_prg_map_int :w } + {#1}{#2}{#3} + { + \tl_set:Nn \exp_not:N #4 {##1} + \exp_not:n {#5} + } + } +\cs_new_protected:Npn \@@_step:NNnnnn #1#2#3#4#5#6 + { + #1 #2 ##1 {#6} + \dim_step_function:nnnN {#3} {#4} {#5} #2 + \prg_break_point:Nn \scan_stop: { \int_gdecr:N \g__kernel_prg_map_int } + } +% \end{macrocode} +% \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:Npn \dim_eval:n #1 + { \dim_use:N \@@_eval:w #1 \@@_eval_end: } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[EXP]{\dim_sign:n, \@@_sign:Nw} +% See \cs{dim_abs:n}. Contrarily to \cs{int_sign:n} the case of a +% zero dimension cannot be distinguished from a positive dimension by +% looking only at the first character, since |0.2pt| and |0pt| start +% the same way. We need explicit comparisons. We start by +% distinguishing the most common case of a positive dimension. +% \begin{macrocode} +\cs_new:Npn \dim_sign:n #1 + { + \int_value:w \exp_after:wN \@@_sign:Nw + \dim_use:N \@@_eval:w #1 \@@_eval_end: ; + \exp_stop_f: + } +\cs_new:Npn \@@_sign:Nw #1#2 ; + { + \if_dim:w #1#2 > \c_zero_dim + 1 + \else: + \if_meaning:w - #1 + -1 + \else: + 0 + \fi: + \fi: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\dim_use:N, \dim_use:c} +% Accessing a \meta{dim}. We hand-code the |c| variant for some speed gain. +% \begin{macrocode} +\cs_new_eq:NN \dim_use:N \tex_the:D +\cs_new:Npn \dim_use:c #1 { \tex_the:D \cs:w #1 \cs_end: } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[EXP]{\dim_to_decimal:n} +% \begin{macro}[EXP]{\@@_to_decimal:w} +% A function which comes up often enough to deserve a place in the +% kernel. Evaluate the dimension expression~|#1| then remove the +% trailing \texttt{pt}. When debugging is enabled, the argument is +% put in parentheses as this prevents the dimension expression from +% terminating early and leaving extra tokens lying around. This is +% used a lot by low-level manipulations. +% \begin{macrocode} +\cs_new:Npn \dim_to_decimal:n #1 + { + \exp_after:wN + \@@_to_decimal:w \dim_use:N \@@_eval:w #1 \@@_eval_end: + } +\use:e + { + \cs_new:Npn \exp_not:N \@@_to_decimal:w + #1 . #2 \tl_to_str:n { pt } + } + { + \int_compare:nNnTF {#2} > \c_zero_int + { #1 . #2 } + { #1 } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[EXP]{\dim_to_fp:n} +% Defined in \pkg{l3fp-convert}, documented here. +% \end{macro} +% +% \subsection{Conversion of \texttt{dim} to other units} +% +% The conversion from \texttt{pt} or \texttt{sp} to other units is complicated +% by the fact that \TeX{}'s conversion to \texttt{sp} involves rounding and +% hard-coded ratios. In order to give re-entrant outcomes, we therefore need +% to do quite a bit of work: see +% \url{https://github.com/latex3/latex3/issues/954} for detailed discussion. +% After dealing with the trivial case, we therefore have some work to do. +% The code to do this is contributed by Ruixi Zhang. +% +% \begin{macro}[EXP]{\dim_to_decimal_in_sp:n} +% The one easy case: the only requirement here is that we avoid an +% overflow. +% \begin{macrocode} +\cs_new:Npn \dim_to_decimal_in_sp:n #1 + { \int_value:w \@@_eval:w #1 \@@_eval_end: } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[EXP] +% { +% \dim_to_decimal_in_bp:n , +% \dim_to_decimal_in_cc:n , +% \dim_to_decimal_in_cm:n , +% \dim_to_decimal_in_dd:n , +% \dim_to_decimal_in_in:n , +% \dim_to_decimal_in_mm:n , +% \dim_to_decimal_in_pc:n +% } +% \begin{macro}[EXP]{\@@_to_decimal_aux:w} +% We first set up a helper macro \cs[no-index]{@@_tmp:w} which takes two +% arguments. The first argument is one of the following engine-defined +% units: |in|,~|pc|, |cm|, |mm|, |bp|, |dd|, |cc|, |nd|, and~|nc|. +% The second argument is $\frac{1}{2}\delta^{-1}$ in reduced fraction, +% where $\delta>1$~is the engine-defined conversion factor for each unit. +% Note that $\delta$~must be strictly larger than~$1$ for the following +% algorithm to work. +% +% Here is how the algorithm works: Suppose that a user inputs a +% non-negative dimension in a unit that has conversion factor~$\delta>1$. +% Then this dimension is internally represented as $X$\,sp, where +% $X=\lfloor N\delta\rfloor$ for some integer $N\ge0$. We then seek a +% formula to express this $N$ using~$X$. +% The \cs[no-index]{dim_to_decimal_in_<unit>:n} functions shall return +% the number $N/2^{16}$ in decimal. This way, we guarantee the returned +% decimal followed by the original unit will parse to exactly~$X$\,sp. +% +% So how do we get $N$ from~$X$? Well, since $X=\lfloor N\delta\rfloor$, +% we have $X\le N\delta<X+1$ and $X\delta^{-1}\le N<(X+1)\delta^{-1}$. +% Let's focus on the midpoint of this bounding interval for~$N$. The +% midpoint is $(X+\frac{1}{2})\delta^{-1}$. The fact $\delta>1$ implies +% that the bounding interval is shorter than~$1$ in length. Thus, +% (1)~$\hbox{midpoint}+\frac{1}{2}>N$ and +% (2)~$\hbox{midpoint}+\frac{1}{2}<N+1$. In other words, +% $N=\lfloor\hbox{midpoint}+\frac{1}{2}\rfloor$. As long as we can +% rewrite the midpoint as the result of a \enquote{scaling operation} of \eTeX, +% the $\lfloor\ldots+\frac{1}{2}\rfloor$ part will follow naturally. +% Indeed we can: $\hbox{midpoint}=(2X+1)\times(\frac{1}{2}\delta^{-1})$. +% +% Addendum: If $\delta\ge2$, then the bounding interval for~$N$ is at +% most~$\frac{1}{2}$ wide in length. In this case, the leftpoint +% $X\delta^{-1}$ suffices as $N=\lfloor X\delta^{-1}+\frac{1}{2}\rfloor$. +% Six out of the nine units listed above can be handled in this way, +% which is much simpler than using midpoint. But three remaining units +% have $1<\delta<2$; they are |bp|~($\delta=7227/7200$), +% |nd|~($\delta=685/642$), and |dd|~($\delta=1238/1157$), +% and these three must be handled using midpoint. +% For consistency, we shall use the midpoint approach for all nine units. +% \begin{macrocode} +\group_begin: + \cs_set_protected:Npn \@@_tmp:w #1#2 + { + \cs_new:cpn { dim_to_decimal_in_ #1 :n } ##1 + { + \exp_after:wN \@@_to_decimal_aux:w + \int_value:w \@@_eval:w ##1 \@@_eval_end: ; #2 ; + } + } +% \end{macrocode} +% Conversions to other units are now coded. +% Consult the pdf\/\TeX{} source for each conversion factor~$\delta$. +% Each factor $\frac{1}{2}\delta^{-1}$ is hand-coded +% for accuracy (and speed). As the units \texttt{nc} and \texttt{nd} +% are not supported by \XeTeX{} or (u)p\TeX{}, they are not included +% here. +% \begin{macrocode} + \@@_tmp:w { in } { 50 / 7227 } % delta = 7227/100 + \@@_tmp:w { pc } { 1 / 24 } % delta = 12/1 + \@@_tmp:w { cm } { 127 / 7227 } % delta = 7227/254 + \@@_tmp:w { mm } { 1270 / 7227 } % delta = 7227/2540 + \@@_tmp:w { bp } { 400 / 803 } % delta = 7227/7200 + \@@_tmp:w { dd } { 1157 / 2476 } % delta = 1238/1157 + \@@_tmp:w { cc } { 1157 / 29712 } % delta = 14856/1157 +\group_end: +% \end{macrocode} +% The tokens after \cs{@@_to_decimal_aux:w} shall have the following form: +% |<number>;<half of delta inverse>;|, where |<number>| represents the +% input dimension in |sp| unit. +% If |<number>| is positive, then |#1| is its leading digit and |#2| +% (possibly empty) is all the remaining digits; +% If |<number>| is zero, then |#1| is~|0|$_{12}$ and |#2| is empty; +% If |<number>| is negative, then |#1| is its sign~|-|$_{12}$ and |#2| +% is all its digits. +% In all three cases, |#1#2| is the original |<number>|. We can use |#1| +% to decide whether to use the |-1| formula or the |+1| formula. +% \begin{macrocode} +\cs_new:Npn \@@_to_decimal_aux:w #1#2 ; #3 ; + { + \dim_to_decimal:n + { +% \end{macrocode} +% We need different formulae depending on whether the user input dimension +% is negative or not. +% For negative dimension (internally represented as $X$\,sp), the formula +% is $(2X-1)\times(\frac{1}{2}\delta^{-1})$. +% For non-negative dimension, the formula +% is $(2X+1)\times(\frac{1}{2}\delta^{-1})$. +% The intermediate step doubles the dimension~$X$. +% To avoid overflow, we must invoke \cs[no-index]{int_eval:n}. +% \begin{macrocode} + \int_eval:n + { ( 2 * #1#2 \if:w #1 - - \else: + \fi: 1 ) * #3 } +% \end{macrocode} +% Now we append~|sp| to finish the dimension specification. +% \begin{macrocode} + sp + } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[EXP]{\dim_to_decimal_in_unit:nn} +% \begin{macrocode} +\cs_new:Npn \dim_to_decimal_in_unit:nn #1#2 + { + \exp_after:wN \@@_chk_unit:w + \int_value:w \@@_eval:w #2 \@@_eval_end: ; {#1} + } +% \end{macrocode} +% \end{macro} +% \begin{macro}[EXP]{\@@_chk_unit:w} +% The tokens after \cs{@@_chk_unit:w} shall have the following form: +% |<number2>;{<dimexpr1>}|, where |<number2>| represents |<dimexpr2>| in +% |sp| unit. +% If |#1| is~|0|$_{12}$, the \enquote{unit} |<dimexpr2>| must also be zero. +% So we throw out a \enquote{division by zero} error message at this point. +% Otherwise, if |#1| is~|-|$_{12}$, we shall negate both |<dimexpr1>| and +% |<dimexpr2>| for later procedures. +% \begin{macrocode} +\cs_new:Npn \@@_chk_unit:w #1#2;#3 + { + \token_if_eq_charcode:NNTF #1 0 + { \msg_expandable_error:nn { dim } { zero-unit } } + { + \exp_after:wN \@@_branch_unit:w + \int_value:w \if:w #1 - - \fi: \@@_eval:w #3 \exp_after:wN ; + \int_value:w \if:w #1 - - \fi: #1#2 ; + } + } +% \end{macrocode} +% \end{macro} +% \begin{macro}[EXP]{\@@_branch_unit:w} +% The tokens after \cs{@@_branch_unit:w} shall have the following form: +% |<number1>;<number2>;|, where |<number1>| represents |<dimexpr1>| in +% |sp| unit (whose sign is taken care of) and |<number2>| represents the +% absolute value of |<dimexpr2>| in |sp| unit (which is strictly positive). +% +% As explained, the formulae $(2X\pm1)\times(\frac{1}{2}\delta^{-1})$ work +% if and only if $\delta=|<number2>|/65536>1$. This corresponds to +% |<dimexpr2>| strictly larger than 1\,pt in absolute value. +% In this case, we simply call \cs{@@_to_decimal_aux:w} and supply +% $\frac{1}{2}\delta^{-1}=32768/|<number2>|$ as |<half of delta inverse>|. +% +% Otherwise if $|<number2>|=65536$, then |<dimexpr2>| is 1\,pt in absolute +% value and we call \cs{dim_to_decimal:n} directly. +% +% Otherwise $0<|<number2>|<65536$ and we shall proceed differently. +% +% For unit less than 1\,pt, write $n=|<number2>|$, then $\delta=n/65536<1$. +% The midpoint formulae are not optimal. Let's go back to the inequalities +% $X\delta^{-1}\le N<(X+1)\delta^{-1}$. Since now $\delta<1$, the bounding +% interval is wider than~$1$ in length. Consider the ceiling integer +% $M=\lceil X\delta^{-1}\rceil$, then $X\delta^{-1}\le M<(X+1)\delta^{-1}$, +% or equivalently $X\le M\delta<X+1$, and thus $\lfloor M\delta\rfloor=X$. +% The key point here is that we \emph{don't} need to solve for~$N$; +% in fact, any integer that can reproduce~$X$ (such as~$M$) is good enough. +% So the algorithm goes like this: (1)~Compute rounding of $X\delta^{-1}$, +% i.e., $M'=\lfloor X\delta^{-1}+\frac{1}{2}\rfloor$; this $M'$ could be +% either $M$ or $M-1$. (2)~Check if $\lfloor M'\delta\rfloor=X$, i.e., +% whether our candidate $M'$ can reproduce~$X$. If so, then this $M'$ is +% good enough; if not, then we add one to~$M'$. +% +% But when $0<n<65536$, we cannot delay the problem of overflow any more. +% For $X\delta^{-1}=X\times65536/n$, where $X$ can go up to $2^{30}-1$ and +% $n$ can be as small as~$1$, the result is well over $2^{31}-1$ (largest +% integer allowed within |\numexpr|). +% For example, |\dim_to_decimal_in_unit:nn { \maxdimen } { 1sp }|. +% Here, all inputs are legal, so we should be able to output |1073741823| +% \emph{without} causing arithmetic overflow. +% +% As a workaround, let's write $X=qn+r$ with some $q\ge0$ and $0\le r<n$. +% Then $X\delta^{-1}=65536q+65536r/n$, and so +% $M'=65536q+\lfloor65536r/n+\frac{1}{2}\rfloor=65536q+R'$. +% Computing $R'$ will never overflow. If this $R'$ can reproduce~$r$, then +% it is good enough; otherwise we add one to~$R'$. In the end, we shall +% output $q+R'/65536$ in decimal. +% +% Note: $q=\lfloor X/n\rfloor=\lfloor\frac{2X-n}{2n}+\frac{1}{2}\rfloor$ +% represents the \enquote{integer} part, while $0\le R'\le65536$ represents the +% \enquote{fractional} part. (Can $R'=65536$ really happen? Didn't investigate.) +% \begin{macrocode} +\cs_new:Npn \@@_branch_unit:w #1;#2; + { + \int_compare:nNnTF {#2} > { 65536 } + { \@@_to_decimal_aux:w #1 ; 32768 / #2 ; } + { + \int_compare:nNnTF {#2} = { 65536 } + { \dim_to_decimal:n { #1sp } } + { \@@_get_quotient:w #1 ; #2 ; } + } + } +% \end{macrocode} +% \end{macro} +% \begin{macro}[EXP]{\@@_get_quotient:w} +% We wish to get the quotient $q$ via rounding of $\frac{2X-n}{2n}$. +% When $0\le X<n/2$, we have $\frac{2X-n}{2n}<0$. So, strictly speaking, +% |\numexpr| performs its rounding as +% $\lceil\frac{2X-n}{2n}-\frac{1}{2}\rceil$, not exactly what we want. +% However, lucky for us, only $X=0$ makes +% $\lceil\frac{2X-n}{2n}-\frac{1}{2}\rceil=-1\neq0$ (we want~$0$); +% all other $0<X<n/2$ make $\lceil\frac{2X-n}{2n}-\frac{1}{2}\rceil=0=q$. +% Thus, let's filter out $X=0$ early. +% If $X\neq0$, we extract its sign and leave the sign to the back. +% The sign does not participate in any calculations (also the code works +% with positive integers only). The sign is used at the last stages when +% we parse the decimal output. +% +% After \cs{@@_get_quotient:w} has done its job, either we have the +% decimal~|0|, or we have \cs{@@_get_remainder:w} followed by +% $q$|;|$\lvert X\rvert$|;|$n$|;<sign of X>;|. +% \begin{macrocode} +\cs_new:Npn \@@_get_quotient:w #1#2;#3; + { + \token_if_eq_charcode:NNTF #1 0 + { 0 } + { + \token_if_eq_charcode:NNTF #1 - + { + \exp_after:wN \exp_after:wN \exp_after:wN \@@_get_remainder:w + \int_eval:n { ( 2 * #2 - #3 ) / ( 2 * #3 ) } ; + #2 ; #3 ; - ; + } + { + \exp_after:wN \exp_after:wN \exp_after:wN \@@_get_remainder:w + \int_eval:n { ( 2 * #1#2 - #3 ) / ( 2 * #3 ) } ; + #1#2 ; #3 ; ; + } + } + } +% \end{macrocode} +% \end{macro} +% \begin{macro}[EXP]{\@@_get_remainder:w} +% \cs{@@_get_remainder:w} does not need to read the sign. +% After finding the remainder~$r$, the number~$\lvert X\rvert$ is no longer +% needed. We should then have \cs{@@_convert_remainder:w} followed by +% $r$|;|$n$|;|$q$|;<sign of X>;|. +% \begin{macrocode} +\cs_new:Npn \@@_get_remainder:w #1;#2;#3; + { + \exp_after:wN \exp_after:wN \exp_after:wN \@@_convert_remainder:w + \int_eval:n { #2 - #1 * #3 } ; + #3 ; #1 ; + } +% \end{macrocode} +% \end{macro} +% \begin{macro}[EXP]{\@@_convert_remainder:w} +% This is trivial. We compute $R'=\lfloor65536r/n+\frac{1}{2}\rfloor$, +% then leave \cs{@@_test_candidate:w} followed by +% $R'$|;|$r$|;|$n$|;|$q$|;<sign of X>;|. +% \begin{macrocode} +\cs_new:Npn \@@_convert_remainder:w #1;#2; + { + \exp_after:wN \exp_after:wN \exp_after:wN \@@_test_candidate:w + \int_eval:n { #1 * 65536 / #2 } ; + #1 ; #2 ; + } +% \end{macrocode} +% \end{macro} +% \begin{macro}[EXP]{\@@_test_candidate:w} +% Now the fun part: We take $R'$, $r$ and~$n$ to test whether +% $r=\lfloor R'\delta\rfloor$. This is done as a dimension comparison. +% The left-hand side, $r$, is simply |r sp|. The right-hand side, +% $\lfloor R'\delta\rfloor$, is exactly |<R' as decimal><dimen = n sp>|. +% If the result is true, then we've found~$R'$; +% otherwise we add one to~$R'$. +% After this step, $r$ and~$n$ are no longer needed. We should then have +% \cs{@@_parse_decimal:w} followed by $R'$|;|$q$|;<sign of X>;|. +% \begin{macrocode} +\cs_new:Npn \@@_test_candidate:w #1;#2;#3; + { + \dim_compare:nNnTF { #2sp } = + { \dim_to_decimal:n { #1sp } \@@_eval:w #3sp \@@_eval_end: } + { \@@_parse_decimal:w #1 ; } + { + \@@_parse_decimal:w \int_eval:n { #1 + 1 } ; + } + } +% \end{macrocode} +% \end{macro} +% \begin{macro}[EXP]{\@@_parse_decimal:w, \@@_parse_decimal_aux:w} +% The Grand Finale: We sum $q$ and $R'/65536$ together, and negate the +% result if necessary. These are all done expandably. +% If $0<R'/65536<1$, the integer summation is naturally terminated at the +% decimal point. If $R'/65536=0$ (or~$1$?), the summation is terminated +% at the semicolon. The auxiliary function \cs{@@_parse_decimal_aux:w} +% takes care of both cases. +% \begin{macrocode} +\cs_new:Npn \@@_parse_decimal:w #1;#2;#3; + { + \exp_after:wN \@@_parse_decimal_aux:w + \int_value:w #3 \int_eval:w #2 + \dim_to_decimal:n { #1sp } ; + } +\cs_new:Npn \@@_parse_decimal_aux:w #1 ; {#1} +% \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} +% +% \begin{macro}{\dim_show:n} +% Diagnostics. We don't use the \TeX{} primitive \tn{showthe} to show +% dimension expressions: this gives a more unified output. +% \begin{macrocode} +\cs_new_protected:Npn \dim_show:n + { \__kernel_msg_show_eval:Nn \dim_eval:n } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\dim_log:N, \dim_log:c, \dim_log:n} +% Diagnostics. Redirect output of \cs{dim_show:n} to the log. +% \begin{macrocode} +\cs_new_eq:NN \dim_log:N \__kernel_register_log:N +\cs_new_eq:NN \dim_log:c \__kernel_register_log:c +\cs_new_protected:Npn \dim_log:n + { \__kernel_msg_log_eval:Nn \dim_eval:n } +% \end{macrocode} +% \end{macro} +% +% \subsection{Constant dimensions} +% +% \begin{variable}{\c_zero_dim, \c_max_dim} +% Constant dimensions. +% \begin{macrocode} +\dim_const:Nn \c_zero_dim { 0 pt } +\dim_const:Nn \c_max_dim { 16383.99999 pt } +% \end{macrocode} +% \end{variable} +% +% \subsection{Scratch dimensions} +% +% \begin{variable}{\l_tmpa_dim, \l_tmpb_dim} +% \begin{variable}{\g_tmpa_dim, \g_tmpb_dim} +% We provide two 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 \g_tmpa_dim +\dim_new:N \g_tmpb_dim +% \end{macrocode} +% \end{variable} +% \end{variable} +% +% \subsection{Creating and initialising \texttt{skip} variables} +% +% \begin{macrocode} +%<@@=skip> +% \end{macrocode} +% +% \begin{variable}{\s_@@_stop} +% Internal scan marks. +% \begin{macrocode} +\scan_new:N \s_@@_stop +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\skip_new:N, \skip_new:c} +% Allocation of a new internal registers. +% \begin{macrocode} +\cs_new_protected:Npn \skip_new:N #1 + { + \__kernel_chk_if_free_cs:N #1 + \cs:w newskip \cs_end: #1 + } +\cs_generate_variant:Nn \skip_new:N { c } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\skip_const:Nn, \skip_const:cn} +% Contrarily to integer constants, we cannot avoid using a register, +% even for constants. See \cs{dim_const:Nn} for why we cannot use +% \cs{skip_gset:Nn}. +% \begin{macrocode} +\cs_new_protected:Npn \skip_const:Nn #1#2 + { + \skip_new:N #1 + \tex_global:D #1 = \skip_eval:n {#2} \scan_stop: + } +\cs_generate_variant:Nn \skip_const:Nn { 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_eq:NN \skip_zero:N \dim_zero:N +\cs_new_eq:NN \skip_gzero:N \dim_gzero:N +\cs_generate_variant:Nn \skip_zero:N { c } +\cs_generate_variant:Nn \skip_gzero:N { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro} +% {\skip_zero_new:N, \skip_zero_new:c, \skip_gzero_new:N, \skip_gzero_new:c} +% Create a register if needed, otherwise clear it. +% \begin{macrocode} +\cs_new_protected:Npn \skip_zero_new:N #1 + { \skip_if_exist:NTF #1 { \skip_zero:N #1 } { \skip_new:N #1 } } +\cs_new_protected:Npn \skip_gzero_new:N #1 + { \skip_if_exist:NTF #1 { \skip_gzero:N #1 } { \skip_new:N #1 } } +\cs_generate_variant:Nn \skip_zero_new:N { c } +\cs_generate_variant:Nn \skip_gzero_new:N { c } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[pTF]{\skip_if_exist:N, \skip_if_exist:c} +% Copies of the \texttt{cs} functions defined in \pkg{l3basics}. +% \begin{macrocode} +\prg_new_eq_conditional:NNn \skip_if_exist:N \cs_if_exist:N + { TF , T , F , p } +\prg_new_eq_conditional:NNn \skip_if_exist:c \cs_if_exist:c + { TF , T , F , p } +% \end{macrocode} +% \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:Npn \skip_set:Nn #1#2 + { #1 = \tex_glueexpr:D #2 \scan_stop: } +\cs_new_protected:Npn \skip_gset:Nn #1#2 + { \tex_global:D #1 = \tex_glueexpr:D #2 \scan_stop: } +\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:Npn \skip_set_eq:NN #1#2 { #1 = #2 } +\cs_generate_variant:Nn \skip_set_eq:NN { c , Nc , cc } +\cs_new_protected:Npn \skip_gset_eq:NN #1#2 { \tex_global:D #1 = #2 } +\cs_generate_variant:Nn \skip_gset_eq:NN { c , 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:Npn \skip_add:Nn #1#2 + { \tex_advance:D #1 \tex_glueexpr:D #2 \scan_stop: } +\cs_new_protected:Npn \skip_gadd:Nn #1#2 + { \tex_global:D \tex_advance:D #1 \tex_glueexpr:D #2 \scan_stop: } +\cs_generate_variant:Nn \skip_add:Nn { c } +\cs_generate_variant:Nn \skip_gadd:Nn { c } +\cs_new_protected:Npn \skip_sub:Nn #1#2 + { \tex_advance:D #1 - \tex_glueexpr:D #2 \scan_stop: } +\cs_new_protected:Npn \skip_gsub:Nn #1#2 + { \tex_global:D \tex_advance:D #1 - \tex_glueexpr:D #2 \scan_stop: } +\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 } + { + \str_if_eq:eeTF { \skip_eval:n {#1} } { \skip_eval:n {#2} } + { \prg_return_true: } + { \prg_return_false: } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[EXP,pTF]{\skip_if_finite:n} +% \begin{macro}[EXP]{\@@_if_finite:wwNw} +% With \eTeX{}, we have an easy access to the order of infinities of +% the stretch and shrink components of a skip. However, to access +% both, we either need to evaluate the expression twice, or evaluate +% it, then call an auxiliary to extract both pieces of information +% from the result. Since we are going to need an auxiliary anyways, +% it is quicker to make it search for the string \texttt{fil} which +% characterizes infinite glue. +% \begin{macrocode} +\cs_set_protected:Npn \@@_tmp:w #1 + { + \prg_new_conditional:Npnn \skip_if_finite:n ##1 { p , T , F , TF } + { + \exp_after:wN \@@_if_finite:wwNw + \skip_use:N \tex_glueexpr:D ##1 ; \prg_return_false: + #1 ; \prg_return_true: \s_@@_stop + } + \cs_new:Npn \@@_if_finite:wwNw ##1 #1 ##2 ; ##3 ##4 \s_@@_stop {##3} + } +\exp_args:No \@@_tmp:w { \tl_to_str:n { fil } } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Using \texttt{skip} expressions and variables} +% +% \begin{macro}{\skip_eval:n} +% Evaluating a skip expression expandably. +% \begin{macrocode} +\cs_new:Npn \skip_eval:n #1 + { \skip_use:N \tex_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 \dim_use:N +\cs_new_eq:NN \skip_use:c \dim_use: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:Npn \skip_horizontal:n #1 + { \skip_horizontal:N \tex_glueexpr:D #1 \scan_stop: } +\cs_new_eq:NN \skip_vertical:N \tex_vskip:D +\cs_new:Npn \skip_vertical:n #1 + { \skip_vertical:N \tex_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} +% +% \begin{macro}{\skip_show:n} +% Diagnostics. We don't use the \TeX{} primitive \tn{showthe} to show +% skip expressions: this gives a more unified output. +% \begin{macrocode} +\cs_new_protected:Npn \skip_show:n + { \__kernel_msg_show_eval:Nn \skip_eval:n } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\skip_log:N, \skip_log:c, \skip_log:n} +% Diagnostics. Redirect output of \cs{skip_show:n} to the log. +% \begin{macrocode} +\cs_new_eq:NN \skip_log:N \__kernel_register_log:N +\cs_new_eq:NN \skip_log:c \__kernel_register_log:c +\cs_new_protected:Npn \skip_log:n + { \__kernel_msg_log_eval:Nn \skip_eval:n } +% \end{macrocode} +% \end{macro} +% +% \subsection{Constant skips} +% +% \begin{macro}{\c_zero_skip, \c_max_skip} +% Skips with no rubber component are just dimensions but need to terminate +% correctly. +% \begin{macrocode} +\skip_const:Nn \c_zero_skip { \c_zero_dim } +\skip_const:Nn \c_max_skip { \c_max_dim } +% \end{macrocode} +% \end{macro} +% +% \subsection{Scratch skips} +% +% \begin{variable}{\l_tmpa_skip, \l_tmpb_skip} +% \begin{variable}{\g_tmpa_skip, \g_tmpb_skip} +% We provide two 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 \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} +\cs_new_protected:Npn \muskip_new:N #1 + { + \__kernel_chk_if_free_cs:N #1 + \cs:w newmuskip \cs_end: #1 + } +\cs_generate_variant:Nn \muskip_new:N { c } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\muskip_const:Nn, \muskip_const:cn} +% See \cs{skip_const:Nn}. +% \begin{macrocode} +\cs_new_protected:Npn \muskip_const:Nn #1#2 + { + \muskip_new:N #1 + \tex_global:D #1 = \muskip_eval:n {#2} \scan_stop: + } +\cs_generate_variant:Nn \muskip_const:Nn { 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:Npn \muskip_zero:N #1 + { #1 = \c_zero_muskip } +\cs_new_protected:Npn \muskip_gzero:N #1 + { \tex_global:D #1 = \c_zero_muskip } +\cs_generate_variant:Nn \muskip_zero:N { c } +\cs_generate_variant:Nn \muskip_gzero:N { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro} +% { +% \muskip_zero_new:N, \muskip_zero_new:c, +% \muskip_gzero_new:N, \muskip_gzero_new:c +% } +% Create a register if needed, otherwise clear it. +% \begin{macrocode} +\cs_new_protected:Npn \muskip_zero_new:N #1 + { \muskip_if_exist:NTF #1 { \muskip_zero:N #1 } { \muskip_new:N #1 } } +\cs_new_protected:Npn \muskip_gzero_new:N #1 + { \muskip_if_exist:NTF #1 { \muskip_gzero:N #1 } { \muskip_new:N #1 } } +\cs_generate_variant:Nn \muskip_zero_new:N { c } +\cs_generate_variant:Nn \muskip_gzero_new:N { c } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[pTF]{\muskip_if_exist:N, \muskip_if_exist:c} +% Copies of the \texttt{cs} functions defined in \pkg{l3basics}. +% \begin{macrocode} +\prg_new_eq_conditional:NNn \muskip_if_exist:N \cs_if_exist:N + { TF , T , F , p } +\prg_new_eq_conditional:NNn \muskip_if_exist:c \cs_if_exist:c + { TF , T , F , p } +% \end{macrocode} +% \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:Npn \muskip_set:Nn #1#2 + { #1 = \tex_muexpr:D #2 \scan_stop: } +\cs_new_protected:Npn \muskip_gset:Nn #1#2 + { \tex_global:D #1 = \tex_muexpr:D #2 \scan_stop: } +\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:Npn \muskip_set_eq:NN #1#2 { #1 = #2 } +\cs_generate_variant:Nn \muskip_set_eq:NN { c , Nc , cc } +\cs_new_protected:Npn \muskip_gset_eq:NN #1#2 { \tex_global:D #1 = #2 } +\cs_generate_variant:Nn \muskip_gset_eq:NN { c , 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:Npn \muskip_add:Nn #1#2 + { \tex_advance:D #1 \tex_muexpr:D #2 \scan_stop: } +\cs_new_protected:Npn \muskip_gadd:Nn #1#2 + { \tex_global:D \tex_advance:D #1 \tex_muexpr:D #2 \scan_stop: } +\cs_generate_variant:Nn \muskip_add:Nn { c } +\cs_generate_variant:Nn \muskip_gadd:Nn { c } +\cs_new_protected:Npn \muskip_sub:Nn #1#2 + { \tex_advance:D #1 - \tex_muexpr:D #2 \scan_stop: } +\cs_new_protected:Npn \muskip_gsub:Nn #1#2 + { \tex_global:D \tex_advance:D #1 - \tex_muexpr:D #2 \scan_stop: } +\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:Npn \muskip_eval:n #1 + { \muskip_use:N \tex_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 \dim_use:N +\cs_new_eq:NN \muskip_use:c \dim_use: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} +% +% \begin{macro}{\muskip_show:n} +% Diagnostics. We don't use the \TeX{} primitive \tn{showthe} to show +% muskip expressions: this gives a more unified output. +% \begin{macrocode} +\cs_new_protected:Npn \muskip_show:n + { \__kernel_msg_show_eval:Nn \muskip_eval:n } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\muskip_log:N, \muskip_log:c, \muskip_log:n} +% Diagnostics. Redirect output of \cs{muskip_show:n} to the log. +% \begin{macrocode} +\cs_new_eq:NN \muskip_log:N \__kernel_register_log:N +\cs_new_eq:NN \muskip_log:c \__kernel_register_log:c +\cs_new_protected:Npn \muskip_log:n + { \__kernel_msg_log_eval:Nn \muskip_eval:n } +% \end{macrocode} +% \end{macro} +% +% \subsection{Constant muskips} +% +% \begin{macro}{\c_zero_muskip} +% \begin{macro}{\c_max_muskip} +% Constant muskips given by their value. +% \begin{macrocode} +\muskip_const:Nn \c_zero_muskip { 0 mu } +\muskip_const:Nn \c_max_muskip { 16383.99999 mu } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Scratch muskips} +% +% \begin{variable}{\l_tmpa_muskip, \l_tmpb_muskip} +% \begin{variable}{\g_tmpa_muskip, \g_tmpb_muskip} +% We provide two local and two global scratch registers, maybe we +% need more or less. +% \begin{macrocode} +\muskip_new:N \l_tmpa_muskip +\muskip_new:N \l_tmpb_muskip +\muskip_new:N \g_tmpa_muskip +\muskip_new:N \g_tmpb_muskip +% \end{macrocode} +% \end{variable} +% \end{variable} +% +% \begin{macrocode} +%</package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintIndex |