% \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} % % \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-11-02} % % \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_set:NV, \dim_set:cV, % \dim_gset:Nn, \dim_gset:cn, \dim_gset:NV, \dim_gset:cV % } % \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 case}s until a match is found. % 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. % Since evaluation of the test expressions stops at the first % successful case, the order of possible matches should normally % be that the most likely are earlier: this will reduce the average % steps required to complete expansion. % \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 % { bp } = % { \dim_to_decimal_in_bp:n { 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 % { } = % { \dim_to_decimal_in_:n { } } % \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_set:NV, \skip_set:cV, % \skip_gset:Nn, \skip_gset:cn, \skip_gset:NV, \skip_gset:cV % } % \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_set:Nn, \muskip_set:cn, % \muskip_gset:Nn, \muskip_gset:cn, \muskip_gset:NV, \muskip_gset:cV % } % \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, \dim_set:NV, \dim_set:cV} % \begin{macro}{\dim_gset:Nn, \dim_gset:cn, \dim_gset:NV, \dim_gset:cV} % 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 { NV , c , cV } \cs_generate_variant:Nn \dim_gset:Nn { NV , c , cV } % \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_: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\delta1$ 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};;|, where || represents the % input dimension in |sp| unit. % If || is positive, then |#1| is its leading digit and |#2| % (possibly empty) is all the remaining digits; % If || is zero, then |#1| is~|0|$_{12}$ and |#2| is empty; % If || is negative, then |#1| is its sign~|-|$_{12}$ and |#2| % is all its digits. % In all three cases, |#1#2| is the original ||. 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: % |;{}|, where || represents || in % |sp| unit. % If |#1| is~|0|$_{12}$, the \enquote{unit} || 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 || and % || 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: % |;;|, where || represents || in % |sp| unit (whose sign is taken care of) and || represents the % absolute value of || 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=||/65536>1$. This corresponds to % || 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/||$ as ||. % % Otherwise if $||=65536$, then || is 1\,pt in absolute % value and we call \cs{dim_to_decimal:n} directly. % % Otherwise $0<||<65536$ and we shall proceed differently. % % For unit less than 1\,pt, write $n=||$, 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 { 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;|. % \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$|;;|. % \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$|;;|. % \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 ||. % 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$|;;|. % \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 % \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, \skip_set:NV, \skip_set:cV} % \begin{macro}{\skip_gset:Nn, \skip_gset:cn, \skip_gset:NV, \skip_gset:cV} % 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 { NV , c , cV } \cs_generate_variant:Nn \skip_gset:Nn { NV , c , cV } % \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, \muskip_set:NV, \muskip_set:cV} % \begin{macro}{\muskip_gset:Nn, \muskip_gset:cn, \muskip_gset:NV, \muskip_gset:cV} % 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 { NV , c , cV } \cs_generate_variant:Nn \muskip_gset:Nn { NV , c , cV } % \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} % % \end{macrocode} % % \end{implementation} % % \PrintIndex