% \iffalse meta-comment % % File: siunitx-compound.dtx Copyright (C) 2018-2021,2023,2024 Joseph Wright % % 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 "siunitx 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 % % https://github.com/josephwright/siunitx % % for those people who are interested. % % ----------------------------------------------------------------------- % %<*driver> \documentclass{l3doc} % Additional commands needed in this source \ProvideDocumentCommand\email{m}{\href{mailto:#1}{\nolinkurl{#1}}} \ProvideDocumentCommand\foreign{m}{\textit{#1}} % The next line is needed so that \GetFileInfo will be able to pick up % version data \usepackage{siunitx} \begin{document} \DocInput{\jobname.dtx} \end{document} % % \fi % % \GetFileInfo{siunitx.sty} % % \title{^^A % \pkg{siunitx-compound} -- Compound numbers and quantities^^A % \thanks{This file describes \fileversion, % last revised \filedate.}^^A % } % % \author{^^A % Joseph Wright^^A % \thanks{^^A % E-mail: % \email{joseph@texdev.net}^^A % }^^A % } % % \date{Released \filedate} % % \maketitle % % \begin{documentation} % % \begin{function}{\siunitx_compound_number:n} % \begin{syntax} % \cs{siunitx_compound_number:n} \Arg{entries} % \end{syntax} % Prints a set of numbers in the \meta{entries}, each of which should % be given as a \meta{balanced text}. Unlike \cs{siunitx_number_list:nn}, this % function may semantically take any form. % \end{function} % % \begin{function}{\siunitx_compound_quantity:nn} % \begin{syntax} % \cs{siunitx_compound_quantity:nn} \Arg{entries} \Arg{unit} % \end{syntax} % Prints a set of quantities in the \meta{entries}, each of which should % be given as a \meta{balanced text}. Unlike \cs{siunitx_quantity_list:nn}, this % function may semantically take any form. % \end{function} % % \begin{function}{\siunitx_number_list:nn} % \begin{syntax} % \cs{siunitx_number_list:nn} \Arg{entries} % \end{syntax} % Prints the list of numbers in the \meta{entries}, each of which should % be given as a \meta{balanced text}. % \end{function} % % \begin{function}{\siunitx_quantity_list:nn} % \begin{syntax} % \cs{siunitx_quantity_list:nn} \Arg{entries} \Arg{unit} % \end{syntax} % Prints the list of quantities in the \meta{entries}, each of which should % be given as a \meta{balanced text}. % \end{function} % % \begin{function}{\siunitx_number_product:n} % \begin{syntax} % \cs{siunitx_number_product:n} \Arg{entries} % \end{syntax} % Prints the series of numbers in the \meta{entries}, each of which should % be given as a \meta{balanced text}. % \end{function} % % \begin{function}{\siunitx_quantity_product:nn} % \begin{syntax} % \cs{siunitx_number_product:n} \Arg{entries} \Arg{unit} % \end{syntax} % Prints the series of quantities in the \meta{entries}, each of which should % be given as a \meta{balanced text}. % \end{function} % % \begin{function}{\siunitx_number_range:nn} % \begin{syntax} % \cs{siunitx_number_range:nn} \Arg{start} \Arg{end} % \end{syntax} % Prints the range of numbers from the \meta{start} to the \meta{end}. % \end{function} % % \begin{function}{\siunitx_quantity_range:nnn} % \begin{syntax} % \cs{siunitx_number_range:nn} \Arg{start} \Arg{end} \Arg{unit} % \end{syntax} % Prints the range of quantities from the \meta{start} to the \meta{end}. % \end{function} % % \begin{variable} % { % \l_siunitx_list_separator_pair_tl, % \l_siunitx_list_separator_tl, % \l_siunitx_list_separator_final_tl % } % Separators for lists of numbers and quantities. % \end{variable} % % \begin{variable}{\l_siunitx_range_phrase_tl} % Phrase (or similar) used between limits of a range. % \end{variable} % % \begin{function}{compound-boundary-mode} % \begin{syntax} % |compound-boundary-mode| = |number|\verb"|"|text| % \end{syntax} % Choice which determines whether the material at the start and % end of a compound quantity are typeset a |number| or as |text|; % the latter is the standard setting. % \end{function} % % \begin{function}{compound-close-boundary, compound-open-boundary} % \begin{syntax} % |compound-close-boundary| = \meta{tokens}\\ % |compound-open-boundary| = \meta{tokens} % \end{syntax} % Literals which are inserted at the opening and closing boundary of a compound % quantity; they are not used when the number of items is one. % The standard settings set these empty. % \end{function} % % \begin{function}{compound-close-bracket, compound-open-bracket} % \begin{syntax} % |compound-close-bracket| = \meta{token} \\ % |compound-open-bracket| = \meta{token} % \end{syntax} % Literals containing the tokens inserted at the start and end of a compound % value when |compounds-units| is set to |bracket|. The standard settings are % |(| and |)|. % \end{function} % % \begin{function}{compound-exponents} % \begin{syntax} % |compound-exponents| = |combine|\verb"|"|combine-bracket|\verb"|"|individual| % \end{syntax} % \end{function} % % \begin{function}{compound-final-separator} % \begin{syntax} % |compound-final-separator| = \meta{text} % \end{syntax} % \end{function} % % \begin{function}{compound-independent-prefix} % \begin{syntax} % |compound-independent-prefix| = |true|\verb"|"|false| % \end{syntax} % Switch which determines whether unit prefixes are calculated % independently when units are repeated. The standard setting is % |false|. % \end{function} % % \begin{function}{compound-pair-separator} % \begin{syntax} % |compound-pair-separator| = \meta{text} % \end{syntax} % \end{function} % % \begin{function}{compound-separator} % \begin{syntax} % |compound-separator| = \meta{text} % \end{syntax} % \end{function} % % \begin{function}{compound-separator-mode} % \begin{syntax} % |compound-separator-mode| = |number|\verb"|"|text| % \end{syntax} % Choice which determines whether the separators between components % of compound quantity are typeset a |number| or as |text|; % the latter is the standard setting. % \end{function} % % \begin{function}{compound-units} % \begin{syntax} % |compound-units| = |bracket|\verb"|"|repeat|\verb"|"|single| % \end{syntax} % \end{function} % % \begin{function}{list-close-bracket, list-open-bracket} % \begin{syntax} % |list-close-bracket| = \meta{token} \\ % |list-open-bracket| = \meta{token} % \end{syntax} % Literals containing the tokens inserted at the start and end of a list when % |list-units| is set to |bracket|. The standard settings are |(| and |)|. % \end{function} % % \begin{function}{list-exponents} % \begin{syntax} % |list-exponents| = |combine|\verb"|"|combine-bracket|\verb"|"|individual| % \end{syntax} % \end{function} % % \begin{function}{list-final-separator} % \begin{syntax} % |list-final-separator| = \meta{text} % \end{syntax} % \end{function} % % \begin{function}{list-independent-prefix} % \begin{syntax} % |list-independent-prefix| = |true|\verb"|"|false| % \end{syntax} % Switch which determines whether unit prefixes are calculated % independently when units are repeated. The standard setting is % |false|. % \end{function} % % \begin{function}{list-pair-separator} % \begin{syntax} % |list-pair-separator| = \meta{text} % \end{syntax} % \end{function} % % \begin{function}{list-separator} % \begin{syntax} % |list-separator| = \meta{text} % \end{syntax} % \end{function} % % \begin{function}{list-units} % \begin{syntax} % |list-units| = |bracket|\verb"|"|repeat|\verb"|"|single| % \end{syntax} % \end{function} % % \begin{function}{product-close-bracket, product-open-bracket} % \begin{syntax} % |product-close-bracket| = \meta{token} \\ % |product-open-bracket| = \meta{token} % \end{syntax} % Literals containing the tokens inserted at the start and end of a product % when |product-units| is set to |bracket|. The standard settings are |(| % and |)|. % \end{function} % % \begin{function}{product-exponents} % \begin{syntax} % |product-exponents| = |combine|\verb"|"|combine-bracket|\verb"|"|individual| % \end{syntax} % \end{function} % % \begin{function}{product-independent-prefix} % \begin{syntax} % |product-independent-prefix| = |true|\verb"|"|false| % \end{syntax} % Switch which determines whether unit prefixes are calculated % independently when units are repeated. The standard setting is % |false|. % \end{function} % % \begin{function}{product-mode} % \begin{syntax} % |product-mode| = |phrase|\verb"|"|choice| % \end{syntax} % \end{function} % % \begin{function}{product-phrase} % \begin{syntax} % |product-phrase| = \meta{text} % \end{syntax} % \end{function} % % \begin{function}{product-symbol} % \begin{syntax} % |product-symbol| = \meta{symbol} % \end{syntax} % \end{function} % % \begin{function}{range-exponents} % \begin{syntax} % |range-exponents| = |combine|\verb"|"|combine-bracket|\verb"|"|individual| % \end{syntax} % \end{function} % % \begin{function}{range-close-bracket, range-open-bracket} % \begin{syntax} % |range-close-bracket| = \meta{token} \\ % |range-open-bracket| = \meta{token} % \end{syntax} % Literals containing the tokens inserted at the start and end of a range when % |range-units| is set to |bracket|. The standard settings are |(| and |)|. % \end{function} % % \begin{function}{range-independent-prefix} % \begin{syntax} % |range-independent-prefix| = |true|\verb"|"|false| % \end{syntax} % Switch which determines whether unit prefixes are calculated % independently when units are repeated. The standard setting is % |false|. % \end{function} % % \begin{function}{range-open-phrase} % \begin{syntax} % |range-open-phrase| = \meta{text} % \end{syntax} % Literal containing the material to be inserted at the start of a range. % The standard setting is empty. % \end{function} % % \begin{function}{range-phrase} % \begin{syntax} % |range-phrase| = \meta{text} % \end{syntax} % Literal containing the material to be inserted between the start and end % of a range. The standard setting contains the word \texttt{to} inside the % \cs{text} command, along with appropriate spacing commands to allow this % material to work in both math and text typesetting modes. % \end{function} % % \begin{function}{range-units} % \begin{syntax} % |range-units| = |bracket|\verb"|"|repeat|\verb"|"|single| % \end{syntax} % \end{function} % % \end{documentation} % % \begin{implementation} % % Start the \pkg{DocStrip} guards. % \begin{macrocode} %<*package> % \end{macrocode} % % \section{\pkg{siunitx-compound} implementation} % % \begin{macrocode} \cs_generate_variant:Nn \seq_use:Nnnn { NVVV } % \end{macrocode} % % \subsection{General mechanism} % % Identify the internal prefix. % \begin{macrocode} %<@@=siunitx_compound> % \end{macrocode} % % Typesetting lists, ranges and products of numbers or quantities has shared % features which mean they are best handled using a common mechanism. The aim % therefore is to abstract out enough of the process such that output-specific % aspects can be left to separate processes. % % \begin{variable}{\l_@@_tmp_fp, \l_@@_tmp_seq, \l_@@_tmp_tl} % Scratch space. % \begin{macrocode} \fp_new:N \l_@@_tmp_fp \seq_new:N \l_@@_tmp_seq \tl_new:N \l_@@_tmp_tl % \end{macrocode} % \end{variable} % % \begin{variable}{\l_@@_first_tl} % The first number in the list in internal format. % \begin{macrocode} \tl_new:N \l_@@_first_tl % \end{macrocode} % \end{variable} % % \begin{variable}{\l_@@_exp_tl} % For storing the combined exponent, if present. % \begin{macrocode} \tl_new:N \l_@@_exp_tl % \end{macrocode} % \end{variable} % % \begin{variable}{\l_@@_start_tl, \l_@@_end_tl} % Data on the end-of-list. % \begin{macrocode} \tl_new:N \l_@@_start_tl \tl_new:N \l_@@_end_tl % \end{macrocode} % \end{variable} % % \begin{variable}{\l_@@_count_int} % Data on the length-of-list. % \begin{macrocode} \int_new:N \l_@@_count_int % \end{macrocode} % \end{variable} % % \begin{variable}{\l_@@_unit_bool, \l_@@_unit_tl} % \begin{macrocode} \bool_new:N \l_@@_unit_bool \tl_new:N \l_@@_unit_tl % \end{macrocode} % \end{variable} % % \begin{variable} % { % \l_@@_boundary_text_bool , % \l_@@_boundary_close_tl , % \l_@@_bracket_close_tl , % \l_@@_independent_bool , % \l_@@_separator_final_tl , % \l_@@_separator_pair_tl , % \l_@@_boundary_open_tl , % \l_@@_bracket_open_tl , % \l_@@_separator_tl , % \l_@@_separator_text_bool , % \l_@@_exp_bracket_bool , % \l_@@_exp_combine_bool , % \l_@@_unit_bracket_bool , % \l_@@_unit_power_bool , % \l_@@_unit_repeat_bool , % } % List options. % \begin{macrocode} \bool_new:N \l_@@_boundary_text_bool \bool_new:N \l_@@_exp_bracket_bool \bool_new:N \l_@@_exp_combine_bool \bool_new:N \l_@@_separator_text_bool \bool_new:N \l_@@_unit_bracket_bool \bool_new:N \l_@@_unit_power_bool \bool_new:N \l_@@_unit_repeat_bool \keys_define:nn { siunitx } { compound-boundary-mode .choice: , compound-boundary-mode / number .code:n = { \bool_set_false:N \l_@@_boundary_text_bool } , compound-boundary-mode / text .code:n = { \bool_set_true:N \l_@@_boundary_text_bool } , compound-close-boundary .tl_set:N = \l_@@_boundary_close_tl , compound-close-bracket .tl_set:N = \l_@@_bracket_close_tl , compound-exponents .choice: , compound-exponents / combine .code:n = { \bool_set_false:N \l_@@_exp_bracket_bool \bool_set_true:N \l_@@_exp_combine_bool } , compound-exponents / combine-bracket .code:n = { \bool_set_true:N \l_@@_exp_bracket_bool \bool_set_true:N \l_@@_exp_combine_bool } , compound-exponents / individual .code:n = { \bool_set_false:N \l_@@_exp_bracket_bool \bool_set_false:N \l_@@_exp_combine_bool } , compound-final-separator .tl_set:N = \l_@@_separator_final_tl , compound-independent-prefix .bool_set:N = \l_@@_independent_bool , compound-pair-separator .tl_set:N = \l_@@_separator_pair_tl , compound-open-boundary .tl_set:N = \l_@@_boundary_open_tl , compound-open-bracket .tl_set:N = \l_@@_bracket_open_tl , compound-separator .tl_set:N = \l_@@_separator_tl , compound-separator-mode .choice: , compound-separator-mode / number .code:n = { \bool_set_false:N \l_@@_separator_text_bool } , compound-separator-mode / text .code:n = { \bool_set_true:N \l_@@_separator_text_bool } , compound-units .choice: , compound-units / bracket .code:n = { \bool_set_true:N \l_@@_unit_bracket_bool \bool_set_false:N \l_@@_unit_power_bool \bool_set_false:N \l_@@_unit_repeat_bool } , compound-units / bracket-power .code:n = { \bool_set_true:N \l_@@_unit_bracket_bool \bool_set_true:N \l_@@_unit_power_bool \bool_set_false:N \l_@@_unit_repeat_bool } , compound-units / power .code:n = { \bool_set_false:N \l_@@_unit_bracket_bool \bool_set_true:N \l_@@_unit_power_bool \bool_set_false:N \l_@@_unit_repeat_bool } , compound-units / repeat .code:n = { \bool_set_false:N \l_@@_unit_bracket_bool \bool_set_false:N \l_@@_unit_power_bool \bool_set_true:N \l_@@_unit_repeat_bool } , compound-units / single .code:n = { \bool_set_false:N \l_@@_unit_bracket_bool \bool_set_false:N \l_@@_unit_power_bool \bool_set_false:N \l_@@_unit_repeat_bool } } % \end{macrocode} % \end{variable} % % \begin{macro}{\siunitx_compound_number:n} % \begin{macro}{\@@_format:n} % \begin{macro}{\@@_format:nn} % \begin{macro}{\@@_format:nnn, \@@_format:een} % Printing a generic set starts with the question of whether we want to % extract exponents. If we do, then there is the work to do with extraction. % Either way, the printing is handed off to a common function. We do a quick % count up-front to avoid excess work when there is not actually a list. % \begin{macrocode} \cs_new_protected:Npn \siunitx_compound_number:n #1 { \group_begin: \bool_set_false:N \l_@@_unit_bool \@@_format:nn {#1} { } \@@_print:N \siunitx_print_number:e \group_end: } \cs_new_protected:Npn \@@_format:nn #1#2 { \seq_clear:N \l_@@_tmp_seq \bool_if:NTF \l_siunitx_number_parse_bool { \@@_format:een { \tl_head:n {#1} } { \tl_tail:n {#1} } {#2} } { \tl_map_function:nN {#1} \@@_unparsed:n } } % \end{macrocode} % Formatting at a low level needs to know about units and numbers: we have to % exchange data between the two. Most of the business of handling the units % is left to a dedicated auxiliary. % \begin{macrocode} \cs_new_protected:Npn \@@_format:nnn #1#2#3 { \tl_if_blank:nTF {#1} { \tl_if_blank:nF {#2} { \@@_format:nn {#2} {#3} } } { \@@_format_aux:nnn {#1} {#2} {#3} } } \cs_generate_variant:Nn \@@_format:nnn { ee } \cs_new_protected:Npn \@@_format_aux:nnn #1#2#3 { \siunitx_number_parse:nN {#1} \l_@@_tmp_tl \bool_if:NTF \l_@@_unit_bool { \@@_format_units:nn {#2} {#3} } { \siunitx_number_process:NN \l_@@_tmp_tl \l_@@_first_tl } \bool_lazy_and:nnTF { \l_@@_exp_combine_bool } { \int_compare_p:nNn { \tl_count:n {#2} } > 0 } { \@@_extract_exponents: } { \bool_if:NTF \l_@@_unit_bool { \tl_set:Nx \l_@@_tmp_tl { \siunitx_number_output:NN \l_@@_first_tl \q_nil } \tl_set:Nx \l_@@_tmp_tl { \@@_uncert_bracket:N \l_@@_tmp_tl } } { \tl_set:Nx \l_@@_tmp_tl { \siunitx_number_output:N \l_@@_first_tl } } \seq_put_right:NV \l_@@_tmp_seq \l_@@_tmp_tl } \tl_map_function:nN {#2} \@@_parsed:n } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\@@_extract_exponents:} % \begin{macro}{\@@_extract_exponents_auxi:w} % \begin{macro}{\@@_extract_exponents_auxii:nw} % \begin{macro}{\@@_extract_exponents_auxiii:nnnnnnn} % Extracting exponents means dealing with the first entry as a special case. % After that, apply fixed processing to all other entries, tidying up using % the number formatter. % \begin{macrocode} \cs_new_protected:Npn \@@_extract_exponents: { \tl_set:Nx \l_@@_tmp_tl { \siunitx_number_output:NN \l_@@_first_tl \q_nil } \exp_after:wN \@@_extract_exponents_auxi:w \l_@@_tmp_tl \q_stop } \cs_new_protected:Npn \@@_extract_exponents_auxi:w #1 \q_nil #2 \q_nil #3 \q_nil #4 \q_nil #5 \q_nil #6 \q_nil #7 \q_nil #8 \q_nil #9 \q_stop { \@@_extract_exponents_auxii:nw {#1#2#3#4#5#6#7#8} #9 \q_stop } \cs_new_protected:Npn \@@_extract_exponents_auxii:nw #1#2 \q_nil #3 \q_nil #4 \q_stop { \seq_put_right:Nn \l_@@_tmp_seq { #1#2 } \tl_set:Nn \l_@@_exp_tl { #3#4 } \exp_after:wN \@@_extract_exponents_auxiii:nnnnnnn \l_@@_first_tl } \cs_new_protected:Npn \@@_extract_exponents_auxiii:nnnnnnn #1#2#3#4#5#6#7 { \keys_set:nn { siunitx } { drop-exponent = true , exponent-mode = fixed , fixed-exponent = #6 0 #7 } } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\@@_parsed:n, \@@_parsed_aux:n, \@@_unparsed:n} % The simple cases for parsing (or not) all entries. % \begin{macrocode} \cs_new_protected:Npn \@@_parsed:n #1 { \tl_if_blank:nF {#1} { \@@_parsed_aux:n {#1} } } \cs_new_protected:Npn \@@_parsed_aux:n #1 { \bool_if:NTF \l_@@_unit_bool { \siunitx_number_parse:nN {#1} \l_@@_tmp_tl \siunitx_number_process:NN \l_@@_tmp_tl \l_@@_tmp_tl \tl_set:Nx \l_@@_tmp_tl { \siunitx_number_output:NN \l_@@_tmp_tl \q_nil } \tl_set:Nx \l_@@_tmp_tl { \@@_uncert_bracket:N \l_@@_tmp_tl } } { \siunitx_number_format:nN {#1} \l_@@_tmp_tl } \seq_put_right:NV \l_@@_tmp_seq \l_@@_tmp_tl } \cs_new_protected:Npn \@@_unparsed:n #1 { \tl_if_blank:nF {#1} { \seq_put_right:Nn \l_@@_tmp_seq { \ensuremath {#1} } } } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_format_units:nn} % \begin{macro} % { % \@@_format_combine-exponent:n , % \@@_format_extract-exponent:n , % \@@_format_input:n % } % \begin{macro} % { % \@@_format_combine-exponent:nn , % \@@_format_extract-exponent:nn % } % \begin{macro} % { % \@@_format_combine-exponent_aux:n , % \@@_format_extract-exponent_aux:n % } % \begin{macro}{\@@_extract_exp:nN, \@@_extract_exp:VN} % \begin{macro}{\@@_extract_exp:nnnnnnnN} % Actually formatting the units is much the same as is done in % the quantities module, except that we have to cover the multiplication % cases too: gets a bit repetitive. Notice that when combining exponents, % there is no adjustment to the original exponent: we purely need to % extract it. % \begin{macrocode} \cs_new_protected:Npn \@@_format_units:nn #1#2 { \bool_if:NTF \l_@@_unit_power_bool { \use:c { @@_format_ \l_siunitx_quantity_prefix_mode_tl :nn } {#2} { \tl_count:n {#1} + 1 } } { \use:c { @@_format_ \l_siunitx_quantity_prefix_mode_tl :n } {#2} } } \cs_new_protected:cpx { @@_format_combine-exponent:n } #1 { \exp_not:c { @@_format_combine-exponent_aux:n } { \exp_not:N \siunitx_unit_format_combine_exponent:nnN {#1} } } \cs_new_protected:cpx { @@_format_combine-exponent:nn } #1#2 { \exp_not:c { @@_format_combine-exponent_aux:n } { \exp_not:N \siunitx_unit_format_multiply_combine_exponent:nnnN {#1} {#2} } } \cs_new_protected:cpn { @@_format_combine-exponent_aux:n } #1 { \bool_set_true:N \l_@@_exp_combine_bool \siunitx_number_process:NN \l_@@_tmp_tl \l_@@_first_tl \@@_extract_exp:VN \l_@@_first_tl \l_@@_tmp_fp #1 \l_@@_tmp_fp \l_@@_unit_tl } \cs_new_protected:cpx { @@_format_extract-exponent:n } #1 { \exp_not:c { @@_format_extract-exponent_aux:n } { \exp_not:N \siunitx_unit_format_extract_prefixes:nNN {#1} } } \cs_new_protected:cpx { @@_format_extract-exponent:nn } #1#2 { \exp_not:c { @@_format_extract-exponent_aux:n } { \exp_not:N \siunitx_unit_format_multiply_extract_prefixes:nnNN {#1} {#2} } } \cs_new_protected:cpn { @@_format_extract-exponent_aux:n } #1 { #1 \l_@@_unit_tl \l_@@_tmp_fp \tl_set:Nx \l_@@_tmp_tl { \siunitx_number_adjust_exponent:Nn \l_@@_tmp_tl \l_@@_tmp_fp } \siunitx_number_process:NN \l_@@_tmp_tl \l_@@_first_tl \bool_set_true:N \l_@@_exp_combine_bool } \cs_new_protected:Npn \@@_format_input:n #1 { \siunitx_number_process:NN \l_@@_tmp_tl \l_@@_first_tl \siunitx_unit_format:nN {#1} \l_@@_unit_tl } \cs_new_protected:Npn \@@_format_input:nn #1#2 { \siunitx_number_process:NN \l_@@_tmp_tl \l_@@_first_tl \siunitx_unit_format_multiply:nnN {#1} {#2} \l_@@_unit_tl } \cs_new_protected:Npn \@@_extract_exp:nN #1#2 { \@@_extract_exp:nnnnnnnN #1 #2 } \cs_generate_variant:Nn \@@_extract_exp:nN { V } \cs_new_protected:Npn \@@_extract_exp:nnnnnnnN #1#2#3#4#5#6#7#8 { \fp_set:Nn #8 { #6 0 #7 } } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro} % { % \siunitx_compound_quantity:nn , % \@@_quantity_auxi:nn , % \@@_quantity_auxii:nn % } % For quantities, life is more complex as there are interactions between the % options for exponents and units. The \cs{c_empty_tl} suppresses any % leading \texttt{1} if the unit starts \cs{per}; the \pkg{siunitx-print} % module will skip any printing in this case. % \begin{macrocode} \cs_new_protected:Npn \siunitx_compound_quantity:nn #1#2 { \group_begin: \bool_lazy_all:nTF { { \l_@@_independent_bool } { \str_if_eq_p:Vn \l_siunitx_quantity_prefix_mode_tl { combine-exponent } } { \int_compare_p:nNn { \tl_count:n {#1} } > 1 } } { \@@_quantity_auxi:nn } { \@@_quantity_auxii:nn } {#1} {#2} \group_end: } % \end{macrocode} % The rather special case where all units are printed independently: % we just convert to a simple sequence then print. % \begin{macrocode} \cs_new_protected:Npn \@@_quantity_auxi:nn #1#2 { \@@_print_boundary:V \l_@@_boundary_open_tl \seq_clear:N \l_@@_tmp_seq \tl_map_inline:nn {#1} { \seq_put_right:Nn \l_@@_tmp_seq { \siunitx_quantity:nn {##1} {#2} } } \seq_use:NVVV \l_@@_tmp_seq \l_@@_separator_pair_tl \l_@@_separator_tl \l_@@_separator_final_tl \@@_print_boundary:V \l_@@_boundary_close_tl } % \end{macrocode} % The business end for all other cases. % \begin{macrocode} \cs_new_protected:Npn \@@_quantity_auxii:nn #1#2 { \bool_if:NT \l_@@_unit_bracket_bool { \bool_set_true:N \l_@@_exp_bracket_bool } \bool_if:NT \l_@@_unit_repeat_bool { \bool_set_false:N \l_@@_exp_combine_bool } \bool_lazy_or:nnT { \l_@@_unit_bracket_bool } { ! \l_@@_unit_repeat_bool } { \bool_set_false:N \l_siunitx_number_bracket_ambiguous_bool } \bool_set_true:N \l_@@_unit_bool \@@_format:nn {#1} {#2} \bool_if:NF \l_siunitx_number_parse_bool { \siunitx_unit_format:nN {#2} \l_@@_unit_tl } \str_if_eq:VnT \l_siunitx_quantity_prefix_mode_tl { combine-exponent } { \tl_clear:N \l_@@_exp_tl } \bool_if:NTF \l_@@_unit_repeat_bool { \@@_print:N \@@_print_quantity:e } { \bool_lazy_and:nnTF { \l_@@_unit_bracket_bool } { \tl_if_empty_p:N \l_@@_exp_tl } { \siunitx_print_number:V \l_@@_bracket_open_tl \@@_print:N \siunitx_print_number:e \siunitx_print_number:V \l_@@_bracket_close_tl } { \@@_print:N \siunitx_print_number:e } \@@_print_quantity:n { \c_empty_tl } } } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_print:N} % \begin{macro}{\@@_print:nnN, \@@_print:nVN, \@@_print:enN, \@@_print:eeN} % \begin{macro}{\@@_print:nnnN, \@@_print:ennN} % \begin{macro}{\@@_print_aux:n} % \begin{macro}{\@@_print_aux:nn} % \begin{macro}{\@@_print_quantity:n, \@@_print_quantity:e} % \begin{macro} % { % \@@_print_boundary:n, \@@_print_boundary:V, % \@@_print_separator:n, \@@_print_separator:V % } % We now need to know how many entries there are: the reason we don't use % \cs{seq_use:Nnnn} is that we want to be able to insert % \cs{siunitx_print_\dots:n} in a controlled way. % \begin{macrocode} \cs_new_protected:Npn \@@_print:N #1 { \bool_lazy_and:nnTF { \l_@@_exp_bracket_bool } { ! \tl_if_empty_p:N \l_@@_exp_tl } { \@@_print:eeN { \exp_not:V \l_@@_bracket_open_tl } { \exp_not:V \l_@@_bracket_close_tl \exp_not:V \l_@@_exp_tl } #1 } { \@@_print:nVN { } \l_@@_exp_tl #1 } } \cs_new_protected:Npn \@@_print:nnN #1#2#3 { \@@_print:ennN { \seq_count:N \l_@@_tmp_seq } {#1} {#2} #3 } \cs_generate_variant:Nn \@@_print:nnN { nV , e , ee } % \end{macrocode} % A rather long auxiliary as we want a way to have the brackets/exponent % available. The actual flow is simple enough: see how many entries there are % and print as required. To keep everything generic, we have some slightly % tricky saving of data to allow everything to go to the mapping. % \begin{macrocode} \cs_new_protected:Npn \@@_print:nnnN #1#2#3#4 { \int_case:nnF {#1} { { 0 } { } { 1 } { #4 { \seq_item:Nn \l_@@_tmp_seq { 1 } } } { 2 } { \@@_print_boundary:V \l_@@_boundary_open_tl #4 { \exp_not:n {#2} \seq_item:Nn \l_@@_tmp_seq { 1 } } \@@_print_separator:V \l_@@_separator_pair_tl #4 { \seq_item:Nn \l_@@_tmp_seq { 2 } \exp_not:n {#3} } \@@_print_boundary:V \l_@@_boundary_close_tl } } { \int_set:Nn \l_@@_count_int {#1} \tl_set:Nn \l_@@_start_tl {#2} \tl_set:Nn \l_@@_end_tl {#3} \cs_set_eq:NN \@@_print_aux:n #4 \@@_print_boundary:V \l_@@_boundary_open_tl \seq_map_indexed_function:NN \l_@@_tmp_seq \@@_print_aux:nn \@@_print_boundary:V \l_@@_boundary_close_tl } } \cs_generate_variant:Nn \@@_print:nnnN { e } \cs_new_protected:Npn \@@_print_aux:n #1 { } \cs_new_protected:Npn \@@_print_aux:nn #1#2 { \int_case:nnF {#1} { { 1 } { \@@_print_aux:n { \exp_not:V \l_@@_start_tl \exp_not:n {#2} } \@@_print_separator:V \l_@@_separator_tl } { \l_@@_count_int - 1 } { \@@_print_aux:n { \exp_not:n {#2} } \@@_print_separator:V \l_@@_separator_final_tl } { \l_@@_count_int } { \@@_print_aux:n { \exp_not:n {#2} \exp_not:V \l_@@_end_tl } } } { \@@_print_aux:n { \exp_not:n {#2} } \@@_print_separator:V \l_@@_separator_tl } } \cs_new_protected:Npn \@@_print_quantity:n #1 { \siunitx_quantity_print:nV {#1} \l_@@_unit_tl } \cs_generate_variant:Nn \@@_print_quantity:n { e } \cs_new_protected:Npn \@@_print_boundary:n #1 { \tl_if_blank:nF {#1} { \bool_if:NTF \l_@@_boundary_text_bool { #1 } { \siunitx_print_number:n {#1} } } } \cs_generate_variant:Nn \@@_print_boundary:n { V } \cs_new_protected:Npn \@@_print_separator:n #1 { \bool_if:NTF \l_@@_separator_text_bool { #1 } { \siunitx_print_number:n {#1} } } \cs_generate_variant:Nn \@@_print_separator:n { V } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}[EXP]{\@@_uncert_bracket:N} % \begin{macro}[EXP]{\@@_uncert_bracket:w} % \begin{macro}[EXP]{\@@_uncert_bracket:nnw} % Check for the case where there is a separate uncertainty but not exponent, % when we are handling units. % \begin{macrocode} \cs_new:Npn \@@_uncert_bracket:N #1 { \exp_after:wN \@@_uncert_bracket:w #1 \q_stop } \cs_new:Npn \@@_uncert_bracket:w #1 \q_nil #2 \q_nil #3 \q_nil #4 \q_nil #5 \q_nil #6 \q_nil #7 \q_nil #8 \q_nil #9 \q_stop { \@@_uncert_bracket:nnw {#1#2#3#4#5#6} {#7#8} #9 \q_stop } \cs_new:Npn \@@_uncert_bracket:nnw #1#2 #3 \q_nil #4 \q_nil #5 \q_stop { \bool_lazy_any:nTF { { ! \l_@@_unit_repeat_bool } { \tl_if_blank_p:n {#2#3} } { ! \tl_if_blank_p:n {#5} } } { \exp_not:n {#1#2#3#4#5} } { \exp_not:V \l_@@_bracket_open_tl \exp_not:n {#1#2#3} \exp_not:V \l_@@_bracket_close_tl \exp_not:n {#4#5} } } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \subsection{Lists} % % Identify the internal prefix. % \begin{macrocode} %<@@=siunitx_list> % \end{macrocode} % % \begin{variable} % { % \l_@@_bracket_close_tl , % \l_@@_independent_bool , % \l_siunitx_list_separator_tl , % \l_siunitx_list_separator_final_tl , % \l_@@_bracket_open_tl , % \l_siunitx_list_separator_pair_tl , % \l_@@_exp_tl , % \l_@@_units_tl % } % Options for products. % \begin{macrocode} \tl_new:N \l_@@_exp_tl \tl_new:N \l_@@_units_tl \keys_define:nn { siunitx } { list-close-bracket .tl_set:N = \l_@@_bracket_close_tl , list-exponents .choices:nn = { combine , combine-bracket , individual } { \tl_set_eq:NN \l_@@_exp_tl \l_keys_choice_tl } , list-final-separator .tl_set:N = \l_siunitx_list_separator_final_tl , list-independent-prefix .bool_set:N = \l_@@_independent_bool , list-open-bracket .tl_set:N = \l_@@_bracket_open_tl , list-pair-separator .tl_set:N = \l_siunitx_list_separator_pair_tl , list-separator .tl_set:N = \l_siunitx_list_separator_tl , list-units .choices:nn = { bracket , independent , repeat , single } { \tl_set_eq:NN \l_@@_units_tl \l_keys_choice_tl } } % \end{macrocode} % \end{variable} % % \begin{macro}{\siunitx_number_list:nn} % \begin{macro}{\siunitx_quantity_list:nn} % \begin{macro}{\@@_aux:} % Simply recover the settings and use as a list. % \begin{macrocode} \cs_new_protected:Npn \siunitx_number_list:nn #1 { \group_begin: \@@_aux: \siunitx_compound_number:n {#1} \group_end: } \cs_new_protected:Npn \siunitx_quantity_list:nn #1#2 { \group_begin: \@@_aux: \siunitx_compound_quantity:nn {#1} {#2} \group_end: } \cs_new_protected:Npn \@@_aux: { \keys_set:nx { siunitx } { compound-close-bracket = { \exp_not:V \l_@@_bracket_close_tl } , compound-close-boundary = , compound-exponents = \l_@@_exp_tl , compound-final-separator = { \exp_not:V \l_siunitx_list_separator_final_tl } , compound-independent-prefix = \bool_if:NTF \l_@@_independent_bool { true } { false } , compound-open-boundary = , compound-open-bracket = { \exp_not:V \l_@@_bracket_open_tl } , compound-pair-separator = { \exp_not:V \l_siunitx_list_separator_pair_tl } , compound-separator = { \exp_not:V \l_siunitx_list_separator_tl } , compound-separator-mode = text , compound-units = \l_@@_units_tl } } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \subsection{Products} % % Identify the internal prefix. % \begin{macrocode} %<@@=siunitx_product> % \end{macrocode} % % \begin{variable} % { % \l_@@_bracket_close_tl , % \l_@@_exp_tl , % \l_@@_independent_bool , % \l_@@_bracket_open_tl , % \l_@@_phrase_bool , % \l_@@_phrase_tl , % \l_@@_symbol_tl , % \l_@@_units_tl % } % Options for products. % \begin{macrocode} \tl_new:N \l_@@_exp_tl \bool_new:N \l_@@_phrase_bool \tl_new:N \l_@@_units_tl \keys_define:nn { siunitx } { product-close-bracket .tl_set:N = \l_@@_bracket_close_tl , product-exponents .choices:nn = { combine , combine-bracket , individual } { \tl_set_eq:NN \l_@@_exp_tl \l_keys_choice_tl } , product-independent-prefix .bool_set:N = \l_@@_independent_bool , product-mode .choice: , product-mode / phrase .code:n = { \bool_set_true:N \l_@@_phrase_bool } , product-mode / symbol .code:n = { \bool_set_false:N \l_@@_phrase_bool } , product-open-bracket .tl_set:N = \l_@@_bracket_open_tl , product-phrase .tl_set:N = \l_@@_phrase_tl , product-symbol .tl_set:N = \l_@@_symbol_tl , product-units .choices:nn = { bracket , bracket-power , independent , power , repeat , single } { \tl_set_eq:NN \l_@@_units_tl \l_keys_choice_tl } } % \end{macrocode} % \end{variable} % % \begin{macro}{\siunitx_number_product:n} % \begin{macro}{\siunitx_quantity_product:nn} % \begin{macro}{\@@_aux:} % \begin{macro}{\@@_aux:n, \@@_aux:e} % Simply recover the settings and use as a list. % \begin{macrocode} \cs_new_protected:Npn \siunitx_number_product:n #1 { \group_begin: \@@_aux: \siunitx_compound_number:n {#1} \group_end: } \cs_new_protected:Npn \siunitx_quantity_product:nn #1#2 { \group_begin: \@@_aux: \siunitx_compound_quantity:nn {#1} {#2} \group_end: } \cs_new_protected:Npn \@@_aux: { \bool_if:NTF \l_@@_phrase_bool { \@@_aux:e { \exp_not:V \l_@@_phrase_tl } } { \@@_aux:e { { } \exp_not:V \l_@@_symbol_tl { } } } } \cs_new_protected:Npn \@@_aux:n #1 { \keys_set:nx { siunitx } { compound-close-boundary = , compound-close-bracket = { \exp_not:V \l_@@_bracket_close_tl } , compound-exponents = \l_@@_exp_tl , compound-final-separator = { \exp_not:n {#1} } , compound-independent-prefix = \bool_if:NTF \l_@@_independent_bool { true } { false } , compound-open-boundary = , compound-open-bracket = { \exp_not:V \l_@@_bracket_open_tl } , compound-pair-separator = { \exp_not:n {#1} } , compound-separator = { \exp_not:n {#1} } , compound-separator-mode = \bool_if:NTF \l_@@_phrase_bool { text } { number } , compound-units = \l_@@_units_tl } } \cs_generate_variant:Nn \@@_aux:n { e } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \subsection{Ranges} % % Identify the internal prefix. % \begin{macrocode} %<@@=siunitx_range> % \end{macrocode} % % \begin{variable} % { % \l_@@_bracket_close_tl , % \l_@@_exp_tl , % \l_@@_independent_bool , % \l_@@_bracket_open_tl , % \l_@@_open_tl , % \l_siunitx_range_phrase_tl , % \l_@@_units_tl % } % Options for products. % \begin{macrocode} \tl_new:N \l_@@_exp_tl \tl_new:N \l_@@_units_tl \keys_define:nn { siunitx } { range-close-bracket .tl_set:N = \l_@@_bracket_close_tl , range-exponents .choices:nn = { combine , combine-bracket , individual } { \tl_set_eq:NN \l_@@_exp_tl \l_keys_choice_tl } , range-independent-prefix .bool_set:N = \l_@@_independent_bool , range-open-bracket .tl_set:N = \l_@@_bracket_open_tl , range-open-phrase .tl_set:N = \l_@@_open_tl , range-phrase .tl_set:N = \l_siunitx_range_phrase_tl , range-units .choices:nn = { bracket , independent , repeat , single } { \tl_set_eq:NN \l_@@_units_tl \l_keys_choice_tl } } % \end{macrocode} % \end{variable} % % \begin{macro}{\siunitx_number_range:nn} % \begin{macro}{\siunitx_quantity_range:nnn} % \begin{macro}{\@@_aux:} % Simply recover the settings and use as a list. % \begin{macrocode} \cs_new_protected:Npn \siunitx_number_range:nn #1#2 { \group_begin: \@@_aux: \siunitx_compound_number:n { {#1} {#2} } \group_end: } \cs_new_protected:Npn \siunitx_quantity_range:nnn #1#2#3 { \group_begin: \@@_aux: \siunitx_compound_quantity:nn { {#1} {#2} } {#3} \group_end: } \cs_new_protected:Npn \@@_aux: { \keys_set:nx { siunitx } { compound-boundary-mode = text , compound-close-boundary = , compound-close-bracket = { \exp_not:V \l_@@_bracket_close_tl } , compound-exponents = \l_@@_exp_tl , compound-independent-prefix = \bool_if:NTF \l_@@_independent_bool { true } { false } , compound-open-boundary = { \exp_not:V \l_@@_open_tl } , compound-open-bracket = { \exp_not:V \l_@@_bracket_open_tl } , compound-pair-separator = { \exp_not:V \l_siunitx_range_phrase_tl } , compound-separator-mode = text , compound-units = \l_@@_units_tl } } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \subsection{Standard settings for module options} % % Some of these follow naturally from the point of definition % (\foreign{e.g.}~boolean variables are always |false| to begin with), % but for clarity everything is set here. % \begin{macrocode} \keys_set:nn { siunitx } { compound-boundary-mode = text , compound-close-boundary = , % ( compound-close-bracket = ) , compound-exponents = individual , compound-final-separator = { \TextOrMath { \space } { \ } \text { and } \TextOrMath { \space } { \ } } , compound-independent-prefix = false , compound-open-boundary = , compound-open-bracket = ( , % ) compound-pair-separator = { \TextOrMath { \space } { \ } \text { and } \TextOrMath { \space } { \ } } , compound-separator = { , \TextOrMath { \space } { \ } } , compound-separator-mode = text , compound-units = repeat , % ( list-close-bracket = ) , list-exponents = individual , list-final-separator = { \TextOrMath { \space } { \ } \text { and } \TextOrMath { \space } { \ } } , list-independent-prefix = false , list-open-bracket = ( , % ) list-pair-separator = { \TextOrMath { \space } { \ } \text { and } \TextOrMath { \space } { \ } } , list-separator = { , \TextOrMath { \space } { \ } } , list-units = repeat , % ( product-close-bracket = ) , product-exponents = individual , product-independent-prefix = false , product-mode = symbol , product-open-bracket = ( , % ) product-phrase = { \TextOrMath { \space } { \ } \text { by } \TextOrMath { \space } { \ } } , product-symbol = \times , product-units = repeat , % ( range-close-bracket = ) , range-exponents = individual , range-independent-prefix = false , range-open-bracket = ( , % ) range-open-phrase = , range-phrase = { \TextOrMath { \space } { \ } \text { to } \TextOrMath { \space } { \ } } , range-units = repeat } % \end{macrocode} % % \begin{macrocode} % % \end{macrocode} % % \end{implementation} % % \PrintIndex