summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex/expl3/l3calc.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/source/latex/expl3/l3calc.dtx')
-rw-r--r--Master/texmf-dist/source/latex/expl3/l3calc.dtx930
1 files changed, 930 insertions, 0 deletions
diff --git a/Master/texmf-dist/source/latex/expl3/l3calc.dtx b/Master/texmf-dist/source/latex/expl3/l3calc.dtx
new file mode 100644
index 00000000000..f00c2941940
--- /dev/null
+++ b/Master/texmf-dist/source/latex/expl3/l3calc.dtx
@@ -0,0 +1,930 @@
+% \iffalse
+%% File: l3calc.dtx Copyright (C) 2006 LaTeX3 project
+%%
+%% It may be distributed and/or modified under the conditions of the
+%% LaTeX Project Public License (LPPL), either version 1.3c of this
+%% license or (at your option) any later version. The latest version
+%% of this license is in the file
+%%
+%% http://www.latex-project.org/lppl.txt
+%%
+%% This file is part of the ``expl3 bundle'' (The Work in LPPL)
+%% and all files in that bundle must be distributed together.
+%%
+%% The released version of this bundle is available from CTAN.
+%%
+%% -----------------------------------------------------------------------
+%%
+%% The development version of the bundle can be found at
+%%
+%% http://www.latex-project.org/cgi-bin/cvsweb.cgi/
+%%
+%% for those people who are interested.
+%%
+%%%%%%%%%%%
+%% NOTE: %%
+%%%%%%%%%%%
+%%
+%% Snapshots taken from the repository represent work in progress and may
+%% not work or may contain conflicting material! We therefore ask
+%% people _not_ to put them into distributions, archives, etc. without
+%% prior consultation with the LaTeX Project Team.
+%%
+%% -----------------------------------------------------------------------
+%<package>\RequirePackage{l3names}
+%<*dtx>
+%\fi
+\def\GetIdInfo$Id: #1.dtx #2 #3-#4-#5 #6 #7$#8{%
+ \def\fileversion{#2}%
+ \def\filedate{#3/#4/#5}%
+ \ProvidesFile{#1.dtx}[#3/#4/#5 v#2 #8]%
+}
+%\iffalse
+%</dtx>
+%\fi
+\GetIdInfo$Id: l3calc.dtx 573 2006-08-21 20:59:37Z morten $
+ {L3 Experimental calc module}
+% \iffalse
+%<*driver>
+\documentclass{l3doc}
+
+\begin{document}
+\DocInput{l3calc.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+% \title{The \textsf{l3calc} package\thanks{This file has version
+% number \fileversion, last
+% revised \filedate.}\\
+% Infix notation arithmetic in \LaTeX3}
+% \author{\Team}
+% \date{\filedate}
+% \maketitle
+%
+% \section{Infix notation arithmetic}
+%
+% This is pretty much a straight adaption of the \textsf{calc} package
+% and as such has same syntax for the \meta{calc expression}. However,
+% there are some noticeable differences.
+% \begin{itemize}
+% \item The calc expression is expanded fully, which means there are
+% no problems with unfinished conditionals. However, the contents of
+% |\widthof| etc.\ is not expanded at all.
+% \item Muskip registers are supported although they can only be used
+% in |\ratio| if already evaluating a muskip expression. For the
+% other three register types, you can use points.
+% \item All results are rounded, not truncated. More precisely, the
+% primitive \TeX\ operations |\divide| and |\multiply| are not used.
+% \end{itemize}
+%
+% \begin{function}{
+% \calc_int_set:Nn |
+% \calc_int_gset:Nn |
+% \calc_int_add:Nn |
+% \calc_int_gadd:Nn |
+% \calc_int_sub:Nn |
+% \calc_int_gsub:Nn |
+% }
+% \begin{syntax}
+% "\calc_int_set:Nn" <int> "{"<calc expression>"}"
+% \end{syntax}
+% Evaluates <calc expression> and either adds or subtracts it from
+% <int> or sets <int> to it. These operations can also be global.
+% \end{function}
+%
+%
+% \begin{function}{
+% \calc_dim_set:Nn |
+% \calc_dim_gset:Nn |
+% \calc_dim_add:Nn |
+% \calc_dim_gadd:Nn |
+% \calc_dim_sub:Nn |
+% \calc_dim_gsub:Nn |
+% }
+% \begin{syntax}
+% "\calc_dim_set:Nn" <dim> "{"<calc expression>"}"
+% \end{syntax}
+% Evaluates <calc expression> and either adds or subtracts it from
+% <dim> or sets <dim> to it. These operations can also be global.
+% \end{function}
+%
+%
+% \begin{function}{
+% \calc_skip_set:Nn |
+% \calc_skip_gset:Nn |
+% \calc_skip_add:Nn |
+% \calc_skip_gadd:Nn |
+% \calc_skip_sub:Nn |
+% \calc_skip_gsub:Nn |
+% }
+% \begin{syntax}
+% "\calc_skip_set:Nn" <skip> "{"<calc expression>"}"
+% \end{syntax}
+% Evaluates <calc expression> and either adds or subtracts it from
+% <skip> or sets <skip> to it. These operations can also be global.
+% \end{function}
+%
+%
+% \begin{function}{
+% \calc_muskip_set:Nn |
+% \calc_muskip_gset:Nn |
+% \calc_muskip_add:Nn |
+% \calc_muskip_gadd:Nn |
+% \calc_muskip_sub:Nn |
+% \calc_muskip_gsub:Nn |
+% }
+% \begin{syntax}
+% "\calc_muskip_set:Nn" <muskip> "{"<calc expression>"}"
+% \end{syntax}
+% Evaluates <calc expression> and either adds or subtracts it from
+% <muskip> or sets <muskip> to it. These operations can also be
+% global.
+% \end{function}
+%
+%
+% \begin{function}{
+% \calc_calculate_box_size:nnn |
+% }
+% \begin{syntax}
+% "\calc_calculate_box_size:nnn" "{"<dim-set>"}" \\
+% "{"<item 1> <item 2> ... <item n>"}" "{"<contents>"}"
+% \end{syntax}
+% Sets <contents> in a temporary box "\l_tmpa_box". Then <dim-set>
+% is put in front of a loop that inserts "+"\meta{item$\sb{i}$} in
+% front of "\l_tmpa_box" and this is evaluated. For instance, if we
+% wanted to determine the total height of the text "xyz" and store
+% it in "\l_tmpa_dim", we would call it as.
+% \begin{verbatim}
+% \calc_calculate_box_size:nnn
+% {\dim_set:Nn\l_tmpa_dim}{\box_ht:N\box_dp:N}{xyz}
+% \end{verbatim}
+% Similarly, if we wanted the difference between height and depth,
+% we could call it as
+% \begin{verbatim}
+% \calc_calculate_box_size:nnn
+% {\dim_set:Nn\l_tmpa_dim}{\box_ht:N{-\box_dp:N}}{xyz}
+% \end{verbatim}
+% \end{function}
+%
+% \StopEventually{}
+%
+% \subsection{The Implementation}
+%
+% Since this is basically a re-worked version of the \textsf{calc}
+% package, I haven't bothered with too many comments except for in the
+% places where this package differs. This may (and should) change at
+% some point.
+%
+% We start by ensuring that the required packages are loaded.
+% \begin{macrocode}
+%<*package>
+\RequirePackage{l3int}
+\RequirePackage{l3skip}
+\RequirePackage{l3box}
+%</package>
+%<*initex|package>
+% \end{macrocode}
+%
+%
+% \begin{macro}{\l_calc_expression_tlp}
+% \begin{macro}{\g_calc_A_register}
+% \begin{macro}{\l_calc_B_register}
+% \begin{macro}{\l_calc_current_type_int}
+% Here we define some registers and pointers we will need.
+% \begin{macrocode}
+\tlp_new:Nn\l_calc_expression_tlp{}
+\def_new:Npn \g_calc_A_register{}
+\def_new:Npn \l_calc_B_register{}
+\int_new:N \l_calc_current_type_int
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\g_calc_A_int}
+% \begin{macro}{\l_calc_B_int}
+% \begin{macro}{\l_calc_C_int}
+% \begin{macro}{\g_calc_A_dim}
+% \begin{macro}{\l_calc_B_dim}
+% \begin{macro}{\l_calc_C_dim}
+% \begin{macro}{\g_calc_A_skip}
+% \begin{macro}{\l_calc_B_skip}
+% \begin{macro}{\l_calc_C_skip}
+% \begin{macro}{\g_calc_A_muskip}
+% \begin{macro}{\l_calc_B_muskip}
+% \begin{macro}{\l_calc_C_muskip}
+% For each type of register we will need three registers to do our
+% manipulations.
+% \begin{macrocode}
+\int_new:N \g_calc_A_int
+\int_new:N \l_calc_B_int
+\int_new:N \l_calc_C_int
+\dim_new:N \g_calc_A_dim
+\dim_new:N \l_calc_B_dim
+\dim_new:N \l_calc_C_dim
+\skip_new:N \g_calc_A_skip
+\skip_new:N \l_calc_B_skip
+\skip_new:N \l_calc_C_skip
+\muskip_new:N \g_calc_A_muskip
+\muskip_new:N \l_calc_B_muskip
+\muskip_new:N \l_calc_C_muskip
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+%
+%
+% \begin{macro}{\calc_assign_generic:NNNNNn}
+% The generic function. |#1| is a number denoting which type we are
+% doing. (0=int, 1=dim, 2=skip, 3=muskip), |#2| = temp register A,
+% |#3| = temp register B, |#4| is a function acting on |#5| which is
+% the register to be set. |#6| is the calc expression. This version
+% relies on |\real| and |\ratio| having our definitions.
+% \begin{macrocode}
+\def_long_new:Npn \calc_assign_generic:NNNNNn#1#2#3#4#5#6{
+ \let:NN\g_calc_A_register#2\let:NN\l_calc_B_register#3
+ \int_set:Nn \l_calc_current_type_int {#1}
+ \tlp_set:Nx\l_calc_expression_tlp{#6}
+ \exp_after:NN\calc_open:w\exp_after:NN(\l_calc_expression_tlp!
+ \pref_global:D\g_calc_A_register\l_calc_B_register
+ \group_end:
+ #4#5\l_calc_B_register
+}
+% \end{macrocode}
+% One could lift these restrictions by defining |\calc_generic:NNNNNn|
+% like this:
+% \begin{verbatim}
+% \def_long_new:Npn \calc_assign_generic:NNNNNn#1#2#3#4#5#6{
+% \let:NN\g_calc_A_register#2\let:NN\l_calc_B_register#3
+% \int_set:Nn \l_calc_current_type_int {#1}
+% \group_begin:
+% \let:NN \real\calc_real:n
+% \let:NN \ratio\calc_ratio:nn
+% \tlp_set:Nx\l_calc_expression_tlp{#6}
+% \exp_after:NN
+% \group_end:
+% \exp_after:NN\calc_open:w\exp_after:NN(\l_calc_expression_tlp!
+% \pref_global:D\g_calc_A_register\l_calc_B_register
+% \group_end:
+% #4#5\l_calc_B_register
+% }
+% \end{verbatim}
+% \end{macro}
+%
+%
+%
+% \begin{macro}{\calc_int_set:Nn}
+% \begin{macro}{\calc_int_gset:Nn}
+% \begin{macro}{\calc_int_add:Nn}
+% \begin{macro}{\calc_int_gadd:Nn}
+% \begin{macro}{\calc_int_sub:Nn}
+% \begin{macro}{\calc_int_gsub:Nn}
+% Here are the individual versions for the different register
+% types. First integer registers.
+% \begin{macrocode}
+\def_new:Npn\calc_int_set:Nn{
+ \calc_assign_generic:NNNNNn\c_zero\g_calc_A_int\l_calc_B_int\int_set:Nn
+}
+\def_new:Npn\calc_int_gset:Nn{
+ \calc_assign_generic:NNNNNn\c_zero\g_calc_A_int\l_calc_B_int\int_gset:Nn
+}
+\def_new:Npn\calc_int_add:Nn{
+ \calc_assign_generic:NNNNNn\c_zero\g_calc_A_int\l_calc_B_int\int_add:Nn
+}
+\def_new:Npn\calc_int_gadd:Nn{
+ \calc_assign_generic:NNNNNn\c_zero\g_calc_A_int\l_calc_B_int\int_gadd:Nn
+}
+\def_new:Npn\calc_int_sub:Nn{
+ \calc_assign_generic:NNNNNn\c_zero\g_calc_A_int\l_calc_B_int\int_sub:Nn
+}
+\def_new:Npn\calc_int_gsub:Nn{
+ \calc_assign_generic:NNNNNn\c_zero\g_calc_A_int\l_calc_B_int\int_gsub:Nn
+}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\calc_dim_set:Nn}
+% \begin{macro}{\calc_dim_gset:Nn}
+% \begin{macro}{\calc_dim_add:Nn}
+% \begin{macro}{\calc_dim_gadd:Nn}
+% \begin{macro}{\calc_dim_sub:Nn}
+% \begin{macro}{\calc_dim_gsub:Nn}
+% Dimens.
+% \begin{macrocode}
+\def_new:Npn\calc_dim_set:Nn{
+ \calc_assign_generic:NNNNNn\c_one\g_calc_A_dim\l_calc_B_dim\dim_set:Nn
+}
+\def_new:Npn\calc_dim_gset:Nn{
+ \calc_assign_generic:NNNNNn\c_one\g_calc_A_dim\l_calc_B_dim\dim_gset:Nn
+}
+\def_new:Npn\calc_dim_add:Nn{
+ \calc_assign_generic:NNNNNn\c_one\g_calc_A_dim\l_calc_B_dim\dim_add:Nn
+}
+\def_new:Npn\calc_dim_gadd:Nn{
+ \calc_assign_generic:NNNNNn\c_one\g_calc_A_dim\l_calc_B_dim\dim_gadd:Nn
+}
+\def_new:Npn\calc_dim_sub:Nn{
+ \calc_assign_generic:NNNNNn\c_one\g_calc_A_int\l_calc_B_int\dim_sub:Nn
+}
+\def_new:Npn\calc_dim_gsub:Nn{
+ \calc_assign_generic:NNNNNn\c_one\g_calc_A_int\l_calc_B_int\dim_gsub:Nn
+}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\calc_skip_set:Nn}
+% \begin{macro}{\calc_skip_gset:Nn}
+% \begin{macro}{\calc_skip_add:Nn}
+% \begin{macro}{\calc_skip_gadd:Nn}
+% \begin{macro}{\calc_skip_sub:Nn}
+% \begin{macro}{\calc_skip_gsub:Nn}
+% Skips.
+% \begin{macrocode}
+\def_new:Npn\calc_skip_set:Nn{
+ \calc_assign_generic:NNNNNn\c_two\g_calc_A_dim\l_calc_B_dim\skip_set:Nn
+}
+\def_new:Npn\calc_skip_gset:Nn{
+ \calc_assign_generic:NNNNNn\c_two\g_calc_A_dim\l_calc_B_dim\skip_gset:Nn
+}
+\def_new:Npn\calc_skip_add:Nn{
+ \calc_assign_generic:NNNNNn\c_two\g_calc_A_dim\l_calc_B_dim\skip_add:Nn
+}
+\def_new:Npn\calc_skip_gadd:Nn{
+ \calc_assign_generic:NNNNNn\c_two\g_calc_A_dim\l_calc_B_dim\skip_gadd:Nn
+}
+\def_new:Npn\calc_skip_sub:Nn{
+ \calc_assign_generic:NNNNNn\c_two\g_calc_A_dim\l_calc_B_dim\skip_sub:Nn
+}
+\def_new:Npn\calc_skip_gsub:Nn{
+ \calc_assign_generic:NNNNNn\c_two\g_calc_A_dim\l_calc_B_dim\skip_gsub:Nn
+}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\calc_muskip_set:Nn}
+% \begin{macro}{\calc_muskip_gset:Nn}
+% \begin{macro}{\calc_muskip_add:Nn}
+% \begin{macro}{\calc_muskip_gadd:Nn}
+% \begin{macro}{\calc_muskip_sub:Nn}
+% \begin{macro}{\calc_muskip_gsub:Nn}
+% Muskips.
+% \begin{macrocode}
+\def_new:Npn\calc_muskip_set:Nn{
+ \calc_assign_generic:NNNNNn\c_three\g_calc_A_dim\l_calc_B_dim\muskip_set:Nn
+}
+\def_new:Npn\calc_muskip_gset:Nn{
+ \calc_assign_generic:NNNNNn\c_three\g_calc_A_dim\l_calc_B_dim\muskip_gset:Nn
+}
+\def_new:Npn\calc_muskip_add:Nn{
+ \calc_assign_generic:NNNNNn\c_three\g_calc_A_dim\l_calc_B_dim\muskip_add:Nn
+}
+\def_new:Npn\calc_muskip_gadd:Nn{
+ \calc_assign_generic:NNNNNn\c_three\g_calc_A_dim\l_calc_B_dim\muskip_gadd:Nn
+}
+\def_new:Npn\calc_muskip_sub:Nn{
+ \calc_assign_generic:NNNNNn\c_three\g_calc_A_dim\l_calc_B_dim\muskip_add:Nn
+}
+\def_new:Npn\calc_muskip_gsub:Nn{
+ \calc_assign_generic:NNNNNn\c_three\g_calc_A_dim\l_calc_B_dim\muskip_gadd:Nn
+}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+%
+% \begin{macro}{\calc_pre_scan:N}
+% In case we found one of the special operations, this should just
+% be executed.
+% \begin{macrocode}
+\def_new:Npn \calc_pre_scan:N #1{
+ \if_meaning:NN(#1
+ \exp_after:NN\calc_open:w
+ \else:
+ \if_meaning:NN \calc_textsize:Nn #1
+ \else:
+ \if_meaning:NN \calc_maxmin_operation:Nnn #1
+ \else:
+% \end{macrocode}
+% |\calc_numeric:| uses a primitive assignment so doesn't care about
+% these dangling |\fi:|s.
+% \begin{macrocode}
+ \calc_numeric:
+ \fi:
+ \fi:
+ \fi:
+ #1}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\calc_open:w}
+% \begin{macrocode}
+\def_new:Npn \calc_open:w({
+ \group_begin:\group_execute_after:N\calc_init_B:
+ \group_begin:\group_execute_after:N\calc_init_B:
+ \calc_pre_scan:N
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\calc_init_B:}
+% \begin{macro}{\calc_numeric:}
+% \begin{macro}{\calc_close:}
+% \begin{macrocode}
+\def_new:Npn\calc_init_B:{\l_calc_B_register\g_calc_A_register}
+\def_new:Npn\calc_numeric:{
+ \tex_afterassignment:D\calc_post_scan:N
+ \pref_global:D\g_calc_A_register
+}
+\def_new:Npn\calc_close:{
+ \group_end:\pref_global:D\g_calc_A_register\l_calc_B_register
+ \group_end:\pref_global:D\g_calc_A_register\l_calc_B_register
+ \calc_post_scan:N}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\calc_post_scan:N}
+% Look at what token we have and decide where to go.
+% \begin{macrocode}
+\def_new:Npn\calc_post_scan:N#1{
+ \if_meaning:NN#1!\let:NN\calc_next:w\group_end: \else:
+ \if_meaning:NN#1+\let:NN\calc_next:w\calc_add: \else:
+ \if_meaning:NN#1-\let:NN\calc_next:w\calc_subtract: \else:
+ \if_meaning:NN#1*\let:NN\calc_next:w\calc_multiply:N \else:
+ \if_meaning:NN#1/\let:NN\calc_next:w\calc_divide:N \else:
+ \if_meaning:NN#1)\let:NN\calc_next:w\calc_close: \else:
+% \end{macrocode}
+% If we get here, there is an error but let's also disable
+% |\calc_next:w| since it is otherwise undefined. No need to give
+% extra errors just for that.
+% \begin{macrocode}
+ \let:NN \calc_next:w \scan_stop:
+ \calc_error:N#1
+ \fi:
+ \fi:
+ \fi:
+ \fi:
+ \fi:
+ \fi:
+ \calc_next:w}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\calc_multiply:N}
+% \begin{macro}{\calc_divide:N}
+% The switches for multiplication and division.
+% \begin{macrocode}
+\def_new:Npn \calc_multiply:N #1{
+ \if_meaning:NN \calc_maxmin_operation:Nnn #1
+ \let:NN \calc_next:w \calc_maxmin_multiply:
+ \else:
+ \if_meaning:NN \calc_ratio_multiply:nn #1
+ \let:NN \calc_next:w \calc_ratio_multiply:nn
+ \else:
+ \if_meaning:NN \calc_real_evaluate:nn #1
+ \let:NN \calc_next:w \calc_real_multiply:n
+ \else:
+ \def:Npn \calc_next:w{\calc_multiply: #1}
+ \fi:
+ \fi:
+ \fi:
+ \calc_next:w
+}
+\def_new:Npn \calc_divide:N #1{
+ \if_meaning:NN \calc_maxmin_operation:Nnn #1
+ \let:NN \calc_next:w \calc_maxmin_divide:
+ \else:
+ \if_meaning:NN \calc_ratio_multiply:nn #1
+ \let:NN \calc_next:w \calc_ratio_divide:nn
+ \else:
+ \if_meaning:NN \calc_real_evaluate:nn #1
+ \let:NN \calc_next:w \calc_real_divide:n
+ \else:
+ \def:Npn \calc_next:w{\calc_divide: #1}
+ \fi:
+ \fi:
+ \fi:
+ \calc_next:w
+}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\calc_generic_add:N}
+% \begin{macro}{\calc_add:}
+% \begin{macro}{\calc_subtract:}
+% \begin{macro}{\calc_add_A_to_B:}
+% \begin{macro}{\calc_subtract_A_from_B:}
+% Here is how we add and subtract.
+% \begin{macrocode}
+\def_new:Npn\calc_generic_add_or_subtract:N#1{
+ \group_end:
+ \pref_global:D\g_calc_A_register\l_calc_B_register\group_end:
+ \group_begin:\group_execute_after:N#1\group_begin:
+ \group_execute_after:N\calc_init_B:
+ \calc_pre_scan:N}
+\def_new:Npn\calc_add:{\calc_generic_add_or_subtract:N\calc_add_A_to_B:}
+\def_new:Npn\calc_subtract:{
+ \calc_generic_add_or_subtract:N\calc_subtract_A_from_B:}
+% \end{macrocode}
+% Don't use |\tex_advance:D| since it allows overflows.
+% \begin{macrocode}
+\def_new:Npn\calc_add_A_to_B:{
+ \l_calc_B_register
+ \if_case:w\l_calc_current_type_int
+ \etex_numexpr:D\or:
+ \etex_dimexpr:D\or:
+ \etex_glueexpr:D\or:
+ \etex_muexpr:D\fi:
+ \l_calc_B_register + \g_calc_A_register\scan_stop:
+}
+\def_new:Npn\calc_subtract_A_from_B:{
+ \l_calc_B_register
+ \if_case:w\l_calc_current_type_int
+ \etex_numexpr:D\or:
+ \etex_dimexpr:D\or:
+ \etex_glueexpr:D\or:
+ \etex_muexpr:D\fi:
+ \l_calc_B_register - \g_calc_A_register\scan_stop:
+}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\calc_generic_multiply_or_divide:N}
+% \begin{macro}{\calc_multiply_B_by_A:}
+% \begin{macro}{\calc_divide_B_by_A:}
+% \begin{macro}{\calc_multiply:}
+% \begin{macro}{\calc_divide:}
+% And here is how we multiply and divide. Note that we do not use the
+% primitive \TeX{} operations but the expandable operations provided
+% by \eTeX. This means that all results are rounded not truncated!
+% \begin{macrocode}
+\def_new:Npn\calc_generic_multiply_or_divide:N#1{
+ \group_end:
+ \group_begin:
+ \let:NN\g_calc_A_register\g_calc_A_int
+ \let:NN\l_calc_B_register\l_calc_B_int
+ \group_execute_after:N#1\calc_pre_scan:N
+}
+\def_new:Npn\calc_multiply_B_by_A:{
+ \l_calc_B_register
+ \if_case:w\l_calc_current_type_int
+ \etex_numexpr:D\or:
+ \etex_dimexpr:D\or:
+ \etex_glueexpr:D\or:
+ \etex_muexpr:D\fi:
+ \l_calc_B_register*\g_calc_A_int\scan_stop:
+}
+\def_new:Npn\calc_divide_B_by_A:{
+ \l_calc_B_register
+ \if_case:w\l_calc_current_type_int
+ \etex_numexpr:D\or:
+ \etex_dimexpr:D\or:
+ \etex_glueexpr:D\or:
+ \etex_muexpr:D\fi:
+ \l_calc_B_register/\g_calc_A_int\scan_stop:
+}
+\def_new:Npn\calc_multiply:{
+ \calc_generic_multiply_or_divide:N\calc_multiply_B_by_A:}
+\def_new:Npn\calc_divide:{
+ \calc_generic_multiply_or_divide:N\calc_divide_B_by_A:}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\calc_calculate_box_size:nnn}
+% \begin{macro}{\calc_calculate_box_size_aux:n}
+% Put something in a box and measure it. |#1| is a list of
+% |\box_ht:N| etc., |#2| should be |\dim_set:Nn|\meta{dim register}
+% or |\dim_gset:Nn|\meta{dim register} and |#3| is the contents.
+% \begin{macrocode}
+\def_long_new:Npn \calc_calculate_box_size:nnn #1#2#3{
+ \hbox_set:Nn \l_tmpa_box {{#3}}
+ #2{\c_zero_dim \tlist_map_function:nN{#1}\calc_calculate_box_size_aux:n}
+}
+% \end{macrocode}
+% Helper for calculating the final dimension.
+% \begin{macrocode}
+\def:Npn \calc_calculate_box_size_aux:n#1{ + #1\l_tmpa_box}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+%
+% \begin{macro}{\calc_textsize:Nn}
+% Now we can define |\calc_textsize:Nn|.
+% \begin{macrocode}
+\def_protected_long:Npn \calc_textsize:Nn#1#2{
+ \group_begin:
+ \let:NN\widthof\box_wd:N
+ \let:NN\heightof\box_ht:N
+ \let:NN\depthof\box_dp:N
+ \def:Npn\totalheightof{\box_ht:N\box_dp:N}
+ \exp_args:No\calc_calculate_box_size:nnn{#1}
+ {\dim_gset:Nn\g_calc_A_register}
+% \end{macrocode}
+% Restore the four user commands here since there might be a recursive
+% call.
+% \begin{macrocode}
+ {
+ \let:NN \depthof\calc_depthof:n
+ \let:NN \widthof\calc_widthof:n
+ \let:NN \heightof\calc_heightof:n
+ \let:NN \totalheightof\calc_totalheightof:n
+ #2
+ }
+ \group_end:
+ \calc_post_scan:N
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\calc_ratio_multiply:nn}
+% \begin{macro}{\calc_ratio_divide:nn}
+% Evaluate a ratio. If we were already evaluation a \meta{muskip}
+% register, the ratio is probably also done with this type and we'll
+% have to convert them to regular points.
+% \begin{macrocode}
+\def_protected_long:Npn\calc_ratio_multiply:nn#1#2{
+ \group_end:\group_begin:
+ \if_num:w\l_calc_current_type_int < \c_three
+ \calc_dim_set:Nn\l_calc_B_int{#1}
+ \calc_dim_set:Nn\l_calc_C_int{#2}
+ \else:
+ \calc_dim_muskip:Nn{\l_calc_B_int\etex_mutoglue:D}{#1}
+ \calc_dim_muskip:Nn{\l_calc_C_int\etex_mutoglue:D}{#2}
+ \fi:
+% \end{macrocode}
+% Then store the ratio as a fraction, which we just pass on.
+% \begin{macrocode}
+ \gdef:Npx\calc_calculated_ratio:{
+ \int_use:N\l_calc_B_int/\int_use:N\l_calc_C_int
+ }
+ \group_end:
+% \end{macrocode}
+% Here we set the new value of |\l_calc_B_register| and remember to
+% evaluate it as the correct type. Note that the intermediate
+% calculation is a scaled operation (meaning the intermediate value is
+% 64-bit) so we don't get into trouble when first multiplying by a
+% large number and then dividing.
+% \begin{macrocode}
+ \l_calc_B_register
+ \if_case:w\l_calc_current_type_int
+ \etex_numexpr:D\or:
+ \etex_dimexpr:D\or:
+ \etex_glueexpr:D\or:
+ \etex_muexpr:D\fi:
+ \l_calc_B_register*\calc_calculated_ratio:\scan_stop:
+ \group_begin:
+ \calc_post_scan:N}
+% \end{macrocode}
+% Division is just flipping the arguments around.
+% \begin{macrocode}
+\def_long_new:Npn \calc_ratio_divide:nn#1#2{\calc_ratio_multiply:nn{#2}{#1}}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\calc_real_evaluate:nn}
+% \begin{macro}{\calc_real_multiply:n}
+% \begin{macro}{\calc_real_divide:n}
+% Although we could define the |\real| function as a subcase of
+% |\ratio|, this is horribly inefficient since we just want to convert
+% the decimal to a fraction.
+% \begin{macrocode}
+\def_protected_new:Npn\calc_real_evaluate:nn #1#2{
+ \group_end:
+ \l_calc_B_register
+ \if_case:w\l_calc_current_type_int
+ \etex_numexpr:D\or:
+ \etex_dimexpr:D\or:
+ \etex_glueexpr:D\or:
+ \etex_muexpr:D\fi:
+ \l_calc_B_register *
+ \tex_number:D \dim_eval:n{#1pt}/
+ \tex_number:D\dim_eval:n{#2pt}
+ \scan_stop:
+ \group_begin:
+ \calc_post_scan:N}
+\def_new:Npn \calc_real_multiply:n #1{\calc_real_evaluate:nn{#1}{1}}
+\def_new:Npn \calc_real_divide:n {\calc_real_evaluate:nn{1}}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\calc_maxmin_operation:Nnn}
+% \begin{macro}{\calc_maxmin_generic:Nnn}
+% \begin{macro}{\calc_maxmin_div_or_mul:NNnn}
+% \begin{macro}{\calc_maxmin_multiply:}
+% \begin{macro}{\calc_maxmin_multiply:}
+% The max and min functions.
+% \begin{macrocode}
+\def_protected_long:Npn\calc_maxmin_operation:Nnn#1#2#3{
+ \group_begin:
+ \calc_maxmin_generic:Nnn#1{#2}{#3}
+ \group_end:
+ \calc_post_scan:N
+}
+% \end{macrocode}
+% |#1| is either |>| or |<| and was expanded into this initially.
+% \begin{macrocode}
+\def_protected_long_new:Npn \calc_maxmin_generic:Nnn#1#2#3{
+ \group_begin:
+ \if_case:w\l_calc_current_type_int
+ \calc_int_set:Nn\l_calc_C_int{#2}%
+ \calc_int_set:Nn\l_calc_B_int{#3}%
+ \pref_global:D\g_calc_A_register
+ \if_num:w\l_calc_C_int#1\l_calc_B_int
+ \l_calc_C_int\else:\l_calc_B_int\fi:
+ \or:
+ \calc_dim_set:Nn\l_calc_C_dim{#2}%
+ \calc_dim_set:Nn\l_calc_B_dim{#3}%
+ \pref_global:D\g_calc_A_register
+ \if_dim:w\l_calc_C_dim#1\l_calc_B_dim
+ \l_calc_C_dim\else:\l_calc_B_dim\fi:
+ \or:
+ \calc_skip_set:Nn\l_calc_C_skip{#2}%
+ \calc_skip_set:Nn\l_calc_B_skip{#3}%
+ \pref_global:D\g_calc_A_register
+ \if_dim:w\l_calc_C_skip#1\l_calc_B_skip
+ \l_calc_C_skip\else:\l_calc_B_skip\fi:
+ \else:
+ \calc_muskip_set:Nn\l_calc_C_muskip{#2}%
+ \calc_muskip_set:Nn\l_calc_B_muskip{#3}%
+ \pref_global:D\g_calc_A_register
+ \if_dim:w\l_calc_C_muskip#1\l_calc_B_muskip
+ \l_calc_C_muskip\else:\l_calc_B_muskip\fi:
+ \fi:
+ \group_end:
+}
+\def_long_new:Npn\calc_maxmin_div_or_mul:NNnn#1#2#3#4{
+ \group_end:
+ \group_begin:
+ \int_zero:N\l_calc_current_type_int
+ \group_execute_after:N#1
+ \calc_maxmin_generic:Nnn#2{#3}{#4}
+ \group_end:
+ \group_begin:
+ \calc_post_scan:N
+}
+\def_new:Npn\calc_maxmin_multiply:{
+ \calc_maxmin_div_or_mul:NNnn\calc_multiply_B_by_A:}
+\def_new:Npn\calc_maxmin_divide: {
+ \calc_maxmin_div_or_mul:NNnn\calc_divide_B_by_A:}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\calc_error:N}
+% The error message.
+% \begin{macrocode}
+\def_new:Npn\calc_error:N#1{
+ \PackageError{calc}
+ {`\token_to_string:N#1'~ invalid~ at~ this~ point}
+ {I~ expected~ to~ see~ one~ of:~ +~ -~ *~ /~ )}
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Higher level commands}
+%
+% The various operations allowed.
+%
+% \begin{macro}{\calc_maxof:nn}
+% \begin{macro}{\calc_minof:nn}
+% \begin{macro}{\maxof}
+% \begin{macro}{\minof}
+% Max and min operations
+% \begin{macrocode}
+\def_long_new:Npn \calc_maxof:nn#1#2{
+ \calc_maxmin_operation:Nnn > \exp_not:n{{#1}{#2}}
+}
+\def_long_new:Npn \calc_minof:nn#1#2{
+ \calc_maxmin_operation:Nnn < \exp_not:n{{#1}{#2}}
+}
+\let_new:NN \maxof \calc_maxof:nn
+\let_new:NN \minof \calc_minof:nn
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\calc_widthof:n}
+% \begin{macro}{\calc_heightof:n}
+% \begin{macro}{\calc_depthof:n}
+% \begin{macro}{\calc_totalheightof:n}
+% \begin{macro}{\widthof}
+% \begin{macro}{\heightof}
+% \begin{macro}{\depthof}
+% \begin{macro}{\totalheightof}
+% Text dimension commands.
+% \begin{macrocode}
+\def_long_new:Npn \calc_widthof:n#1{
+ \calc_textsize:Nn \exp_not:N\widthof\exp_not:n{{#1}}
+}
+\def_long_new:Npn \calc_heightof:n#1{
+ \calc_textsize:Nn \exp_not:N\heightof\exp_not:n{{#1}}
+}
+\def_long_new:Npn \calc_depthof:n#1{
+ \calc_textsize:Nn \exp_not:N\depthof\exp_not:n{{#1}}
+}
+\def_long_new:Npn \calc_totalheightof:n#1{
+ \calc_textsize:Nn \exp_not:N\totalheightof\exp_not:n{{#1}}
+}
+\let:NN \depthof\calc_depthof:n
+\let:NN \widthof\calc_widthof:n
+\let:NN \heightof\calc_heightof:n
+\let:NN \totalheightof\calc_totalheightof:n
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\calc_ratio:nn}
+% \begin{macro}{\calc_real:n}
+% \begin{macro}{\ratio}
+% \begin{macro}{\real}
+% Ratio and real.
+% \begin{macrocode}
+\def_long_new:Npn \calc_ratio:nn#1#2{
+ \calc_ratio_multiply:nn\exp_not:n{{#1}{#2}}}
+\let_new:NN \calc_real:n \calc_real_evaluate:nn
+% \end{macrocode}
+% We can implement real and ratio without actually using these
+% names. We'll see.
+% \begin{macrocode}
+\let_new:NN \ratio\calc_ratio:nn
+\let_new:NN \real\calc_real:n
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+%
+% \begin{macrocode}
+%</initex|package>
+%<*showmemory>
+\showMemUsage
+%</showmemory>
+% \end{macrocode}
+%
+% \endinput
+%
+% $Log$
+% Revision 1.2 2006/01/27 23:11:47 morten
+% Fixed bug in \calc_pre_scan:N and avoid using \advance in order to
+% catch overflows.
+%
+% Revision 1.1 2006/01/27 07:51:13 morten
+% Initial version of a calc module
+%