% \iffalse meta-comment
%
% File: siunitx-unit.dtx Copyright (C) 2014-2026 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
\ExplSyntaxOn
\makeatletter
\NewDocumentCommand \acro { m }
  {
    \textsc
      {
        \exp_args:NV \tl_if_head_eq_charcode:nNTF \f@series { m }
          { \text_lowercase:n }
          { \use:n }
            {#1}
      }
  }
\makeatother
\ExplSyntaxOff
\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}
%</driver>
% \fi
%
% \GetFileInfo{siunitx.sty}
%
% \title{^^A
%   \pkg{siunitx-unit} -- Parsing and formatting units^^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}
%
% \section{Parsing and formatting units}
%
% This submodule is dedicated to formatting physical units. The main function,
% \cs{siunitx_unit_format:nN}, takes user input specifying physical units and
% converts it into a formatted token list suitable for typesetting in math
% mode. While the formatter will deal correctly with \enquote{literal} user
% input, the key strength of the module is providing a method to describe
% physical units in a \enquote{symbolic} manner. The output format of these
% symbolic units can then be controlled by a number of key--value options
% made available by the module.
%
% A small number of \LaTeXe{} math mode commands are assumed to be available
% as part of the formatted output. The \cs{mathchoice} command
% (normally the \TeX{} primitive) is needed when using different settings
% for inline and display |per-mode|. The commands \cs{frac}, \cs{mathrm},
% \cs{mbox}, \verb*|\ | and \cs{,} are used by the standard module settings.
% For the display of colored (highlighted) and cancelled units, the commands
% \cs{textcolor} and \cs{cancel} are assumed to be available.
%
% \subsection{Formatting units}
%
% \begin{function}{\siunitx_unit_format:nN, \siunitx_unit_format:VN}
%   \begin{syntax}
%     \cs{siunitx_unit_format:nN} \Arg{units} \meta{tl~var}
%   \end{syntax}
%   This function converts the input \meta{units} into a processed
%   \meta{tl~var} which can then be inserted in math mode to typeset the
%   material. Where the \meta{units} are given in symbolic form, described
%   elsewhere, this formatting process takes place in two stages: the
%   \meta{units} are parsed into a structured form before the generation
%   of the appropriate output form based on the active settings. When the
%   \meta{units} are given as literals, processing is minimal: the
%   characters |.| and |~| are converted to unit products (boundaries).
%   In both cases, the result is a series of tokens intended to be typeset
%   in math mode with appropriate choice of font for typesetting of the
%   textual parts.
%
%   For example,
%   \begin{verbatim}
%     \siunitx_unit_format:nN { \kilo \metre \per \second } \l_tmpa_tl
%   \end{verbatim}
%   will, with standard settings, result in \cs{l_tmpa_tl} being set to
%   \begin{verbatim}
%     \mathrm{km}\,\mathrm{s}^{-1}
%   \end{verbatim}
% \end{function}
%
% \begin{function}{\siunitx_unit_format_extract_prefixes:nNN}
%   \begin{syntax}
%     \cs{siunitx_unit_format_extract_prefixes:nNN} \Arg{units} \meta{tl~var} \meta{fp~var}
%   \end{syntax}
%   This function formats the \meta{units} in the same way as described for
%   \cs{siunitx_unit_format:nN}. When the input is given in symbolic form,
%   any decimal unit prefixes will be extracted and the overall power of
%   ten that these represent will be stored in the \meta{fp~var}.
%
%   For example,
%   \begin{verbatim}
%     \siunitx_unit_format_extract_prefixes:nNN { \kilo \metre \per \second }
%       \l_tmpa_tl \l_tmpa_fp
%   \end{verbatim}
%   will, with standard settings, result in \cs{l_tmpa_tl} being set to
%   \begin{verbatim}
%     \mathrm{m}\,\mathrm{s}^{-1}
%   \end{verbatim}
%   with \cs{l_tmpa_fp} taking value~$3$. Note that the latter is a floating
%   point variable: it is possible for non-integer values to be obtained here.
% \end{function}
%
% \begin{function}{\siunitx_unit_format_combine_exponent:nnN}
%   \begin{syntax}
%     \cs{siunitx_unit_format_combine_exponent:nnN} \Arg{units} \Arg{exponent} \meta{tl~var}
%   \end{syntax}
%   This function formats the \meta{units} in the same way as described for
%   \cs{siunitx_unit_format:nN}. The \meta{exponent} is combined with any
%   prefix for the \emph{first} unit of the \meta{units}, and an updated
%   prefix is introduced.
%
%   For example,
%   \begin{verbatim}
%     \siunitx_unit_format_combine_exponent:nnN { \metre \per \second }
%       { 3 } \l_tmpa_tl
%   \end{verbatim}
%   will, with standard settings, result in \cs{l_tmpa_tl} being set to
%   \begin{verbatim}
%     \mathrm{km}\,\mathrm{s}^{-1}
%   \end{verbatim}
% \end{function}
%
% \begin{function}
%   {
%     \siunitx_unit_format_multiply:nnN ,
%     \siunitx_unit_format_multiply_extract_prefixes:nnNN ,
%     \siunitx_unit_format_multiply_combine_exponent:nnnN
%   }
%   \begin{syntax}
%     \cs{siunitx_unit_format_multiply:nnN} \Arg{units} \Arg{factor} \meta{tl~var}
%     \cs{siunitx_unit_format_multiply_extract_prefixes:nnNN}
%       \Arg{units} \Arg{factor} \meta{tl~var} \meta{fp~var}
%     \cs{siunitx_unit_format_multiply_combine_exponent:nnnN}
%       \Arg{units} \Arg{factor} \Arg{exponent} \meta{tl~var}
%   \end{syntax}
%   These function formats the \meta{units} in the same way as described for
%   \cs{siunitx_unit_format:nN}. The units are multiplied by the \meta{factor},
%   and further processing takes place as previously described.
%
%   For example,
%   \begin{verbatim}
%     \siunitx_unit_format_multiply:nnN { \metre \per \second }
%       { 3 } \l_tmpa_tl
%   \end{verbatim}
%   will, with standard settings, result in \cs{l_tmpa_tl} being set to
%   \begin{verbatim}
%     \mathrm{km}^{3}\,\mathrm{s}^{-3}
%   \end{verbatim}
% \end{function}
%
% \subsection{Defining symbolic units}
%
% \begin{function}{\siunitx_declare_prefix:Nnn, \siunitx_declare_prefix:Nne}
%   \begin{syntax}
%     \cs{siunitx_declare_prefix:Nnn} \meta{prefix} \Arg{power} \Arg{symbol}
%   \end{syntax}
%   Defines a symbolic \meta{prefix} (which should be a control sequence
%   such as |\kilo|) to be converted by the parser to the \meta{symbol}.
%   The latter should consist of literal content (\foreign{e.g.}~|k|).
%   In literal mode the \meta{symbol} will be typeset directly. The prefix
%   should represent an integer \meta{power} of $10$, and this information
%   may be used to convert from one or more \meta{prefix} symbols to an
%   overall power applying to a unit. See also
%   \cs{siunitx_declare_prefix:Nn}.
% \end{function}
%
% \begin{function}{\siunitx_declare_prefix:Nn}
%   \begin{syntax}
%     \cs{siunitx_declare_prefix:Nn} \meta{prefix} \Arg{symbol}
%   \end{syntax}
%   Defines a symbolic \meta{prefix} (which should be a control sequence
%   such as |\kilo|) to be converted by the parser to the \meta{symbol}.
%   The latter should consist of literal content (\foreign{e.g.}~|k|).
%   In literal mode the \meta{symbol} will be typeset directly. In contrast
%   to \cs{siunitx_declare_prefix:Nnn}, there is no assumption about the
%   mathematical nature of the \meta{prefix}, \foreign{i.e.}~the prefix may
%   represent a power of any base. As a result, no conversion of the
%   \meta{prefix} to a numerical power will be possible.
% \end{function}
%
% \begin{function}{\siunitx_declare_power:NNn}
%   \begin{syntax}
%     \cs{siunitx_declare_power:NNn} \meta{pre-power} \meta{post-power} \Arg{value}
%   \end{syntax}
%   Defines \emph{two} symbolic \meta{powers} (which should be control
%   sequences such as |\squared|) to be converted by the parser to the
%   \meta{value}. The latter should be an integer or floating point number in
%   the format defined for \pkg{l3fp}. Powers may precede a unit or be give
%   after it: both forms are declared at once, as indicated by the argument
%   naming. In literal mode, the \meta{value} will be applied as
%   a superscript to either the next token in the input (for the
%   \meta{pre-power}) or appended to the previously-typeset material
%   (for the \meta{post-power}).
% \end{function}
%
% \begin{function}{\siunitx_declare_qualifier:Nn}
%   \begin{syntax}
%     \cs{siunitx_declare_qualifier:Nn} \meta{qualifier} \Arg{meaning}
%   \end{syntax}
%   Defines a symbolic \meta{qualifier} (which should be a control sequence
%   such as |\catalyst|) to be converted by the parser to the \meta{meaning}.
%   The latter should consist of literal content (\foreign{e.g.}~|cat|). In
%   literal mode the \meta{meaning} will be typeset following a space after
%   the unit to which it applies.
% \end{function}
%
% \begin{function}
%   {
%     \siunitx_declare_unit:Nn,
%     \siunitx_declare_unit:Ne,
%     \siunitx_declare_unit:Nnn,
%     \siunitx_declare_unit:Nen
%   }
%   \begin{syntax}
%     \cs{siunitx_declare_unit:Nn}  \meta{unit} \Arg{meaning}
%     \cs{siunitx_declare_unit:Nnn} \meta{unit} \Arg{meaning} \Arg{options}
%   \end{syntax}
%   Defines a symbolic \meta{unit} (which should be a control sequence
%   such as |\kilogram|) to be converted by the parser to the \meta{meaning}.
%   The latter may consist of literal content (\foreign{e.g.}~|kg|), other
%   symbolic unit commands (\foreign{e.g.}~|\kilo\gram|) or a mixture of the
%   two. In literal mode the \meta{meaning} will be typeset directly. The
%   version taking an \meta{options} argument may be used to support per-unit
%   options: these are applied at the top level or using
%   \cs{siunitx_unit_options_apply:n}.
% \end{function}
%
% \begin{variable}{\l_siunitx_unit_font_tl}
%    The font function which is applied to the text of units when constructing
%    formatted units: set by |font-command|.
% \end{variable}
%
% \begin{variable}{\l_siunitx_unit_fraction_tl}
%    The fraction function which is applied when constructing fractional units:
%    set by |fraction-command|.
% \end{variable}
%
% \begin{variable}{\l_siunitx_unit_symbolic_seq}
%   This sequence contains all of the symbolic names defined:
%   these will be in the form of control sequences such as |\kilogram|.
%   The order of the sequence is unimportant. This includes prefixes and
%   powers as well as units themselves.
% \end{variable}
%
% \begin{variable}{\l_siunitx_unit_seq}
%   This sequence contains all of the symbolic \emph{unit} names defined:
%   these will be in the form of control sequences such as |\kilogram|.
%   In contrast to \cs{l_siunitx_unit_symbolic_seq}, it \emph{only} holds
%   units themselves
% \end{variable}
%
% \subsection{Per-unit options}
%
% \begin{function}{\siunitx_unit_options_declare:Nn}
%   \begin{syntax}
%     \cs{siunitx_unit_options_declare:Nn} \meta{unit} \Arg{options}
%   \end{syntax}
%   Declares that the \meta{options} should be applied with the \meta{unit}
%   is used. The \meta{options} stored override any saved when the unit was
%   declared. This function is intended for adjusting options when the unit
%   command is otherwise unchanged.
% \end{function}
%
% \begin{function}{\siunitx_unit_options_apply:n}
%   \begin{syntax}
%     \cs{siunitx_unit_options_apply:n} \Arg{unit(s)}
%   \end{syntax}
%   Applies any unit-specific options set up using
%   \cs{siunitx_declare_unit:Nnn}. This allows there use outside of unit
%   formatting, for example to influence spacing in quantities. The options
%   are applied only once at a given group level, which allows for user
%   override \foreign{via} |\keys_set:nn { siunitx } { ... }|.
% \end{function}
%
% \subsection{Units in (PDF) strings}
%
% \begin{function}{\siunitx_unit_pdfstring_context:}
%   \begin{syntax}
%     \cs{group_begin:}
%       \cs{siunitx_unit_pdfstring_context:}
%       \meta{Expansion context} \meta{units}
%     \cs{group_end:}
%   \end{syntax}
%   Sets symbol unit macros to generate text directly. This is needed in
%   expansion contexts where units must be converted to simple text. This
%   function is itself not expandable, so must be using within a
%   surrounding group as show in the example.
% \end{function}
%
% \subsection{Pre-defined symbolic unit components}
%
% The unit parser is defined to recognise a number of pre-defined units,
% prefixes and powers, and also interpret a small selection of
% \enquote{generic} symbolic parts.
%
% Broadly, the pre-defined units are those defined by the \textsc{bipm} in the
% documentation for the \emph{International System of Units}
% (\acro{SI})~\cite{BIPM}. As far as possible, the names given to the command
% names for units are those used by the \acro{bipm}, omitting spaces and using
% only \acro{ASCII} characters. The standard symbols are also taken from the
% same documentation. In the following documentation, the order of the
% description of units broadly follows the \acro{SI}~Brochure.
%
% \begin{function}
%   {
%     \kilogram ,
%     \metre    ,
%     \meter    ,
%     \mole     ,
%     \kelvin   ,
%     \candela  ,
%     \second   ,
%     \ampere
%   }
%   The base units as defined in the \acro{SI} Brochure~\cite{base-units}.
%   Notice that \cs{meter} is defined as an alias for \cs{metre} as the former
%   spelling is common in the US (although the latter is the official spelling).
% \end{function}
%
% \begin{function}{\gram}
%   The base unit \cs{kilogram} is defined using an \acro{SI} prefix: as such
%   the (derived) unit \cs{gram} is required by the module to correctly produce
%   output for the \cs{kilogram}.
% \end{function}
%
% \begin{function}
%   {
%     \quecto ,
%     \ronto  ,
%     \yocto  ,
%     \zepto  ,
%     \atto   ,
%     \femto  ,
%     \pico   ,
%     \nano   ,
%     \micro  ,
%     \milli  ,
%     \centi  ,
%     \deci   ,
%     \deca   ,
%     \deka   ,
%     \hecto  ,
%     \kilo   ,
%     \mega   ,
%     \giga   ,
%     \tera   ,
%     \peta   ,
%     \exa    ,
%     \zetta  ,
%     \yotta  ,
%     \ronna  ,
%     \quetta
%   }
%   Prefixes, all of which are integer powers of $10$: the powers are stored
%   internally by the module and can be used for conversion from prefixes to
%   their numerical equivalent. These prefixes are documented in Section~3.1
%   of the \acro{SI}~Brochure.
%
%   Note that the \cs{kilo} prefix is required to
%   define the base \cs{kilogram} unit. Also note the two spellings available
%   for \cs{deca}/\cs{deka}.
% \end{function}
%
% \begin{function}
%   {
%     \becquerel     ,
%     \degreeCelsius ,
%     \coulomb       ,
%     \farad         ,
%     \gray          ,
%     \hertz         ,
%     \henry         ,
%     \joule         ,
%     \katal         ,
%     \lumen         ,
%     \lux           ,
%     \newton        ,
%     \ohm           ,
%     \pascal        ,
%     \radian        ,
%     \siemens       ,
%     \sievert       ,
%     \steradian     ,
%     \tesla         ,
%     \volt          ,
%     \watt          ,
%     \weber
%   }
%   The defined \acro{SI}~units with defined names and symbols, as given in
%   Table~4 of the \acro{SI}~Brochure. Notice that the names
%   of the units are lower case with the exception of \cs{degreeCelsius}, and
%   that this unit name includes \enquote{degree}.
% \end{function}
%
% \begin{function}
%   {
%     \astronomicalunit ,
%     \bel              ,
%     \dalton           ,
%     \day              ,
%     \decibel          ,
%     \electronvolt     ,
%     \hectare          ,
%     \hour             ,
%     \litre            ,
%     \liter            ,
%     \neper            ,
%     \minute           ,
%     \tonne
%   }
%   Units accepted for use with the \acro{SI}: here \cs{minute} is a unit of
%   time not of plane angle. These units are taken from Table~8 of the
%   \acro{SI}~Brochure.
%
%   For the unit \cs{litre}, both |l| and |L| are listed
%   as acceptable symbols: the latter is the standard setting of the module.
%   The alternative spelling \cs{liter} is also given for this unit for US
%   users (as with \cs{metre}, the official spelling is \enquote{re}).
% \end{function}
%
% \begin{function}
%   {
%     \arcminute ,
%     \arcsecond ,
%     \degree
%   }
%   Units for plane angles accepted for use with the \acro{SI}: to avoid a
%   clash with units for time, here \cs{arcminute} and \cs{arcsecond} are
%   used in place of \cs{minute} and \cs{second}. These units are taken from
%   Table~8 of the \acro{SI}~Brochure.
% \end{function}
%
% \begin{function}{\percent}
%   The mathematical concept of percent, usable with the \acro{SI} as detailed
%   in Section~5.4.7 of the \acro{SI}~Brochure.
% \end{function}
%
% \begin{function}{\square, \cubic}
%   \begin{syntax}
%     \cs{square} \meta{prefix} \meta{unit}
%     \cs{cubic} \meta{prefix} \meta{unit}
%   \end{syntax}
%   Pre-defined unit powers which apply to the next \meta{prefix}/\meta{unit}
%   combination.
% \end{function}
%
% \begin{function}{\squared, \cubed}
%   \begin{syntax}
%     \meta{prefix} \meta{unit} \cs{squared}
%     \meta{prefix} \meta{unit} \cs{cubed}
%   \end{syntax}
%   Pre-defined unit powers which apply to the preceding
%   \meta{prefix}/\meta{unit} combination.
% \end{function}
%
% \begin{function}{\per}
%   \begin{syntax}
%     \cs{per} \meta{prefix} \meta{unit} \meta{power}
%   \end{syntax}
%   Indicates that the next \meta{prefix}/\meta{unit}/\meta{power} combination
%   is reciprocal, \foreign{i.e.}~raises it to the power $-1$. This symbolic
%   representation may be applied in addition to a \cs{power}, and will work
%   correctly if the \cs{power} itself is negative. In literal mode \cs{per}
%   will print a slash (\enquote{$/$}).
% \end{function}
%
% \begin{function}{\cancel}
%   \begin{syntax}
%     \cs{cancel} \meta{prefix} \meta{unit} \meta{power}
%   \end{syntax}
%   Indicates that the next \meta{prefix}/\meta{unit}/\meta{power} combination
%   should be \enquote{cancelled out}. In the parsed output, the entire unit
%   combination will be given as the argument to a function \cs{cancel}, which
%   is assumed to be available at a higher level. In literal mode, the same
%   higher-level \cs{cancel} will be applied to the next token. It is the
%   responsibility of the calling code to provide an appropriate definition
%   for \cs{cancel} outside of the scope of the unit parser.
% \end{function}
%
% \begin{function}{\highlight}
%   \begin{syntax}
%     \cs{highlight} \Arg{color} \meta{prefix} \meta{unit} \meta{power}
%   \end{syntax}
%   Indicates that the next \meta{prefix}/\meta{unit}/\meta{power} combination
%   should be highlighted in the specified \meta{color}. In the parsed output,
%   the entire unit combination will be given as the argument to a function
%   \cs{textcolor}, which is assumed to be available at a higher level. In
%   literal mode, the same higher-level \cs{textcolor} will be applied to the
%   next token. It is the responsibility of the calling code to provide an
%   appropriate definition for \cs{textcolor} outside of the scope of the unit
%   parser.
% \end{function}
%
% \begin{function}{\of}
%   \begin{syntax}
%     \meta{prefix} \meta{unit} \meta{power} \cs{of} \Arg{qualifier}
%   \end{syntax}
%   Indicates that the \meta{qualifier} applies to the current
%   \meta{prefix}/\meta{unit}/\meta{power} combination. In parsed mode, the
%   display of the result will depend upon module options. In literal mode,
%   the \meta{qualifier} will be printed in parentheses following the preceding
%   \meta{unit} and a full-width space.
% \end{function}
%
% \begin{function}{\raiseto, \tothe}
%   \begin{syntax}
%     \cs{raiseto} \Arg{power} \meta{prefix} \meta{unit}
%     \meta{prefix} \meta{unit} \cs{tothe} \Arg{power}
%   \end{syntax}
%   Indicates that the \meta{power} applies to the current
%   \meta{prefix}/\meta{unit} combination. As shown, \cs{raiseto} applies to
%   the next \meta{unit} whereas \cs{tothe} applies to the preceding unit. In
%   literal mode the \cs{power} will be printed as a superscript attached to
%   the next token (\cs{raiseto}) or preceding token (\cs{tothe}) as
%   appropriate.
% \end{function}
%
% \subsection{Key--value options for units}
%
% \begin{function}{bracket-unit-denominator}
%   \begin{syntax}
%     |bracket-unit-denominator| = |true|\verb"|"|false|
%   \end{syntax}
%   Switch to determine whether brackets are added to the denominator part of
%   a unit when printed using inline fractional form (with |per-mode| as
%   |repeated-symbol| or |symbol|). The standard setting is |true|.
% \end{function}
%
% \begin{function}{extract-mass-in-kilograms}
%   \begin{syntax}
%     |extract-mass-in-kilograms| = |true|\verb"|"|false|
%   \end{syntax}
%   Determines whether prefix extraction treats kilograms as a base unit; when
%   set |false|, grams are used. The standard setting is |true|.
% \end{function}
%
% \begin{function}{forbid-literal-units}
%   \begin{syntax}
%     |forbid-literal-units| = |true|\verb"|"|false|
%   \end{syntax}
%   Switch which determines if literal units are allowed when parsing is
%   active; does not apply when |parse-units| is |false|.
% \end{function}
%
% \begin{function}{fraction-command}
%   \begin{syntax}
%     |fraction-command| = \meta{command}
%   \end{syntax}
%   Command used to create fractional output when |per-mode| is set to
%   |fraction|. The standard setting is |\frac|.
% \end{function}
%
% \begin{function}{inter-unit-product}
%   \begin{syntax}
%     |inter-unit-product| = \meta{separator}
%   \end{syntax}
%   Inserted between unit combinations in parsed mode, and used to replace
%   |.| and |~| in literal mode. The standard setting is |\,|.
% \end{function}
%
% \begin{function}{parse-units}
%   \begin{syntax}
%     |parse-units| = |true|\verb"|"|false|
%   \end{syntax}
%   Determines whether parsing of unit symbols is attempted or literal
%   mode is used directly. The standard setting is |true|.
% \end{function}
%
% \begin{function}{per-mode, inline-per-mode, display-per-mode}
%   \begin{syntax}
%     |per-mode| = |fraction|\verb"|"|power|\verb"|"|power-positive-first|\verb"|"|repeated-symbol|\verb"|"|single-symbol|\verb"|"|symbol|
%   \end{syntax}
%   Selects how the negative powers (\cs{per}) are formatted: a choice from
%   the options |fraction|, |power|, |power-positive-first|, |repeated-symbol|,
%   |single-symbol| and |symbol|. The option |fraction|
%   generates fractional output when appropriate using the command specified by
%   the |fraction-command| option. The setting |power| uses reciprocal powers
%   leaving the units in the order of input, while |power-positive-first| uses
%   the same display format but sorts units such that the positive powers
%   come before negative ones. The |symbol| setting uses a symbol (specified
%   by |per-symbol|) between positive and negative powers, while
%   |repeated-symbol| uses the same symbol but places it before \emph{every}
%   unit with a negative power (this is mathematically \enquote{wrong} but
%   often seen in real work). The option |single-symbol| will use a symbol if
%   exactly one is required (\foreign{i.e.}~with a single negative power), and
%   will otherwise use powers. The standard setting is |power|.
%
%  The |inline-...| and |display-...| settings take the same options and work
%  in exactly the same way, but are restricted in where they apply. The
%  |display| version only applies in display math contexts, and the |inline|
%  version applies in all others.
% \end{function}
%
% \begin{function}{per-symbol}
%   \begin{syntax}
%     |per-symbol| = \meta{symbol}
%   \end{syntax}
%   Specifies the symbol to be used to denote negative powers when the option
%   |per-mode| is set to |repeated-symbol| or |symbol|. The standard setting
%   is |/|.
% \end{function}
%
% \begin{function}{per-symbol-script-correction}
%   \begin{syntax}
%     |per-symbol-script-correction| = \meta{insert}
%   \end{syntax}
%   Specifies the tokens used to correct spacing when the symbol set by
%   |per-symbol| is immediately preceded by a superscript power. The
%   standard setting is |\!|.
% \end{function}
%
% \begin{function}{power-half-as-sqrt}
%   \begin{syntax}
%     |power-half-as-sqrt| = |true|\verb"|"|false|
%   \end{syntax}
%   Used to determine whether a power of exactly half is converted to
%   \cs{sqrt} in the output. The standard setting is |false|.
% \end{function}
%
% \begin{function}{qualifier-mode}
%   \begin{syntax}
%     |qualifier-mode| = |bracket|\verb"|"|combine|\verb"|"|phrase|\verb"|"|subscript|
%   \end{syntax}
%   Selects how qualifiers are formatted: a choice from the options |bracket|,
%   |combine|, |phrase| and |subscript|. The option |bracket| wraps the
%   qualifier in parenthesis, |combine| joins the qualifier with the unit
%   directly, |phrase| joins the material using |qualifier-phrase| as a link,
%   and |subscript| formats the qualifier as a subscript. The standard setting
%   is |subscript|.
% \end{function}
%
% \begin{function}{qualifier-phrase}
%   \begin{syntax}
%     |qualifier-phrase| = \meta{phrase}
%   \end{syntax}
%   Defines the \meta{phrase} used when |qualifier-mode| is set to |phrase|.
% \end{function}
%
% \begin{function}{sticky-per}
%   \begin{syntax}
%     |sticky-per| = |true|\verb"|"|false|
%   \end{syntax}
%   Used to determine whether \cs{per} should be applied one a unit-by-unit
%   basis (when |false|) or should apply to all following units
%   (when |true|). The latter mode is somewhat akin conceptually to the
%   \TeX{} \cs{over} primitive. The standard setting is |false|.
% \end{function}
%
% \begin{function}{unit-font-command}
%   \begin{syntax}
%     |unit-font-command| = \meta{command}
%   \end{syntax}
%   Command applied to text during output of units: should be command usable
%   in math mode for font selection. Notice that in a typical unit this does
%   not (necessarily) apply to all output, for example powers or brackets.
%   The standard setting is |\mathrm|.
% \end{function}
%
% \end{documentation}
%
% \begin{implementation}
%
% \section{\pkg{siunitx-unit} implementation}
%
% Start the \pkg{DocStrip} guards.
%    \begin{macrocode}
%<*package>
%    \end{macrocode}
%
% Identify the internal prefix.
%    \begin{macrocode}
%<@@=siunitx_unit>
%    \end{macrocode}
%
% \subsection{Initial set up}
%
% The mechanisms defined here need a few variables to exist and to be
% correctly set: these don't belong to one subsection and so are created
% in a small general block.
%
% \begin{variable}{\l_@@_tmp_bool}
% \begin{variable}{\l_@@_tmp_fp}
% \begin{variable}{\l_@@_tmp_int}
% \begin{variable}{\l_@@_tmp_tl}
%   Scratch space.
%    \begin{macrocode}
\bool_new:N \l_@@_tmp_bool
\fp_new:N \l_@@_tmp_fp
\int_new:N \l_@@_tmp_int
\tl_new:N  \l_@@_tmp_tl
%    \end{macrocode}
% \end{variable}
% \end{variable}
% \end{variable}
% \end{variable}
%
% \begin{variable}{\c_@@_math_subscript_tl}
%   Useful tokens with awkward category codes.
%    \begin{macrocode}
\tl_const:Ne \c_@@_math_subscript_tl
  { \char_generate:nn { `\_ } { 8 } }
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_parsing_bool}
%   A boolean is used to indicate when the symbolic unit functions should
%   produce symbolic or literal output. This is used when the symbolic names
%   are used along with literal input, and ensures that there is a sensible
%   fall-back for these cases.
%    \begin{macrocode}
\bool_new:N \l_@@_parsing_bool
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_test_bool}
%   A switch used to indicate that the code is testing the input to find
%   if there is any typeset output from individual unit macros. This is needed
%   to allow the \enquote{base} macros to be found, and also to pick up the
%   difference between symbolic and literal unit input.
%    \begin{macrocode}
\bool_new:N \l_@@_test_bool
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}{\@@_if_symbolic:nTF}
%   The test for symbolic units is needed in two places. First, there is the
%   case of \enquote{pre-parsing} input to check if it can be parsed. Second,
%   when parsing there is a need to check if the current unit is built up
%   from others (symbolic) or is defined in terms of some literals. To do this,
%   the approach used is to set all of the symbolic unit commands expandable
%   and to do nothing, with the few special cases handled manually. We expand
%   the input here twice: this handles the case where there is a mapping or
%   similar in |#1| which returns its result in \cs{exp_not:n}. In the second
%   \tn{protected@edef}, changing the meaning of \tn{@unexpandable@protect}
%   allows removal of a literal \cs{protect} at the top level before
%   known symbolic entries: this deals with the case where the user has
%   put in a \cs{protect} for some edge cases.
%    \begin{macrocode}
\prg_new_protected_conditional:Npnn \@@_if_symbolic:n #1 { TF }
  {
    \group_begin:
      \bool_set_true:N \l_@@_test_bool
      \protected@edef \l_@@_tmp_tl {#1}
      \cs_set_eq:NN \@@_saved_@unexpandable@protect: \@unexpandable@protect
      \cs_set_nopar:Npn \@unexpandable@protect ##1
        {
          \cs_if_exist:cF { @@_ \token_to_str:N ##1 :w }
            { \@@_saved_@unexpandable@protect: }
              ##1
        }
      \protected@edef \l_@@_tmp_tl { \l_@@_tmp_tl }
    \exp_args:NNV \group_end:
    \tl_if_blank:nTF \l_@@_tmp_tl
      { \prg_return_true: }
      { \prg_return_false: }
  }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Defining symbolic unit}
%
% Unit macros and related support are created here. These exist only within
% the scope of the unit processor code, thus not polluting document-level
% namespace and allowing overlap with other areas in the case of useful short
% names (for example \cs{pm}). Setting up the mechanisms to allow this requires
% a few additional steps on top of simply saving the data given by the user
% in creating the unit.
%
% \begin{variable}{\l_siunitx_unit_symbolic_seq}
%   A list of all of the symbolic units, \foreign{etc.}, set up. This is needed
%   to allow the symbolic names to be defined within the scope of the unit
%   parser but not elsewhere using simple mappings.
%    \begin{macrocode}
\seq_new:N \l_siunitx_unit_symbolic_seq
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_siunitx_unit_seq}
%   A second list featuring only the units themselves.
%    \begin{macrocode}
\seq_new:N \l_siunitx_unit_seq
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}{\@@_set_symbolic:Nnn}
% \begin{macro}{\@@_set_symbolic:Npnn}
% \begin{macro}{\@@_set_symbolic:Nnnn}
%   The majority of the work for saving each symbolic definition is the same
%   irrespective of the item being defined (unit, prefix, power, qualifier).
%   This is therefore all carried out in a single internal function which
%   does the common tasks. The three arguments here are the symbolic macro
%   name, the literal output and the code to insert when doing full unit
%   parsing. To allow for the \enquote{special cases} (where arguments are
%   required) the entire mechanism is set up in a two-part fashion allowing
%   for flexibility at the slight cost of additional functions.
%
%   Importantly, notice that the unit macros are declared as expandable. This
%   is required so that literals can be correctly converted into a token list
%   of material which does not depend on local redefinitions for the unit
%   macros. That is required so that the unit formatting system can be grouped.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_set_symbolic:Nnn #1
  { \@@_set_symbolic:Nnnn #1 { } }
\cs_new_protected:Npn \@@_set_symbolic:Npnn #1#2#
  { \@@_set_symbolic:Nnnn #1 {#2} }
\cs_new_protected:Npn \@@_set_symbolic:Nnnn #1#2#3#4
  {
    \seq_put_right:Nn \l_siunitx_unit_symbolic_seq {#1}
    \cs_set:cpn { @@_ \token_to_str:N #1 :w } #2
      {
        \bool_if:NF \l_@@_test_bool
          {
            \bool_if:NTF \l_@@_parsing_bool
              {#4}
              {#3}
          }
      }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\siunitx_declare_power:NNn}
%   Powers can come either before or after the unit. As they always come
%   (logically) in matching, we handle this by declaring two commands,
%   and setting each up separately.
%    \begin{macrocode}
\cs_new_protected:Npn \siunitx_declare_power:NNn #1#2#3
  {
    \@@_set_symbolic:Nnn #1
      { \@@_literal_power:nn {#3} }
      { \@@_parse_power:nnN {#1} {#3} \c_true_bool }
    \@@_set_symbolic:Nnn #2
      { ^ {#3} }
      { \@@_parse_power:nnN {#2} {#3} \c_false_bool }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\siunitx_declare_prefix:Nn}
% \begin{macro}{\siunitx_declare_prefix:Nnn, \siunitx_declare_prefix:Nne}
% \begin{variable}
%   {\l_@@_prefixes_forward_prop, \l_@@_prefixes_reverse_prop}
%   For prefixes there are a couple of options. In all cases, the basic
%   requirement is to set up to parse the prefix using the appropriate
%   internal function. For prefixes which are powers of $10$, there is also
%   the need to be able to do conversion to/from the numerical equivalent.
%   That is handled using two properly lists which can be used to supply
%   the conversion data later.
%    \begin{macrocode}
\cs_new_protected:Npn \siunitx_declare_prefix:Nn #1#2
  {
    \@@_set_symbolic:Nnn #1
      {#2}
      { \@@_parse_prefix:Nn #1 {#2} }
  }
\cs_new_protected:Npn \siunitx_declare_prefix:Nnn #1#2#3
  {
    \siunitx_declare_prefix:Nn #1 {#3}
    \prop_put:Nnn \l_@@_prefixes_forward_prop {#3} {#2}
    \prop_put:Nnn \l_@@_prefixes_reverse_prop {#2} {#3}
  }
\cs_generate_variant:Nn \siunitx_declare_prefix:Nnn { Nne , Nnx }
\prop_new:N \l_@@_prefixes_forward_prop
\prop_new:N \l_@@_prefixes_reverse_prop
%    \end{macrocode}
% \end{variable}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\siunitx_declare_qualifier:Nn}
%   Qualifiers are relatively easy to handle: nothing to do other than save
%   the input appropriately.
%    \begin{macrocode}
\cs_new_protected:Npn \siunitx_declare_qualifier:Nn #1#2
  {
    \@@_set_symbolic:Nnn #1
      { ~ ( #2 ) }
      { \@@_parse_qualifier:nn {#1} {#2} }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\siunitx_declare_unit:Nn, \siunitx_declare_unit:Ne}
% \begin{macro}{\siunitx_declare_unit:Nnn, \siunitx_declare_unit:Nen}
%   For the unit parsing, allowing for variations in definition order requires
%   that a test is made for the output of each unit at point of use.
%    \begin{macrocode}
\cs_new_protected:Npn \siunitx_declare_unit:Nn #1#2
  { \siunitx_declare_unit:Nnn #1 {#2} { } }
\cs_generate_variant:Nn \siunitx_declare_unit:Nn { Ne , Nx }
\cs_new_protected:Npn \siunitx_declare_unit:Nnn #1#2#3
  {
    \seq_put_right:Nn \l_siunitx_unit_seq {#1}
    \@@_set_symbolic:Nnn #1
      {#2}
      {
        \@@_if_symbolic:nTF {#2}
          {#2}
          { \@@_parse_unit:Nn #1 {#2} }
      }
    \siunitx_unit_options_declare:Nn #1 {#3}
  }
\cs_generate_variant:Nn \siunitx_declare_unit:Nnn { Ne , Nx }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \subsection{Applying unit options}
%
% \begin{macro}{\siunitx_unit_options_declare:Nn}
%   For setting options for existing units without needing to alter the
%   symbol.
%    \begin{macrocode}
\cs_new_protected:Npn \siunitx_unit_options_declare:Nn #1#2
  {
    \tl_clear_new:c { l_@@_options_ \token_to_str:N #1 _tl }
    \tl_set:cn { l_@@_options_ \token_to_str:N #1 _tl } {#2}
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{variable}{\l_@@_active_opts_str}
%   Tracks which unit, if any, is currently \enquote{live} for applied
%   options.
%    \begin{macrocode}
\str_new:N \l_@@_active_opts_str
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}{\siunitx_unit_options_apply:n}
%   Options apply only if they have not already been set at this group
%   level.
%    \begin{macrocode}
\cs_new_protected:Npn \siunitx_unit_options_apply:n #1
  {
    \tl_if_single_token:nT {#1}
      {
        \tl_if_exist:cT { l_@@_options_ \token_to_str:N #1 _tl }
          {
            \str_if_eq:VnF \l_@@_active_opts_str {#1}
              {
                \keys_set:nv { siunitx }
                  { l_@@_options_ \token_to_str:N #1 _tl }
                \str_set:Nn \l_@@_active_opts_str {#1}
              }
          }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Non-standard symbolic units}
%
% A few of the symbolic units require non-standard definitions: these are
% created here. They all use parts of the more general code but have particular
% requirements which can only be addressed by hand. Some of these could in
% principle be used in place of the dedicated definitions above, but at point
% of use that would then require additional expansions for each unit parsed:
% as the macro names would still be needed, this does not offer any real
% benefits.
%
% \begin{macro}{\per}
%   The \cs{per} symbolic unit is a bit special: it has a mechanism entirely
%   different from everything else, so has to be set up by hand. In literal
%   mode it is represented by a very simple symbol!
%    \begin{macrocode}
\@@_set_symbolic:Nnn \per
  { / }
  { \@@_parse_per: }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\cancel}
% \begin{macro}{\highlight}
%   The two special cases, \cs{cancel} and \cs{highlight}, are easy to deal
%   with when parsing. When not parsing, a precaution is taken to ensure that
%   the user level equivalents always get a braced argument.
%    \begin{macrocode}
\@@_set_symbolic:Npnn \cancel
  { }
  { \@@_parse_special:n { \cancel } }
\@@_set_symbolic:Npnn \highlight #1
  { \@@_literal_special:nN { \textcolor {#1} } }
  { \@@_parse_special:n { \textcolor {#1} } }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\of}
%   The generic qualifier is simply the same as the dedicated ones except for
%   needing to grab an argument.
%    \begin{macrocode}
\@@_set_symbolic:Npnn \of #1
  { \  ( #1 ) }
  { \@@_parse_qualifier:nn { \of {#1} } {#1} }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\raiseto, \tothe}
%   Generic versions of the pre-defined power macros. These require an
%   argument and so cannot be handled using the general approach. Other than
%   that, the code here is very similar to that in
%   \cs{siunitx_unit_power_set:NnN}.
%    \begin{macrocode}
\@@_set_symbolic:Npnn \raiseto #1
  { \@@_literal_power:nn {#1} }
  { \@@_parse_power:nnN { \raiseto {#1} } {#1} \c_true_bool }
\@@_set_symbolic:Npnn \tothe #1
  { ^ {#1} }
  { \@@_parse_power:nnN { \tothe {#1} } {#1} \c_false_bool }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Main formatting routine}
%
% Unit input can take two forms, \enquote{literal} units (material to be
% typeset directly) or \enquote{symbolic} units (macro-based). Before any
% parsing or typesetting is carried out, a small amount of pre-parsing has to
% be carried out to decide which of these cases applies.
%
% \begin{variable}
%   {\l_siunitx_unit_font_tl, \l_@@_product_tl, \l_@@_mass_kilogram_bool}
%   Options which apply to the main formatting routine, and so are not tied
%   to either symbolic or literal input.
%    \begin{macrocode}
\keys_define:nn { siunitx }
  {
    extract-mass-in-kilograms .bool_set:N =
      \l_@@_mass_kilogram_bool ,
    inter-unit-product .tl_set:N =
      \l_@@_product_tl ,
    unit-font-command .tl_set:N =
      \l_siunitx_unit_font_tl
  }
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_formatted_tl}
%   A token list for the final formatted result: may or may not be generated
%   by the parser, depending on the nature of the input.
%    \begin{macrocode}
\tl_new:N \l_@@_formatted_tl
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}{\siunitx_unit_format:nN, \siunitx_unit_format:VN}
% \begin{macro}{\siunitx_unit_format_extract_prefixes:nNN}
% \begin{macro}{\siunitx_unit_format_combine_exponent:nnN}
% \begin{macro}{\siunitx_unit_format_multiply:nnN}
% \begin{macro}{\siunitx_unit_format_multiply_extract_prefixes:nnNN}
% \begin{macro}{\siunitx_unit_format_multiply_combine_exponent:nnnN}
% \begin{macro}{\@@_format:nNN}
% \begin{macro}{\@@_format_aux:}
%   Formatting parsed units can take place either with the prefixes printed or
%   separated out into a power of ten. This variation is handled using two
%   separate functions: as this submodule does not really deal with numbers,
%   formatting the numeral part here would be tricky and it is better therefore
%   to have a mechanism to return a simple numerical power. At the same time,
%   most uses will no want this more complex return format and so a version of
%   the code which does not do this is also provided.
%
%   The main unit formatting routine groups all of the parsing/formatting, so
%   that the only value altered will be the return token list. As definitions
%   for the various unit macros are not globally created, the first step is to
%   map over the list of names and active the unit definitions: these do
%   different things depending on the switches set. There is then a decision to
%   be made: is the unit input one that can be parsed (\enquote{symbolic}), or
%   is one containing one or more literals. In the latter case, there is a
%   still the need to convert the input into an expanded token list as some
%   parts of the input could still be using unit macros.
%
%   Notice that for \cs{siunitx_unit_format:nN} a second return value from the
%   auxiliary has to be allowed for, but is simply discarded.
%    \begin{macrocode}
\cs_new_protected:Npn \siunitx_unit_format:nN #1#2
  {
    \bool_set_false:N \l_@@_prefix_exp_bool
    \fp_zero:N \l_@@_combine_exp_fp
    \fp_set:Nn \l_@@_multiple_fp { \c_one_fp }
    \@@_format:nNN {#1} #2 \l_@@_tmp_fp
  }
\cs_generate_variant:Nn \siunitx_unit_format:nN { V }
\cs_new_protected:Npn \siunitx_unit_format_extract_prefixes:nNN #1#2#3
  {
    \bool_set_true:N \l_@@_prefix_exp_bool
    \fp_zero:N \l_@@_combine_exp_fp
    \fp_set:Nn \l_@@_multiple_fp { \c_one_fp }
    \@@_format:nNN {#1} #2 #3
  }
\cs_new_protected:Npn \siunitx_unit_format_combine_exponent:nnN #1#2#3
  {
    \bool_set_false:N \l_@@_prefix_exp_bool
    \fp_set:Nn \l_@@_combine_exp_fp {#2}
    \fp_set:Nn \l_@@_multiple_fp { \c_one_fp }
    \@@_format:nNN {#1} #3 \l_@@_tmp_fp
  }
\cs_new_protected:Npn \siunitx_unit_format_multiply:nnN #1#2#3
  {
    \bool_set_false:N \l_@@_prefix_exp_bool
    \fp_zero:N \l_@@_combine_exp_fp
    \fp_set:Nn \l_@@_multiple_fp {#2}
    \@@_format:nNN {#1} #3 \l_@@_tmp_fp
  }
\cs_new_protected:Npn \siunitx_unit_format_multiply_extract_prefixes:nnNN
  #1#2#3#4
  {
    \bool_set_true:N \l_@@_prefix_exp_bool
    \fp_zero:N \l_@@_combine_exp_fp
    \fp_set:Nn \l_@@_multiple_fp {#2}
    \@@_format:nNN {#1} #3 #4
  }
\cs_new_protected:Npn \siunitx_unit_format_multiply_combine_exponent:nnnN
  #1#2#3#4
  {
    \bool_set_false:N \l_@@_prefix_exp_bool
    \fp_set:Nn \l_@@_combine_exp_fp {#3}
    \fp_set:Nn \l_@@_multiple_fp {#2}
    \@@_format:nNN {#1} #4 \l_@@_tmp_fp
  }
\cs_new_protected:Npn \@@_format:nNN #1#2#3
  {
    \group_begin:
      \seq_map_inline:Nn \l_siunitx_unit_symbolic_seq
        { \cs_set_eq:Nc ##1 { @@_ \token_to_str:N ##1 :w } }
      \tl_clear:N \l_@@_formatted_tl
      \fp_zero:N \l_@@_prefix_fp
      \bool_if:NTF \l_@@_parse_bool
        {
          \@@_if_symbolic:nTF {#1}
            {
              \@@_parse:n {#1}
              \prop_if_empty:NF \l_@@_parsed_prop
                { \@@_format_parsed: }
            }
            {
              \bool_if:NTF \l_@@_forbid_literal_bool
                { \msg_error:nnn { siunitx } { literal-unit } {#1} }
                { \@@_format_literal:n {#1} }
            }
        }
        { \@@_format_literal:n {#1} }
      \cs_set_protected:Npe \@@_format_aux:
        {
          \tl_set:Nn \exp_not:N #2
            { \exp_not:V \l_@@_formatted_tl }
          \fp_set:Nn \exp_not:N #3
            { \fp_use:N \l_@@_prefix_fp }
        }
    \exp_after:wN \group_end:
    \@@_format_aux:
  }
\cs_new_protected:Npn \@@_format_aux: { }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \subsection{Formatting literal units}
%
% While in literal mode no parsing occurs, there is a need to provide a few
% auxiliary functions to handle one or two special cases.
%
% \begin{macro}[EXP]{\@@_literal_power:nn}
%   For printing literal units which are given before the unit they apply to,
%   there is a slight rearrangement. This is ex[EXP]pandable to cover the case
%   of creation of a PDF string.
%    \begin{macrocode}
\cs_new:Npn \@@_literal_power:nn #1#2 { #2 ^ {#1} }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_literal_special:nN}
%   When dealing with the special cases, there is an argument to absorb. This
%   should be braced to be passed up to the user level, which is dealt with
%   here.
%    \begin{macrocode}
\cs_new:Npn \@@_literal_special:nN #1#2 { #1 {#2} }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_format_literal:n}
% \begin{macro}
%   {
%     \@@_format_literal_tilde:      ,
%     \@@_format_literal_subscript:  ,
%     \@@_format_literal_superscript:
%   }
% \begin{macro}{\@@_format_literal_auxi:w}
% \begin{macro}{\@@_format_literal_auxii:w}
% \begin{macro}{\@@_format_literal_auxiii:w}
% \begin{macro}{\@@_format_literal_auxiv:n}
% \begin{macro}{\@@_format_literal_auxv:nw}
% \begin{macro}
%   {
%     \@@_format_literal_auxvi:nN   ,
%     \@@_format_literal_auxvii:nN  ,
%     \@@_format_literal_auxviii:nN
%   }
% \begin{macro}{\@@_format_literal_super:nn, \@@_format_literal_sub:nn}
% \begin{macro}{\@@_format_literal_add:n}
% \begin{macro}{\@@_format_literal_auxix:nn}
% \begin{macro}{\@@_format_literal_auxx:nw}
% \begin{variable}{\l_@@_separator_tl}
%   To format literal units, there are two tasks to do. The input is
%   \texttt{x}-type expanded to force any symbolic units to be converted into
%   their literal representation: this requires setting the appropriate
%   switch. In the resulting token list, all |.| and |~| tokens are then
%   replaced by the current unit product token list. To enable this to happen
%   correctly with a normal (active) |~|, a small amount of
%   \enquote{protection} is needed first. To cover active sub- and superscript
%   tokens, appropriate definitions are provided at this stage. Those have
%   to be expandable macros rather than implicit character tokens.
%
%   As with other code dealing with user input, \cs{protected@edef} is used
%   here rather than \cs{tl_set:Ne} as \LaTeXe{} robust commands may be
%   present.
%    \begin{macrocode}
\group_begin:
  \char_set_catcode_active:n { `\~ }
  \cs_new_protected:Npe \@@_format_literal:n #1
    {
      \group_begin:
        \exp_not:n { \bool_set_false:N \l_@@_parsing_bool }
        \tl_set:Nn \exp_not:N \l_@@_tmp_tl {#1}
        \tl_replace_all:Nnn \exp_not:N \l_@@_tmp_tl
          { \token_to_str:N ^ } { ^ }
        \tl_replace_all:Nnn \exp_not:N \l_@@_tmp_tl
          { \token_to_str:N _ } { \c_@@_math_subscript_tl }
        \cs_set_eq:NN \exp_not:N \text \scan_stop:
        \char_set_active_eq:NN ^
          \exp_not:N \@@_format_literal_superscript:
        \char_set_active_eq:NN _
          \exp_not:N \@@_format_literal_subscript:
        \char_set_active_eq:NN \exp_not:N ~
          \exp_not:N \@@_format_literal_tilde:
        \exp_not:n
          {
            \protected@edef \l_@@_tmp_tl
              { \l_@@_tmp_tl }
            \tl_clear:N \l_@@_formatted_tl
            \tl_if_empty:NF \l_@@_tmp_tl
              {
                \exp_after:wN \@@_format_literal_auxi:w
                  \l_@@_tmp_tl .
                  \q_recursion_tail . \q_recursion_stop
              }
            \exp_args:NNNV \group_end:
            \tl_set:Nn \l_@@_formatted_tl
              \l_@@_formatted_tl
          }
    }
\group_end:
\cs_new:Npe \@@_format_literal_subscript: { \c_@@_math_subscript_tl }
\cs_new:Npn \@@_format_literal_superscript: { ^ }
\cs_new:Npn \@@_format_literal_tilde: { . }
%    \end{macrocode}
%   To introduce the font changing commands while still allowing for line
%   breaks in literal units, a loop is needed to replace one |.| at a time.
%   To also allow for division, a second loop is used within that to handle
%   |/|: as a result, the separator between parts has to be tracked.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_format_literal_auxi:w #1 .
  {
    \quark_if_recursion_tail_stop:n {#1}
    \@@_format_literal_auxii:n {#1}
    \tl_set_eq:NN \l_@@_separator_tl \l_@@_product_tl
    \@@_format_literal_auxi:w
  }
\cs_set_protected:Npn \@@_format_literal_auxii:n #1
  {
    \@@_format_literal_auxiii:w
      #1 / \q_recursion_tail / \q_recursion_stop
  }
\cs_new_protected:Npn \@@_format_literal_auxiii:w #1 /
  {
    \quark_if_recursion_tail_stop:n {#1}
    \@@_format_literal_auxiv:n {#1}
    \tl_set:Nn \l_@@_separator_tl { / }
    \@@_format_literal_auxiii:w
  }
\cs_new_protected:Npn \@@_format_literal_auxiv:n #1
  {
    \@@_format_literal_auxv:nw { }
      #1 \q_recursion_tail \q_recursion_stop
  }
%    \end{macrocode}
%   To deal properly with literal formatting, we have to worry about super-
%   and subscript markers. That can be complicated as they could come anywhere
%   in the input: we handle that by iterating through the input and picking
%   them out. This avoids any issue with losing braces for mid-input scripts.
%   We also have to deal with fractions, hence needing a series of nested
%   loops and a change of separator.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_format_literal_auxv:nw
  #1#2 \q_recursion_stop
  {
    \tl_if_head_is_N_type:nTF {#2}
      { \@@_format_literal_auxvi:nN }
      {
        \tl_if_head_is_group:nTF {#2}
          { \@@_format_literal_auxix:nn }
          { \@@_format_literal_auxx:nw }
      }
        {#1} #2 \q_recursion_stop
  }
\cs_new_protected:Npe \@@_format_literal_auxvi:nN #1#2
  {
    \exp_not:N \quark_if_recursion_tail_stop_do:Nn #2
      { \exp_not:N \@@_format_literal_add:n {#1} }
    \exp_not:N \token_if_eq_meaning:NNTF #2 ^
      { \exp_not:N \@@_format_literal_super:nn {#1} }
      {
        \exp_not:N \token_if_eq_meaning:NNTF
          #2 \c_@@_math_subscript_tl
          { \exp_not:N \@@_format_literal_sub:nn {#1} }
          { \exp_not:N \@@_format_literal_auxvii:nN {#1} #2 }
      }
  }
%    \end{macrocode}
%   We need to make sure |\protect| sticks with the next token.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_format_literal_auxvii:nN #1#2
  {
    \str_if_eq:nnTF {#2} { \protect }
      { \@@_format_literal_auxviii:nN {#1} }
      { \@@_format_literal_auxv:nw {#1#2} }
  }
\cs_new_protected:Npn \@@_format_literal_auxviii:nN #1#2
  { \@@_format_literal_auxv:nw { #1 \protect #2 } }
\cs_new_protected:Npn \@@_format_literal_super:nn #1#2
  {
    \quark_if_recursion_tail_stop:n {#2}
    \@@_format_literal_add:n {#1}
    \tl_put_right:Nn \l_@@_formatted_tl { ^ {#2} }
    \@@_format_literal_auxvi:nN { }
  }
\cs_new_protected:Npe \@@_format_literal_sub:nn #1#2
  {
    \exp_not:N \quark_if_recursion_tail_stop:n {#2}
    \exp_not:N \@@_format_literal_add:n {#1}
    \tl_put_right:Ne \exp_not:N \l_@@_formatted_tl
      {
        \c_@@_math_subscript_tl
          {
            \exp_not:N \exp_not:V
              \exp_not:N \l_siunitx_unit_font_tl
                { \exp_not:N \exp_not:n {#2} }
          }
      }
    \exp_not:N \@@_format_literal_auxvi:nN { }
  }
\cs_new_protected:Npn \@@_format_literal_add:n #1
  {
    \tl_put_right:Ne \l_@@_formatted_tl
      {
        \tl_if_empty:NF \l_@@_formatted_tl
          { \exp_not:V \l_@@_separator_tl }
        \tl_if_empty:nF {#1}
          { \exp_not:V \l_siunitx_unit_font_tl { \exp_not:n {#1} } }
      }
    \tl_clear:N \l_@@_separator_tl
  }
\cs_new_protected:Npn \@@_format_literal_auxix:nn #1#2
  { \@@_format_literal_auxv:nw { #1 {#2} } }
\use:e
  {
    \cs_new_protected:Npn \exp_not:N \@@_format_literal_auxx:nw
      #1 \c_space_tl
  }
  { \@@_format_literal_auxv:nw {#1} }
\tl_new:N \l_@@_separator_tl
%    \end{macrocode}
% \end{variable}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \subsection{(PDF) String creation}
%
% \begin{macro}{\siunitx_unit_pdfstring_context:}
%   A simple function that sets up to make units equal to their text
%   representation.
%    \begin{macrocode}
\cs_new_protected:Npn \siunitx_unit_pdfstring_context:
  {
    \bool_set_false:N \l_@@_parsing_bool
    \seq_map_inline:Nn \l_siunitx_unit_symbolic_seq
      { \cs_set_eq:Nc ##1 { @@_ \token_to_str:N ##1 :w } }
  }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Parsing symbolic units}
%
% Parsing units takes place by storing information about each unit in a
% \texttt{prop}. As well as the unit itself, there are various other optional
% data points, for example a prefix or a power. Some of these can come before
% the unit, others only after. The parser therefore tracks the number of units
% read and uses the current position to allocate data to individual units.
%
% The result of parsing is a property list (\cs{l_@@_parsed_prop}) which
% contains one or more entries for each unit:
% \begin{itemize}
%   \item \texttt{prefix-$n$} The symbol for the prefix which applies to this
%     unit, \foreign{e.g.} for \cs{kilo} with (almost certainly) would be
%     |k|.
%   \item \texttt{unit-$n$} The symbol for the unit itself, \foreign{e.g.}~for
%     \cs{metre} with (almost certainly) would be |m|.
%   \item \texttt{power-$n$} The power which a unit is raised to. During
%     initial parsing this will (almost certainly) be positive, but is combined
%     with \texttt{per-$n$} to give a \enquote{fully qualified} power before
%     any formatting takes place
%   \item \texttt{per-$n$} Indicates that \texttt{per} applies to the current
%     unit: stored during initial parsing then combined with \texttt{power-$n$}
%     (and removed from the list) before further work.
%   \item \texttt{qualifier-$n$} Any qualifier which applies to the current
%     unit.
%   \item \texttt{special-$n$} Any \enquote{special effect} to apply to the
%     current unit.
%   \item \texttt{command-$1$} The command corresponding to \texttt{unit-$n$}:
%     needed to track base units; used for \cs{gram} only.
% \end{itemize}
%
% \begin{variable}{\l_@@_sticky_per_bool}
%   There is one option when \emph{parsing} the input (as opposed to
%   \emph{formatting} for output): how to deal with \cs{per}.
%    \begin{macrocode}
\keys_define:nn { siunitx }
  {
    sticky-per .bool_set:N = \l_@@_sticky_per_bool
  }
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_parsed_prop}
% \begin{variable}{\l_@@_per_bool}
% \begin{variable}{\l_@@_position_int}
%   Parsing units requires a small number of variables are available: a
%   \texttt{prop} for the parsed units themselves, a \texttt{bool} to
%   indicate if \cs{per} is active and an \texttt{int} to track how many units
%   have be parsed.
%    \begin{macrocode}
\prop_new:N \l_@@_parsed_prop
\bool_new:N \l_@@_per_bool
\int_new:N \l_@@_position_int
%    \end{macrocode}
% \end{variable}
% \end{variable}
% \end{variable}
%
% \begin{macro}{\@@_parse:n}
%   The main parsing function is quite simple. After initialising the variables,
%   each symbolic unit is set up. The input is then simply inserted into the
%   input stream: the symbolic units themselves then do the real work of
%   placing data into the parsing system. There is then a bit of tidying up to
%   ensure that later stages can rely on the nature of the data here.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_parse:n #1
  {
    \prop_clear:N \l_@@_parsed_prop
    \bool_set_true:N \l_@@_parsing_bool
    \bool_set_false:N \l_@@_per_bool
    \bool_set_false:N \l_@@_test_bool
    \int_zero:N \l_@@_position_int
    \siunitx_unit_options_apply:n {#1}
    #1
    \int_step_inline:nn \l_@@_position_int
      { \@@_parse_finalise:n {##1} }
    \@@_parse_finalise:
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_parse_add:nnnn}
%   In all cases, storing a data item requires setting a temporary \texttt{tl}
%   which will be used as the key, then using this to store the value. The
%   \texttt{tl} is  set using \texttt{x}-type expansion as this will expand the
%   unit index and any additional calculations made for this.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_parse_add:nnnn #1#2#3#4
  {
    \tl_set:Ne \l_@@_tmp_tl { #1 - #2 }
    \prop_if_in:NVTF \l_@@_parsed_prop
      \l_@@_tmp_tl
      {
        \msg_error:nnee { siunitx } { duplicate-part }
          { \exp_not:n {#1} } { \token_to_str:N #3 }
      }
      {
        \prop_put:NVn \l_@@_parsed_prop
          \l_@@_tmp_tl {#4}
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_parse_prefix:Nn}
% \begin{macro}{\@@_parse_power:nnN}
% \begin{macro}{\@@_parse_qualifier:nn}
% \begin{macro}{\@@_parse_special:n}
%   Storage of the various optional items follows broadly the same pattern
%   in each case. The data to be stored is passed along with an appropriate
%   key name to the underlying storage system. The details for each type of
%   item should be relatively clear. For example, prefixes have to come before
%   their \enquote{parent} unit and so there is some adjustment to do to add
%   them to the correct unit.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_parse_prefix:Nn #1#2
  {
    \int_set:Nn \l_@@_tmp_int { \l_@@_position_int + 1 }
    \@@_parse_add:nnnn { prefix }
      { \int_use:N \l_@@_tmp_int } {#1} {#2}
  }
\cs_new_protected:Npn \@@_parse_power:nnN #1#2#3
  {
    \tl_set:Ne \l_@@_tmp_tl
      { unit- \int_use:N \l_@@_position_int }
    \bool_lazy_or:nnTF
      {#3}
      {
        \prop_if_in_p:NV
          \l_@@_parsed_prop \l_@@_tmp_tl
      }
      {
        \@@_parse_add:nnnn { power }
          {
            \int_eval:n
              { \l_@@_position_int \bool_if:NT #3 { + 1 } }
          }
          {#1} {#2}
      }
      {
        \msg_error:nnee { siunitx }
          { part-before-unit } { power } { \token_to_str:N #1 }
      }
  }
\cs_new_protected:Npn \@@_parse_qualifier:nn #1#2
  {
    \tl_set:Ne \l_@@_tmp_tl
      { unit- \int_use:N \l_@@_position_int }
    \prop_if_in:NVTF \l_@@_parsed_prop \l_@@_tmp_tl
      {
        \@@_parse_add:nnnn { qualifier }
          { \int_use:N \l_@@_position_int } {#1} {#2}
      }
      {
        \msg_error:nnnn { siunitx }
          { part-before-unit } { qualifier } { \token_to_str:N #1 }
      }
  }
%    \end{macrocode}
%  Special (exceptional) items should always come before the relevant units.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_parse_special:n #1
  {
    \@@_parse_add:nnnn { special }
      { \int_eval:n { \l_@@_position_int + 1 } }
      {#1} {#1}
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_parse_unit:Nn}
%   Parsing units is slightly more involved than the other cases: this is the
%   one place where the tracking value is incremented.  If the switch
%   \cs{l_@@_per_bool} is set true then the current unit is also
%   reciprocal: this can only happen if \cs{l_@@_sticky_per_bool} is also
%   true, so only one test is required.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_parse_unit:Nn #1#2
  {
    \int_incr:N \l_@@_position_int
    \tl_if_eq:nnT {#1} { \gram }
      {
        \@@_parse_add:nnnn { command }
          { \int_use:N \l_@@_position_int }
          {#1} {#1}
      }
    \@@_parse_add:nnnn { unit }
      { \int_use:N \l_@@_position_int }
      {#1} {#2}
    \bool_if:NT \l_@@_per_bool
      {
        \@@_parse_add:nnnn { per }
          { \int_use:N \l_@@_position_int }
          { \per } { true }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_parse_per:}
%   Storing the \cs{per} command requires adding a data item separate from
%   the power which applies: this makes later formatting much more
%   straight-forward. This data could in principle be combined with the
%   \texttt{power}, but depending on the output format required that may make
%   life  more complex. Thus this information is stored separately for later
%   retrieval. If \cs{per} is set to be \enquote{sticky} then after parsing
%   the first occurrence, any further uses are in error.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_parse_per:
  {
    \bool_if:NTF \l_@@_sticky_per_bool
      {
        \bool_set_true:N \l_@@_per_bool
        \cs_set_protected:Npn \per
          { \msg_error:nn { siunitx } { duplicate-sticky-per } }
      }
      {
        \@@_parse_add:nnnn
          { per } { \int_eval:n { \l_@@_position_int + 1 } }
          { \per } { true }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_parse_finalise:n}
%   If \cs{per} applies to the current unit, the power needs to be multiplied
%   by $-1$. That is done using an \texttt{fp} operation so that non-integer
%   powers are supported. The flag for \cs{per} is also removed as this means
%   we don't have to check that the original power was positive. To be on
%   the safe side, there is a check for a trivial power at this stage.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_parse_finalise:n #1
  {
    \tl_set:Ne \l_@@_tmp_tl { per- #1 }
    \prop_if_in:NVT \l_@@_parsed_prop \l_@@_tmp_tl
      {
        \prop_remove:NV \l_@@_parsed_prop
          \l_@@_tmp_tl
        \tl_set:Ne \l_@@_tmp_tl { power- #1 }
        \prop_get:NVNTF
          \l_@@_parsed_prop
          \l_@@_tmp_tl
          \l_@@_part_tl
          {
            \tl_set:Ne \l_@@_part_tl
              { \fp_eval:n { \l_@@_part_tl * -1 } }
            \fp_compare:nNnTF \l_@@_part_tl = 1
              {
                \prop_remove:NV \l_@@_parsed_prop
                  \l_@@_tmp_tl
              }
              {
                \prop_put:NVV \l_@@_parsed_prop
                  \l_@@_tmp_tl \l_@@_part_tl
              }
          }
          {
            \prop_put:NVn \l_@@_parsed_prop
              \l_@@_tmp_tl { -1 }
          }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_parse_finalise:}
%   The final task is to check that there is not a \enquote{dangling} power
%   or prefix: these are added to the \enquote{next} unit so are easy to
%   test for.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_parse_finalise:
  {
    \clist_map_inline:nn { per , power , prefix }
      {
        \tl_set:Ne \l_@@_tmp_tl
          { ##1 - \int_eval:n { \l_@@_position_int + 1 } }
        \prop_if_in:NVT \l_@@_parsed_prop \l_@@_tmp_tl
          { \msg_error:nnn { siunitx } { dangling-part } { ##1 } }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Formatting parsed units}
%
% \begin{variable}
%   {
%     \l_siunitx_unit_fraction_tl    ,
%     \l_@@_denominator_bracket_bool ,
%     \l_@@_forbid_literal_bool      ,
%     \l_@@_parse_bool               ,
%     \l_@@_per_symbol_tl            ,
%     \l_@@_per_script_tl            ,
%     \l_@@_half_sqrt_bool           ,
%     \l_@@_qualifier_mode_str       ,
%     \l_@@_qualifier_phrase_tl
%   }
%   Set up the options which apply to formatting.
%    \begin{macrocode}
\keys_define:nn { siunitx }
  {
    bracket-unit-denominator .bool_set:N =
      \l_@@_denominator_bracket_bool ,
    display-per-mode .choices:nn =
      {
        fraction             ,
        power                ,
        power-positive-first , 
        repeated-symbol      ,
        symbol               ,
        single-symbol
      }
      { \str_set:Nn \l_@@_per_display_str {#1} } ,
    forbid-literal-units .bool_set:N =
      \l_@@_forbid_literal_bool ,
    fraction-command .tl_set:N =
      \l_siunitx_unit_fraction_tl ,
    parse-units .bool_set:N =
      \l_@@_parse_bool ,
    inline-per-mode .choices:nn =
      {
        fraction             ,
        power                ,
        power-positive-first , 
        repeated-symbol      ,
        symbol               ,
        single-symbol
      }
      { \str_set:Nn \l_@@_per_inline_str {#1} } ,
    per-mode .meta:n =
      { display-per-mode = {#1} , inline-per-mode  = {#1} } ,
    per-symbol .tl_set:N =
      \l_@@_per_symbol_tl ,
    per-symbol-script-correction .tl_set:N =
      \l_@@_per_script_tl ,
    power-half-as-sqrt .bool_set:N =
      \l_@@_half_sqrt_bool ,
    qualifier-mode .choices:nn =
      { bracket , combine , phrase , subscript }
      { \str_set_eq:NN \l_@@_qualifier_mode_str \l_keys_choice_str } ,
    qualifier-phrase .tl_set:N =
      \l_@@_qualifier_phrase_tl
  }
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_bracket_bool}
%   A flag to indicate that the unit currently under construction will require
%   brackets if a power is added.
%    \begin{macrocode}
\bool_new:N \l_@@_bracket_bool
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_bracket_open_tl, \l_@@_bracket_close_tl}
%   Abstracted out but currently purely internal.
%    \begin{macrocode}
\tl_new:N \l_@@_bracket_open_tl
\tl_new:N \l_@@_bracket_close_tl
\tl_set:Nn \l_@@_bracket_open_tl { ( }
\tl_set:Nn \l_@@_bracket_close_tl { ) }
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_font_bool}
%   A flag to control when font wrapping is applied to the output.
%    \begin{macrocode}
\bool_new:N \l_@@_font_bool
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_per_display_str, \l_@@_per_inline_str}
%   The data storage for |per-mode| settings.
%    \begin{macrocode}
\str_new:N \l_@@_per_display_str
\str_new:N \l_@@_per_inline_str
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}
%   {
%     \l_@@_powers_positive_bool ,
%     \l_@@_per_symbol_bool      ,
%     \l_@@_two_part_bool
%   }
%   Dealing with the various ways that reciprocal (\cs{per}) can be handled
%   requires a few different switches.
%    \begin{macrocode}
\bool_new:N \l_@@_per_symbol_bool
\bool_new:N \l_@@_powers_positive_bool
\bool_new:N \l_@@_two_part_bool
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_numerator_bool}
%   Indicates that the current unit should go into the numerator when splitting
%   into two parts (fractions or other \enquote{sorted} styles).
%    \begin{macrocode}
\bool_new:N \l_@@_numerator_bool
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_qualifier_mode_str}
%   For storing the text of options which are best handled by picking
%   function names.
%    \begin{macrocode}
\str_new:N \l_@@_qualifier_mode_str
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_combine_exp_fp}
%   For combining an exponent with the first unit.
%    \begin{macrocode}
\fp_new:N \l_@@_combine_exp_fp
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_prefix_exp_bool}
%   Used to determine if prefixes are converted into powers. Note that
%   while this may be set as an option \enquote{higher up}, at this point it
%   is handled as an internal switch (see the two formatting interfaces for
%   reasons).
%    \begin{macrocode}
\bool_new:N \l_@@_prefix_exp_bool
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_prefix_fp}
%   When converting prefixes to powers, the calculations are done as an
%   \texttt{fp}.
%    \begin{macrocode}
\fp_new:N \l_@@_prefix_fp
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_multiple_fp}
%   For multiplying units.
%    \begin{macrocode}
\fp_new:N \l_@@_multiple_fp
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_current_script_bool, \l_@@_script_bool}
%   A pair of flags to track whether the last entry in the numerator has a
%   superscript. This is tracked to deal with spacing immediately before
%   a slash (symbol), if required. Two flags are needed as otherwise the
%   denominator interferes.
%    \begin{macrocode}
\bool_new:N \l_@@_current_script_bool
\bool_new:N \l_@@_script_bool
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_current_tl, \l_@@_part_tl}
%   Building up the (partial) formatted unit requires some token list storage.
%   Each part of the unit combination that is recovered also has to be
%   placed in a token list: this is a dedicated one to leave the scratch
%   variables available.
%    \begin{macrocode}
\tl_new:N \l_@@_current_tl
\tl_new:N \l_@@_part_tl
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_denominator_tl}
%   For fraction-like units, space is needed for the denominator as well as
%   the numerator (which is handled using \cs{l_@@_formatted_tl}).
%    \begin{macrocode}
\tl_new:N \l_@@_denominator_tl
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_total_int}
%   The formatting routine needs to know both the total number of units and
%   the current unit. Thus an \texttt{int} is required in addition to
%   \cs{l_@@_position_int}.
%    \begin{macrocode}
\int_new:N \l_@@_total_int
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}{\@@_format_parsed:}
% \begin{macro}
%   {\@@_format_parsed:n, \@@_format_parsed:V, \@@_format_parsed_aux:n}
%   The main formatting routine is essentially a loop over each position,
%   reading the various parts of the unit to build up complete unit
%   combination. When the two types of output need to be different, the
%   formatter has to be run twice.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_format_parsed:
  {
    \str_if_eq:NNTF
      \l_@@_per_inline_str
      \l_@@_per_display_str
      { \@@_format_parsed:V \l_@@_per_inline_str }
      {
        \group_begin:
          \@@_format_parsed:V \l_@@_per_inline_str
        \exp_args:NNNV \group_end:
        \tl_set:Nn \l_@@_tmp_tl \l_@@_formatted_tl
        \group_begin:
          \@@_format_parsed:V \l_@@_per_display_str
        \exp_args:NNNV \group_end:
        \tl_set:Nn \l_@@_formatted_tl \l_@@_formatted_tl
        \tl_set:Ne \l_@@_formatted_tl
          {
            \mathchoice
              { \exp_not:V \l_@@_formatted_tl }
              { \exp_not:V \l_@@_tmp_tl }
              { \exp_not:V \l_@@_tmp_tl }
              { \exp_not:V \l_@@_tmp_tl }
          }
       }
  }
\cs_new_protected:Npn \@@_format_parsed:n #1
  {
    \int_set_eq:NN \l_@@_total_int \l_@@_position_int
    \use:c { @@_format_init_ #1 : }
    \tl_clear:N \l_@@_denominator_tl
    \tl_clear:N \l_@@_formatted_tl
    \fp_zero:N \l_@@_prefix_fp
    \int_zero:N \l_@@_position_int
    \fp_compare:nNnF \l_@@_combine_exp_fp = \c_zero_fp
      { \@@_format_combine_exp: }
    \fp_compare:nNnF \l_@@_multiple_fp = \c_one_fp
      { \@@_format_multiply: }
    \bool_lazy_and:nnT
      { \l_@@_prefix_exp_bool }
      { \l_@@_mass_kilogram_bool }
      { \@@_format_mass_to_kilogram: }
    \int_do_while:nNnn
      \l_@@_position_int < \l_@@_total_int
      {
        \bool_set_false:N \l_@@_bracket_bool
        \bool_set_false:N \l_@@_current_script_bool
        \tl_clear:N \l_@@_current_tl
        \bool_set_false:N \l_@@_font_bool
        \bool_set_true:N \l_@@_numerator_bool
        \int_incr:N \l_@@_position_int
        \clist_map_inline:nn { prefix , unit , qualifier , power , special }
          { \@@_format_parsed_aux:n {##1} }
        \@@_format_output:
      }
    \@@_format_finalise:
  }
\cs_generate_variant:Nn \@@_format_parsed:n { V }
\cs_new_protected:Npn \@@_format_parsed_aux:n #1
  {
    \tl_set:Ne \l_@@_tmp_tl
      { #1 - \int_use:N \l_@@_position_int }
    \prop_get:NVNT \l_@@_parsed_prop
      \l_@@_tmp_tl \l_@@_part_tl
      { \use:c { @@_format_ #1 : } }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}
%   {
%     \@@_format_init_fraction:             ,
%     \@@_format_init_power:                ,
%     \@@_format_init_power-positive-first: ,
%     \@@_format_init_repeated-symbol:      ,
%     \@@_format_init_symbol:               ,
%     \@@_format_init_single-symbol:        ,
%   }
%   To set up the various versions of |per-mode|.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_format_init_fraction:
  {
    \bool_set_false:N \l_@@_per_symbol_bool
    \bool_set_true:N \l_@@_powers_positive_bool
    \bool_set_true:N \l_@@_two_part_bool
  }
\cs_new_protected:Npn \@@_format_init_power:
  {
    \bool_set_false:N \l_@@_per_symbol_bool
    \bool_set_false:N \l_@@_powers_positive_bool
    \bool_set_false:N \l_@@_two_part_bool
  }
\cs_new_protected:cpn { @@_format_init_power-positive-first: }
  {
    \bool_set_false:N \l_@@_per_symbol_bool
    \bool_set_false:N \l_@@_powers_positive_bool
    \bool_set_true:N \l_@@_two_part_bool
  }
\cs_new_protected:cpn { @@_format_init_repeated-symbol: }
  {
    \bool_set_true:N \l_@@_per_symbol_bool
    \bool_set_true:N \l_@@_powers_positive_bool
    \bool_set_false:N \l_@@_two_part_bool
  }
\cs_new_protected:Npn \@@_format_init_symbol:
  {
    \bool_set_true:N \l_@@_per_symbol_bool
    \bool_set_true:N \l_@@_powers_positive_bool
    \bool_set_true:N \l_@@_two_part_bool
  }
\cs_new_protected:cpn { @@_format_init_single-symbol: }
  {
    \@@_format_init_power:
    \@@_format_symbol_or_power:
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_format_combine_exp:}
%   To combine an exponent into the first prefix, we first adjust for any
%   power, then deal with any existing prefix, before looking up the
%   final result.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_format_combine_exp:
  {
    \prop_get:NnNF \l_@@_parsed_prop { power-1 } \l_@@_tmp_tl
      { \tl_set:Nn \l_@@_tmp_tl { 1 } }
    \fp_set:Nn \l_@@_tmp_fp
      { \l_@@_combine_exp_fp / \l_@@_tmp_tl }
    \prop_get:NnNTF \l_@@_parsed_prop { prefix-1 } \l_@@_tmp_tl
      {
        \prop_get:NVNF \l_@@_prefixes_forward_prop
          \l_@@_tmp_tl \l_@@_tmp_tl
          {
            \prop_get:NnN \l_@@_parsed_prop { prefix-1 } \l_@@_tmp_tl
            \msg_error:nne { siunitx } { non-numeric-exponent }
              { \l_@@_tmp_tl }
            \tl_set:Nn \l_@@_tmp_tl { 0 }
          }
      }
      { \tl_set:Nn \l_@@_tmp_tl { 0 } }
    \tl_set:Ne \l_@@_tmp_tl
      { \fp_eval:n { \l_@@_tmp_fp + \l_@@_tmp_tl } }
    \fp_compare:nNnTF \l_@@_tmp_tl = \c_zero_fp
      { \prop_remove:Nn \l_@@_parsed_prop { prefix-1 } }
      {
        \prop_get:NVNTF \l_@@_prefixes_reverse_prop
          \l_@@_tmp_tl \l_@@_tmp_tl
          { \prop_put:NnV \l_@@_parsed_prop { prefix-1 } \l_@@_tmp_tl }
          {
            \msg_error:nne { siunitx } { non-convertible-exponent }
              { \l_@@_tmp_tl }
          }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_format_multiply:}
%   A simple mapping.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_format_multiply:
  {
    \int_step_inline:nn { \prop_count:N \l_@@_parsed_prop  }
      {
        \prop_get:NnNF \l_@@_parsed_prop { power- ##1 } \l_@@_tmp_tl
          { \tl_set:Nn \l_@@_tmp_tl { 1 } }
        \fp_set:Nn \l_@@_tmp_fp
          { \l_@@_tmp_tl * \l_@@_multiple_fp }
        \fp_compare:nNnTF \l_@@_tmp_fp = \c_one_fp
          { \prop_remove:N \l_@@_parsed_prop { power- ##1 } }
          {
            \prop_put:Nne \l_@@_parsed_prop { power- ##1 }
              { \fp_use:N \l_@@_tmp_fp }
          }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_format_mass_to_kilogram:}
%   To deal correctly with prefix extraction in combination with kilograms, we
%   need to coerce the prefix for grams. Currently, only this one special case
%   is recorded in the property list, so we do not actually need to check the
%   value. If there is then no prefix we do a bit of gymnastics to create one
%   and then shift the starting point for the prefix extraction.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_format_mass_to_kilogram:
  {
    \int_step_inline:nn \l_@@_total_int
      {
        \prop_if_in:NnT \l_@@_parsed_prop { command- ##1 }
          {
            \prop_if_in:NnF \l_@@_parsed_prop { prefix- ##1 }
              {
                \group_begin:
                  \bool_set_false:N \l_@@_parsing_bool
                  \tl_set:Ne \l_@@_tmp_tl { \kilo }
                \exp_args:NNNV \group_end:
                \tl_set:Nn \l_@@_tmp_tl \l_@@_tmp_tl
                \prop_put:NnV \l_@@_parsed_prop { prefix- ##1 }
                  \l_@@_tmp_tl
                \prop_get:NnNF \l_@@_parsed_prop { power- ##1 }
                  \l_@@_tmp_tl
                  { \tl_set:Nn \l_@@_tmp_tl { 1 } }
                \fp_set:Nn \l_@@_prefix_fp
                  { \l_@@_prefix_fp - 3 * \l_@@_tmp_tl }
              }
          }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_format_symbol_or_power:}
%   Check if there is exactly one negative power align with at least one
%   positive one. Assuming there is, flip from (effectively) |power| to
%   |symbol|.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_format_symbol_or_power:
  {
    \int_compare:nNnT \l_@@_total_int > 1
      {
        \bool_set_false:N \l_@@_tmp_bool
        \int_step_inline:nn \l_@@_total_int
          {
            \prop_get:NnNT \l_@@_parsed_prop { power- ##1 }
              \l_@@_tmp_tl
              {
                \int_compare:nNnT \l_@@_tmp_tl < 0
                  {
                    \bool_if:NTF \l_@@_tmp_bool
                      { \bool_set_false:N \l_@@_tmp_bool }
                      { \bool_set_true:N \l_@@_tmp_bool }
                  }
              }
          }
        \bool_if:NT \l_@@_tmp_bool
          { \@@_format_init_symbol: }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[EXP]{\@@_format_bracket:N}
%   A quick utility function which wraps up a token list variable in brackets
%   if they are required.
%    \begin{macrocode}
\cs_new:Npn \@@_format_bracket:N #1
  {
    \bool_if:NTF \l_@@_bracket_bool
      {
        \exp_not:V \l_@@_bracket_open_tl
        \exp_not:V #1
        \exp_not:V \l_@@_bracket_close_tl
      }
      { \exp_not:V #1 }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_format_power:}
% \begin{macro}[EXP]{\@@_format_power_aux:w}
% \begin{macro}
%   {
%     \@@_format_power_positive: ,
%     \@@_format_power_negative:
%   }
% \begin{macro}[EXP]{\@@_format_power_negative_aux:w}
% \begin{macro}{\@@_format_power_superscript:}
%   Formatting powers requires a test for negative numbers and depending on
%   output format requests some adjustment to the stored value. This could be
%   done using an \texttt{fp} function, but that would be slow compared to
%   a dedicated if lower-level approach based on delimited arguments.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_format_power:
  {
    \@@_format_font:
    \exp_after:wN \@@_format_power_aux:w
      \l_@@_part_tl - \q_stop
      { \@@_format_power_negative: }
      { \@@_format_power_positive: }
  }
\cs_new:Npn \@@_format_power_aux:w #1 - #2 \q_stop
  { \tl_if_empty:nTF {#1} }
%    \end{macrocode}
%   In the case of positive powers, there is little to do: add the power
%   as a superscript (the parser ensures that this is $\neq 1$, so we do not
%   need a test here).
%    \begin{macrocode}
\cs_new_protected:Npn \@@_format_power_positive:
  { \@@_format_power_superscript: }
%    \end{macrocode}
%   Dealing with negative powers starts by flipping the switch used to track
%   where in the final output the current part should get added to. For the
%   case where the output is fraction-like, strip off the |~| then ensure that
%   the result is not the trivial power~$1$. Assuming all is well, addition
%   to the current unit combination goes ahead.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_format_power_negative:
  {
    \bool_set_false:N \l_@@_numerator_bool
    \bool_if:NTF \l_@@_powers_positive_bool
      {
        \tl_set:Ne \l_@@_part_tl
          {
            \exp_after:wN \@@_format_power_negative_aux:w
              \l_@@_part_tl \q_stop
          }
        \str_if_eq:VnF \l_@@_part_tl { 1 }
          { \@@_format_power_superscript: }
      }
      { \@@_format_power_superscript: }
  }
\cs_new:Npn \@@_format_power_negative_aux:w - #1 \q_stop
  { \exp_not:n {#1} }
%    \end{macrocode}
%   Adding the power as a superscript has the slight complication that there
%   is the possibility of needing some brackets.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_format_power_superscript:
  {
    \bool_lazy_and:nnTF
      { \l_@@_half_sqrt_bool }
      { \str_if_eq_p:Vn \l_@@_part_tl { 0.5 } }
      {
        \tl_set:Ne \l_@@_current_tl
          {
            \exp_not:N \sqrt
              { \exp_not:V \l_@@_current_tl }
          }
      }
      {
        \exp_after:wN \@@_format_power_superscipt:w
          \l_@@_part_tl . . \q_stop
      }
  }
\cs_new_protected:Npn \@@_format_power_superscipt:w #1 . #2 . #3 \q_stop
  {
    \tl_if_blank:nTF {#2}
      {
        \tl_set:Ne \l_@@_current_tl
          {
            \@@_format_bracket:N \l_@@_current_tl
            ^ { \exp_not:n {#1} }
          }
      }
      {
        \tl_set:Ne \l_@@_tmp_tl
          {
            { }
            \tl_if_head_eq_charcode:nNTF {#1} -
              { { - } { \exp_not:o { \use_none:n #1 } } }
              { { } { \exp_not:n {#1} } }
            {#2}
            { }
            { }
            { 0 }
          }
        \tl_set:Ne \l_@@_current_tl
          {
            \@@_format_bracket:N \l_@@_current_tl
            ^ { \siunitx_number_output:N \l_@@_tmp_tl }
          }
      }
    \bool_set_true:N \l_@@_current_script_bool
    \bool_set_false:N \l_@@_bracket_bool
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_format_prefix:}
% \begin{macro}
%   {
%     \@@_format_prefix_exp:   ,
%     \@@_format_prefix_gram:  ,
%     \@@_format_prefix_symbol:
%   }
%   Formatting for prefixes depends on whether they are to be expressed as
%   symbols or collected up to be returned as a power of $10$. The latter
%   case requires a bit of processing, which includes checking that the
%   conversion is possible and allowing for any power that applies to the
%   current unit.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_format_prefix:
  {
    \bool_if:NTF \l_@@_prefix_exp_bool
      { \@@_format_prefix_exp: }
      { \@@_format_prefix_symbol: }
  }
\cs_new_protected:Npn \@@_format_prefix_exp:
  {
    \prop_get:NVNTF \l_@@_prefixes_forward_prop
      \l_@@_part_tl \l_@@_part_tl
      {
        \bool_if:NT \l_@@_mass_kilogram_bool
          {
            \tl_set:Ne \l_@@_tmp_tl
              { command- \int_use:N \l_@@_position_int }
            \prop_if_in:NVT \l_@@_parsed_prop \l_@@_tmp_tl
              { \@@_format_prefix_gram: }
          }
        \tl_set:Ne \l_@@_tmp_tl
          { power- \int_use:N \l_@@_position_int }
        \prop_get:NVNF \l_@@_parsed_prop
          \l_@@_tmp_tl \l_@@_tmp_tl
          { \tl_set:Nn \l_@@_tmp_tl { 1 } }
        \fp_add:Nn \l_@@_prefix_fp
          { \l_@@_tmp_tl * \l_@@_part_tl }
      }
      { \@@_format_prefix_symbol: }
  }
%    \end{macrocode}
%   When the units in use are grams, we may need to deal with conversion to
%   kilograms.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_format_prefix_gram:
  {
    \tl_set:Ne \l_@@_part_tl
      { \int_eval:n { \l_@@_part_tl - 3 } }
    \group_begin:
      \bool_set_false:N \l_@@_parsing_bool
      \tl_set:Ne \l_@@_current_tl { \kilo }
    \exp_args:NNNV \group_end:
    \tl_set:Nn \l_@@_current_tl \l_@@_current_tl
  }
\cs_new_protected:Npn \@@_format_prefix_symbol:
  { \tl_set_eq:NN \l_@@_current_tl \l_@@_part_tl }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_format_qualifier:}
% \begin{macro}
%   {
%     \@@_format_qualifier_bracket:   ,
%     \@@_format_qualifier_combine:   ,
%     \@@_format_qualifier_phrase:    ,
%     \@@_format_qualifier_subscript:
%   }
%  There are various ways that a qualifier can be added to the output. The
%  idea here is to modify the \enquote{base} text appropriately and then add
%  to the current unit. Notice that when the qualifier is just treated as
%  \enquote{text}, the auxiliary is actually a no-op.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_format_qualifier:
  {
    \bool_set_false:N \l_@@_current_script_bool
    \bool_set_false:N \l_@@_bracket_bool
    \use:c
      {
        @@_format_qualifier_
        \l_@@_qualifier_mode_str :
      }
    \tl_put_right:NV \l_@@_current_tl \l_@@_part_tl
  }
\cs_new_protected:Npn \@@_format_qualifier_bracket:
  {
    \@@_format_font:
    \tl_set:Ne \l_@@_part_tl
      {
        \exp_not:V \l_@@_bracket_open_tl
        \exp_not:V \l_siunitx_unit_font_tl
          { \exp_not:V \l_@@_part_tl }
        \exp_not:V \l_@@_bracket_close_tl
      }
  }
\cs_new_protected:Npn \@@_format_qualifier_combine: { }
%    \end{macrocode}
%   Extra work is needed here to see if we need to add brackets.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_format_qualifier_phrase:
  {
    \@@_format_font:
    \tl_set:Ne \l_@@_part_tl
      {
        \exp_not:V \l_@@_qualifier_phrase_tl
        \exp_not:V \l_siunitx_unit_font_tl
          { \exp_not:V \l_@@_part_tl }
      }
    \tl_set:Ne \l_@@_tmp_tl
      { power - \int_use:N \l_@@_position_int }
    \prop_get:NVNT \l_@@_parsed_prop \l_@@_tmp_tl
      \l_@@_tmp_tl
      {
        \int_compare:nNnF \l_@@_tmp_tl = 1
          { \bool_set_true:N \l_@@_bracket_bool }
      }
  }
\cs_new_protected:Npn \@@_format_qualifier_subscript:
  {
    \@@_format_font:
    \tl_set:Ne \l_@@_part_tl
      {
        \c_@@_math_subscript_tl
          {
            \exp_not:V \l_siunitx_unit_font_tl
              { \exp_not:V \l_@@_part_tl }
          }
      }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_format_special:}
%   Any special odds and ends are handled by simply making the current
%   combination into an argument for the recovered code. Font control
%   needs to be \emph{inside} the special formatting here.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_format_special:
  {
    \tl_set:Ne \l_@@_current_tl
      {
        \exp_not:V \l_@@_part_tl
         {
           \bool_if:NTF \l_@@_font_bool
             { \use:n }
             { \exp_not:V \l_siunitx_unit_font_tl }
              { \exp_not:V \l_@@_current_tl }
         }
      }
    \bool_set_true:N \l_@@_font_bool
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_format_unit:}
%   A very simple task: add the unit to the output currently being
%   constructed.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_format_unit:
  {
    \tl_put_right:NV
      \l_@@_current_tl \l_@@_part_tl
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_format_output:}
% \begin{macro}
%   {\@@_format_output_aux:, \@@_format_output_denominator:}
% \begin{macro}
%   {
%     \@@_format_output_aux:nn ,
%     \@@_format_output_aux:nV ,
%     \@@_format_output_aux:nv
%   }
%   The first step here is to make a choice based on whether the current
%   part should be stored as part of the numerator or denominator of a
%   fraction. In all cases, if the switch \cs{l_@@_numerator_bool} is
%   true then life is simple: add the current part to the numerator with
%   a standard separator
%    \begin{macrocode}
\cs_new_protected:Npn \@@_format_output:
  {
    \@@_format_font:
    \bool_set_false:N \l_@@_bracket_bool
    \use:c
      {
        @@_format_output_
        \bool_if:NTF \l_@@_numerator_bool
          { aux: }
          { denominator: }
      }
  }
\cs_new_protected:Npn \@@_format_output_aux:
  {
    \bool_set_eq:NN \l_@@_script_bool
      \l_@@_current_script_bool
    \@@_format_output_aux:nV { formatted }
      \l_@@_product_tl
  }
%    \end{macrocode}
%   There are a few things to worry about at this stage if the current part
%   is in the denominator.  Powers have already been dealt with and some
%   formatting outcomes only need a branch at the final point of building
%   the entire unit. That means that there are three possible outcomes here:
%   if collecting two separate parts, add to the denominator with a product
%   separator, or if only building one token list there may be a need to use
%   a symbol separator. When the |repeated-symbol| option is in use there may
%   be a need to add a leading |1| to the output in the case where the
%   first unit is in the denominator: that can be picked up by looking for
%   empty output in combination with the flag for using a symbol in the output
%   but not a two-part strategy.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_format_output_denominator:
  {
    \bool_if:NTF \l_@@_two_part_bool
      {
        \bool_lazy_and:nnT
          { \l_@@_denominator_bracket_bool }
          { ! \tl_if_empty_p:N \l_@@_denominator_tl }
          { \bool_set_true:N \l_@@_bracket_bool }
        \@@_format_output_aux:nV { denominator }
          \l_@@_product_tl
      }
      {
        \bool_lazy_and:nnT
          { \l_@@_per_symbol_bool }
          { \tl_if_empty_p:N \l_@@_formatted_tl }
          { \tl_set:Nn \l_@@_formatted_tl { 1 } }
        \@@_format_output_aux:nv { formatted }
          {
            l_@@_
            \bool_if:NTF \l_@@_per_symbol_bool
              { per_symbol }
              { product }
            _tl
          }
      }
  }
\cs_new_protected:Npn \@@_format_output_aux:nn #1#2
  {
    \tl_set:ce { l_@@_ #1 _tl }
      {
         \exp_not:v { l_@@_ #1 _tl }
         \tl_if_empty:cF { l_@@_ #1 _tl }
           { \exp_not:n {#2} }
         \exp_not:V \l_@@_current_tl
      }
  }
\cs_generate_variant:Nn \@@_format_output_aux:nn { nV , nv }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_format_font:}
%   A short auxiliary which checks if the font has been applied to the
%   main part of the output: if not, add it and set the flag.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_format_font:
  {
    \bool_if:NF \l_@@_font_bool
      {
        \tl_set:Ne \l_@@_current_tl
          {
            \exp_not:V \l_siunitx_unit_font_tl
              { \exp_not:V \l_@@_current_tl }
          }
        \bool_set_true:N \l_@@_font_bool
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_format_finalise:}
% \begin{macro}
%   {
%     \@@_format_finalise_autofrac:   ,
%     \@@_format_finalise_fractional: ,
%     \@@_format_finalise_power:
%   }
%   Finalising the unit format is really about picking up the cases involving
%   fractions: these require assembly of the parts with the need to add
%   additional material in some cases
%    \begin{macrocode}
\cs_new_protected:Npn \@@_format_finalise:
  {
    \tl_if_empty:NF \l_@@_denominator_tl
      {
        \bool_if:NTF \l_@@_powers_positive_bool
          { \@@_format_finalise_fractional: }
          { \@@_format_finalise_power: }
      }
  }
%    \end{macrocode}
%   For fraction-like output, there are three possible choices and two
%   actual styles. In all cases, if the numerator is empty then it is set
%   here to |1|.  To deal with the \enquote{auto-format} case, the two
%   styles (fraction and symbol) are handled in auxiliaries: this allows both
%   to be used at the same time! Beyond that, the key here is to use a
%   single \cs{tl_set:Ne} to keep down the number of assignments.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_format_finalise_fractional:
  {
    \tl_if_empty:NT \l_@@_formatted_tl
      { \tl_set:Nn \l_@@_formatted_tl { 1 } }
    \bool_if:NTF \l_@@_per_symbol_bool
      { \@@_format_finalise_symbol: }
      { \@@_format_finalise_fraction: }
  }
%    \end{macrocode}
%   When using a fraction function the two parts are now assembled.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_format_finalise_fraction:
  {
    \tl_set:Ne \l_@@_formatted_tl
      {
        \exp_not:V \l_siunitx_unit_fraction_tl
          { \exp_not:V \l_@@_formatted_tl }
          { \exp_not:V \l_@@_denominator_tl }
      }
  }
%    \end{macrocode}
%   Add the correction if required: no \cs{relax} needed as we know there is a
%   non-expandable token following.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_format_finalise_symbol:
  {
    \tl_set:Ne \l_@@_formatted_tl
      {
        \exp_not:V \l_@@_formatted_tl
        \bool_if:NT \l_@@_script_bool
          { \exp_not:V \l_@@_per_script_tl }
        \exp_not:V \l_@@_per_symbol_tl
        \@@_format_bracket:N \l_@@_denominator_tl
      }
  }
%    \end{macrocode}
%   In the case of sorted powers, there is a test to make sure there was
%   at least one positive power, and if so a simple join of the two parts
%   with the appropriate product.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_format_finalise_power:
  {
    \tl_if_empty:NTF \l_@@_formatted_tl
      {
        \tl_set_eq:NN
          \l_@@_formatted_tl
          \l_@@_denominator_tl
      }
      {
        \tl_set:Ne \l_@@_formatted_tl
          {
            \exp_not:V \l_@@_formatted_tl
            \exp_not:V \l_@@_product_tl
            \exp_not:V \l_@@_denominator_tl
          }
      }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \subsection{Non-Latin character support}
%
% \begin{macro}{\@@_non_latin:n}
%   A shortcut.
%    \begin{macrocode}
\cs_new:Npn \@@_non_latin:n #1
  { \codepoint_generate:nn {#1} { \char_value_catcode:n {#1} } }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Pre-defined unit components}
%
% Quite a number of units can be predefined: while this is a code-level module,
% there is little point having a unit parser which does not start off able to
% parse any units!
%
% \begin{macro}
%   {
%     \kilogram ,
%     \metre    ,
%     \meter    ,
%     \mole     ,
%     \kelvin   ,
%     \candela  ,
%     \second   ,
%     \ampere
%   }
%   The basic \acro{SI} units: technically the correct spelling is \cs{metre}
%   but US users tend to use \cs{meter}.
%    \begin{macrocode}
\siunitx_declare_unit:Nn \kilogram { \kilo \gram }
\siunitx_declare_unit:Nn \metre    { m }
\siunitx_declare_unit:Nn \meter    { \metre }
\siunitx_declare_unit:Nn \mole     { mol }
\siunitx_declare_unit:Nn \second   { s }
\siunitx_declare_unit:Nn \ampere   { A }
\siunitx_declare_unit:Nn \kelvin   { K }
\siunitx_declare_unit:Nn \candela  { cd }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\gram}
%   The gram is an odd unit as it is needed for the base unit kilogram.
%    \begin{macrocode}
\siunitx_declare_unit:Nn \gram { g }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}
%   {
%     \quecto ,
%     \ronto  ,
%     \yocto  ,
%     \zepto  ,
%     \atto   ,
%     \femto  ,
%     \pico   ,
%     \nano   ,
%     \micro  ,
%     \milli  ,
%     \centi  ,
%     \deci
%  }
%   The various \acro{SI} multiple prefixes are defined here: first the small
%   ones.
%    \begin{macrocode}
\siunitx_declare_prefix:Nnn \quecto { -30 } { q }
\siunitx_declare_prefix:Nnn \ronto  { -27 } { r }
\siunitx_declare_prefix:Nnn \yocto  { -24 } { y }
\siunitx_declare_prefix:Nnn \zepto  { -21 } { z }
\siunitx_declare_prefix:Nnn \atto   { -18 } { a }
\siunitx_declare_prefix:Nnn \femto  { -15 } { f }
\siunitx_declare_prefix:Nnn \pico   { -12 } { p }
\siunitx_declare_prefix:Nnn \nano   {  -9 } { n }
\siunitx_declare_prefix:Nne \micro  { -6 } { \@@_non_latin:n { "03BC } }
\siunitx_declare_prefix:Nnn \milli  { -3 } { m }
\siunitx_declare_prefix:Nnn \centi  { -2 } { c }
\siunitx_declare_prefix:Nnn \deci   { -1 } { d }
%    \end{macrocode}
% \end{macro}
% \begin{macro}
%   {
%     \deca   ,
%     \deka   ,
%     \hecto  ,
%     \kilo   ,
%     \mega   ,
%     \giga   ,
%     \tera   ,
%     \peta   ,
%     \exa    ,
%     \zetta  ,
%     \yotta  ,
%     \ronna  ,
%     \quetta
%   }
%   Now the large ones.
%    \begin{macrocode}
\siunitx_declare_prefix:Nnn \deca   { 1 }  { da }
\siunitx_declare_prefix:Nnn \deka   { 1 }  { da }
\siunitx_declare_prefix:Nnn \hecto  { 2 }  { h }
\siunitx_declare_prefix:Nnn \kilo   { 3 }  { k }
\siunitx_declare_prefix:Nnn \mega   { 6 }  { M }
\siunitx_declare_prefix:Nnn \giga   { 9 }  { G }
\siunitx_declare_prefix:Nnn \tera   { 12 } { T }
\siunitx_declare_prefix:Nnn \peta   { 15 } { P }
\siunitx_declare_prefix:Nnn \exa    { 18 } { E }
\siunitx_declare_prefix:Nnn \zetta  { 21 } { Z }
\siunitx_declare_prefix:Nnn \yotta  { 24 } { Y }
\siunitx_declare_prefix:Nnn \ronna  { 27 } { R }
\siunitx_declare_prefix:Nnn \quetta { 30 } { Q }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}
%   {
%     \becquerel     ,
%     \degreeCelsius ,
%     \coulomb       ,
%     \farad         ,
%     \gray          ,
%     \hertz         ,
%     \henry         ,
%     \joule         ,
%     \katal         ,
%     \lumen         ,
%     \lux
%  }
%    Named derived units: first half of alphabet.
%    \begin{macrocode}
\siunitx_declare_unit:Nn \becquerel { Bq }
\siunitx_declare_unit:Ne \degreeCelsius { \@@_non_latin:n { "00B0 } C }
\siunitx_declare_unit:Nn \coulomb   { C }
\siunitx_declare_unit:Nn \farad     { F }
\siunitx_declare_unit:Nn \gray      { Gy }
\siunitx_declare_unit:Nn \hertz     { Hz }
\siunitx_declare_unit:Nn \henry     { H }
\siunitx_declare_unit:Nn \joule     { J }
\siunitx_declare_unit:Nn \katal     { kat }
\siunitx_declare_unit:Nn \lumen     { lm }
\siunitx_declare_unit:Nn \lux       { lx }
%    \end{macrocode}
% \end{macro}
% \begin{macro}
%   {
%     \newton    ,
%     \ohm       ,
%     \pascal    ,
%     \radian    ,
%     \siemens   ,
%     \sievert   ,
%     \steradian ,
%     \tesla     ,
%     \volt      ,
%     \watt      ,
%     \weber
%  }
%    Named derived units: second half of alphabet.
%    \begin{macrocode}
\siunitx_declare_unit:Nn \newton    { N }
\siunitx_declare_unit:Ne \ohm       { \@@_non_latin:n { "2126 } }
\siunitx_declare_unit:Nn \pascal    { Pa }
\siunitx_declare_unit:Nn \radian    { rad }
\siunitx_declare_unit:Nn \siemens   { S }
\siunitx_declare_unit:Nn \sievert   { Sv }
\siunitx_declare_unit:Nn \steradian { sr }
\siunitx_declare_unit:Nn \tesla     { T }
\siunitx_declare_unit:Nn \volt      { V }
\siunitx_declare_unit:Nn \watt      { W }
\siunitx_declare_unit:Nn \weber     { Wb }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}
%   {
%     \astronomicalunit ,
%     \bel              ,
%     \dalton           ,
%     \day              ,
%     \decibel          ,
%     \electronvolt     ,
%     \hectare          ,
%     \hour             ,
%     \litre            ,
%     \liter            ,
%     \minute           ,
%     \neper            ,
%     \tonne
%  }
%   Non-\acro{SI}, but accepted for general use. Once again there are two
%   spellings, here for litre and with different output in this case.
%    \begin{macrocode}
\siunitx_declare_unit:Nn \astronomicalunit { au }
\siunitx_declare_unit:Nn \bel              { B }
\siunitx_declare_unit:Nn \decibel          { \deci \bel }
\siunitx_declare_unit:Nn \dalton           { Da }
\siunitx_declare_unit:Nn \day              { d }
\siunitx_declare_unit:Nn \electronvolt     { eV }
\siunitx_declare_unit:Nn \hectare          { ha }
\siunitx_declare_unit:Nn \hour             { h }
\siunitx_declare_unit:Nn \litre            { L }
\siunitx_declare_unit:Nn \liter            { \litre }
\siunitx_declare_unit:Nn \minute           { min }
\siunitx_declare_unit:Nn \neper            { Np }
\siunitx_declare_unit:Nn \tonne            { t }
%    \end{macrocode}
% \end{macro}
% \begin{macro}
%   {
%     \arcminute ,
%     \arcsecond ,
%     \degree
%  }
%   Arc units: again, non-\acro{SI}, but accepted for general use.
%    \begin{macrocode}
\siunitx_declare_unit:Ne \arcminute { \@@_non_latin:n { "02B9 } }
\siunitx_declare_unit:Ne \arcsecond { \@@_non_latin:n { "02BA } }
\siunitx_declare_unit:Ne \degree { \@@_non_latin:n { "00B0 } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\percent}
%   For percent, the raw character is the most flexible way of handling output.
%    \begin{macrocode}
\siunitx_declare_unit:Ne \percent { \cs_to_str:N \% }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\square, \squared, \cubic, \cubed}
%   Basic powers.
%    \begin{macrocode}
\siunitx_declare_power:NNn \square \squared { 2 }
\siunitx_declare_power:NNn \cubic  \cubed   { 3 }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Messages}
%
%    \begin{macrocode}
\msg_new:nnnn { siunitx } { dangling-part }
  { Found~#1~part~with~no~unit. }
  {
    Each~#1~part~must~be~associated~with~a~unit:~a~#1~part~was~found~
    but~no~following~unit~was~given.
  }
\msg_new:nnnn { siunitx } { duplicate-part }
  { Duplicate~#1~part:~#2. }
  {
    Each~unit~may~have~only~one~#1:\\
    the~additional~#1~part~'#2'~will~be~ignored.
  }
\msg_new:nnnn { siunitx } { duplicate-sticky-per }
  { Duplicate~\token_to_str:N \per. }
  {
    When~the~'sticky-per'~option~is~active,~only~one~
    \token_to_str:N \per \  may~appear~in~a~unit.
  }
\msg_new:nnnn { siunitx } { literal-unit }
  { Literal~units~disabled. }
  {
    You~gave~the~literal~input~'#1'~
    but~literal~unit~output~is~disabled.
  }
\msg_new:nnnn { siunitx } { non-convertible-exponent }
  { Exponent~'#1'~cannot~be~converted~into~a~symbolic~prefix. }
  {
    The~exponent~'#1'~does~not~match~with~any~of~the~symbolic~prefixes~
    set~up.
  }
\msg_new:nnnn { siunitx } { non-numeric-exponent }
  { Prefix~'#1'~does~not~have~a~numerical~value. }
  {
    The~prefix~'#1'~needs~to~be~combined~with~a~number,~but~it~has~no
    numerical~value.
  }
\msg_new:nnnn { siunitx } { part-before-unit }
  { Found~#1~part~before~first~unit:~#2. }
  {
    The~#1~part~'#2'~must~follow~after~a~unit:~
    it~cannot~appear~before~any~units~and~will~therefore~be~ignored.
  }
%    \end{macrocode}
%
% \subsection{Deprecated options}
%
% To handle |per-mode = symbol-or-fraction|, there needs to be allowance for
% the fact that it is set up as a meta-option. That is done with appropriate
% code here for the two newer options.
%    \begin{macrocode}
\keys_define:nn { siunitx }
  {
    display-per-mode / symbol-or-fraction .code:n =
      {
        \msg_info:nnnn { siunitx } { option-deprecated }
          { per-mode~=~symbol-or-fraction }
          { display-per-mode~=~fraction,~inline-per-mode~=~symbol }
        \str_set:Nn \l_@@_per_display_str { fraction }
      } ,
    inline-per-mode / symbol-or-fraction .code:n =
      {
        \msg_info:nnnn { siunitx } { option-deprecated }
          { per-mode~=~symbol-or-fraction }
          { display-per-mode~=~fraction,~inline-per-mode~=~symbol }
        \str_set:Nn \l_@@_per_inline_str { symbol }
      }
  }
%    \end{macrocode}
%
% \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 }
  {
    bracket-unit-denominator     = true      ,
    forbid-literal-units         = false     ,
    fraction-command             = \frac     ,
    inter-unit-product           = \,        ,
    extract-mass-in-kilograms    = true      ,
    parse-units                  = true      ,
    per-mode                     = power     ,
    per-symbol                   = /         ,
    per-symbol-script-correction = \!        ,
    power-half-as-sqrt           = false     ,
    qualifier-mode               = subscript ,
    qualifier-phrase             =           ,
    sticky-per                   = false     ,
    unit-font-command            = \mathrm
  }
%    \end{macrocode}
%
% Cover the case where the default font is sanserif with \pkg{beamer}.
%    \begin{macrocode}
\AtBeginDocument
  {
    \@ifclassloaded { beamer }
      {
        \str_if_eq:eeT
          { \exp_not:o { \familydefault } }
          { \exp_not:n { \sfdefault } }
          {
            \tl_if_eq:VnT \l_siunitx_unit_font_tl { \mathrm }
              { \keys_set:nn { siunitx } { unit-font-command = \mathsf } }
          }
      }
      { }
  }
%    \end{macrocode}
%
%    \begin{macrocode}
%</package>
%    \end{macrocode}
%
% \end{implementation}
%
% \begin{thebibliography}{1}
%   \bibitem{BIPM}
%     \emph{The International System of Units (\acro{SI})},
%     \url{https://www.bipm.org/en/measurement-units/}.
%   \bibitem{base-units}
%     \emph{SI base units},
%     \url{https://www.bipm.org/en/measurement-units/si-base-units}.
% \end{thebibliography}
%
% \PrintIndex
