% \iffalse meta-comment % !TEX encoding = UTF-8 Unicode % !TEX program = pdfLaTeX %^^A PdfLaTeX-dev % %<*internal> \iffalse % %<*readme> cooking-units ============= Overview -------- While writing a cookery book, units and their format can be quite troublesome. This contains not only the question of how to print those units, but also the question of the conversion of units. A cookery book doesn't contain only SI units, it contains a much more colorful range of units (kg, dag, g, oz, ... for example) and it may cause some confusion if too many different units are used, but if you just write a cookery book for fun you don't think about this ... until someone (my mother in my case) tells you that it's too confusing. This package solves both problems: It formats your input and you have the option to convert the units globally or locally using an easy to use key-value system. Please note that this package is not intended to be used to print units (and numbers) physically correct. It should be used for more light-hearted stuff (like a cookery book for example). Requirements ------------ * expl3 & xparse * translations * xfrac * l3keys2e * fmtcount (optional) This file contains ------------------ * README * cooking-units.pdf * cooking-units.dtx * cooking-units.ins Changes ------- See section 'Change History' in the documentation. Supported Languages ------------------- * German * English * French (suboptimal) License ------- This material is subject to the LaTeX Project Public License 1.3c or later. See https://www.latex-project.org/lppl/ for the details of that license. % %<*internal> \fi \def\nameofplainTeX{plain} \ifx\fmtname\nameofplainTeX\else \expandafter\begingroup \fi % %<*install> \input l3docstrip.tex %\keepsilent \askforoverwritefalse \preamble Copyright (C) 2016--2020 by Ben Vitecek (current Maintainer) This file may be distributed and/or modified under the conditions of the LaTeX Project Public License, either version 1.3c of this license or (at your option) any later version. The latest version of this license is in: https://www.latex-project.org/lppl/ and version 1.3c or later is part of all distributions of LaTeX version 2008-05-04 or later. This work has the LPPL maintenance status `maintained'. This work consists of the files README.md, cooking-units.dtx and cooking-units.ins and the derived file cooking-units.sty. \endpreamble %\postamble %\endpostamble \usedir{tex/latex/cooking-units} \generate{ \file{\jobname.sty}{\from{\jobname.dtx}{package}} } % %\endbatchfile %<*internal> \usedir{source/latex/cooking-units} \generate{ \file{\jobname.ins}{\from{\jobname.dtx}{install}} } \nopreamble\nopostamble \usedir{doc/latex/cooking-units} \generate{ \file{README.md}{\from{\jobname.dtx}{readme}} } \ifx\fmtname\nameofplainTeX \expandafter\endbatchfile \else \expandafter\endgroup \fi % %<*driver> \documentclass[ ngerman, french, english, %french, naustrian onlydoc, % check-declarations, ]{l3doc} \usepackage[utf8]{inputenc} \usepackage[main=english]{babel} \usepackage[use-fmtcount-numerals=true]{cooking-units} \usepackage{tikzsymbols} \usepackage{listings} \usepackage{environ} \usepackage{nicefrac} \usepackage{cleveref} \usepackage{mathtools} \usepackage{siunitx} \usepackage{totalcount} \usepackage{microtype} \usepackage{enumitem} \newcounter{CookingUnitsCounter} \newcounter{cunumCounter} \newcounter{cuamCounter} \newcounter{cutextCounter} \newcounter{CutextCounter} \DeclareTotalCounter{CookingUnitsCounter} \DeclareTotalCounter{cunumCounter} \DeclareTotalCounter{cuamCounter} \DeclareTotalCounter{cutextCounter} \DeclareTotalCounter{CutextCounter} \babeltags{myde = ngerman} \DeclareSIUnit{\ounce}{oz} \DeclareSIUnit{\oz}{\ounce} \DeclareSIUnit{\pound}{lb} \DeclareSIUnit{\lb}{\pound} \DeclareSIUnit{\stone}{st} \DeclareSIUnit{\st}{\stone} \DeclareSIUnit{\stick}{st} \DeclareSIUnit{\inch}{in} \cusetup{print-numerals=false} %\EnableCrossrefs \newcommand\US{$^{\mathrm{U.S.}}$} \ExplSyntaxOn \NewDocumentCommand \cookingunitsToDo { m } { % \marginpar { \textcolor{red}{#1} } } \clist_new:N \l_cookingunits_list_of_defined_befehlen_clist \clist_set:Nn \l_cookingunits_list_of_defined_befehlen_clist { cunum, cutext, Cutext, cuam, newcookingunit, declarecookingunit, providecookingunit, cudefinename, cudefinesymbol, cusetup, cudefinekeys, cudefinesinglekey, cuaddkeys, cuaddsinglekeys, cuaddtokeys, culabel, curef, cudefinephrase, declarecookingderivatives , cufrac , cusetoptionfor, cuaddoptionfor, cuclearoptionfor, cudeclareunitgroup, cuaddtounitgroup, cuclearunitgroup } \NewDocumentCommand \mycs { m } { \clist_if_in:NnTF \l_cookingunits_list_of_defined_befehlen_clist {#1} { \cs_if_exist:cTF {#1} { \cs{\textcolor{blue}{#1}} } { \mycsERRORII } } { \mycsERROR } } \newcommand\opt{\texttt} \newcommand\myunit{\texttt} \newcommand\mygroup{\texttt} \newcommand\myaarg[1]{\texttt{<}\meta{#1}\texttt{>}} \newcommand\true{\opt{true}} \newcommand\false{\opt{false}} %: \PrintUnit \NewDocumentCommand \PrintUnit { o m } { \SaveTranslation \l_tmpa_tl { #2 (cu-unitname) } \tl_if_eq:NNF \l_tmpa_tl \q__cookingunits_no_translation { \l_tmpa_tl } \IfNoValueF {#1} {#1} & \texttt {#2} & \tl_use:c { l__cookingunits_default_unit_ #2 _tl } } \NewDocumentCommand \PrintUnitSymbol { m } { \texttt {#1} & \tl_use:c { l__cookingunits_default_unit_ #1 _tl } } \NewDocumentCommand \PrintGroup { m } { \mygroup {#1} & \texttt{\seq_use:cn { l__cookingunits_group_ #1 _seq } { \textrm{,~} }} } \NewDocumentCommand \DeactivateForbiddenUnitError { } { \msg_redirect_name:nnn { cooking-units } { curef-forbidden-unit } { warning } } %% Allyourwhitespacearebelongtous (too long) %% 42 %% Miep! %% Ducks \NewDocumentCommand \dothewhitespace { O{ cup~of~tea } } { \textcolor{white} {#1} \\ } \newcommand\eatthewhitespace{} \NewEnviron { cuexamplecode }[1][] { \begin{center} \begin{minipage}{0.4\linewidth} \tl_replace_all:Nnn \BODY { @ } { \dothewhitespace } \tl_replace_all:Nnn \BODY { \% } { \color{red} \% \ignorespaces } \tl_replace_all:Nnn \BODY { \\ } { \\ \color{black} } \tl_replace_all:Nnn \BODY { & } { \ignorespaces } \BODY \end{minipage} #1 \int_zero:N \l_tmpa_int \begin{minipage}{0.5\linewidth} \ttfamily \tl_set_rescan:Nno \l_tmpa_tl { \char_set_catcode_other:N \{ % \char_set_catcode_other:N \} % \char_set_catcode_other:N \_ % \char_set_catcode_other:N \~ % } { \BODY } \tl_map_inline:Nn \l_tmpa_tl { \token_if_cs:NTF ##1 { \cs_if_eq:NNTF ##1 \\ { \textbackslash\textbackslash \\ } { \tl_set_rescan:Nnn \l_tmpb_tl { \char_set_catcode_ignore:N \\ % \char_set_catcode_ignore:N \ % } {##1} \textbackslash \textcolor{blue}{\l_tmpb_tl} } } { \bool_lazy_any:nTF { { \str_if_eq_p:nn {##1} { @ } } { \str_if_eq_p:nn {##1} { ! } } { \str_if_eq_p:nn {##1} { & } } } { \str_if_eq:nnTF {##1} { & } { \space } { \str_if_eq:nnTF {##1} { ! } { \ERROR } { \\ } } } { \token_if_active:NTF ##1 {##1} { \token_if_parameter:NTF ##1 { \int_compare:nNnTF { \l_tmpa_int } = { 0 } { \c_hash_str \int_incr:N \l_tmpa_int } { \int_zero:N \l_tmpa_int } } { ##1 {} } } } } } \end{minipage} \end{center} } \ProvideDocumentEnvironment{cuexamplecode}{}{}{}{} \NewDocumentEnvironment { cuexample } { } { \paragraph{Example:} % \par \bigskip \noindent % \mbox{} % \marginpar{\raggedleft\textbf{Example}}\ % \ignorespaces } { } \NewDocumentEnvironment { cunote } { } { \paragraph{Note:} }{ } \NewEnviron { cuenumnote } { \begin{enumerate}[label={Note \space \arabic*:}] \BODY \end{enumerate} } \NewDocumentEnvironment { cuinterest } { m } { \par \bigskip \clist_set:Nn \l_tmpa_clist {#1} \mbox{}\marginpar{\raggedleft\opt{ \clist_use:Nn \l_tmpa_clist { \\ } }} \ignorespaces } { } %: table \tl_new:N \l_translation_does_not_exist_tl \tl_set:Nn \l_translation_does_not_exist_tl { --- } \tl_new:N \translationdoesnotexisttl \tl_set_eq:NN \translationdoesnotexisttl \l_translation_does_not_exist_tl \tl_new:N \mytablecolumns \tl_set:Nn \mytablecolumns { l l l l l } \clist_new:N \l_list_of_units_clist \clist_new:N \l_list_of_textunits_clist \clist_set:Nn \l_list_of_textunits_clist { decimal-mark , one (m) , one (f) , one (n) , } \clist_set:Nx \l_list_of_units_clist { kg , dag , g , oz , lb , space , C , F , Re , K , space , d , h , min , s , space , m , dm , cm , mm , in , space , l , dl , cl , ml , space , cal , kcal , J , kJ , eV , space , pn , EL , TL , csp , dsp , ssp , Msp , space , \clist_use:Nn \l_list_of_textunits_clist { , } , THEEND } \cs_new:Npn \__table_midrule: { \\ \midrule \cs_gset:Npn \__table_midrule: { \\ } } \cs_new_eq:NN \__table_default_midrule: \__table_midrule: \cs_new:Npn \_cook_use:n #1 { \cs_if_exist_use:cF { __cookingunits_#1 } {\ERRORcommandNOTexist} } \NewDocumentCommand \CreateTableForLanguages { s >{\TrimSpaces} m } { \IfBooleanTF {#1} { \clist_gset_eq:NN \l_tmpa_clist \l_list_of_textunits_clist } { \clist_gset_eq:NN \l_tmpa_clist \l_list_of_units_clist } \cs_gset_eq:NN \__table_midrule: \__table_default_midrule: \CreateTableHeader {#2} \CreateTableRow {#2} } \NewDocumentCommand \CreateTableHeader { m } { \meta{unit-key} & printed \ unit & unit name & (plural) & gender } \NewDocumentCommand \CreateTableRow { m } { \clist_map_inline:Nn \l_tmpa_clist { \str_case:nnF {##1} { { space } { \\ \addlinespace \cs_set:Npn \__table_midrule: {} } { THEEND } { \\ \bottomrule } }{ \__table_midrule: \texttt{##1} & \clist_if_in:NnTF \l_list_of_textunits_clist {##1} { \l_translation_does_not_exist_tl } { \_cook_use:n { translate_let:nNnV } {#1} \l_tmpa_tl {##1} \c__cookingunits_postfix_unit_tl \tl_if_in:NnTF \l_tmpa_tl \q__cookingunits_no_translation { \l_translation_does_not_exist_tl } { \l_tmpa_tl } } & \_cook_use:n { translate_let:nNnV } {#1} \l_tmpa_tl {##1} \c__cookingunits_postfix_unitname_tl \tl_if_in:NnTF \l_tmpa_tl \q__cookingunits_no_translation { \l_translation_does_not_exist_tl } { \l_tmpa_tl } & \_cook_use:n { translate_let:nNnV } {#1} \l_tmpa_tl {##1} \c__cookingunits_postfix_unitname_tl \_cook_use:n { translate_let:nNnV } {#1} \l_tmpb_tl {##1} \c__cookingunits_postfix_unitname_pl_tl \tl_if_eq:NNF \l_tmpa_tl \l_tmpb_tl { \tl_if_in:NnTF \l_tmpb_tl \q__cookingunits_no_translation { \l_translation_does_not_exist_tl } { (\l_tmpb_tl) } } & \_cook_use:n { translate_let:nNnV } {#1} \l_tmpa_tl {##1} \c__cookingunits_postfix_gender_tl \tl_if_in:NnTF \l_tmpa_tl \q__cookingunits_no_translation { \l_translation_does_not_exist_tl } { \l_tmpa_tl } } } } \NewDocumentCommand \CreateTableForPhrases { >{\TrimSpaces} m } { \tl_set:Nn \l_tmpa_tl {#1} \__cookingunits_phrase_list_get_for:NNTF \l_tmpa_prop \l_tmpa_tl { \__cookingunits_translate_let:VNnV \l_tmpa_tl \l_tmpa_seq { phrase-clist } \c__cookingunits_postfix_phrase_tl } { \ERRORCreateTable } \seq_gput_right:Nn \l_tmpa_seq { THEEND } \cs_gset_eq:NN \__table_midrule: \__table_default_midrule: \begin{tabular}{ l l l l l } \toprule \meta{Phrase-key} & phrase & (plural) & gender \CreatePhraseTableRow {#1} \end{tabular} } \NewDocumentCommand \CreatePhraseTableRow { m } { \seq_map_inline:Nn \l_tmpa_seq { \str_case:nnF {##1} { { space } { \addlinespace \cs_set:Npn \__table_midrule: {} } { THEEND } { \\ \bottomrule } }{ \__table_midrule: ##1 & \prop_get:NnN \l__cookingunits_phrase_prop {##1} \l_tmpa_tl \tl_gset:NV \l_tmpa_tl \l_tmpa_tl %% Damit global \l_tmpa_tl & \prop_get:NnN \l__cookingunits_phrase_prop {##1-pl} \l_tmpb_tl \tl_if_eq:NNF \l_tmpa_tl \l_tmpb_tl { \l_tmpb_tl } & \__cookingunits_translate_let:nNnV {#1} \l_tmpa_tl { ##1 -phrase-gender } \c__cookingunits_postfix_gender_tl \l_tmpa_tl } } } \newcommand\txtupde{\textsuperscript{de}} \newcommand\txtupsic{\textsuperscript{sicilian}} \newcommand\txtupen{\textsuperscript{en}} \NewDocumentCommand\unititem { m d** O{} O{} } { \item [{ #1 \IfNoValueF {#2} { \use:c { txtup #2 } } \tl_if_empty:nF {#3} {\ (#3) } \tl_if_empty:nF {#4} {\ [#4] } }] } \NewDocumentEnvironment { myquote } { o o } { \list{}{% \topsep 0pt \leftmargin 0pt } \item\relax \itshape }{ \normalfont \IfNoValueF{#1}{(see\ \cite{#1} \IfNoValueF{#2}{\ page \ #2} )} \endlist } \makeatletter \newenvironment{mydescription} {\list{}{\labelwidth\z@ \itemindent-\leftmargin \let\makelabel\descriptionlabel}} {\endlist} \renewcommand*\descriptionlabel[1]{\hspace\labelsep \normalfont\bfseries #1} \makeatother \ExplSyntaxOff \newcommand\cCutext{\mycs{cutext} and \mycs{Cutext}} \lstset { basicstyle = \ttfamily, basewidth = 0.51em, gobble = 3, keywordstyle = \color{blue}, language = [LaTeX]{TeX}, commentstyle=\color{red!80!black}, moretexcs = { cunum, cutext, Cutext, cuam, newcookingunit, declarecookingunit, providecookingunit, cudefinename, cudefinesymbol, cusetup, cudefinekeys, cudefinesinglekey, cuaddkeys, cuaddsinglekeys, cuaddtokeys, culabel, curef, cudefinephrase, declarecookingderivatives } } \newcommand\eneunit[3]{\sfrac{#1\,#2${}^2$}{#3${}^2$}} %% Can overflow and takes too long, hard code it %\declarecookingderivatives{kg,m,s}{#1*#2-#3}{ (#1)*(#2)^2/(#3)^2 } {\eneunit{#1}{#2}{#3}} \newcookingunit[\eneunit{kg}{m}{s}]{kg*m-s} \newcookingunit[\eneunit{oz}{in}{min}]{oz*in-min} \newcookingunit {st} \newcookingunit [\ensuremath{ {} ^ { \circ } }\kern-\scriptspace R{\text{\o}}] {Ro} \newcookingunit {ft} \cuaddkeys {lb} { {st} { 1/14 } %% 1 lb are 1/14 st } \cuaddtokeys {m} {ft} {0.3048} \cuaddsinglekeys {C} { {Ro} { #1*21/40 + 7.5 } } \cusetup { commands-add-hook = {\stepcounter{CookingUnitsCounter}} , cunum-add-hook = {\stepcounter{cunumCounter}} , cutext-add-hook = {\stepcounter{cutextCounter}} , Cutext-add-hook = {\stepcounter{CutextCounter}} , cuam-add-hook = {\stepcounter{cuamCounter}} , set-option-for-Ro = { round-precision= 0 } , % add-unit-to-group = { weight = {st} , temperature = {Ro} } } %: \cusetup \cusetup { % weight=stick, % 42 = true , % convert-to-eV=true , % cutext-range-sign = {as}, % erase-all-options, % set-option-for-K= {}, % set-unknown-message = error , % check-temperature = true, % round-precision = 30 , } \EnableCrossrefs \CodelineIndex \RecordChanges \AtEndDocument { \PrintChanges \PrintIndex } \begin{document} \DocInput{\jobname.dtx} \end{document} % % \fi % % % % % \CharacterTable % {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z % Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z % Digits \0\1\2\3\4\5\6\7\8\9 % Exclamation \! Double quote \" Hash (number) \# % Dollar \$ Percent \% Ampersand \& % Acute accent \' Left paren \( Right paren \) % Asterisk \* Plus \+ Comma \, % Minus \- Point \. Solidus \/ % Colon \: Semicolon \; Less than \< % Equals \= Greater than \> Question mark \? % Commercial at \@ Left bracket \[ Backslash \\ % Right bracket \] Circumflex \^ Underscore \_ % Grave accent \` Left brace \{ Vertical bar \| % Right brace \} Tilde \~} % % % \iffalse %: changes % \fi % % \changes {2016/06/11} {0.99} {Added the package option to load 'fmtcount'.} % \changes {2016/08/31} {1.00} {Initial version} % \changes {2016/08/31} {1.00a} {Fixed calculation: degree Reamur to eV} % \changes {2016/09/03} {1.01} {Added units 'ssp', 'csp', 'dsp'} % \changes {2016/09/03} {1.01} {English unit: litre (and only litre) uses the curly l \protect\ensuremath{\protect\ell} now } % \changes {2016/09/03} {1.01} {British English: 'pinch' is written in full} % \changes {2016/09/03} {1.01} {Separated Messerspitze and pinch} % \changes {2016/09/05} {1.02} {Replaced \cs{cufrac} by \cs{cuam}} % \changes {2016/09/05} {1.02} {New message: 'obsolete-command'} % \changes {2016/09/09} {1.02a} {Changed name from \cs{@@_parse_fraction_in_input:www} to \cs{@@_parse_mixed_fraction_in_input:www}} % \changes {2016/09/09} {1.02b} {Changed name from \cs{@@_cunum_parse_range} (and derivatives) to \cs{@@_cutext_parse_range}.} % \changes {2016/09/09} {1.02c} {In \cs{@@_cutext_default:nnn} it is only % checked once if a range is inside.} % \changes {2016/09/09} {1.02d} {\cs{@@_calculate_input_and_store_in:nN} optimiert durch neue property-key: single.} % \changes {2016/09/09} {1.02d} {Add 'single' to property list of singlekeys.} % \changes {2016/09/16} {1.02e} {Only use \cs{phantom} if the argument (for \cs{phantom}) is not empty.} % \changes {2016/09/09} {1.02i} {Delete 'single' from property lists of singlekeys cause it is not as safe as I thought.} % \changes {2016/09/09} {1.02f} {Corrected mistake: 'ELektronenvolt' (note uppercase L) to 'Elektronenvolt' in german.} % \changes {2016/09/26} {1.03} {New option (and needed macros): add-temperature-to-check.} % \changes {2016/09/26} {1.03a} {\cs{cuaddsinglekeys} now tests if the unit exists (it didn't before).} % \changes {2016/09/26} {1.03b} {Replaced \cs{prop_clear_new:c} by \cs{prop_clear:c}.} % \changes {2016/09/26} {1.03b} {Recalculated all electron volt values for conversion (as 'kg' was wrong before). Let's hope they are correct this time.} % \changes {2016/09/26} {1.04} {New option: 'round-half'.} % \changes {2016/10/19} {1.04} {Use \cs{keys_set:nn} only if second argument is not empty.} % \changes {2016/10/19} {1.04} {'convert-to-eV' now also as optional argument available.} % \changes {2016/10/19} {1.04} {Option 'load-time-option' now spells 'available' correct.} % \changes {2016/10/19} {1.04} {Update of documentation.} % \changes {2016/10/28} {1.10alpha} {Start implementation of \enquote{Change recipe from $n$ to $m$ persons.}.} % \changes {2016/10/28} {1.10alpha} {\cs{cutext} (and \cs{Cutext}) and \cs{cuam} now parse their input like \cs{cunum}. This is needed as they also need to be changed.} % \changes {2016/10/29} {1.10alpha} {Tiding code: Now every command is separated into a \enquote{calc} function, a \enquote{print numeric value} and a \enquote{print unit} (if there) function. At least, that's the plan.} % \changes {2016/10/30} {1.10} {Fractions should now deal correctly with minus signs.} % \changes {2016/11/07} {1.10} {Finished writing v1.10.} % \changes {2016/11/13} {1.10} {Change amounts for specific number of persons.} % \changes {2016/11/13} {1.10} {\cs{cutext}, \cs{Cutext} and \cs{cuam} check their input, allows conversion of units.} % \changes {2016/11/13} {1.10} {New commands: \cs{culabel} and \cs{curef}.} % \changes {2016/11/13} {1.10} {New commands: \cs{declarecookingunit} and \cs{providecookingunit}.} % \changes {2016/11/13} {1.10} {New options: \opt{cutext-to-cunum}, \opt{cutext-change-unit} and \opt{cutext-space}.} % \changes {2016/11/13} {1.10} {New options: \opt{cuam-version} and \opt{cutext-version}} % \changes {2016/11/13} {1.10} {New options: \opt{recalculate-amount} and \opt{set-number-of-persons}, \opt{label}, \opt{get-label}, \opt{ref}.} % \changes {2017/03/10} {1.10a} {\cs{curef} is now defined by \cs{NewExpandableDocumentCommand} instead of the Declare variant.} % \changes {2017/03/10} {1.11} {Removed \cs{translate} and others from code % and replaced them with wrapper-macros.} % \changes {2017/03/10} {1.11} {Removed things like 'cu-unit' from translate input % and placed them into separate tl's.} % % \changes {2017/10/23} {1.20} {Replaced \pkg{translator} by \pkg{translations}.} % \changes {2017/10/23} {1.20} {Added \enquote{phrases}.} % \changes {2017/10/23} {1.20} {Added unit \enquote{stick} (of butter).} % \changes {2017/10/23} {1.20} {|<| is not allowed as a special sign anymore.} % \changes {2017/10/23} {1.20} {New option: \opt{set-cutext-translation-message}.} % \changes {2017/10/23} {1.20} {New option: \opt{print-numerals}.} % \changes {2017/10/23} {1.20} {New option: \opt{use-phrases}.} % \changes {2017/10/23} {1.20} {New option: \opt{phrase-space}.} % \changes {2017/10/23} {1.20} {New option: \opt{amount-unit-space}.} % \changes {2017/10/23} {1.20} {Now checks for ranges if both values can be printed as numerals (if activated) (bug fix).} % \changes {2017/10/23} {1.20} {Reworked quite a lot of code.} % % \changes {2018/04/20} {1.30} {Allow round precision to be negative.} % \changes {2018/04/20} {1.30} {Fix argument specifiers.} % \changes {2018/04/20} {1.30} {Change large portions of code.} % \changes {2018/04/20} {1.30} {Introduce key-groups (weight, volume, etc.).} % \changes {2018/04/20} {1.30} {Option: \opt{add-natural-unit}.} % \changes {2018/04/20} {1.30} {New Option: \opt{42}.} % \changes {2018/04/20} {1.30} {New options: \opt{expand-both}, \opt{expand-amount}, \opt{expand-unit}.} % \changes {2018/04/20} {1.30} {New options: \opt{set-option-for} \& \opt{add-option-for}.} % \changes {2018/04/20} {1.30} {New option: \opt{erase-all-options-for}} % \changes {2018/04/20} {1.30} {New option: \opt{add-unit-to-group}} % \changes {2018/04/20} {1.30} {New feature: Hooks} % \changes {2018/04/20} {1.30} {New parsing algorithm. Hopefully better % error recovery (if signs for fractions are in wrong order e.g.)} % \changes {2018/04/20} {1.30} {Add \enquote{Division-by-zero} error.} % \changes {2018/04/20} {1.30} {Cooking Units-keys are not allowed to contain % either \enquote{,} or \enquote{/}.} % % \changes {2018/06/05} {1.40} {This version introduces mayor internal changes. % For users not many things change.} % \changes {2018/06/05} {1.40} {Rework parsing code (again). As this is % basically an improved version of the old parsing algorithm, there is % no huge version change.} % \changes {2018/06/05} {1.40} {Improve error-recovery by a lot!} % \changes {2018/06/05} {1.40} {Bugfix: A range in \mycs{Cutext} (and numerals=true) % will print the second word small.} % \changes {2018/06/05} {1.40} {Add \enquote{range-sign} for translations (not usable yet).} % \changes {2018/06/05} {1.40} {Convert \texttt{clist} to \texttt{seq} if possible.} % \changes {2018/06/05} {1.40} {Remove unnecessary variants.} % \changes {2018/06/05} {1.40} {Fix some more argument specifiers.} % \changes {2018/06/05} {1.40} {Renaming of some internal commands.} % \changes {2018/06/05} {1.40} {\opt{set-unknown-message}: Fix default value.} % \changes {2018/06/05} {1.40} {Change (\texttt{amount-not-known}): Change message a bit.} % \changes {2018/06/05} {1.40} {Bugfix (\texttt{label-not-defined}): Add |'#1'|.} % \changes {2018/06/05} {1.40} {Bugfix (\texttt{unit-change}): \opt{convert-to-eV} % can be again used as a local argument.} % \changes {2018/06/05} {1.40} {Change order of boolean testing for |\@@_calc_references:NN|.} % \changes {2018/06/05} {1.40} {Bugfix (\texttt{phrases}): Use the phrase from the first amount to check % the second (and don't parse through the second amount).} % % \changes {2018/09/24} {1.45} {Changes prefix from \texttt{cooking\_units} to \texttt{cookingunits}.} % \changes {2018/09/24} {1.45} {New language symbols: \opt{cutext-range-sign}} % \changes {2018/09/24} {1.45} {Improved french (not in general, only for this package)} % \changes {2018/09/24} {1.45} {New section in documentation.} % \changes {2018/09/24} {1.45} {Remove exhaustive expansion from internals (shouldn't change anything for users).} % % % % % % % % \GetFileInfo{\jobname.sty} % %\title{The \pkg{\jobname} package^^A %\thanks{This document corresponds to \textsf{Benedikt Vitecek}~\fileversion, dated~\filedate.}} %\author{Ben Vitecek \\ b.vitecek@gmx.at}% %\date{\filedate}% % % % \maketitle % % \begin{documentation} % \begin{abstract} % This package enables user to globally format units, to switch % between them and change your recipes to a given % number of persons. % % For not implemented units or differences between Imperial and U.S.\ unit % you may have a look at \cref{sec:other-units}. % % It should be used for light-hearted things like % cookery books (and not e.g. scientific texts; use e.g.\ \pkg{siunitx} for those). % % Please read through the section \enquote{Important Changes} % \end{abstract} % % \tableofcontents % % \section{Introduction} % % % While writing on a cookery book I used -- for some reasons whatsoever -- % three different units for weight: kilogram (kg), gram (g) and % decagram (dag, or older: dkg). Later my mother told me that she % doesn't like it if a cookery book uses more than two different units % (for weight in this case). Happily I hardly used Decagram and % therefore didn't have many problems changing the units. But, well % \dots\ I am using \LaTeX\ and changing those units by hand seemed % not very \LaTeX-like, so I started writing some code to convert % units. I expanded the code, rewrote it in \LaTeX3 (which is much % more pleasant than \LaTeXe) and here it is. % % % \begin{comment} % \subsection{Overview} % \begin{description} % \item[Language] I am now using the \pkg{translations} package % and I hope it makes things easier. As such, declaring the used language % through class options shouldn't be necessary anymore. % \item[Phrases] This package now supports the usage of \enquote{phrases} % (words used instead of certain integers) (which I think are called \enquote{counting % measures} in english, but I am not sure). % \item[\cCutext] If no translation is found for a specific language, % \cCutext\ are replaced by \mycs{cunum} with a warning is given. % \item[Commands] Currently, it seems that allowing \meta{label} % to be set by arrow-brackets was not the best idea as it leads to problems % if they are made active (e.g. \pkg{babel} and option \opt{spanish}). As such, % |<| is not allowed as a \enquote{special-sign} anymore as this package % tries to \enquote{fix} this idea (at least make it work). If any problems occur % (for this specific case or in general) please feel free to contact me. % \end{description} % \end{comment} % % % % \subsection{Supported languages} % \cookingunitsToDo{Passt.} % \begin{itemize} % \item German % \item English % \item French (currently suboptimal\footnote{You can only get limited information from the internet.}) % \end{itemize} % Want to contribute a new language or make a correction to an existing one? % See \cref{sec:bug-feed} for more details. Wanna just check the % existing translations? See \cref{sec:Translations}. % % \section {The Commands} % \label{sec:commands} % \cookingunitsToDo{Passt.} % % This package offers the following commands for unit printing (and % converting): % % \begin{itemize} % \item \mycs{cunum}\myaarg{label}\oarg{options}\marg{amount}\oarg{space}\marg{unit-key} % \item \mycs{cutext}\myaarg{label}\oarg{options}\marg{amount}\marg{unit-key} % \item \mycs{Cutext}\myaarg{label}\oarg{options}\marg{amount}\marg{unit-key} % \item \mycs{cuam}\myaarg{label}\oarg{options} \marg{amount} % \item \mycs{cusetup}\marg{options} % \end{itemize} % % Numbers and units are printed using \mycs{cunum}. The numerical part % can interpret \verb|_| and \texttt{/} as (mixed) fractions and % \verb|--| as a separator for ranges; to convert units use the option % \texttt{\meta{old-unit}=\meta{new-unit}}\footnote{New keys can be % added and defined, see \cref{sec:pred-units} and % \cref{sec:def-units} for further information.}. It furthermore % allows the sign \texttt{?} to be used as a placeholder for not known % amounts and raises a warning to remind that this amount needs a % check-up\footnote{You can customize this behavior, see % \cref{sec:options}}. \oarg{space} adds a space between the number % and the unit using \lstinline|\phantom|. % % For a list of predefined units have a look at \cref{tab:def-units}. % % \meta{label} is explained in \cref{sec:labeletref}. % % % \begin{cuexamplecode} % \cunum{1}{kg} \\ % \cunum{2.3}{kg} \\ % \cunum{2,3}{kg} \\ % \cunum{2--3}{kg} \\ % \cunum{2.5--3.5}{kg} \\ % \cunum[kg=g]{2.5--3,5}{kg} \\ % \cunum[C=F]{200}{C} \\ % \cunum[C=F]{180--200}{C} \\ % \cunum{1/2}{m} \\ % \cunum{1_1/2}{m} \\ % \cunum[m=cm]{1_1/2}{m} \\ % \cunum{?}{l} \\ % \cunum{50}{dag} \\ % \cunum{5}[0]{dag} \\ % \cunum{1.1234}{m} % \end{cuexamplecode} % % Decimal numbers are automatically rounded to 2 digits after the % colon, temperatures (\myunit{C}, \myunit{F}, \myunit{K} and % \myunit{Re}) are automatically rounded to integers.\footnote{You can % -- of course -- change this behavior, see \cref{sec:options}.} % % % \cCutext\ print the number and the written name of the unit. Since % v1.10 it works similar\footnote{One could also say \enquote{exactly % like}.} to \mycs{cunum}: it allows the conversion between units and % interprets the numerical part (again |_| and |/| are used for % (mixed) fractions and |--| for ranges). Furthermore, \cCutext\ allow % the usages of numerals (see \cref{sec:load-time-options} for more information). %^^A if the package %^^A option \opt{use-fmtcount-numerals} (see \cref{sec:load-time-options}) %^^A is used, integers below a specific integer %^^A (by default 13; see \opt{use-numerals-below}) are written out with %^^A \lstinline|\Cutext| capitalizing the first letter (using package %^^A \pkg{fmtcount}). % % % \begin{cuexamplecode} % \cutext{1}{l} \\ % \Cutext{1}{l} \\ % \Cutext{1--2}{l} \\ % \cutext{12}{l} \\ % \Cutext{13}{l} % \end{cuexamplecode} % and using (e.g.) package option \opt{use-fmtcount-numerals=true} % \cusetup{print-numerals=true} % \begin{cuexamplecode} % \cutext{1}{l} \\ % \Cutext{1}{l} \\ % \cutext{1--2}{l} \\ % \Cutext{1--2}{l} \\ % \cutext{12}{l} \\ % \Cutext{13}{l} % \end{cuexamplecode} % \cusetup{print-numerals=false} % You can customize the numeral functions used with \opt{numeral-function} and % \opt{Numeral-function}. % % Furthermore, % since v1.10 \cCutext\ also allow their units to be changed (this behavior % can be altered using \opt{cutext-change-unit}): % \begin{cuexamplecode} % \cusetup{ l=ml } @ % \cutext{1}{l} \\ % \Cutext{1}{l} \\ % \cutext{1--2}{l} \\ % \cutext{12}{l} \\ % \Cutext{13}{l} \\ % \Cutext{?}{l} \\ % \Cutext{1/2}{l} \\ % \end{cuexamplecode} % % % \lstinline|\cuam| works like \mycs{cunum}, but without a unit, so % changing units doesn't affect it. Like \mycs{cunum} \texttt{\_} and % \texttt{/} are used to imply a (mixed) fraction and |--| is used for ranges. % % \begin{cuexamplecode} % \cuam{3} \\ % \cuam{2--3} \\ % \cuam{2/3} \\ % \cuam{1_2/3} % \end{cuexamplecode} % % Furthermore it allows the concept of \enquote{phrases} (replacing a positive integer % by a word; such as \enquote{12} becoming \enquote{dozen}\footnote{At least I think}) % which can be activated by the option \opt{use-phrases} % (as I don't know any english phrases, I switched the language to german for the following examples) % \begin{myde} % \begin{cuexamplecode} % \cusetup{use-phrases=true} @ % \cuam{11} \\ % \cuam{12} \\ % \cuam{13} \\ % \cuam{24} \\ % \cuam{12--24} \\ % \cuam{12--13}\\ % \cuam{18} \\ % \cuam{60} % \end{cuexamplecode} % \end{myde} % % % \section{Label \& refs: Changing the amount of the recipe} % \label{sec:labeletref} % \cookingunitsToDo{Also not much to change} % % What if you don't want to change units, but the amounts of the recipe because % you cook not for 4 persons, but for 2 and don't like to do the math? % Simple, use the following commands: % % \begin{itemize} % \item \mycs{culabel}\marg{label}\marg{number of persons} % \item \mycs{curef}\marg{label} % \end{itemize} % % % The first one is the important one: It defines a \meta{label} for a recipe % which is initially for \meta{number of persons}. Afterwards \meta{label} % can be used to tell the commands from \cref{sec:commands} that the given % amounts are for \meta{number of persons}. % Each \meta{label} must be unique and an error is raised if a \meta{label} % is already defined. % % If you would like to print the number of persons this recipe is for, use % \mycs{curef}, which is fully expandable. % % The following example uses \mycs{culabel} to specify that the recipe is % initially intended for 2 persons: % \begin{cuexamplecode} % \culabel{recipe}{2} @ % recipe & for & \curef{recipe} & persons: \\ % \cunum{10--20}{dag} & flour, \\ % \cunum{1/2}{l} & water, \\ % \cutext[ref=recipe]{10}{g} & nuts, \\ % \cuam{2--3} & eggs, \\ % \cunum{180}{C} & (\cunum[C=F]{180}{C}) & open & fire % \end{cuexamplecode} % % In combination with the option \opt{set-number-of-persons} % and \opt{recalculate-amount} you can have this recipe % changed to four persons: % \begin{lstlisting} % \culabel{recipe}{2} % %% adding options: % \cusetup{set-number-of-persons=4,recalculate-amount=true} % \end{lstlisting} % \cusetup{set-number-of-persons=4,recalculate-amount=true} % % \begin{cuexamplecode} % recipe & for & \curef{recipe} & persons: \\ % \cunum{10--20}{dag} & flour, \\ % \cunum{1/2}{l} & water, \\ % \cutext[ref=recipe]{10}{g} & nuts, \\ % \cuam{2--3} & eggs, \\ % \cunum{180}{C} & & (\cunum[C=F]{180}{C}) & open & fire % \end{cuexamplecode} % \cusetup{recalculate-amount=false} % % Note that fractions are automatically evaluated and that only values % with a \meta{label} are changed (\lstinline|\cunum{180}{C}| for example % stays the same which also makes sense as the heat should be the same). % % % % \begin{comment} % \section{Some Interesting options} % \cookingunitsToDo{This section is horrible, change or delete as a whole, but later} % This package has some options which might be of interest and to highlight them, this section exists. All options can be % found in \cref{sec:options}. % % %\subsection{Numerals} % \begin{cuinterest}{use-fmtcount-numerals, use-numerals-below, print-numerals} % As seen above, you can use the \emph{package}-option % \opt{use-fmtcount-numerals} to print integers used by \cCutext{} below % \opt{use-numerals-below} (13 by default) by \pkg{fmtcount}. % You can still decide if numerals should be printed or not with \opt{print-numerals}. % % \begin{cunote} % \opt{use-fmtcount-numerals} is a package option as it needs to load % \pkg{fmtcount} which is not loaded by default. % \end{cunote} % % \end{cuinterest} % % \subsection{Phrases} % \begin{cuinterest}{use-phrases} % In (I presume) all languages there exist phrases for a given % amount or a number of things (think it is called \enquote{counting measurement}). % In German you may say instead of % \enquote{12}: \enquote{ein Dutzend}. Using this option you can tell this % package to replace predefined integers used in \mycs{cuam} % by phrases for the currently used language % (to define new ones, see \cref{sec:phrases}) % % Using (for example) language \opt{ngerman} (or \opt{naustrian}, etc.) with % package option \opt{use-phrases=true} gives: % \begin{myde} % \begin{cuexamplecode} % \cusetup{use-phrases=true} @ % \cuam{12} \\ % \cuam{24} \\ % \cuam{12--24} \\ % \cuam{12--13} \\ % \cuam{18} \\ % \cuam{60} % \end{cuexamplecode} % \end{myde} % This of course also works with the \emph{package}-option \opt{use-fmtcount-numerals}: % \begin{myde} % \cusetup{print-numerals=true} % \begin{cuexamplecode} % \cusetup{use-phrases=true} @ % \cuam{12} \\ % \cuam{24} \\ % \cuam{12--24} \\ % \cuam{12--13} \\ % \cuam{18} \\ % \cuam{60} % \end{cuexamplecode} % \end{myde} % % % \begin{cunote} % Currently only the lower-case variant for \opt{use-fmtcount-numerals} is % supported. Furthermore this feature is only available for \mycs{cuam}. % \end{cunote} % % \end{cuinterest} % % \end{comment} % % % % % % % %\subsection{Rounding temperatures} % % By default temperatures are rounded to integers (using \opt{round-precision=0}). % Since 1.30 it is possible to round amounts to a negative precision. % If you want to round temperatures to the tens see the following % example (\opt{set-option-for-\meta{unit}} is described in \cref{sec:opt:unit-spec}). % % \begin{cuexamplecode} % \cunum{182}{C} \\ % \cunum[C=F]{180}{C} \\ % \cunum[C=Re]{180}{C} \\ % \cunum[C=K]{180}{C} \\ % \cusetoptionfor{C,F,K,Re}{ round-precision = -1 } @ %^^A \cusetup{set-option-for-C = { round-precision = -1 } } @ %^^A \cusetup{set-option-for-F = { round-precision = -1 } } @ %^^A \cusetup{set-option-for-Re = { round-precision = -1 } } @ %^^A \cusetup{set-option-for-K = { round-precision = -1 } } @ % \cunum{182}{C} \\ % \cunum[C=F]{180}{C} \\ % \cunum[C=Re]{180}{C} \\ % \cunum[C=K]{180}{C} \\ % \end{cuexamplecode} % % \section{Predefined units \& some notes} % \label{sec:pred-units} % \cookingunitsToDo{Passt.} % \begin{comment} % In \cref{tab:def-units} and \cref{tab:some-more-units} (and \cref{tab:strange-units}) % you can find % all predefined units. In \cref{sec:Translations} all translations available % are listed. % \end{comment} % % In \cref{tab:def-units} and you can find all predefined units which can be % transformed into each other (sorted by group). Other predefined units % (which cannot be used for transformation) are shown in \cref{tab:some-more-units}. % \Cref{tab:strange-units} pretty much exists just for fun. % % % \begin{table}[htbp] % \centering % \caption{^^A %^^A The first column shows a list of predefined unit-keys. %^^A The column \enquote{default} shows the abbreviation used if %^^A for given language no translation is defined. The translations used for \cCutext\ %^^A are shown in \cref{sec:Translations}. %^^A Note that \enquote{electron volt} exists just for fun. %^^A % This table shows all units which can be transformed into each other, sorted % by group. The columns \enquote{default} show the abbreviations used if % for given language no translation is defined. The translations used for \cCutext\ % are shown in \cref{sec:Translations}. % Note that \enquote{electron volt} exists just for fun. % } % \smallskip % \begin{tabular}{ lll @{\hspace{1cm}} lll } % \toprule % description & key & default & description & key & default \\ \midrule % \PrintUnit {kg} & \PrintUnit{m} \\ % \PrintUnit {dag} & \PrintUnit{dm} \\ % \PrintUnit {g} & \PrintUnit{cm} \\ % \PrintUnit {oz} & \PrintUnit{mm} \\ % \PrintUnit {lb} & \PrintUnit{in} \\ % \PrintUnit [ (of butter)] {stick} \\ \addlinespace % % \PrintUnit {d} & \PrintUnit {l} \\ % \PrintUnit {h} & \PrintUnit {dl} \\ % \PrintUnit {min} & \PrintUnit {cl} \\ % \PrintUnit {s} & \PrintUnit{ml} \\ \addlinespace % % \PrintUnit{cal} & \PrintUnit{C} \\ % \PrintUnit{kcal} & \PrintUnit{F} \\ % \PrintUnit{J} & \PrintUnit{Re} \\ % \PrintUnit{kJ} & \PrintUnit{K} \\ % \PrintUnit{eV} % % \\ \bottomrule % \end{tabular} % \label{tab:def-units} % \end{table} % % \begin{table}[htbp] % \centering % \caption{A (not only) spoonful of (more or less) country and % language dependent units. Please note that sometimes a % translation is nearly impossible as a unit % (e.g. \enquote{saltspoonful}) may not exist in another language % (like german; at least I never heard of it). So please only use % units known to you.} % \smallskip % \begin{tabular}{ lll } % \toprule % description & key & symbol \\ \midrule % \PrintUnit {pn} \\ \addlinespace % \PrintUnit {EL} \\ % \PrintUnit {TL} \\ % \PrintUnit {dsp} \\ % \PrintUnit {csp} \\ % \PrintUnit {ssp} \\ \addlinespace % \PrintUnit [Messerspitze (point of a knife)] {Msp} \\ % \bottomrule % \end{tabular} % \label{tab:some-more-units} % \end{table} % % \begin{table}[htbp] % \centering % \caption{List of (not really) nonsense units (exist just for fun, there will be % no support for those units; unless -- of course -- you really want it).} % \smallskip % \begin{tabular}{ ll } % \toprule % unit-key & symbol \\ \midrule % \PrintUnitSymbol {eVc-2} \\ % \PrintUnitSymbol {hbareV-1} \\ % \PrintUnitSymbol {chbareV-1} \\ % \PrintUnitSymbol {(chbareV-1)3} \\ % \bottomrule % \end{tabular} % \label{tab:strange-units} % \end{table} % % % % \section{Defining units} % \label{sec:def-units} % \cookingunitsToDo{Passt.} % New units can be defined using % \begin{itemize} % \item \mycs{declarecookingunit}\oarg{symbol}\marg{unit-key} % \item \mycs{newcookingunit}\oarg{symbol}\marg{new-unit-key} % \item \mycs{providecookingunit}\oarg{symbol}\marg{new-unit-key} % \end{itemize} % % \begin{function}{\declarecookingunit,\newcookingunit,\providecookingunit} % \begin{syntax} % \mycs{declarecookingunit}\oarg{symbol}\marg{unit-key} % \mycs{newcookingunit}\oarg{symbol}\marg{new-unit-key} % \mycs{providecookingunit}\oarg{symbol}\marg{unit-key} % \end{syntax} % These commands define the unit \meta{unit-key}. If the % key is not the same as the printed symbol use \oarg{symbol}. % Note that \meta{unit-key} can neither contain |/| nor |,|. % % Please note due to the current implementation catcodes may cause % trouble. For example using |:| inside \meta{unit-key} may cause % the key to \enquote{not be defined} in the document. If that happens % try removing or changing the \meta{unit-key}. % % \mycs{newcookingunit} raises an error if the unit is already defined, % \mycs{declarecookingunit} creates or (if given) overwrites \meta{symbol} % and \mycs{providecookingunit} does nothing if the unit is already % defined. % % All units have male gender |m| by default. % % Some examples: % \begin{lstlisting} % \declarecookingunit{kg} % \declarecookingunit{g} % \declarecookingunit[Msp.] {Msp} % \declarecookingunit[\ensuremath{{}^{\circ}}\kern-\scriptspace C] {C} % \end{lstlisting} % % \end{function} % \begin{cunote} % The definition of the printed degree Celsius is % copied and pasted from (a maybe older version of) \pkg{siunitx}. % \end{cunote} % % % % \begin{function}{\declarecookingderivatives} % \begin{syntax} % \mycs{declarecookingderivatives} \marg{unit-list} \marg{unit-key} % \ \ \marg{mathematical-relation} \marg{unit-symbol} % \end{syntax} % % \emph{This function is experimental}. Defines new units which are a combination % of the units given in \meta{unit-list} \emph{and} their linked-units. % \meta{unit-key}, \meta{mathematical-relation} and \meta{unit-symbol} % accept |#1| to |#n| as arguments with $n$ being the number of units % given in \meta{unit-list}. $n$ \emph{cannot} be greater than $8$ (and it will % probably compile for quite a while). Also note that this command doesn't work/isn't % tested for single keys. % % Also note that it is quite possible that an \enquote{overflow-error} will % occur if there are too many units. % % \end{function} % % \begin{cunote} % Due to catcodes (and my inability to deal with them properly) % there can be problems when using |:| % (and probably other signs) inside \meta{unit-key}. % \end{cunote} % % \begin{cuexample} % Your homework is to change the unit of energy \si{\kg\m\squared\per\s\squared} % into \si{\ounce\inch\squared\per\minute\squared}. To check if you are correct % you use \mycs{declarecookingderivatives}: % \begin{lstlisting} % \declarecookingderivatives{kg,m,s}{#1*#2-#3} % { (#1)*(#2)^2/(#3)^2 } {\sfrac{#1\,#2${}^2$}{#3${}^2$}} % \end{lstlisting} % % Using |\cunum[kg*m-s=oz*in-min]{1}{kg*m-s}| shows that % \cunum{1}{kg*m-s} is equal to \cunum{196829101.34}{oz*in-min}. % (Note: This is \emph{really} experimental and it can easily happen that % an \enquote{overflow-error} occurs) (like for me which is why I hard-coded the % results after testing). % % \end{cuexample} % % % % \section{Defining options to change units} % \label{sec:defining-opt} % \cookingunitsToDo{Passt.} % Options (to change units) can be newly defined or added to already existing keys (units) % using % \begin{itemize} % \item \mycs{cudefinekeys} % \item \mycs{cudefinesinglekey} % \item \mycs{cuaddkeys} % \item \mycs{cuaddsinglekeys} % \item \mycs{cuaddtokeys} % \end{itemize} % I apologize for the (name) inconsistency between \mycs{cudefinekeys} and % \mycs{cudefinesinglekey} (although they are named similarly, they work differently). % % \begin{function}{\cudefinekeys,\cudefinesinglekey} % \begin{syntax} % \mycs{cudefinekeys}\marg{unit-key-1} % \ \ \{ % \ \ \ \ \marg{unit-key-2} \marg{$1$ unit-key-1 are \dots\ unit-key-2} % \ \ \ \ \marg{unit-key-3} \marg{$1$ unit-key-1 are \dots\ unit-key-3} % \ \ \ \ \marg{unit-key-4} \marg{$1$ unit-key-1 are \dots\ unit-key-4} % \ \ \ \ \dots % \ \ \} % % \mycs{cudefinesinglekey}\marg{unit-key-1} % \ \ \{ % \ \ \ \ \marg{unit-key-2} \marg{$1$ unit-key-2 are \dots\ unit-key-1} % \ \ \ \ \marg{unit-key-3} \marg{$1$ unit-key-3 are \dots\ unit-key-1} % \ \ \ \ \dots % \ \ \} % \end{syntax} % % If you define new units (see \cref{sec:def-units}) and cannot add % them to already existing keys you can use % \lstinline|\cudefinekeys| or \lstinline|\cudefinesinglekey| respectively to % define new keys. % % \lstinline|\cudefinekeys| takes \marg{unit-key-1} as a % \enquote{basis}, defines a key with the name \meta{unit-key-1} and % adds the values \meta{unit-key-1}, \meta{unit-key-2}, % \meta{unit-key-3}, etc. Furthermore this command also defines the % keys \meta{unit-key-2}, \meta{unit-key-3}, etc. with the same % values as \meta{unit-key-1}. Please note that \meta{\dots} has to % be a number. % % Sometimes it is not that easy and the conversion of one unit into % another needs are more complicated formula (see for example % temperatures). If that is the case use % \lstinline|\cudefinesinglekey|. As the name says it defines % \emph{only} the key \meta{unit-key-1} with the values % \meta{unit-key-1}, \meta{unit-key-2}, etc. The advantage of this % command is that now \meta{\dots} can be a formula and the % numerical input can be placed explicitly using \texttt{\#1}. % % % \end{function} % % \begin{cuexample} % % This example defines following keys with their respective value: % \begin{itemize} % \item the key \myunit{kg} with the values \myunit{kg}, \myunit{dag}, % \myunit{g} and \myunit{oz} % \item the key \myunit{dag} with the values \myunit{kg}, % \myunit{dag}, \myunit{g} and \myunit{oz} % \item the key \myunit{g} with the values \myunit{kg}, \myunit{dag}, % \myunit{g} and \myunit{oz} % \item the key \myunit{oz} with the values \myunit{kg}, \myunit{dag}, % \myunit{g} and \myunit{oz} % \item the key \myunit{d} with the values \myunit{d}, \myunit{h}, % \myunit{min} and \myunit{s} % \item \dots % \end{itemize} % \begin{align*} % \SI{1}{\kg}&= \SI{1}{\kg} & % \SI{1}{\kg}&= \SI{100}{\deka\g} & % \SI{1}{\kg}&= \SI{1000}{\g} \\ % \SI{1}{\kg}&= \SI{35.27399}{\ounce} & % \SI{1}{\kg}&= \SI{2.204 622 6}{\pound} % \end{align*} % \begin{lstlisting} % \cudefinekeys {kg} % { % {dag}{ 100 } %% 1 kg are 100 dag % {g} { 1000 } %% 1 kg are 1000 g % {oz} { 35.27399 } %% 1 kg are 35.27399 oz % {lb} { 2.204 622 6 } %% 1 kg are 2.204 622 6 lb % } % % \cudefinekeys {d} % { % {h} { 24 } %% 1 day are 24 hours % {min}{ 1440 } %% 1 day are 1440 minutes % {s} { 86400 } %% 1 day are 86400 seconds % } % \end{lstlisting} % % To convert degree Fahrenheit to degree Celsius, kelvin and degree R\'eamur one % needs the formulas\footnote{See Wikipedia.} % \begin{align*} % T_C &= ( T_F - 32 ) \cdot \frac{5}{9} \\ % T_K &= ( T_F - 459.67 ) \cdot \frac{5}{9} \\ % T_{Re} &= ( T_F - 32 ) \cdot \frac{4}{9} % \end{align*} % with $T_F$ being the input temperature in degree Fahrenheit and % $T_C$ being the same temperature in degree Celsius, etc. Using % \lstinline|\cudefinesinglekey| the key \myunit{F} with values % \myunit{C}, \myunit{K} and \myunit{Re} is defined: % % \begin{lstlisting} % \cudefinesinglekey {F} % { % {C} { ( #1 - 32 ) * 5/9 } %% see formulas above % {K} { ( #1 + 459.67 ) * 5/9 } % {Re} { ( #1 - 32 ) * 4/9 } % } % \end{lstlisting} % % This defines the key \myunit{F} with the values \myunit{F}, \myunit{C}, % \myunit{K} and \myunit{Re}. % % \end{cuexample} % % % % \begin{function}{\cuaddkeys,\cuaddsinglekeys} % % \begin{syntax} % \mycs{cuaddkeys}\marg{unit-key-1} % \ \ \{ % \ \ \ \ \marg{unit-key-2} \marg{$1$ unit-key-1 are \dots\ unit-key-2} % \ \ \ \ \marg{unit-key-3} \marg{$1$ unit-key-1 are \dots\ unit-key-3} % \ \ \ \ \marg{unit-key-4} \marg{$1$ unit-key-1 are \dots\ unit-key-4} % \ \ \ \ \dots % \ \ \} % % \mycs{cuaddsinglekeys}\marg{unit-key-1} % \ \ \{ % \ \ \ \ \marg{unit-key-2} \marg{$1$ unit-key-2 are \dots\ unit-key-1} % \ \ \ \ \marg{unit-key-3} \marg{$1$ unit-key-3 are \dots\ unit-key-1} % \ \ \ \ \dots % \ \ \} % \end{syntax} % % These commands add \meta{unit-key-2}, etc. to the already defined % key \meta{unit-key-1}. % % \lstinline|\cuaddkeys| takes the already defined key % \marg{unit-key-1} as a \enquote{basis}, and adds % \meta{unit-key-2}, \meta{unit-key-3}, etc. to its % values. Furthermore it adds those new values to other keys linked % to \meta{unit-key-1} and defines the new keys \meta{unit-key-2}, % etc.\ with the same values as \meta{unit-key-1}. % % % If the conversion is more complicated use % \lstinline|\cuaddsinglekeys|. It adds \meta{unit-key-2}, etc.\ as % values to \meta{unit-key-1}. The numerical input can be placed % using \myunit{\#1} (see \lstinline|\cudefinesinglekey|). This % command neither defines new keys nor does it add values to other % keys than \meta{unit-key-1}. % % % \end{function} % % % \begin{cuexample} % Suppose you are British (I am sorry, I can't think of another % reason to use those units) and you want to implement 'stone' (yes, % I was surprised myself that such a unit exists, but it even % appears in a Sherlock Holmes story). You exactly know that % \SI{1}{\st} equals \SI{14}{\lb}, well \dots\ now you have two % choices. \lstinline|\cuaddkeys| or \lstinline|\cuaddtokeys| (use % the one best fitting). This example uses the first, the next the % latter one. % \begin{lstlisting} % \newcookingunit{st} %% defining new unit 'stone' % \cuaddkeys{lb} %% adding st to lb (could also add to kg, dag and oz) % { % {st} { 1/14 } %% 1 lb are 1/14 st as 14 lb are 1 st % } % \end{lstlisting} % \begin{cuexamplecode} % \cunum[lb=st]{1}{lb} \\ % \cunum[st=lb]{1}{st} \\ % \cunum[st=g]{1}{st} \\ % \cunum[st=kg]{1}{st} \\ % \cunum[kg=st]{1}{kg} \\ % \cunum[st=kg]{16}{st} % \end{cuexamplecode} % \end{cuexample} % % % \begin{cuexample} % Now you want to add degree R{\o}mer and convert Celsius to degree % R{\o}mer: % \begin{equation*} % T_{R\text\o} = T_C * \frac{21}{40} + 7.5 % \end{equation*} % % \begin{lstlisting} % %% defining new unit 'degree R{\o}mer' % \newcookingunit [\ensuremath{ {} ^ { \circ } }\kern-\scriptspace R{\o}] {Ro} % \cuaddsinglekeys {C} %% adds value 'Ro' to 'C'. % { % {Ro} { #1 * 21/40 + 7.5 } % } % \cusetup %% round to integer automatically % { % set-option-for-Ro = { round-precision = 0 } % } % \end{lstlisting} % \begin{cuexamplecode} % \cunum{10}{C} \\ % \cunum[C=Ro]{10}{C} % \end{cuexamplecode} % \end{cuexample} % % % % % % % % % % % % \begin{function}{\cuaddtokeys} % \begin{syntax} % \mycs{cuaddtokeys} \marg{unit-key-1} \marg{unit-key-2} \marg{$1$ unit-key-2 are \dots\ unit-key-1} % \end{syntax} % Works similar to \mycs{cuaddkeys} regarding the definition of keys. % \end{function} % % \begin{cuexample} % Continuing the example from before, this time with \lstinline|\cuaddtokeys|: % \begin{lstlisting} % \newcookingunit{st} %% defining (again) new unit 'stone' % \cuaddtokeys {lb} {st} { 14 } %% 1 st are 14 lb % \end{lstlisting} % \begin{cuexamplecode} % \cunum[lb=st]{1}{lb} \\ % \cunum[st=lb]{1}{st} \\ % \cunum[st=g]{1}{st} \\ % \cunum[st=kg]{1}{st} \\ % \cunum[kg=st]{1}{kg} \\ % \cunum[st=kg]{16}{st} % \end{cuexamplecode} % \end{cuexample} % % \begin{comment} % \begin{cuexample} % Implementation of \myunit{stick}. From https://cooking.stackexchange.com/questions/784/translating-cooking-terms-between-us-uk-au-ca-nz % we know that % \[ \SI{1}{\stick} = \SI{0.25}{\lb} \] % % There are two ways to implement \myunit{stick}: % either use \mycs{cuaddkeys} or \mycs{cuaddtokeys}. % % The easier way (in this case) is \mycs{cuaddtokeys} which is pretty straight forward: % \begin{lstlisting} % \cuaddtokeys { lb } { st } { 0.25 } % \end{lstlisting} % \dots\ and finished % % \end{cuexample} % \end{comment} % % % % % % % % % % % % % % % \section{Language support} % \label{sec:language} % \cookingunitsToDo{Passt.} % % Unit names and symbols depend on the language. To change the % name and symbol for given language you can use \lstinline|\cudefinename|; % to only change symbols use \lstinline|\cudefinesymbol|. % % \begin{function}{decimal-mark,cutext-range-sign, one(m),one(f),one(n)} % Those are special keys (as they cannot be used as units). Not only % are printed units language depending, but as is the decimal mark % (|.| or |,|) and the text which substitutes the range-sign. % To set the decimal mark use % \opt{decimal-mark} (see examples below), to set the range-sign for \cCutext\ % use \opt{cutext-range-sign}. % % Note that \opt{cutext-range-sign} is \enquote{overwritten} by the \emph{option} % \opt{cutext-range-sign}. If the \emph{option} is set, then the language symbol % will be ignored. % % Furthermore if you are using numerals % you may also use the keys \opt{one(m)}, \opt{one(f)} and % \opt{one(n)}. Integers below a certain % value (see option \opt{use-numerals-below}) are written-out. The % only problem is the written-out \enquote{1} mostly depends on the % gender of the word following (e.g. \enquote{ein Baum} (m), % \enquote{eine Pflanze} (f) and \enquote{ein Auto} (n)). To set the % written-out \enquote{1} to be correct with the gender of the used unit, use % these keys (see also examples below) % \end{function} % % \begin{function}{\cudefinename} % \begin{syntax} % \mycs{cudefinename}\marg{Language} % \ \ \{ % \ \ \ \ \marg{unit-key-1} \oarg{symbol-1} \marg{singular-1} \oarg{plural-1} \myaarg{gender} % \ \ \ \ \marg{unit-key-2} \oarg{symbol-2} \marg{singular-2} \oarg{plural-2} \myaarg{gender} % \ \ \ \ \dots % \ \ \} % \end{syntax} % % This command defines the names (and optionally the symbol) of the % units printed in \lstinline|\cutext| and \lstinline|\Cutext| % (and \lstinline|\cunum| regarding the symbol) for the specific % \meta{Language}. For details regarding \meta{language} see the % \pkg{translations} documentation. % % If the plural form of the name differs from the singular form use % \oarg{plural} to specify the plural form, else it will be equal to its singular % form. The singular form % is only used if the number in \lstinline|\cutext| and % \lstinline|\Cutext| is equal to $1$. % % \meta{gender} can be \texttt{m} (maskulin), \texttt{f} (feminin) or % \texttt{n} (neutrum). If not given \texttt{m} is used as default. % \end{function} % % \begin{lstlisting} % \cudefinename {English} % { % {kg} {kilogramme} % {oz} {ounce} % {h} {hour} [hours] % {C} {degree\space Celsius} [degrees\space Celsius] % {decimal-marker} {.} % {cutext-range-sign} {~to~} % {one(m)} {one} % {one(f)} {one} % {one(n)} {one} % } % \end{lstlisting} % \begin{lstlisting} % \cudefinename {German} % { % {kg} {Kilogramm} % {oz} {Unze} % {d} {Tag} [Tage] % {h} {Stunde} [Stunden] % {C} {Grad\space Celsius} % {decimal-marker} {,} % {cutext-range-sign} {~bis~} % {one(m)} {ein} % {one(f)} {eine} % {one(n)} {ein} % } % \end{lstlisting} % % % \begin{function}{\cudefinesymbol} % % \begin{syntax} % \mycs{cudefinesymbol}\marg{Language} % \ \ \{ % \ \ \ \ \marg{unit-key-1} \marg{symbol-1} % \ \ \ \ \marg{unit-key-2} \marg{symbol-2} % \ \ \ \ \dots % \ \ \} % \end{syntax} % % This command defines the symbols of the units printed in % \lstinline|\cunum| for the specific \meta{Language}. It works % similar as \lstinline|\cudefinename|, but only the symbols (and no % names) can be set. For details regarding \meta{Language} see % the \pkg{translations} documentation. % % \end{function} % % % \begin{lstlisting} % \cudefinesymbol {English} % { % {decimal-mark} {.} % {cutext-range-sign} {~to~} % {one(m)} {one} % {one(f)} {one} % {one(n)} {one} % } % \cudefinesymbol {German} % { % {decimal-mark} {,} % {cutext-range-sign} {~bis~} % {one(m)} {ein} % {one(f)} {eine} % {one(n)} {ein} % } % \cudefinesymbol {French} % { % {l} {L} % {dl} {dL} % {cl} {cL} % {ml} {mL} % {decimal-mark} {.} % {one(m)} {un} % {one(f)} {une} % {one(n)} {un} % } % \end{lstlisting} % % \begin{cuexample} % Imagine that instead of the abbreviation \enquote{dag} for \enquote{decagramme} % you want to use \enquote{ducks} (because \dots\ I don't know). You can easily % do this via % \begin{lstlisting} % \cudefinesymbol {English} % { % {dag} {ducks} % } % \end{lstlisting} % \cudefinesymbol {English} % { % {dag} {ducks} % } % As you can see it may be a bit suboptimal as there is no plural version allowed. % You do it anyway and end up with: % \begin{cuexamplecode} % \cunum{12}{dag} & weed\\ % \cunum{3}[0]{dag} & nuts\\ % \cunum{10}{dag} & duckmeat % \end{cuexamplecode} % % % \end{cuexample} % % % % % % % \subsection{Phrases} % \label{sec:phrases} % % Each language has synonyms for certain (integer) numbers. This package % supports those phrases and they can be implemented with the following % command and used by \mycs{cuam}: % % \begin{function}{\cudefinephrase} % \begin{syntax} % \mycs{cudefinephrase}\marg{Language} % \ \ \{ % \ \marg{integer-1} \marg{phrase-1} \oarg{phrase-1-plural} \myaarg{gender-1} % \ \marg{integer-2} * \marg{phrase-2} \oarg{phrase-2-plural} \myaarg{gender-2} % \ \dots % \ \ \} % \end{syntax} % % This command pairs for a given \marg{Language} (see package \pkg{translations}) % the number \marg{integer-1} % with \marg{phrase-1} (\& plural and gender). The package then checks if the amount % given in \mycs{cuam} is either this number or a \emph{multiple} of it. % % If the behavior of checking for a multiple is not wanted, you can use the optional % star \texttt{*} for a given \marg{integer} % % \meta{gender} can be \opt{m}, \opt{f} or \opt{n}. It is \opt{m} by default. % % Afterwards the numbers are ordered from highest to lowest so that % the phrase with the highest number is used (if used at all). % % Furthermore, it chooses star (|*|) phrases over non-star phrases. % \begin{cunote} % Numbers with the optional star |*| are stored as negative numbers. % \end{cunote} % \end{function} % \begin{cuexample} % The following example creates some phrases for the language % \enquote{German}: % % \cudefinephrase {German} % { % { 60 } {Schock} % { 6 }* {halbes\ Dutzend} % } % % % \begin{lstlisting} % \cudefinephrase {German} % { % { 12 } {Dutzend} %% implemented by default % { 60 } {Schock} % { 6 }* {halbes\ Dutzend} % } % \end{lstlisting} % Let's just use them (german language activated!): % \begin{myde} % \begin{cuexamplecode} % \cusetup{use-phrases=true} @ % \cuam{12} \\ % \cuam{24} \\ % \cuam{60} \\ % \cuam{120} \\ % \cuam{6} \\ % \cuam{18} % \end{cuexamplecode} % \end{myde} % % As you can see, \enquote{Schock} ($60$) is preferred over \enquote{Dutzend} ($12$) % as it linked to the higher number. Furthermore, for $6$ the phrase \enquote{halbes % Dutzend} (half a dozen) is used, but because it is a star version it is \emph{not} % used for $18$. % % \end{cuexample} % % % \section{Options} % \label{sec:options} % % \cookingunitsToDo{Done. Passr.} % % Options in \pkg{cooking-units} can mostly be set globally using % \lstinline|\cusetup| or locally using the optional argument of the % respective command (but \emph{not} as a package option). The only % exception is the option given in \cref{sec:load-time-options} which % needs to be used as a package option. % % \begin{function}{\cusetup} % \begin{syntax} % \mycs{cusetup}\marg{options} % \end{syntax} % Options can be set using \mycs{cusetup}\Arg{options}. % \end{function} % % % \begin{function}{\cusetoptionfor,\cuaddoptionfor,\cuclearoptionfor} % % \begin{syntax} % \mycs{cusetoptionfor}\marg{unit-list}\marg{options} % \mycs{cuaddoptionfor}\marg{unit-list}\marg{options} % \mycs{cuclearoptionfor}\marg{unit-list} % \end{syntax} % \pkg{cooking-units} allows you to attach options to units. % Those % options are activated if (and only if) the specific unit is used \emph{or} % if another unit is converted % into it. Those options allow you to e.g.\ round temperatures to % integers automatically. Furthermore, those added options are % overwritten by local options. % % \mycs{cusetoptionfor} \emph{sets} \meta{options} to each unit in \meta{unit-list} % overwriting the old ones. % % \mycs{cuaddoptionfor} \emph{add}s \meta{options} to each unit in \meta{unit-list}. % % \mycs{cuclearoptionfor} clears all options given to each unit in \meta{unit-list}. % \end{function} % \begin{cuexample} % Temperatures \myunit{C}, \myunit{F}, \myunit{K} and \myunit{Re} are % by default rounded to integers. % \begin{cuexamplecode} % \cunum{75.23}{C} \\ % \cunum{75.23}{F} \\ % \cunum{75.23}{K} \\ % \cunum{75.23}{Re} \\ % \cusetoptionfor{C,F,K,Re}{round-precision=-1} @ % \cunum{75.23}{C} \\ % \cunum{75.23}{F} \\ % \cunum{75.23}{K} \\ % \cunum{75.23}{Re} \\ % \cuclearoptionfor{C,F,K,Re} @ % \cunum{75.23}{C} \\ % \cunum{75.23}{F} \\ % \cunum{75.23}{K} \\ % \cunum{75.23}{Re} % \end{cuexamplecode} % \end{cuexample} % % \subsection{Load time options} % \label{sec:load-time-options} % \begin{function}{use-fmtcount-numerals} % \begin{syntax} % \cs{usepackage}[use-fmtcount-numerals=\meta{true/false}]\{cooking-units\} % \end{syntax} % If set to \true\ loads package \pkg{fmtcount} and uses % \cs{numberstringnum} for \mycs{cutext} % and \cs{Numberstringnum} for \mycs{Cutext} to write-out numbers below % \opt{use-numerals-below} ($13$ by default), integers above are % printed as numbers. % You can decide to not print any numerals by setting \opt{print-numerals} % to \false. % % Note: You don't need to use this function to use numerals. Using % \opt{print-numerals} and setting \opt{numeral-function} and \opt{Numeral-function} % also works. % \end{function} % % \cusetup{print-numerals=true} % \begin{cuexamplecode} % \cutext{1}{kg} \\ % \Cutext{1}{kg} \\ % \cutext{2}{kg} \\ % \Cutext{2}{kg} \\ % \cutext{12}{kg} \\ % \Cutext{12}{kg} \\ % \cutext{13}{kg} \\ % \cutext{13}{kg} \\ % \Cutext{14}{kg} % \end{cuexamplecode} % \cusetup{print-numerals=false} % % \begin{cunote} % \opt{use-fmtcount-numerals} is a package option as it needs to load % \pkg{fmtcount} which is not loaded by default. % \end{cunote} % % \begin{cunote} % Please note the keys \opt{one(m)}, \opt{one(f)} % and \opt{one(n)} to change the printed \enquote{one} (as % \enquote{one} is in many languages dependent on the gender of the % following word. E.g in German: Masculine: ein Baum, % Feminin: eine Pflanze, Neutrum: ein Auto). % \end{cunote} % % \begin{cunote} % You can always change the functions used to print numerals with % \opt{numeral-function} and \opt{Numeral-function}. % \end{cunote} % % \subsection{Normal options} % % Options in this subsection can only be set as local options or using % \lstinline|\cusetup|, but \emph{not} as load time options. % % % \subsubsection{Unit Specific options} % \label{sec:opt:unit-spec} % % \begin{function}{} % \begin{syntax} % \meta{unit-key-1} = \meta{unit-key-2} % \end{syntax} % Change \meta{unit-key-1} to \meta{unit-key-2} (see % \cref{sec:defining-opt} to define new options). % \end{function} % % \begin{function}{} % \begin{syntax} % \meta{group} = \meta{unit-key} % \end{syntax} % Changes each unit contained in \meta{group} to \meta{unit-key} (\meta{unit-key} % must be part of \meta{group}). % % \begin{center} % \begin{tabular}{ll} % \toprule % \meta{group} & default \meta{unit-key}s \\ \midrule % \PrintGroup{weight} \\ % \PrintGroup{length} \\ % \PrintGroup{volume} \\ % \PrintGroup{temperature} \\ % \PrintGroup{energy} \\ % \PrintGroup{time} \\ \bottomrule % \end{tabular} % \end{center} % \end{function} % % \begin{cuexamplecode} % \cusetup{weight=g} @ % \cunum{1}{kg} \\ % \cunum{1}{dag} \\ % \cunum{1}{g} \\ % \cunum{1}{oz} \\ % \cunum{1}{lb} \\ % \cunum{1}{stick} \\ % \end{cuexamplecode} % % You can define new groups using \mycs{cudeclareunitgroup}: % \begin{function} {\cudeclareunitgroup} % \begin{syntax} % \mycs{cudeclareunitgroup} \marg{group-name} \marg{unit-list} % \end{syntax} % Defines the group \meta{group-name} containing the list \meta{unit-list}. % This allows the usage of |\meta{group-name}=\meta{unit-key}| to % change all units in the group \meta{group-name} to \meta{unit-key} % (which has to be part of \meta{unit-list}). % \end{function} % % \begin{cuexample} % Define the group \enquote{weight}: % \begin{lstlisting} % \cudeclareunitgroup {weight} { kg , dag, g, oz, lb, stick } % \end{lstlisting} % Now \lstinline|\cusetup{weight=dag}| can be used to change all units % contained in |weight| to |dag|. % \end{cuexample} % % % \begin{function}{\cuaddtounitgroup} % \begin{syntax} % \mycs{cuaddtounitgroup}\marg{group}\marg{unit-list} % \end{syntax} % Adds \meta{unit-list} to an already existing \meta{group} (both need to exist). % \end{function} % \begin{cuexample} % Adding \myunit{st} to the group \mygroup{weight} % \begin{cuexamplecode} % \cuaddtounitgroup {weight} {st} @ % \cusetup{weight = g } @ % \cunum{1}{kg} \\ % \cunum{1}{dag} \\ % \cunum{1}{g} \\ % \cunum{1}{oz} \\ % \cunum{1}{lb} \\ % \cunum{1}{stick} \\ % \cunum{1}{st} % \end{cuexamplecode} % \end{cuexample} % % % \begin{function}{add-unit-to-group} % \begin{syntax} % add-unit-to-group = % \ \{ % \ \meta{group1} = \marg{unit-key-list}, % \ \meta{group2} = \marg{unit-key-list}, % \ \dots % \ \} % \end{syntax} % Adds each \meta{unit-key} in \meta{unit-keys-list} to \meta{group}. % The key-val equivalent of \mycs{cuaddtounitgroup}. % \end{function} % \begin{cuexample} % The same as above: % This example adds the unit \myunit{st} to the group \mygroup{weight} % and \myunit{Ro} to \mygroup{temperature}. % \begin{lstlisting} % \cusetup % { % add-unit-to-group = { weight = {st} , temperature = {Ro} } % } % \end{lstlisting} % % \cusetup{ add-unit-to-group = { weight = {st} } } % % \begin{cuexamplecode} % \cusetup{weight=g} @ % \cunum{1}{kg} \\ % \cunum{1}{dag} \\ % \cunum{1}{g} \\ % \cunum{1}{oz} \\ % \cunum{1}{lb} \\ % \cunum{1}{stick} \\ % \cunum{1}{st} % \end{cuexamplecode} % \end{cuexample} % % % % \begin{function}{set-option-for-,add-option-for-} % \begin{syntax} % set-option-for-\meta{unit-key} = \marg{ key1 = value1, \dots\ } % add-option-for-\meta{unit-key} = \marg{ key1 = value1, \dots\ } % \end{syntax} % Sets and adds \meta{key1=value1,\dots} to a specific % \meta{unit-key}, % \opt{erase-all-options} (see below) is used to erase all options for all % \meta{unit-key}s. % % The less flexible key-value version of \mycs{cusetoptionfor} and % \mycs{cuaddoptionfor}. % % %^^A You may want to attach some options to a special %^^A \meta{unit-key}. Those options are automatically activated if (and %^^A only if) the specific \meta{unit-key} is used (or changed into this %^^A unit). Setting options overwrites old options. Adding options, well %^^A \dots\ adds the options to the old ones. % %^^A You can \enquote{delete} the options by setting %^^A an empty value for a specific \meta{unit-key} (or use %^^A \opt{erase-all-options} (or \opt{erase-all-options-for} ) %^^A (see below) to erase all options for all \meta{unit-key}s) % % \end{function} % % \begin{cuexample} % The following rounds the values to integers for \myunit{F}, \myunit{C}, % \myunit{K} and \myunit{Re}: % \begin{lstlisting} % \cusetup % { % set-option-for-F = { round-precision = 0 } , % set-option-for-C = { round-precision = 0 } , % set-option-for-K = { round-precision = 0 } , % set-option-for-Re = { round-precision = 0 } % } % \end{lstlisting} % although note that it would be easier to simply write % \begin{lstlisting} % \cusetoptionfor {F,C,K,Re} { round-precision = 0 } % \end{lstlisting} % % \end{cuexample} % % % \begin{function}{set-option-for, add-option-for} % \begin{syntax} % set-option-for = % \ \{ % \ \meta{unit-key1} = \marg{keys=vals}, % \ \meta{unit-key2} = \marg{keys=vals}, % \ \dots % \ \} % add-option-for = % \ \{ % \ \meta{unit-key1} = \marg{keys=vals}, % \ \meta{unit-key2} = \marg{keys=vals}, % \ \dots % \ \} % \end{syntax} % Sets/adds each \meta{keys=vals} to the specific \meta{unit-key}. Works pretty much % the same way their \opt{set-option-for-\meta{unit-key}} and % \opt{add-option-for-\meta{unit-key}} counterparts. % % The less flexible versions of the commands \mycs{cusetoptionfor} and % \mycs{cuaddoptionfor}. % \end{function} % % \begin{cuexample} % The following example does the same as the example above: % \begin{lstlisting} % \cusetup % { % set-option-for = % { % F = { round-precision = 0 } , % C = { round-precision = 0 } , % K = { round-precision = 0 } , % Re = { round-precision = 0 } % } % } % \end{lstlisting} % \end{cuexample} % % \begin{function}{erase-all-options, erase-all-options-for} % \begin{syntax} % erase-all-options % erase-all-options-for = \marg{unit-key1, unit-key2, \dots} % \end{syntax} % Erase options added to units. \opt{erase-all-options} erases all options % for \emph{all} \meta{unit-key}s. % %^^A If you only want to erase options for specific \meta{unit-key}s, you may %^^A use \opt{erase-all-options-for}. % % \opt{erase-all-options-for} is used to remove added options from % the specified \meta{unit-key}s (key-value version of \mycs{cuclearoptionfor}). % % \end{function} % % \begin{cuexample} % The following code erases all attached options from \myunit{C}, \myunit{F}, % \myunit{K} and \myunit{Re}: % % \begin{lstlisting} % \cusetup{ erase-all-options-for = {C, F, K, Re} } % \end{lstlisting} % It's the same as % \begin{lstlisting} % \cuclearoptionfor {C, F, K, Re} % \end{lstlisting} % \end{cuexample} % % % % \subsubsection{Command behavior} % % \begin{function}{cutext-to-cunum} % \begin{syntax} % cutext-to-cunum = \meta{true/false} % \end{syntax} % Want to get rid of all \cCutext? Set this option to \opt{true} and all % \cCutext\ are changed into \mycs{cunum}. % \end{function} % \begin{cuexamplecode} % \cutext{1}{kg} \\ % \Cutext{2}{kg} \\ % \cutext{1/2}{kg} \\ % \cutext{?}{kg} \\ % \cutext[kg=g]{1--2}{kg} \\ % \cusetup{cutext-to-cunum = true } @ % \cutext{1}{kg} \\ % \Cutext{2}{kg} \\ % \cutext{1/2}{kg} \\ % \cutext{?}{kg} \\ % \cutext[kg=g]{1--2}{kg} % \end{cuexamplecode} % % % \begin{function}{cutext-change-unit} % \begin{syntax} % cutext-change-unit = \meta{true/false} % \end{syntax} % Set this option to \opt{false} if you do \emph{not} want the units of \cCutext\ % to be changed. Set to \true\ by default % \end{function} % \begin{cuexamplecode} % \cutext[kg=g]{1}{kg} \\ % \cutext[kg=g]{1/2}{kg} \\ % \cutext[kg=g]{1--2}{kg} \\ % \cusetup{cutext-change-unit = false } @ % \cutext[kg=g]{1}{kg} \\ % \cutext[kg=g]{1/2}{kg} \\ % \cutext[kg=g]{1--2}{kg} % \end{cuexamplecode} % % \begin{function}{cuam-version,cutext-version} % \begin{syntax} % cuam-version = \meta{old/new} % cutext-version = \meta{old/new} % \end{syntax} % Since v1.10 this package also parses and checks the input of % \cCutext\ and \mycs{cuam}. If you want to restore the old % behavior, set this option to \opt{old}, but note that then you can % neither change the amounts for a given number of persons nor % change the unit of \cCutext. Both of them are set to \opt{new} by % default. % \end{function} % % % % % \subsubsection{Hooks} % % \begin{function}{commands-add-hook,cunum-add-hook,cutext-add-hook,Cutext-add-hook,cuam-add-hook} % \begin{syntax} % commands-add-hook = \marg{code} % cunum-add-hook = \marg{code} % cutext-add-hook = \marg{code} % Cutext-add-hook = \marg{code} % cuam-add-hook = \marg{code} % \end{syntax} % Adds \meta{code} to the respective command (or in case of the first key: % to \emph{all} commands). The hook is executed % \emph{after} setting the keys, but \emph{before} parsing and processing the input. % % Please be carful with spaces, they will be printed. % \end{function} % % \begin{cuexample} % You would like to count how often all commands of this package are used. % Simply add: % \begin{lstlisting} % \newcounter{CookingUnitsCounter} %% or however you like it % \cusetup{commands-add-hook={\stepcounter{CookingUnitsCounter}}} % %% beware of spaces inside the add-hook keys. % \end{lstlisting} % to your preamble. The following table lists how often each command % is used in this documentation (with help of \pkg{totalcount}): % % \begin{center} % \begin{tabular}{lr} % \toprule % command & times \\ \midrule % \mycs{cunum} & \totalcunumCounters \\ % \mycs{cutext} & \totalcutextCounters \\ % \mycs{Cutext} & \totalCutextCounters \\ % \mycs{cuam} & \totalcuamCounters \\ % \cmidrule{2-2} % total & \totalCookingUnitsCounters \\ % \bottomrule % \end{tabular} % \end{center} % \end{cuexample} % % \subsubsection{Input and Outputs} % % % \begin{function}{expand-both , expand-amount, expand-unit} % \begin{syntax} % expand-both = \meta{n/o/f/x} % expand-amount = \meta{n/o/f/x} % expand-unit = \meta{n/o/f/x} % \end{syntax} % By default the commands \mycs{cunum}, \cCutext{} and \mycs{cunum} % do \emph{not} expand their input. You can change the expansion behavior of % \meta{amount} and/or \meta{unit-key} using the options specified % above. The meaning of the available values are the same as specified % in the \LaTeX3\ document \enquote{interface3}. % % It is set to \texttt{n} (no expansion) by default. % % \end{function} % % % % % \begin{function}{set-special-sign,add-special-sign} % \begin{syntax} % set-special-sign = \marg{character(s)} % add-special-sign = \marg{character(s)} % \end{syntax} % Allows \meta{character(s)} to be used in the first mandatory argument of % \mycs{cunum}, \mycs{cuam}, \cCutext{} without raising an error (you can customize this % behavior, see \opt{set-unknown-message}). By default it is set to |?|. % Please note that the sign |<| is not allowed as a special sign. % \end{function} % % \begin{cuexamplecode} % \cunum{?}{kg} \\ % \cunum[g=kg]{10?--20?}{kg} \\ % \cusetup{add-special-sign={xX} } @ % \cunum{x}{kg} \\ % \cunum{X--?}{kg} \\ % \cusetup{set-special-sign={} } @ % \cunum{1}{kg} \\ % \cunum{1--2}{kg} % \end{cuexamplecode} % % \begin{function}{set-unknown-message} % \begin{syntax} % set-unknown-message = \meta{error/warning/none} % \end{syntax} % Using a special sign (\texttt{?} by default) causes a warning to % be raised. Set this option to \opt{error} if you want an error (as % an extra emphasis), \opt{warning} if you want a warning (default) % and \opt{none} if you don't want to know anything about it. % \end{function} % % \begin{function}{set-cutext-translation-message} % \begin{syntax} % set-cutext-translation-message = \meta{error/warning/none} % \end{syntax} % If a translation for \cCutext\ is not available the commands are replaced % by \mycs{cunum}. Currently -- if this is happening -- a warning is shown, % you may change the behavior of the message (error, warning or not showing at all) % using this option. % \end{function} % % \begin{function}{print-numerals} % \begin{syntax} % print-numerals = \meta{true/false} % \end{syntax} % % Prints numerals for integers smaller then \opt{use-numerals-below} if % set to \true. If set to \false\ no numerals are printed. % % If you use the package option \opt{use-fmtcount-numerals} this option % is automatically set to \true. % % If you want to use another package, just set this option to \true\ and % use \opt{numeral-function} and \opt{Numeral-function}. % %^^A If the package option \opt{use-fmtcount-numerals} is set to \true\ you can %^^A deactivate the printing of numerals by setting \opt{print-numerals} to %^^A \false\ and activate them by setting it to \true. % % \end{function} % \begin{cuexample} % (Using the package option \opt{use-fmtcount-numerals}: % \cusetup{ print-numerals=true } % \begin{cuexamplecode} % \cutext{1}{kg} \\ % \cutext{2}{kg} \\ % \cutext{12}{kg} \\ % \cutext{13}{kg} \\ % \cusetup{ print-numerals=false } @ % \cutext{1}{kg} \\ % \cutext{2}{kg} \\ % \cutext{12}{kg} \\ % \cutext{13}{kg} \\ % \end{cuexamplecode} % \cusetup{ print-numerals=false } % \end{cuexample} % % \begin{function}{use-numerals-below} % \begin{syntax} % use-numerals-below = \meta{integer} % \end{syntax} % If \opt{print-numerals} is \true, prints the numerals in % \mycs{cutext} and \mycs{Cutext} for integers smaller than % \meta{integer}. \meta{integer} is by default 13. % You can deactivate the printing of numerals by \opt{print-numerals=false}. % \end{function} % \cusetup{ print-numerals=true } % \begin{cuexamplecode} % \cutext{1}{kg} \\ % \cutext{2}{kg} \\ % \cutext{12}{kg} \\ % \cutext{13}{kg} \\ % \cusetup{ use-numerals-below=10 } @ % \cutext{1}{kg} \\ % \cutext{2}{kg} \\ % \cutext{12}{kg} \\ % \cutext{13}{kg} \\ % \cusetup{ use-numerals-below=0 } @ % \cutext{1}{kg} \\ % \cutext{2}{kg} \\ % \cutext{12}{kg} \\ % \cutext{13}{kg} \\ % \cusetup{ use-numerals-below=12001 } @ % \cutext[kg=g]{1}{kg} \\ % \cutext[kg=g]{2}{kg} \\ % \cutext[kg=g]{12}{kg} \\ % \cutext[kg=g]{13}{kg} \\ % \end{cuexamplecode} % \cusetup{ print-numerals=false } % % \begin{function}{numeral-function, Numeral-function } % \begin{syntax} % numeral-function = \meta{function} % Numeral-function = \meta{function} % \end{syntax} % Sets the functions used for printing numerals. % \opt{numeral-function} is used for lowercase, \opt{Numeral-function} % for capitalized cases. % \end{function} % \begin{cuexample} % Using the commands from \pkg{fmtcount} you can set the % numeral function equal to % \begin{lstlisting} % \cusetup{ % numeral-function = \numberstringnum , % Numeral-function = \Numberstringnum % } % \end{lstlisting} % (this happens if you use the package option \opt{use-fmtcount-numerals}) % \end{cuexample} % % % % \begin{function}{parse-number} % \begin{syntax} % parse-number = \meta{true/false} % \end{syntax} % If set to \false\ prints the number of \lstinline!\cunum!, % \lstinline!\cutext!, \lstinline!\Cutext! and \mycs{cuam} as they % are (after some \dots\ well \dots\ parsing due to % \enquote{\lstinline|_|}). Is set to \true\ by default. % \end{function} % % \begin{cuexamplecode} % \cusetup{ parse-number=false } @ % \cunum[kg=g]{1}{kg} \\ % \cunum{1--2}{kg} \\ % \cunum{1----------2}{kg} \\ % \cunum{1.2}{kg} \\ % \cunum[kg=g]{1,2}{kg} \\ % \cunum{1/2}{kg} \\ % \cunum{1_2/3}{kg} \\ % \cunum{1/2_3}{kg} \\ % \cunum{some weird stuff}{kg} \\ % \cutext{1}{kg} \\ % \cutext{100}{kg} \\ % \cutext{gjfak}{kg} \\ % \cutext[kg=g]{12}{kg} \\ % \cuam{1----------2} \\ % \cuam{1,2} \\ % \cuam{1_1/2} \\ % \cuam{kwflk} \\ % \end{cuexamplecode} % % % % \begin{function}{range-sign} % \begin{syntax} % range-sign = \marg{string} % cunum-range-sign = \marg{string} % cutext-range-sign = \marg{string} % \end{syntax} % \opt{cunum-range-sign} sets the \emph{printed} range sign used in \mycs{cunum} % (and \mycs{cuam}) to \meta{string}, \opt{cutext-range-sign} sets the printed % range sign used in \cCutext{} to \meta{string}. % Using \opt{range-sign} sets the % range signs for both \mycs{cunum} (and \mycs{cuam}) and % \mycs{cutext}/\mycs{Cutext} to \meta{string}. % % The default for \meta{string} is \texttt{-{}-} (for both). % \end{function} % % Since version 1.45 there also exits the language symbol \opt{cutext-range-sign} % (see \cref{sec:language}). If the \emph{option} \opt{cutext-range-sign} is set % the language symbol will be ignored. % % \begin{cuexamplecode} % \cunum{1--2}{kg} \\ % \cuam{1--2} \\ % \cutext{1--2}{kg} \\ % \Cutext{1--2}{kg} % \end{cuexamplecode} % \begin{cuexamplecode} % \cusetup{cunum-range-sign={~to~}} @ % \cunum{1--2}{kg} \\ % \cuam{1--2} \\ % \cutext{1--2}{kg} \\ % \Cutext{1--2}{kg} % \end{cuexamplecode} % \begin{cuexamplecode} % \cusetup{cutext-range-sign={--}} @ % \cunum{1--2}{kg} \\ % \cuam{1--2} \\ % \cutext{1--2}{kg} \\ % \Cutext{1--2}{kg} % \end{cuexamplecode} % \begin{cuexamplecode} % \cusetup{range-sign={-to-}} @ % \cunum{1--2}{kg} \\ % \cuam{1--2} \\ % \cutext{1--2}{kg} \\ % \Cutext{1--2}{kg} % \end{cuexamplecode} % % \begin{function} {use-phrases} % \begin{syntax} % use-phrases = \meta{true/false} % \end{syntax} % Setting this option to \true\ replaces certain integers (see \cref{sec:phrases} for % more information) with their phrase counterpart. This option is set to \false\ by default. % \end{function} % % \begin{cuexample} % \begin{myde} % For the German language: % \begin{cuexamplecode} % \cuam{12} \\ % \cuam{12--24} \\ % \cuam{36} \\ % \cusetup{use-phrases=true} @ % \cuam{12} \\ % \cuam{12--24} \\ % \cuam{36} \\ % \cusetup{use-phrases=true, print-numerals=true} @ % \cuam{12} \\ % \cuam{12--24} \\ % \cuam{36} \\ % \end{cuexamplecode} % \end{myde} % \end{cuexample} % % % \subsubsection{Rounding options} % % \begin{function}{round-precision} % \begin{syntax} % round-precision = \meta{integer} % \end{syntax} % Rounds the amount automatically to \meta{integer} digits after the % colon. Note that units like \myunit{C}, \myunit{F}, \myunit{K} and % \myunit{Re} are still rounded to integers due to % \texttt{set-option-for-}. % \end{function} % % % \begin{cuexamplecode} % \cusetup{round-precision= 5} @ % \cunum{1.23456789}{kg} \\ % \cunum[g=kg]{12.587}{g} \\ % \cunum{194}{kg} \\ % \cunum[C=F]{200--210}{C} \\ % \cunum[K=C]{0.0012}{K} \\ % \cusetup{round-precision= 1} @ % \cunum{1.23456789}{kg} \\ % \cunum{12.58}{kg} \\ % \cunum[g=kg]{194}{g} \\ % \cunum[C=F]{200--210}{C} \\ % \cunum[K=C]{0.0012}{K} % \end{cuexamplecode} % % \begin{cunote} % Also negative numbers are allowed. % \begin{cuexamplecode} % \cusetoptionfor{C,F}{round-precision=-1} @ % \cunum{-271,2}{C} \\ % \cunum[K=C]{0.0012}{K} \\ % \cunum{185}{C} \\ % \cunum[C=F]{180--200}{C} \\ % \end{cuexamplecode} % \end{cunote} % % \begin{function}{round-to-int} % \begin{syntax} % round-to-int = \meta{true/false} % \end{syntax} % \emph{This option is deprecated.} Rounds the amount to an integer if set \true. % Use \opt{round-precision=0} instead. % \end{function} % % %^^A \begin{cuexamplecode} %^^A \cusetup{round-to-int=true} @ %^^A \cunum{1.23456789}{kg} \\ %^^A \cunum{12.58}{kg} \\ %^^A \cunum[g=kg]{194--294}{g} \\ %^^A \cunum[kg=g]{1.23456789}{kg} %^^A \end{cuexamplecode} % % \begin{function}{round-half} % \begin{syntax} % round-half = \meta{default/commercial} % \end{syntax} % This option is only important for half-way numbers % (e.g. $0.005$). By setting it to \opt{default} the value will be % rounded to the nearest even number. Setting it to % \opt{commercial} rounds the value away from zero. % % It is set to \opt{default} by \dots\ default. % % \begin{cunote} % \opt{default} actually refers to the fact that it is the default % rounding algorithm used by \cs{fp\_eval:n \{ round( ) \}} % without a third argument. % \end{cunote} % % \end{function} % % % \begin{cuexamplecode} % \cusetup{round-half=default} @ % \cunum{0.005}{kg} \\ % \cunum{-0.005}{kg} \\ % \cunum{1.245}{kg} \\ % \cusetup{round-half=commercial} @ % \cunum{0.005}{kg} \\ % \cunum{-0.005}{kg} \\ % \cunum{1.245}{kg} @ % \end{cuexamplecode} % % % % \subsubsection{Fractions} % % \begin{function}{eval-fraction} % \begin{syntax} % eval-fraction = \meta{true/false} % \end{syntax} % This option takes \true\ or \false\ as values. % If set to \true\ all fractions are evaluated. Please note that divisions % through zero are not allowed. % \end{function} % % \begin{cuexamplecode} % \cusetup{eval-fraction=true} @ % \cunum{1/3}{kg} \\ % \cunum{1/2}{kg} \\ % \cunum[kg=g]{1/2}{kg} \\ % \cunum{1_1/2}{kg} \\ % \cunum[kg=g]{1_1/2}{kg} \\ % \cunum[kg=g]{-1_1/2}{kg} \\ % \cunum[kg=g]{1_?/2}{kg} \\ % \end{cuexamplecode} % % % % \begin{function}{convert-fraction} % \begin{syntax} % convert-fraction = \meta{true/false} % \end{syntax} % By default units of fractions are not converted into another unit. % Setting this option to \true\ % allows fractions to be evaluated when a change of units is requested % (and \emph{only} if a change of unit is requested). % \end{function} % % \begin{cuexamplecode} % \cusetup{convert-fraction=true} @ % \cunum{1/3}{kg} \\ % \cunum[kg=g]{1/3}{kg} \\ % \cunum{1_1/2}{kg} \\ % \cunum[kg=g]{1_1/2}{kg} \\ % \cunum[kg=g]{1_?/2}{kg} \\ % \end{cuexamplecode} % % % % % \begin{function}{fraction-command} % \begin{syntax} % fraction-command = \cs{command} % \end{syntax} % Sets the command used for printing fractions equal to \cs{command}. % \cs{command} has to take two arguments. By default % it is equal to |\sfrac| from \pkg{xfrac}. % % Please note that the amount is \emph{not} printed inside a math % environment by default. % \end{function} % % \begin{cuexamplecode} % \newcommand\myfrac[2]{#1/#2} @ % \cusetup{fraction-command=\myfrac} @ % \cuam{1/8} \\ % \cunum{1/2}{kg} \\ % \cunum{4/5}{C} \\ % \cunum{1_2/3}{kg} \\ % \cusetup{fraction-command=\nicefrac} @ % \cuam{1/8} \\ % \cunum{1/2}{kg} \\ % \cunum{4/5}{C} \\ % \cunum{1_2/3}{kg} % \end{cuexamplecode} % % \begin{function}{fraction-inline} % \begin{syntax} % fraction-inline = \marg{input containing \#1 and \#2} % \end{syntax} % Similar to \opt{fraction-command} only that you don't have to % define a command to alter the output of the fraction. % \end{function} % % \begin{cuexamplecode} % \cusetup{fraction-inline={#1/#2} } @ % \cuam{1/8} \\ % \cunum{1/2}{kg} \\ % \cunum{4/5}{C} \\ % \cunum{1_2/3}{kg} \\ % \cusetup{fraction-inline={\nicefrac{#2}{#1}} } @ % \cuam{1/8} \\ % \cunum{1/2}{kg} \\ % \cunum{4/5}{C} \\ % \cunum{1_2/3}{kg} % \end{cuexamplecode} % % \subsubsection{Spaces} % % \begin{function}{mixed-fraction-space} % \begin{syntax} % mixed-fraction-space = \meta{length} % \end{syntax} % Sets the length between the fraction and the number in a mixed-fraction, % default is \texttt{0.1em} (because I said so; if someone has some literature % or sources to look up the space, please let me know). % \end{function} % \begin{cuexamplecode} % \cuam{1_2/3} \\ % \cunum{1_2/3}{kg} \\ % \cunum{10_2/3}{kg} \\ % \cusetup{mixed-fraction-space=1em } @ % \cuam{1_2/3} \\ % \cunum{1_2/3}{kg} \\ % \cunum{10_2/3}{kg} \\ % \cusetup{mixed-fraction-space=0em } @ % \cuam{1_2/3} \\ % \cunum{1_2/3}{kg} \\ % \cunum{10_2/3}{kg} % \end{cuexamplecode} % % \begin{function}{cutext-space} % \begin{syntax} % cutext-space = \marg{string} % \end{syntax} % \meta{string} is inserted between the numeral part and the unit part % when using \cCutext. By default it is set to \cs{space}. Use this option % if you want to e.g.\ insert an unbreakable space. % \end{function} % \begin{cuexamplecode} % \cutext{1}{kg}\\ % \Cutext{10}{kg}\\ % \cusetup { cutext-space = ~ } @ % \cutext{1}{kg}\\ % \Cutext{10}{kg}\\ % \cusetup { cutext-space = {} } @ % \cutext{1}{kg}\\ % \Cutext{10}{kg}\\ % \cusetup { cutext-space = {qwe} } @ % \cutext{1}{kg}\\ % \Cutext{10}{kg}\\ % \end{cuexamplecode} % % % \begin{function}{phrase-space} % \begin{syntax} % phrase-space = \marg{string} % \end{syntax} % \meta{string} is inserted between the numeral part and the phrase part % while using \mycs{cuam}. By default it is set to \cs{space}. Use this option % if you want to e.g.\ insert an unbreakable space. % \end{function} % \begin{myde} % \cusetup{use-phrases=true} % (Switching to german) % \begin{cuexamplecode} % \cuam{12}\\ % \cuam{144}\\ % \cusetup { phrase-space = ~ } @ % \cuam{12}\\ % \cuam{144}\\ % \cusetup { phrase-space = {} } @ % \cuam{12}\\ % \cuam{144}\\ % \cusetup { phrase-space = {qwe} } @ % \cuam{12}\\ % \cuam{144}\\ % \end{cuexamplecode} % \cusetup{use-phrases=false} % \end{myde} % % \begin{function}{amount-unit-space} % \begin{syntax} % amount-unit-space = \marg{string} % \end{syntax} % Change the spacing for \mycs{cunum} between the printed amount(s) and % the unit. The default value is |\thinspace|. % \end{function} % % \begin{cuexamplecode} % \cunum{1}{kg}\\ % \cunum{1/2}{kg}\\ % \cunum{1--2}{kg}\\ % \cusetup { amount-unit-space = {\hspace{1em}} } @ % \cunum{1}{kg}\\ % \cunum{1/2}{kg}\\ % \cunum{1--2}{kg}\\ % \cusetup { amount-unit-space = {} } @ % \cunum{1}{kg}\\ % \cunum{1/2}{kg}\\ % \cunum{1--2}{kg}\\ % \cusetup { amount-unit-space = {qwe} } @ % \cunum{1}{kg}\\ % \cunum{1/2}{kg}\\ % \cunum{1--2}{kg}\\ % \end{cuexamplecode} % % \subsubsection{label \& refs} % % \begin{function}{recalculate-amount} % \begin{syntax} % recalculate-amount = \meta{true/false} % \end{syntax} % Set this option to \opt{true} if you want to change your recipes to the given % number of people set by \opt{set-number-of-persons}. Note that only those % values who have a label are changed. % \end{function} % % \begin{function}{set-number-of-persons} % \begin{syntax} % set-number-of-persons = \meta{integer} % \end{syntax} % With this option you can determine the number of people your recipes % are for. Note that this option only has an effect on those who have a \meta{label} % given. It is set to \opt{4} by default. Please also note the use of % \opt{recalculate-amount}. % \end{function} % \begin{cuexamplecode} % \culabel{anotherrecipe}{2} @ % \curef{anotherrecipe}~persons \\ % \cunum{1}{kg}\\ % \cuam{1}\\ % \cutext{1}{kg}\\ % \curef{anotherrecipe}~persons \\ @ % \cusetup{ recalculate-amount = true } @ % \curef{anotherrecipe}~persons \\ % \cunum{1}{kg}\\ % \cuam{1}\\ % \cutext{1}{kg}\\ % \Cutext[ref=anotherrecipe]{10}{kg}\\ @ % \cusetup { set-number-of-persons = 3 } @ % \curef{anotherrecipe}~persons \\ % \cunum{1}{kg}\\ % \cuam{1}\\ % \cutext{1}{kg}\\ % \Cutext[ref=anotherrecipe]{10}{kg}\\ @ % \cusetup { set-number-of-persons = 2 } @ % \curef{anotherrecipe}~persons \\ % \cunum{1}{kg}\\ % \cuam{1}\\ % \cutext{1}{kg}\\ % \Cutext[ref=anotherrecipe]{10}{kg}\\ @ % \cusetup { set-number-of-persons = 1 } @ % \curef{anotherrecipe}~person \\ % \cunum{1}{kg}\\ % \cuam{1}\\ % \cutext{1}{kg}\\ % \Cutext[ref=anotherrecipe]{10}{kg}\\ % \end{cuexamplecode} % % % \begin{function}{label} % \begin{syntax} % label = \{\meta{string}*\meta{integer}\} % \end{syntax} % The key-value version of \mycs{culabel}. It defines the label \meta{string} % which is originally for \meta{integer} people. Please note that the \texttt{*} % is mandatory as it separates the string from the integer. Each % label is defined globally and must be unique. % \end{function} % \begin{cuexamplecode} % \cusetup{label=Toast*1} @ % \curef{Toast}~person \\ % \cuam{2} \\ % \cunum{2}{dag} \\ % \cusetup { recalculate-amount = true } @ % \curef{Toast}~persons \\ % \cuam{2} \\ % \cunum{2}{dag} % \end{cuexamplecode} % % % \begin{function}{get-label} % \begin{syntax} % get-label = \marg{label} % \end{syntax} % The key-value version of \mycs{curef}. Note that this key doesn't save the value % inside a macro but rather prints it directly into the document. % \end{function} % \begin{cuexamplecode} % \culabel{Schinken}{3} @ % \cusetup{get-label=Schinken} \\ % \curef{Schinken} \\ % \cusetup { recalculate-amount = true } @ % \cusetup{get-label=Schinken} \\ % \curef{Schinken} \\ % \end{cuexamplecode} % % \begin{cunote} % \mycs{curef} \emph{is} expendable. % \end{cunote} % % % \begin{function}{ref} % \begin{syntax} % ref = \marg{label} % \end{syntax} % Instead of using the first optional arguments of the commands in \cref{sec:commands} % you may use this option. It requires a valid value and throws an error if \meta{label} % is not defined. % \end{function} % \begin{cuexamplecode} % \culabel{Kaese}{3} @ % \cunum [m=dm]{1}{m} \\ % \cunum[ref=Kaese,m=dm]{1}{m} \\ % \cusetup { recalculate-amount = true } @ % \cunum[m=dm]{1}{m} \\ % \cunum[ref=Kaese,m=dm]{1}{m} % \end{cuexamplecode} % % % % \begin{function}{curef-add-forbidden-unit, curef-remove-forbidden-unit,curef-clear-forbidden-units} % \begin{syntax} % curef-add-forbidden-unit = \marg{unit list} % curef-remove-forbidden-unit = \marg{unit list} % curef-clear-forbidden-units = \meta{true/false} % \end{syntax} %^^A How much of a specify ingredient is used generally depends on the number of folks the meal %^^A is for. Change the number of folks and the needed weight of an ingredient will most probably %^^A change, \emph{but} there are units which do not change automatically if you have $2$ instead %^^A of $4$ guests. Units which measure the temperature are for example one of them. So changing %^^A them using the label \& ref system would be accidental and should in the best case create an error. %^^A Use the given options to define units which will throw an error if they are about to be changed %^^A by the label \& ref system. Of course, you can also remove units or clear the whole list. % % There are units which do not depend on the number of folks you are cooking for, units measuring % the temperature are an example. Changing those units with the label \& ref % system would be accidental and in the best case throw an error. With the following options % you can add units to the \enquote{forbidden unit list}, remove them and clear the whole list % entirely. % % By default the list contains \texttt{C}, \texttt{F}, \texttt{K} and \texttt{Re}. % \end{function} % \begingroup % \DeactivateForbiddenUnitError % \begin{cuexamplecode} % \culabel{check}{2} @ % \cusetup{ recalculate-amount=true } @ % \cunum{1}{m} \\ % \cunum{1}{kg} \\ % \cunum[ref=check]{1}{C} \\ % \cusetup { curef-add-forbidden-unit = { m, kg } } @ % \cunum[m]{1}{m} \\ % \cunum[m]{1}{kg} \\ % \cunum[ref=check]{1}{C} \\ % \cusetup { curef-remove-forbidden-unit = { C } } @ % \cunum[m]{1}{m} \\ % \cunum[m]{1}{kg} \\ % \cunum[ref=check]{1}{C} \\ % \cusetup { curef-clear-forbidden-units = true } @ % \cunum[m]{1}{m} \\ % \cunum[m]{1}{kg} \\ % \cunum[ref=check]{1}{C} % \end{cuexamplecode} % \endgroup % % % % % % % % % % % % % % % % \subsection{Weird options} % % \begin{function}{check-temperature} % \begin{syntax} % check-temperature = \meta{true/false} % \end{syntax} % Checks if the used temperature is below absolute zero. % Currently \myunit{C}, \myunit{F}, \myunit{K} and \myunit{Re} are supported. % While \lstinline|\cunum{0}{K}| is ok, \lstinline!\cunum{-1}{K}! raises an error, % same for the others. Is set to \false\ by default. To add new units % see \opt{add-temperature-to-check}. % \end{function} % % \begin{function}{add-temperature-to-check} % \begin{syntax} % add-temperature-to-check = % \ \ \{ % \ \ \ \ \meta{unit-key-1} = \meta{minimum-value-1} , % \ \ \ \ \meta{unit-key-2} = \meta{minimum-value-2} , % \ \ \ \ \dots % \ \ \} % \end{syntax} % This option adds \meta{unit-key-1} and so on to the list of units to be checked % if \opt{check-temperature} is active. The argument can be a comma-separated % list of \meta{unit-key} = \meta{minimum-value}. This sets the allowed minimum % value of \meta{unit-key} to \meta{minimum-value}. % % \end{function} % % \begin{cuexample} % This package implements the allowed minimum values for the % temperatures \myunit{C}, \myunit{F}, \myunit{K} and \myunit{Re} to be checked if % \opt{check-temperature} is active using: % \begin{lstlisting} % \cusetup % { % add-temperature-to-check = % { % K = 0, % C = -273.15 , % F = -459.67 , % Re = -218.52 % } % } % \end{lstlisting} % % If you want to add a new value, for example degree R{\o}mer % (which has be defined in another example) you can write: % \begin{lstlisting} % \cusetup % { % add-temperature-to-check = { Ro = -135.90375 } % } % \end{lstlisting} % \end{cuexample} % % % % % \begin{function}{convert-to-eV} % \begin{syntax} % convert-to-eV = \meta{true/false} % \end{syntax} % Converts (nearly) every unit in \cref{tab:def-units} % to electron volt or the respective derivative (if possible). Note that this % option is: % a) experimental and probably will forever be and b) just a joke, you are not % supposed to use this units in a cookery book (and as you see this package % doesn't support the arrangement of such huge numbers). Also you may % want to check the values if you really want to use them, just to be sure % (I've checked them several times and hope they are finally correct, but mistakes % happen). % % \end{function} % % \begin{cuexamplecode}[\hfill] % \cusetup{ convert-to-eV=true } @ % \cunum{1}{kg} \\ % \cunum{1}{l} \\ % \cunum{1}{J} \\ % \cunum{1}{m} \\ % \cunum{1}{C} \\ % \cunum{1}{s} % \end{cuexamplecode} % % \begin{function}{add-natural-unit} % \begin{syntax} % add-natural-unit = \meta{unit-key} % \end{syntax} % This option adds \meta{unit-key} to the list of units \opt{convert-to-eV} % uses to determine how a unit is transformed if set to \true. % \end{function} % % % % % \begin{function}{42} % \begin{syntax} % 42 = \meta{true/false} % \end{syntax} % Take a good guess. % \end{function} % % \begin{cuexamplecode}[\hfill] % \cusetup{ 42=true } @ % \cunum{1}{kg} \\ % \cunum[kg=g]{1}{kg} \\ % \cunum{1.5}{J} \\ % \cunum{180}{C} \\ % \cunum{15}{s} % \end{cuexamplecode} % % % % % % % %^^A \section{Notes} % %^^A There is a unit called \enquote{Batman}. % % % % % % % % % % % % % % \section{Bugs \& Feedback} % \label{sec:bug-feed} % % Bug reports are always welcome. If you are sending a bug report % please include a minimal working example showing the bug and a short % description. If you use mail please add \pkg{cooking-units} % to the e-mail header. GMX has the habit of putting e-mails into the % spam account and adding \pkg{cooking-units} to the header makes % it easier to recognize those e-mails. It can also take longer of GitHub, % but I hope I figured out how to get a mail if a new issue is created (by not me). % % Feedback and requests (commands, units, etc.) are also welcome. Please % also add (if possible) an example of the desired output into the % minimal example (and -- if by mail -- add \pkg{cooking-units} to the % header). % % Furthermore, as you can see I am not able to speak too many % languages (german and english to be precise; I managed to add french % with the help of the internet, which is not optimal) so if you are % able to speak a language not yet implemented and would like to help % you can send me the translations known to you. A list of all units % (and their current translations) is given in \cref{sec:Translations}. % % % % % %\clearpage % % \section{Bens Einheitensammelsurium (Bens unit Almanac)} % % Units are a fascinating mess. There are so many different ones which are different and % the few ones which are the same (in name at least) are \emph{also} different, depending on % geographical position, time period and probably pure spite. We can be glad that SI-units exist. % % %^^A Units are a fascinating mess. There are so many different ones that one can be glad %^^A that SI-units exist in this world. This section offers some units which didn't manage %^^A to appear in \cref{tab:def-units} and \cref{tab:some-more-units}.^^A\footnote{This somehow %^^A ^^A reminds me of the story of \enquote{Tower of Babel} in the bible. This tower is -- according to the %^^A ^^A story -- the reason (or the symptom) of why people speak different languages. %^^A ^^A I suppose what didn't make it into the story was that as even more severe punishment, %^^A ^^A different units were created. Just my take at lest.}. % % So for those units which didn't make it into \cref{tab:def-units} and \cref{tab:some-more-units}, % this section exists. Please note that this list is intended to be a just-for-fun list and not a % compilation of every unit in existence with its exact value ordered by geographical and chronological % position. I am sadly neither a historian nor very good in regards to languages. It would sound like % fun, but ultimately, I wouldn't have the time. % Therefore I am only taking units into account which I either found in literature (stone, canna, etc.), % are well known (foot) or have some other experience with them (ell) (exception: Batman). The reason I % am not including units which I found in the internet is that I would like to % see those units in their \enquote{natural environment}. % % \begin{comment} % \begin{tabular}{lllllll} % \toprule % unit & original & abréviation & type & source \\ \midrule % % Batman & & & weight\\ %^^A Rottel\txtupde & Sicilian: \emph{rotolo} && length & \cite{Gattopardo}\\ %^^A Rute\txtupde & Sicilian: \emph{canna} & & weight & \cite{Gattopardo}\\ % rotolo\txtupsic & Rottel\txtupde && length & \cite{Gattopardo}\\ % canna\txtupsic & rod\txtupen, Rute\txtupde & & weight & \cite{Gattopardo}\\ % \bottomrule % \end{tabular} % % {\footnotesize \txtupde German } % \end{comment} % % \begin{description} % % \unititem{unit}*in given language*[translation][abbreviation] Description, containing a % quote or not. \emph{Please note that most of the units are country dependent! % So the translation may not have the same amount as the word it is translated to.} % % \unititem{Batman} % So \dots\ You wanna be Batman? Be like Bruce Wayne? Having a secret identity? % Then congratulations! You \emph{are} Batman! How much Batman depends on the location, % but Wikipedia is your friend in this matter. % % % \unititem{Rotolo}*sic*[Rottel\txtupde] Around \SI{0.850}{\kg} % \begin{myquote}[Gattopardo][51] % Auf den Fußboden lagen vier ungereifte Käse zu je \emph{zwölf Rottel}, % jeder ungefähr zehn Kilo schwer. % \end{myquote} % % \unititem{Canna}*sic*[Rute\txtupde, rod\txtupen] About \SI{2}{\m} bzw.\ about $6$ foot. % \begin{myquote}[Gattopardo][25] % \enquote{Unsinn, Stella, Unsinn; was soll mir zustoßen? Sie kennen mich alle: % Männer, die \emph{eine Rute} lange sind, gibt es wenige in Palermo.} % \end{myquote} % % \unititem{Stone}[][st] \cunum[st=kg]{1}{st}. According to a fellow student % this unit is still used in % Great Britain. I've also recently found it in a video game; in the german translation % of said video game to be precise. Why is the german translation using stone % and not kilogram (at least in braces)? % % \begin{myquote}[Sh:3][988] % As we had expected, the telegramm was soon followed by its sender, and the card of Mr.\ Cyril Overton, Trinity College, Cambridge, announced the arrival of an enormous young man, \emph{sixteen stone} \emph{[\cunum[st=kg]{16}{st}]} of solid bone and muscle, who spanned the doorway with his broad shoulders \emph{[\dots\!]} % \end{myquote} (Story \enquote{The missing Three Quarters}) % % \unititem{Foot}[][ft] Equals exactly \cunum[ft=m,round-precision=10]{1}{ft} % or \cunum[ft=in]{1}{ft}. % % A bit of a strange unit (for me at least). Where I am from, people % tend to have different feet sizes. Also present in the german translation of the % video game that uses \enquote{Stone}. % % \unititem{degree Rèamur}[][\ensuremath{{}^{\circ}}\kern-\scriptspace R\'{e}] Like degree Celsius, but instead of having the % water boiling at \SI{100}{\degree} (Celsius), water boils at \SI{80}{\degree}. % Water thankfully still freezes at \SI{0}{\degree}. Don't think that this unit % is used anymore. I think I learned about in physics. % % \unititem{Ell} Just read the Wikipedia article. % % Fun Fact: At the Stephansdom % in Vienna left of the main entrance are two metal bars. One is the % \enquote{Tuchelle} (drapery ell, circa \SI{78}{\cm}), the other the % \enquote{Leinenelle} (linen ell, around \SI{89.6}{\cm}). % % \unititem{cup} I think the idea of having a \enquote{cup} and it not being % equal to \cunum{250}{ml} is a bit strange, for me at least. What other sizes can a % cup have? I can imagine \cunum{500}{ml}, but are there other sizes? % ^^A Any person who writes \enquote{cup} and % ^^A \emph{doesn't} mean % ^^A a cup equal to \SI{250}{\ml} should be %^^A^^A -- in my humble opinion\footnote{Which, now that I admitted %^^A^^A my humbleness, is automatically %^^A^^A more important than yours.} -- %^^A excommunicated by default (or incommunicated, %^^A if you are an atheist). % % \unititem{stick} A unit I've made fun of because it is quite regional and doesn't make % any sense for foreigners. Then I realized that I am using the unit \enquote{Packerl} % in my cookery book which is also quite locally\footnote{And maybe doesn't even exist % outside my family} and -- even worse -- the weight changes depending % the content (See \emph{Packerl}). % % \unititem{Packerl}*de*[small bag] I'm a bit split on this unit as I don't actually % know if it exists. The reason I have the unit \emph{Packerl} for my cookery % book is that in Austria you can buy baking powder, (dry) Germ, Natrium, etc. % in small bags (similar to \emph{stick}). The problem: Depending on the content, % the weight of \emph{Packerl} differs. Not only that, but it can also differ % between different producers (but not more than \SI{2}{\g} bzw.\ \cunum[g=oz]{2}{g}). % Here is a table: % % \begin{tabular}{l @{\space} l @{\space} l r l} % % 1 Packerl & Backpulver & (baking powder) & \cunum{16}{g} & (\cunum[g=oz]{16}{g}) \\ % & Natrium & & \cunum{14}{g} & (\cunum[g=oz]{14}{g}) \\ % & Vanillin(-zucker) & (vanillin(-sugar)) & \cunum{8}{g} & (\cunum[g=oz]{8}{g}) \\ % & Germ* & & \cunum{7}{g} & (\cunum[g=oz]{7}{g}) \\ % \end{tabular} % % {\footnotesize *Tockengerm (dry Germ) to be precise} % % For what kind of thing do I need \emph{Natrium} for? % \end{description} % % % \begin{comment} % Fun Wikipedia articles: % \begin{itemize} % \item Old Austrian units: https://en.wikipedia.org/wiki/Obsolete_Austrian_units_of_measurement % \end{itemize} % \end{comment} % % % % % % % \appendix % % \section{Translations} % \label{sec:Translations} % This section contains the list of available translations. Each table % shows the available translations regarding the unit symbol, the unit name % (printed if \mycs{cutext} or \mycs{Cutext} is used) and % the plural form (if different from the singular form). A second table % shows the translations used for phrases (if given). % % If a translation is not available a \enquote{\translationdoesnotexisttl} is % shown. % % \small % %\clearpage % \subsection{English} % \begin{tabular}{ l l l l l } % \toprule % \CreateTableForLanguages{ English } % \end{tabular} % % %\clearpage % \subsection{american} % % \begin{tabular}{ l l l l l } % \toprule % \CreateTableForLanguages{ american } % \end{tabular} % %\clearpage % \subsection{German} % \begin{tabular}{ l l l l l } % \toprule % \CreateTableForLanguages{ German } % \end{tabular} % % \bigskip % % \CreateTableForPhrases { German } % % \bigskip % \begin{minipage}{\textwidth} % Some further phrases, just to write them down (they are not implemented, % as they are barely used). % % \begin{tabular} { l l @{\space} l l l l } % \toprule % \meta{number} & name & \multicolumn{2}{c}{Note} & (plural) & gender \\ \midrule % 60 & Schock & (5 Dutzend, & $12*5$) & & n \\ % 144 & Gros & (12 Dutzend, & $12*12$) && n \\ % 1728 & Gro{\ss}gros &(12 Gro{\ss}, & $12*144$) && n \\ % \bottomrule % \end{tabular} % \end{minipage} % % Note that Gro{\ss}gros has other (probably more common) synonyms. % %\clearpage % \subsection{French} % \begin{tabular}{ l l l l l } % \toprule % \CreateTableForLanguages{ French } % \end{tabular} % % If the spoons should be extra full: % \begin{itemize} % \item cuill\`{e}re \`{a} soupe rase % \item cuill\`{e}re \`{a} caf\'{e} rase % \end{itemize} % %\clearpage % % % % % % % % % \section{US, Imperial and Other units} % \label{sec:other-units} % % As source \cite{WM1985} has been used for imperial units, while \cite{Nist2006} % and \cite{Nist2008} were used for U.S.\ units. I hope someone will find this % bringing together useful. % %\begin{center} %\begin{tabular}{ l @{ } l } %\toprule % 1 yard &= \SI{0.9144}{\m} (exact) \\ % 1 yard &= 3 foot \\ % 1 yard &= 36 Inch \\ \midrule % 1 Inch &= \SI{0.0254}{\m} (also exact) \\ % \bottomrule %\end{tabular} %\end{center} % %\begin{center} %\begin{tabular}{r@{ }l r@{ }l} %\toprule % \multicolumn{4}{c}{ 1 liter = \SI{1}{\cubic\deci\meter} } \\ \midrule % 1 gallon &= \SI{4.54609}{liter} (exact) & 1 U.S.\ gallon &= 231\,Inch$^3$ $=$ % $231\times \num{0,016387064}$ liter \\ % 1 gallon &= 4 Quart & 1 U.S.\ gallon &= 4 Quart\US\\ % 1 gallon &= 8 Pint & 1 U.S.\ gallon &= 8 Pint\US\\ % 1 gallon &= 32 Gill & 1 U.S.\ gallon &= 32 Gill\US\\ % 1 gallon &= 160\,fl.\,oz & 1 U.S.\ gallon &= 128\,fl.\,oz\US \\\midrule % 1 \,fl.\,oz&= \num{0.0284130625} liter & 1\,fl.\,oz\US & = \num{0.0295735295625} liter % \\ \bottomrule %\end{tabular}\\ \footnotesize\raggedright %\begin{cuenumnote} % \item I think the American fl.\,oz\US\ is more common. Maybe. Most bottles % have something like 10\,fl.\,oz, which they say is equal to \SI{30}{\ml}. This would % work really well with fl.\,oz\US. % \item Sometimes \enquote{fl.\,oz} is written without the dot. I am also not sure what % kind of spacing has to be between \enquote{fl.} and \enquote{oz} (currently % using \cs{thinspace}). % \item This maybe sounds stupid, but could we introduce something like % \enquote{flouz}, \enquote{floiz} and \enquote{floez}? \enquote{flouz} would be % \enquote{fl.\,oz\US}, \enquote{floiz} would be \enquote{Imperial fl.\,oz} and % \enquote{floez} would simply be equal to \SI{30}{\ml}? %\end{cuenumnote} %\end{center} % % % For \enquote{stick} see \cite{StickSource}. %\begin{center} %\begin{tabular} { l @{ } l } % \toprule % 1\,lb &= \SI{0.453 592 37}{\kg} (exact) \\ % 1\,lb &= 16\,oz \\ % 1\,lb &= \sfrac{1}{14}\,st \\ % 1\,lb &= \sfrac{175}{12}\,ounce~troy \\ % 1\,lb &= 4 stick \\ % \bottomrule %\end{tabular} %\end{center} % % % %\begin{center} %\begin{tabular} { r @{ } l @{ }l r @{ } l } % \toprule % 1 cup &$\approx$ \num{0.25} litre &= \SI{250}{\ml} &1 cup\US &= 8\, fl.\,oz\US \\ % 1 tablespoon &$\approx$ \num{0.015} litre&= \SI{15}{\ml} & 1 tablespoon\US &= \sfrac{1}{2}\, fl.\,oz\US \\ % 1 teaspoon &$\approx$ \num{0.005} litre &= \SI{5}{\ml} & 1 teaspoon\US&= \sfrac{1}{6}\, fl.\,oz\US \\ % \bottomrule %\end{tabular} \footnotesize \\ \raggedright %\begin{cuenumnote} % \item I tested the approximation for tablespoon with water % ($\SI{1}{\mg} \approx \SI{1}{\mg}$) and the approximation looks good enough. % It of course depends on how full you fill your spoon. %\end{cuenumnote} %\end{center} % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % \begin{comment} %^^A \section{Notes and other stuff} %^^A This section contains stuff which might or might not be interesting. %^^A %^^A \subsection{More or less FAQ} %^^A %^^A \num{624150912.6 +- 3.9 e+10} %^^A \num{6.241509126 +- 0.000000039 e+18} %^^A %^^A \num{8.6173303 +- 00000.0000050 e-5} %^^A %^^A \subsection{Calculation} %^^A This subsection deals with some regarding the conversion to certain units. %^^A Mostly to (I like to call them) \enquote{electron volt units} (or natural units). %^^A Let's begin. %^^A %^^A We start with the easiest one: conversion of joule into electron volt. %^^A Easy because Wikipedia and nearly every physics book knows the answer. %^^A And according to Wikipedia %^^A \begin{align} %^^A \SI{1}{\eV} &= \SI{1.6021766208(98)e-19}{\joule} \\ %^^A \SI{1}{\joule} &= \SI{6.241509126 +- 0.000000039 e+18}{\eV} %^^A \end{align} %^^A Adding this is no problem: %^^A \begin{lstlisting} %^^A \cuaddtokeys {J} {eV} { 1.6021766208e-19 } %^^A \end{lstlisting} %^^A %^^A %^^A Great, next Temperature (kelvin) to electron volt. Also no problem at all %^^A because joule and kelvin are related by the boltzmann constant $k_B$ with %^^A \begin{equation} %^^A energy (\si{\joule}) = k_B \cdot temperature (\si{\kelvin}) %^^A \end{equation} %^^A as $[k_B]= \sfrac{\si{\joule}}{\si{\kelvin}}$ and %^^A $k_B= \SI{1.38064852(79)e-23}{\joule\per\kelvin}$. Now using the power %^^A of (more or less basic, but somehow annoying) mathematics we get: %^^A \begin{align} %^^A [k_B] &= \SI{1.38064852(79)e-23}{\joule\per\kelvin} = \\ %^^A &= \num{1.38064852(79)e-23} \cdot \SI{6.241509126 +- 0.000000039 e+18 }{\eV\per\K} = \\ %^^A &= \SI{8.6173303 +- 0.0000050 e-5 }{\eV\per\K} %^^A \end{align} % % %^^A \section{Notes and other stuff} %^^A \subsection{Some details to electron volts} %^^A This section explains how I calculated the values for conversion into electron volt %^^A or the respective derivative. Let's begin with some constants (from Wikipedia), note that %^^A \begin{equation*} %^^A \num{1.23456(78)e-9} = \num[separate-uncertainty = true]{1.23456(78)e-9} %^^A \end{equation*} %^^A just for info. %^^A %^^A \begin{align} %^^A \SI{1}{\eV} &= \SI{1.6021766208(98)e-19}{\J} \\ %^^A \hbar &= \SI{1.054571800(13)e-34}{\J\s} \\ %^^A k_B &= \SI{1.38064852(79)e-23}{\J\per\K} = \SI{8.6173303(50)e-5}{\eV\per\K}\\ %^^A c &= \SI{299792458}{\m\per\s} %^^A \end{align} %^^A %^^A Note that all those and following values are rounded to the second relevant figure of the %^^A uncertainty of the value. %^^A %^^A Well then, next are temperatures. %^^A %^^A Temperatures are fairly easy. Just convert the temperature of your choice to kelvin %^^A and multiplicate it with $k_B$: %^^A \begin{align} %^^A \SI{1}{\K} * k_B &= \SI{8.6173303(50)e-5}{\eV} %^^A \end{align} %^^A %^^A Next is more complicated. To compute the resulting unceartanity I using %^^A \enquote{Gauß'sches Fehlerfortpflanzungsgesetz} (I don't know if this has %^^A a translation). Anyway. We know that %^^A \begin{align*} %^^A \frac{\SI{1}{\eV}}{c^2} &= \frac{\SI{1.6021766208e-19}{\J}}{(\SI{299792458}{\m\per\s})^2} %^^A = \frac{\SI{1.6021766208e-19}{\kg\m\squared\per\s\squared}}{\SI{8,98755178736818E16}{\m\squared\per\s\squared}} = \\ %^^A &\frac{\SI{1.6021766208e-3}{\kg}}{\num{8,98755178736818}} = %^^A \SI{1782661906,94091624922088}{\kg} %^^A \end{align*} %^^A %^^A Great, now we have to calucalte the unceartinity: %^^A \begin{align} %^^A f(\si{\eV},c) &= \frac{\si{\eV}}{c^2} \\ %^^A df(\si\eV,c) &= \sqrt{ (\frac{\partial f}{\partial \si\eV})^2 * (\Delta \si\eV)^2 + (\frac{\partial f}{\partial c})^2 * (\Delta c)^2 } = \\ %^^A &= \sqrt{ (\frac{1}{c^2})^2 * (\Delta \si\eV)^2 + (-2\frac{eV}{c^{-3}})^2 * (\Delta c)^2 } %^^A \end{align} %^^A %^^A Now we know that $\Delta c = 0$: %^^A \begin{align} %^^A df(\si\eV,c) &= \sqrt{ (\frac{1}{c^2})^2 * (\Delta \si\eV)^2 } = %^^A \sqrt{ \frac{1}{(\SI{299792458}{\m\per\s} )^2} * (\SI{0.0000000098e-19}{\J})^2 } \\ %^^A &= %^^A \end{align} % \end{comment} % % % % % % % \end{documentation} % % % % % % % % % % % \begin{implementation} % % \section{Implementation} % % \subsection{Beginning} % % \begin{macrocode} %<@@=cookingunits> % \end{macrocode} % % \begin{macrocode} %<*package> % \end{macrocode} % % % % Na dann, auf gehts! % % \begin{macrocode} \@ifpackageloaded {xparse} { } { \RequirePackage {xparse} } \@ifpackageloaded {expl3} { } { \RequirePackage {expl3} } % \end{macrocode} % %: Package % \begin{macrocode} \ProvidesExplPackage {cooking-units} {2020/01/13} {1.46} {Ein Paket fuer Kocheinheiten} % \end{macrocode} % % Checking if \pkg{expl3} is up-to-date, otherwise abort the loading of the package. % \begin{macrocode} \@ifpackagelater { expl3 } { 2018/08/23 } { } { \PackageError { cooking-units } { Support~package~expl3~too~old } { You~need~to~update~your~installation~of~the~bundles~'l3kernel'~and~ 'l3packages'.\MessageBreak Loading~cooking-units~will~abort! } \tex_endinput:D } % \end{macrocode} % Loading some needed packages. % \begin{macrocode} \@ifpackageloaded { translations } { } { \RequirePackage { translations } } \@ifpackageloaded { xfrac } { } { \RequirePackage { xfrac } } \@ifpackageloaded { l3keys2e } { } { \RequirePackage { l3keys2e } } % \end{macrocode} % % Checking if \pkg{translations} is up-to-date, otherwise abort the loading of the package. % \begin{macrocode} \@ifpackagelater { translations } { 2017/08/31 } { } { \PackageError { cooking-units } { Support~package~translations~too~old } { You~need~to~update~your~installation~of~the~package~'translations'.\MessageBreak Loading~cooking-units~will~abort! } \tex_endinput:D } % \end{macrocode} % % \begin{macrocode} \msg_new:nnnn { cooking-units } { Option-deprecated } { The \ option \ '#1' \ is \ deprecated \ and \ should \ be \ replaced \ by \ '#2'. }{ Please \ replace \ the \ option. \msg_see_documentation_text:n { cooking-units } } % \end{macrocode} % \begin{macrocode} \bool_new:N \g_@@_opt_numeral_bool \keys_define:nn { cooking-units } { use-numerals .code:n = { \msg_warning:nnnn { cooking-units } { Option-deprecated } { use-numerals } { use-fmtcount-numerals } \keys_set:nn { cooking-units } { use-fmtcount-numerals = #1 } } , use-numerals .default:n = { false }, use-fmtcount-numerals .bool_gset:N = \g_@@_opt_numeral_bool , use-fmtcount-numerals .default:n = { false }, } % \end{macrocode} % Now process the package options \dots % \begin{macrocode} \ProcessKeysOptions { cooking-units } \bool_if:NT \g_@@_opt_numeral_bool { \@ifpackageloaded { fmtcount } { } { \RequirePackage { fmtcount } } } % \end{macrocode} % \dots\ and redefine the package option such that it cannot be used elsewhere. % \begin{macrocode} \keys_define:nn { cooking-units } { use-numerals .code:n = { \msg_warning:nnnn { cooking-units } { Option-deprecated } { use-numerals } { use-fmtcount-numerals } \msg_error:nnn { cooking-units } { load-time-option } { fmtcount } } , use-fmtcount-numerals .code:n = { \msg_error:nnn { cooking-units } { load-time-option } { fmtcount } } , } % \end{macrocode} % % % % \subsection {Defining Variables} % % \begin{macro} % { % \tl_replace_all:NVn, % \tl_replace_once:NVn , % \tl_if_in:nVTF , % \tl_if_in:NVTF , % \tl_if_in:NVT , % \fp_compare:vNnT , % \prop_get:cVc , % \tl_set_rescan:NnV, % \msg_error:nnnV, \msg_error:nnV, \msg_warning:nnV, % \prop_put:cnx % } % Some variations of commands we will need later. % \begin{macrocode} \cs_generate_variant:Nn \tl_replace_all:Nnn { NVn } \cs_generate_variant:Nn \tl_replace_once:Nnn { NVn } \cs_generate_variant:Nn \tl_if_in:nnTF { nV } \cs_generate_variant:Nn \tl_if_in:NnTF { NVTF } \cs_generate_variant:Nn \tl_if_in:NnT { NVT } \cs_generate_variant:Nn \fp_compare:nNnT { vNnT } \cs_generate_variant:Nn \prop_get:NnN { cVc } \cs_generate_variant:Nn \tl_set_rescan:Nnn { NnV } \cs_generate_variant:Nn \msg_error:nnnn { nnnV } \cs_generate_variant:Nn \msg_error:nnn { nnV } \cs_generate_variant:Nn \msg_warning:nnn { nnV } \cs_generate_variant:Nn \prop_put:Nnn { cnx } % \end{macrocode} % \end{macro} % % % % \begin{macro}{\@@_frac:nn} % This command is used to print fractions and can be changed % accordingly. % \begin{macrocode} \cs_new_eq:NN \@@_frac:nn \sfrac % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_set_amount:Nn,\@@_set_unit:Nn} % Allows for potential parsing of amount and or unit. % \begin{macrocode} \cs_new_eq:NN \@@_set_amount:Nn \tl_set:Nn \cs_new_eq:NN \@@_set_unit:Nn \tl_set:Nn % \end{macrocode} % \end{macro} % % % \begin{macro}{\@@_print_numeral:n , \@@_print_Numeral:n} % Commands to print numerals. Either use default or set yourself. % \begin{macrocode} \cs_new:Npn \@@_print_numeral:n #1 { \msg_error:nnn {cooking-units} { define-numeral-function } } \cs_new:Npn \@@_print_Numeral:n #1 { \msg_error:nnn {cooking-units} { define-Numeral-function } } \bool_if:NT \g_@@_opt_numeral_bool { \cs_set_eq:NN \@@_print_numeral:n \numberstringnum \cs_set_eq:NN \@@_print_Numeral:n \Numberstringnum } % \end{macrocode} % \end{macro} % % % \begin{macro}{ \l_@@_change_unit_prop } % Conversions of units are stored within this property list. % If someone requests that \myunit{kg} should be changed into \myunit{g}, % \myunit{kg} is stored as a key with the value \myunit{g}. If someone % then uses the unit \myunit{kg} the value \myunit{g} is restored and the unit % is changed accordingly. % \begin{macrocode} \prop_new:N \l_@@_change_unit_prop % \end{macrocode} % \end{macro} % % % % \begin{macro} { \g_@@_master_changer_prop } % Similar to |\l_@@_change_unit_prop|, but doesn't store the requested % unit change, but the values needed for conversion. Either a numerical % value is stored or a formula (using |#1| to insert the original value). % % Put and get values via \cs{\@@_prop_gput_master:nnn} % and \cs{@@_prop_get_master:nnNTF}. % \begin{macrocode} \prop_new:N \g_@@_master_changer_prop % \end{macrocode} % \end{macro} % % % % \begin{macro} % { % \l_@@_number_tmpa_tl, % \l_@@_number_tmpb_tl, % \l_@@_mixed_fraction_tl, % \l_@@_original_amount_tl, % \l_@@_original_unit_tl, % \l_@@_option_unit_tl, % \l_@@_language_tl, % \l_@@_cunum_range_sign_tl, % \l_@@_cutext_range_sign_tl, % \l_@@_value_unit_space_tl, % \l_@@_input_digits_tl , % \l_@@_input_decimal_mark_tl, % \l_@@_input_value_signs_tl, % \l_@@_input_allowed_special_signs_tl , % \g_@@_input_str_hash_one_tl , % \l_@@_input_range_sign_tl, % \l_@@_cutext_space_tl, % \l_@@_cuphrase_space_tl, % \l_@@_translation_tmpa_tl, % \l_@@_cutext_last_value_tl, % \l_@@_phantom_tl, % \l_@@_phrase_phrase_tl, % \l_@@_unit_letter_not_allowed_tl, % \l_@@_input_fraction_sign_tl, % \l_@@_input_mixed_fraction_sign_tl, % \l_@@_list_of_units_tl, % \l_@@_list_of_values_tl, % \l_@@_cunum_hook_tl , \l_@@_cutext_hook_tl , % \l_@@_Cutext_hook_tl , \l_@@_cuam_hook_tl % } % Quite a lot of tl's. % \begin{macrocode} \tl_new:N \l_@@_number_tmpa_tl \tl_new:N \l_@@_number_tmpb_tl \tl_new:N \l_@@_mixed_fraction_tl \tl_new:N \l_@@_original_amount_tl \tl_new:N \l_@@_original_unit_tl \tl_new:N \l_@@_option_unit_tl \tl_new:N \l_@@_language_tl \tl_new:N \l_@@_cunum_range_sign_tl \tl_new:N \l_@@_cutext_range_sign_tl \tl_new:N \l_@@_value_unit_space_tl \tl_new:N \l_@@_input_digits_tl \tl_new:N \l_@@_input_decimal_mark_tl \tl_new:N \l_@@_input_value_signs_tl \tl_new:N \l_@@_input_allowed_special_signs_tl \tl_new:N \g_@@_input_str_hash_one_tl \tl_new:N \l_@@_input_range_sign_tl \tl_new:N \l_@@_cutext_space_tl \tl_new:N \l_@@_cuphrase_space_tl \tl_new:N \l_@@_translation_tmpa_tl \tl_new:N \l_@@_cutext_last_value_tl \tl_new:N \l_@@_phantom_tl \tl_new:N \l_@@_phrase_phrase_tl \tl_new:N \l_@@_unit_letter_not_allowed_tl \tl_new:N \l_@@_input_fraction_sign_tl \tl_new:N \l_@@_input_mixed_fraction_sign_tl \tl_new:N \l_@@_list_of_units_tl \tl_new:N \l_@@_list_of_values_tl % \end{macrocode} % \begin{macrocode} \tl_new:N \l_@@_cunum_hook_tl \tl_new:N \l_@@_cutext_hook_tl \tl_new:N \l_@@_Cutext_hook_tl \tl_new:N \l_@@_cuam_hook_tl % \end{macrocode} % \end{macro} % % % Setting some token lists to their default value. % \cs{c_@@_input_str_hash_one_tl} is used for defining single keys. % (As you will see, I didn't have a better idea) % \begin{macrocode} \tl_set:Nn \l_@@_input_digits_tl { 0123456789 } \tl_set:Nn \l_@@_input_range_sign_tl { -- } \tl_set:Nn \l_@@_input_fraction_sign_tl { / } \tl_set:Nn \l_@@_input_mixed_fraction_sign_tl { _ } \tl_set:Nn \l_@@_input_decimal_mark_tl { . , } \tl_set:Nn \l_@@_input_value_signs_tl { + - } \tl_set:Nn \l_@@_input_allowed_special_signs_tl { ? } \tl_gset_rescan:Nnn \g_@@_input_str_hash_one_tl { \char_set_catcode_letter:N \# } {#1} % \end{macrocode} % \begin{macrocode} \tl_set:Nn \l_@@_cunum_range_sign_tl { -- } \tl_set:Nn \l_@@_cutext_range_sign_tl { } \tl_set:Nn \l_@@_value_unit_space_tl { \thinspace } \tl_set:Nn \l_@@_cutext_space_tl { \space } \tl_set:Nn \l_@@_cuphrase_space_tl { \space } \tl_set:Nn \l_@@_unit_letter_not_allowed_tl { , / } % \end{macrocode} % % Flat out stolen from \pkg{siunitx}. % \begin{macrocode} \AtBeginDocument { \cs_if_free:cT { T@TS1 } { \DeclareFontEncoding { TS1 } { } { } \DeclareFontSubstitution { TS1 } { cmr } { m } { n } } } % \end{macrocode} % \begin{macrocode} \DeclareTextSymbolDefault \c_@@_minus_tl { TS1 } \DeclareTextSymbol \c_@@_minus_tl { TS1 } { 61 } \AtBeginDocument { \@ifpackageloaded { fontspec } { \@ifpackageloaded { eulervm } { } { \int_const:Nn \c_@@_minus_int { 8722 } \tl_set:Nn \c_@@_minus_tl { \tex_char:D \c_@@_minus_int } } } { } } % \end{macrocode} % % \begin{macro}{ \l_@@_mixed_frac_dim } % The dimension between the fraction and the mixed fraction part is % stored within this macro. There is no real reason why I have % chosen this distance to be 0.1em, I just thought that it looks % best. But if someone has some ideas of how large this distance % should be I am happy to listen. % \begin{macrocode} \dim_new:N \l_@@_mixed_frac_dim \dim_set:Nn \l_@@_mixed_frac_dim { 0.1 em } % \end{macrocode} % \end{macro} % % % \begin{macro}{ \l_@@_round_precision_int } % Stores the round-precision inside. Can also take negative values. % \begin{macrocode} \int_new:N \l_@@_round_precision_int \int_set:Nn \l_@@_round_precision_int { 2 } % \end{macrocode} % \end{macro} % % \begin{macro}{ \l_@@_print_numerals_below_int } % Used if option \opt{use-numerals} is active. Uses numerals for % integers smaller than this number. I learned this number % at school. % \begin{macrocode} \int_new:N \l_@@_print_numerals_below_int \int_set:Nn \l_@@_print_numerals_below_int { 13 } % \end{macrocode} % \end{macro} % % % \begin{macro}{ \l_@@_local_number_of_persons_int } % Each recipe defined by \cs{culabel} defines a counter to % store the number of persons the recipe is for. For calculation % the value is retrieved and stored inside this temporal integer variable. % \begin{macrocode} \int_new:N \l_@@_local_number_of_persons_int % \end{macrocode} % \end{macro} % % \begin{macro}{ \l_@@_wanted_number_of_persons_int } % Not only the number of persons are recipe is for is needed % for calculation, but also the number of persons you want % the recipe to be. This information is stored here. % \begin{macrocode} \int_new:N \l_@@_wanted_number_of_persons_int \int_set:Nn \l_@@_wanted_number_of_persons_int { 4 } % \end{macrocode} % \end{macro} % % % \begin{macro}{ \l_@@_phrase_number_tl } % Stores the current \enquote{phrase number}. For \enquote{Dutzend} this would % be \enquote{12}, etc. % \begin{macrocode} \int_new:N \l_@@_phrase_number_tl % \end{macrocode} % \end{macro} % % \begin{macro}{ \l_@@_list_of_defined_keys_clist , \g_@@_list_of_defined_units_clist } % Sequence of defined units and keys. Units are defined % globally as they create new commands, keys do not do that % (I think). Could be my mistake. % \begin{macrocode} \seq_new:N \l_@@_list_of_defined_keys_seq \seq_new:N \g_@@_list_of_defined_units_seq % \end{macrocode} %\end{macro} % % % \begin{macro} { \g_@@_allowed_special_keys_seq } % \changes {2016/06/12} {New: \cs{g_@@_allowed_unit_phrases_tl}} % Used for the keys 'one(m)', 'one(f)', etc. Those are special keys % which cannot be used as units, but are processed by the commands in % the language section as such. % \begin{macrocode} \seq_new:N \g_@@_allowed_special_keys_seq % \end{macrocode} % \end{macro} % % \begin{macro} { \l_@@_phrase_numbers_seq } % Inside this list the numbers for which a phrase is defined % is stored in. As this is language specific, the list is stored % inside a language-sensitive command and retrieved when needed. % \begin{macrocode} \seq_new:N \l_@@_phrase_numbers_seq % \end{macrocode} % \end{macro} % % % \begin{macro}{\l_@@_number_of_iterations_seq, \l_@@_derivative_unit_list_seq , % \l_@@_derivative_symbol_list_seq , \l_@@_derivative_value_list_seq % } % Variables used in \mycs{declarecookingderivatives}. % \begin{macrocode} \seq_new:N \l_@@_number_of_iterations_seq \seq_new:N \l_@@_derivative_unit_list_seq \seq_new:N \l_@@_derivative_symbol_list_seq \seq_new:N \l_@@_derivative_value_list_seq % \end{macrocode} % \end{macro} % % \begin{macro}{\l_@@_max_depth_int, \l_@@_curr_depth_int} % Also some variables used in \mycs{declarecookingderivatives}. % \begin{macrocode} \int_new:N \l_@@_max_depth_int \int_new:N \l_@@_curr_depth_int % \end{macrocode} % \end{macro} % % % % \begin{macro} { \l_@@_temperatures_to_check_seq } % \changes {1.02h} {New.} % Stores units which should be tested if \opt{check-temperature} equals true. % \begin{macrocode} \seq_new:N \l_@@_temperatures_to_check_seq % \end{macrocode} % \end{macro} % % \begin{macro} { \l_@@_curef_do_not_change_seq } % This contains the units which shouldn't be changed. % \begin{macrocode} \seq_new:N \l_@@_curef_do_not_change_seq % \end{macrocode} % \end{macro} % % \begin{macro} { \l_@@_phrase_prop } % Stores the number and he respective phrase. For example % if \enquote{12} has the phrase \enquote{Dutzend}, this % key-value pair is stored inside. % \begin{macrocode} \prop_new:N \l_@@_phrase_prop % \end{macrocode} % \end{macro} % % % % \begin{macro} % { % \l_@@_minus_bool, % \l_@@_round_number_bool, % \l_@@_error_bool, % \l_@@_unit_error_bool, % \l_@@_eval_fractions_bool, % \l_@@_convert_fractions_bool, % \l_@@_draft_bool, % \l_@@_round_to_int_bool, % \l_@@_special_sign_bool, % \l_@@_single_key_bool, % \l_@@_check_temperature_bool, % \l_@@_convert_to_eV_bool, % \l_@@_cutext_uppercase_word_bool, % \l_@@_using_cutext_bool, % \l_@@_cuam_old_bool, % \l_@@_change_number_of_persons_bool, % \l_@@_calc_because_ref_was_given_bool, % \l_@@_lokal_persons_bool, % \l_@@_cutext_to_cunum_bool, % \l_@@_cutext_old_bool, % \l_@@_cutext_keep_unit_bool, % \l_@@_round_commercial_bool, % \l_@@_use_phrases_bool, % \l_@@_lokal_phrase_bool, % \l_@@_print_numeral_bool, % \l_@@_lokal_numeral_bool, % \l_@@_round_precision_negative_bool, % \l_@@_fourty_two_bool, % \l_@@_phrase_negative_bool , % \l_@@_range_in_input_bool, \l_@@_lokal_fraction_bool , % \l_@@_print_fraction_bool, \l_@@_check_decimal_bool , % } % Some booleans we need later. % \begin{macrocode} \bool_new:N \l_@@_minus_bool \bool_new:N \l_@@_round_number_bool \bool_new:N \l_@@_error_bool \bool_new:N \l_@@_unit_error_bool \bool_new:N \l_@@_eval_fractions_bool \bool_new:N \l_@@_convert_fractions_bool \bool_new:N \l_@@_draft_bool \bool_new:N \l_@@_round_to_int_bool \bool_new:N \l_@@_special_sign_bool \bool_new:N \l_@@_single_key_bool \bool_new:N \l_@@_check_temperature_bool \bool_new:N \l_@@_convert_to_eV_bool \bool_new:N \l_@@_cutext_uppercase_word_bool \bool_new:N \l_@@_using_cutext_bool \bool_new:N \l_@@_cuam_old_bool \bool_new:N \l_@@_change_number_of_persons_bool \bool_new:N \l_@@_calc_because_ref_was_given_bool \bool_new:N \l_@@_lokal_persons_bool \bool_new:N \l_@@_cutext_to_cunum_bool \bool_new:N \l_@@_cutext_old_bool \bool_new:N \l_@@_cutext_keep_unit_bool \bool_new:N \l_@@_round_commercial_bool \bool_new:N \l_@@_use_phrases_bool \bool_new:N \l_@@_lokal_phrase_bool \bool_new:N \l_@@_print_numeral_bool \bool_new:N \l_@@_lokal_numeral_bool \bool_new:N \l_@@_round_precision_negative_bool \bool_new:N \l_@@_fourty_two_bool \bool_new:N \l_@@_phrase_negative_bool % \end{macrocode} % % While rewriting the code I searched for those % booleans a lot. % \begin{macrocode} \bool_new:N \l_@@_range_in_input_bool \bool_new:N \l_@@_lokal_fraction_bool \bool_new:N \l_@@_print_fraction_bool \bool_new:N \l_@@_check_decimal_bool % \end{macrocode} % \end{macro} % % % % Setting some of them to \true\ or another boolean respectively. % \begin{macrocode} \bool_set_false:N \l_@@_cutext_keep_unit_bool \bool_set_eq:NN \l_@@_print_numeral_bool \g_@@_opt_numeral_bool % \end{macrocode} % % % \begin{macro}{ \q_@@_range } % Replacing the sign \enquote{-{}-} with \lstinline|\q_@@_range| for testing. % \begin{macrocode} \quark_new:N \q_@@_range % \end{macrocode} %\end{macro} % % \begin{macro}{ \q_@@_no_translation } % Checking value if a translation is avaiable. % \begin{macrocode} \quark_new:N \q_@@_no_translation % \end{macrocode} %\end{macro} % % % \begin{macro}{ % \l_@@_tmpa_tl , \l_@@_tmpb_tl , \l_@@_tmp_unit_tl , % \l_@@_tmpa_fp , % \l_@@_tmpa_clist , % \l_@@_tmpa_prop , \l_@@_tmpb_prop , % \l_@@_tmpa_seq , % \l_@@_tmpa_int , \l_@@_tmpb_int , % } % Some temporal stores which are used throughout the code. % \begin{macrocode} \tl_new:N \l_@@_tmpa_tl \tl_new:N \l_@@_tmpb_tl \tl_new:N \l_@@_tmp_unit_tl \fp_new:N \l_@@_tmpa_fp \clist_new:N \l_@@_tmpa_clist \prop_new:N \l_@@_tmpa_prop \prop_new:N \l_@@_tmpb_prop \seq_new:N \l_@@_tmpa_seq \int_new:N \l_@@_tmpa_int \int_new:N \l_@@_tmpb_int % \end{macrocode} %\end{macro} % % % % \subsection {Keys} % % % Let's define some keys. % \begin{macrocode} \keys_define:nn { cooking-units } { % \end{macrocode} % % % \begin{macro}{ add-unit-to-group } % \begin{macrocode} add-unit-to-group .code:n = { \keyval_parse:NNn \@@_add_to_unit_group_error:n \@@_add_to_unit_group:nn {#1} } , add-unit-to-group .default:n = {} , % \end{macrocode} % \end{macro} % %\begin{macro}{ set-option-for } % Setting options. % \begin{macrocode} set-option-for .code:n = { \keyval_parse:NNn \@@_set_options_for_error:n \@@_set_options_for:nn {#1} }, % \end{macrocode} % \end{macro} % %\begin{macro}{ add-option-for } % Setting options. % \begin{macrocode} add-option-for .code:n = { \keyval_parse:NNn \@@_add_options_for_error:n \@@_add_options_for:nn {#1} }, % \end{macrocode} % \end{macro} % % \begin{macro}{ erase-all-options } % Erasing all preset options. Again not the best approach \dots\ maybe I need a lower % level \enquote{clear} option. % \begin{macrocode} erase-all-options .code:n = { \exp_args:Nx \cuclearoptionfor { \seq_use:Nn \g_@@_list_of_defined_units_seq { , } } }, erase-all-options .value_forbidden:n = { true } , % \end{macrocode} % \end{macro} % %\begin{macro}{ erase-all-options-for } % Erasing options. As this simply clears the unit options the argument |#1| % is simply a clist, as such no keyval parsing is needed. % \begin{macrocode} erase-all-options-for .code:n = { \cuclearoptionfor {#1} % \keyval_parse:NNn % \@@_erase_options_for:n % \@@_erase_options_for_error:nn % {#1} }, erase-all-options-for .value_required:n = { true } , % \end{macrocode} % \end{macro} % % % % % % % \begin{macro}{ cutext-to-cunum } % Don't want any \mycs{cutext} (or \mycs{Cutext}) in your % document? Use this option! % \begin{macrocode} cutext-to-cunum .bool_set:N = \l_@@_cutext_to_cunum_bool , cutext-to-cunum .default:n = { false } , cutext-to-cunum .groups:n = { change-command } , % \end{macrocode} % \end{macro} % % \begin{macro}{ cutext-change-unit } % Do not wanna change units in \mycs{cutext}? Use this option. % \begin{macrocode} cutext-change-unit .bool_set_inverse:N = \l_@@_cutext_keep_unit_bool , cutext-change-unit .default:n = { true } , cutext-change-unit .groups:n = { change-unit } , % \end{macrocode} % \end{macro} % % \begin{macro}{ cuam-version , cutext-version} % Some keys with horrible option names. Reverts % the respective command back to its older state (pre v1.10). % \begin{macrocode} cuam-version .choices:nn = { new , old } { \int_case:nn { \l_keys_choice_int } { { 1 } { \bool_set_false:N \l_@@_cuam_old_bool } { 2 } { \bool_set_true:N \l_@@_cuam_old_bool } } } , cuam-version .default:n = { new } , cutext-version .choices:nn = { new , old } { \int_case:nn { \l_keys_choice_int } { { 1 } { \bool_set_false:N \l_@@_cutext_old_bool } { 2 } { \bool_set_true:N \l_@@_cutext_old_bool } } } , cutext-version .default:n = { new } , % \end{macrocode} % \end{macro} % % \begin{macro}{ expand-both , expand-amount, expand-unit } % \begin{macrocode} expand-both .choices:nn = { n , o , f , x } { \cs_set_eq:Nc \@@_set_unit:Nn { tl_set:N \l_keys_choice_tl } \cs_set_eq:Nc \@@_set_amount:Nn { tl_set:N \l_keys_choice_tl } } , expand-both .default:n = { n } , % \end{macrocode} % \begin{macrocode} expand-amount .choices:nn = { n , o , f , x } { \cs_set_eq:Nc \@@_set_amount:Nn { tl_set:N \l_keys_choice_tl } } , expand-amount .default:n = { n } , % \end{macrocode} % \begin{macrocode} expand-unit .choices:nn = { n , o , f , x } { \cs_set_eq:Nc \@@_set_unit:Nn { tl_set:N \l_keys_choice_tl } } , expand-unit .default:n = { n } , % \end{macrocode} % \end{macro} % % % % % %\begin{macro}{ set-special-sign } % Setting allowd special signs. Note that |<| is not allowed. % \begin{macrocode} set-special-sign .code:n = { \tl_map_inline:nn {#1} { \str_if_eq:nnT {##1} { < } { \msg_error:nn { cooking-units } { <-not-allowed-as-special-sign } \tl_map_break:n { \use_none:nn } } } \use:n { \tl_set:Nn \l_@@_input_allowed_special_signs_tl {#1} } } , % \end{macrocode} %\end{macro} %\begin{macro}{ add-special-sign } % Adding a (some) special sign(s) which is (are) allowed in the input. % \begin{macrocode} add-special-sign .code:n = { \tl_map_inline:nn {#1} { \str_if_eq:nnTF {##1} { < } { \msg_error:nn { cooking-units } { <-not-allowed-as-special-sign } }{ \tl_put_right:Nn \l_@@_input_allowed_special_signs_tl {##1} } } } , add-special-sign .default:n = { } , % \end{macrocode} %\end{macro} % % % \begin{macro}{ set-unknown-message } % Sets the message for a special-sign to error, warning or none. % \begin{macrocode} set-unknown-message .choices:nn = { error , warning , none } { \msg_redirect_name:nnn { cooking-units } { amount-not-known } { \l_keys_choice_tl } } , set-unknown-message .default:n = { warning } , % \end{macrocode} %\end{macro} % % \begin{macro}{ set-unknown-message } % Sets the message for a special-sign to error, warning or none. % \begin{macrocode} set-cutext-translation-message .choices:nn = { error , warning , none } { \msg_redirect_name:nnn { cooking-units } { cutext-no-translation-available } { \l_keys_choice_tl } } , set-cutext-translation-message .default:n = { warning } , % \end{macrocode} %\end{macro} % % % \begin{macro}{ print-numerals } % A not very good name, but I couldn't think of a better name. % \begin{macrocode} print-numerals .bool_set:N = \l_@@_print_numeral_bool , print-numerals .default:n = { true } , % \end{macrocode} % \end{macro} % % \begin{macro}{ use-numerals-below } % Use numerals if the integer is below the integer set by this option. % \begin{macrocode} use-numerals-below .int_set:N = \l_@@_print_numerals_below_int , use-numerals-below .default:n = { 13 } , % \end{macrocode} %\end{macro} % %\begin{macro}{ parse-number } % Parse the input? If no the input is printed as is (after some safety parsing). % \begin{macrocode} parse-number .bool_set_inverse:N = \l_@@_draft_bool , parse-number .default:n= { true } , % \end{macrocode} %\end{macro} % %\begin{macro}{ range-sign } % Setting the printed range sign and make a difference between cunum % and c(C)utext. % \begin{macrocode} range-sign .meta:n = { cunum-range-sign = {#1} , cutext-range-sign = {#1} } , range-sign .default:n = { -- } , cunum-range-sign .tl_set:N = \l_@@_cunum_range_sign_tl , cunum-range-sign .default:n = { -- } , cutext-range-sign .tl_set:N = \l_@@_cutext_range_sign_tl , cutext-range-sign .default:n = { -- } , % \end{macrocode} %\end{macro} % % \begin{macro}{ use-phrases } % Do not wanna use phrases in \mycs{cuam}? Use this option! % \begin{macrocode} use-phrases .bool_set:N = \l_@@_use_phrases_bool , use-phrases .default:n = { true } , % \end{macrocode} % \end{macro} % % % % % % %\begin{macro}{ round-precision } % Setting the round-precision. Setting those two at once to % not calculate it every time. % \begin{macrocode} round-precision .code:n = { \int_set:Nn \l_@@_round_precision_int {#1} \int_compare:nNnTF {#1} < { 0 } { \bool_set_true:N } { \bool_set_false:N } \l_@@_round_precision_negative_bool } , round-precision .default:n = { 2 } , % \end{macrocode} %\end{macro} % %\begin{macro}{ round-to-int } % Rounding the results to an integer. % \begin{macrocode} round-to-int .bool_set:N = \l_@@_round_to_int_bool , round-to-int .choices:nn = { true , false } { \msg_error:nnnn { cooking-units } { Option-deprecated } { round-to-int } { round-precision = 0 } \int_compare:nNnTF { \l_keys_choice_int } = { 1 } { \int_set:Nn \l_@@_round_precision_int { 0 } }{ } \use:c { bool_set_ \l_keys_choice_tl :N } \l_@@_round_to_int_bool } , round-to-int .default:n = { false } , % \end{macrocode} %\end{macro} % % \begin{macro}{ round-half } % Choosing between \enquote{normal} rounding to even % and commercial rounding and sets the boolean accordingly. % \begin{macrocode} round-half .choices:nn = { default , commercial } { \int_case:nn { \l_keys_choice_int } { { 1 } { \bool_set_false:N \l_@@_round_commercial_bool } { 2 } { \bool_set_true:N \l_@@_round_commercial_bool } } }, round-half .default:n = { default }, % \end{macrocode} % \end{macro} % %\begin{macro}{ eval-fraction } % If set to true the fractions are evaluated. % \begin{macrocode} eval-fraction .bool_set:N = \l_@@_eval_fractions_bool , eval-fraction .default:n = { false } , % \end{macrocode} %\end{macro} % %\begin{macro}{ convert-fraction } % If set to true the fractions are evaluated \emph{if} the unit is transformed! % \begin{macrocode} convert-fraction .bool_set:N = \l_@@_convert_fractions_bool , convert-fraction .default:n = { true } , % \end{macrocode} %\end{macro} % % %\begin{macro}{ fraction-command } % Setting the fraction command % \begin{macrocode} fraction-command .code:n = { \cs_set_eq:NN \@@_frac:nn #1 } , fraction-command .default:n = { \sfrac } , % \end{macrocode} %\end{macro} % %\begin{macro}{ fraction-inline } % Setting the code inline. % \begin{macrocode} fraction-inline .code:n = { \cs_set:Npn \@@_frac:nn ##1##2 {#1} } , fraction-inline .default:n = { \sfrac {#1} {#2} } , % \end{macrocode} %\end{macro} % % % % % % %\begin{macro}{ mixed-fraction-space } % Setting the space between the mixed fraction part and the fraction. % \begin{macrocode} mixed-fraction-space .dim_set:N = \l_@@_mixed_frac_dim , mixed-fraction-space .default:n = { 0.1 em } , % \end{macrocode} %\end{macro} % % \begin{macro}{ cutext-space } % The space used in \mycs{cutext} between the number (or numeral) % and unit. % \begin{macrocode} cutext-space .tl_set:N = \l_@@_cutext_space_tl , cutext-space .default:n = { \space } , % \end{macrocode} % \end{macro} % % \begin{macro}{ phrase-space } % Same as before, but for phrases % \begin{macrocode} phrase-space .tl_set:N = \l_@@_cuphrase_space_tl , phrase-space .default:n = { \space } , % \end{macrocode} % \end{macro} % %\begin{macro}{ amount-unit-space } % Setting the space between the value and the printed unit. % \begin{macrocode} amount-unit-space .tl_set:N = \l_@@_value_unit_space_tl , amount-unit-space .default:n = { \thinspace } , % \end{macrocode} %\end{macro} % % % % % % % \begin{macro}{ recalculate-amount } % Setting the number of persons your recipes should be for % is not enough; it is also needed to tell the package to % recalculate the amounts. % \begin{macrocode} recalculate-amount .bool_set:N = \l_@@_change_number_of_persons_bool , recalculate-amount .default:n = { false } , % \end{macrocode} % \end{macro} % % \begin{macro}{ set-number-of-persons } % Setting the number of persons the recipe should be for. % \begin{macrocode} set-number-of-persons .int_set:N = \l_@@_wanted_number_of_persons_int , set-number-of-persons .default:n = { 4 } , % \end{macrocode} % \end{macro} % % \begin{macro}{ label } % Defines a label. Is \mycs{culabel} in key form. % \begin{macrocode} label .code:n = \@@_label_and_persons:n {#1} , label .value_required:n = { true } , % \end{macrocode} % \end{macro} % % \begin{macro}{ get-label } % \mycs{curef} as a key. % \begin{macrocode} get-label .code:n = \@@_curef:n {#1} , label .value_required:n = { true } , % \end{macrocode} % \end{macro} % % \begin{macro}{ ref } % The |<>| option for keys. % \begin{macrocode} ref .code:n = \@@_reference_label_and_persons:n {#1} , ref .value_required:n = { true } , % \end{macrocode} % \end{macro} % % % % % % %\begin{macro}{ check-temperature } % Weird option. Checking the temperature, if the temperature is below the absolute zero temperature % it raises an error. % \begin{macrocode} check-temperature .bool_set:N = \l_@@_check_temperature_bool , check-temperature .default:n = { true } , % \end{macrocode} % %\begin{macro}{ add-temperature-to-check } % Adds a temperature to check for \texttt{check-temperature}. % It uses the \cs{keyval\_parse:NNn} command as this % macro is used to parse keys (which is what I need). % \begin{macrocode} add-temperature-to-check .code:n = { \keyval_parse:NNn \@@_temperature_to_check_print_error:n \@@_temperatures_to_check_define:nn {#1} } , temperature-to-check .value_required:n = { true } , % \end{macrocode} % \end{macro} % %\begin{macro}{ convert-to-eV } % Another weird option, converts pretty much any unit defined by this % package to electron volt or the respective derivative. % As this is a unit transformation, it needs to be inside the % group. % \begin{macrocode} convert-to-eV .bool_set:N = \l_@@_convert_to_eV_bool , convert-to-eV .default:n = { true } , convert-to-eV .groups:n = { change-unit } , % \end{macrocode} %\end{macro} % % \begin{macro}{ add-natural-unit } % \begin{macrocode} add-natural-unit .code:n = { \seq_set_from_clist:Nn \l_@@_tmpa_seq {#1} \seq_map_inline:Nn \l_@@_tmpa_seq { \@@_error_if_unit_not_defined:nF {##1} { \seq_if_in:NnF \g_@@_natural_units_seq {##1} { \seq_gput_right:Nn \g_@@_natural_units_seq {##1} } } } } , add-natural-unit .value_required:n = { true } , % \end{macrocode} % \end{macro} % % \begin{macro}{ 42 } % \begin{macrocode} 42 .choice: , 42 / true .code:n = { \bool_set_true:N \l_@@_fourty_two_bool } , 42 / false .code:n = { \msg_fatal:nnn { cooking-units } { 42-is-...-wrong? } } , 42 .default:n = { true } , % \end{macrocode} % \end{macro} % % % % % % % % % % % % % % % % % % % % \begin{macro}{ input-range-sign } % Don't wanna use \verb|--| as a range sperator in \mycs{cunum}? % Use this option. % \begin{macrocode} input-range-sign .tl_set:N = \l_@@_input_range_sign_tl , input-range-sign .default:n = { -- } , % \end{macrocode} %\end{macro} % % \begin{macro}{ numeral-function , Numeral-function } % \begin{macrocode} numeral-function .code:n = { \cs_set_eq:NN \@@_print_numeral:n #1 } , Numeral-function .code:n = { \cs_set_eq:NN \@@_print_Numeral:n #1 } , % \end{macrocode} % \end{macro} % % % % % \begin{macro}{ % commands-add-hook , % cunum-add-hook , % cutext-add-hook , Cutext-add-hook , % cuam-add-hook , % } % \begin{macrocode} commands-add-hook .meta:n = { cunum-add-hook = {#1} , cutext-add-hook = {#1} , Cutext-add-hook = {#1} , cuam-add-hook = {#1} , } , cunum-add-hook .code:n = { \tl_put_right:Nn \l_@@_cunum_hook_tl {#1} } , cutext-add-hook .code:n = { \tl_put_right:Nn \l_@@_cutext_hook_tl {#1} } , Cutext-add-hook .code:n = { \tl_put_right:Nn \l_@@_Cutext_hook_tl {#1} } , cuam-add-hook .code:n = { \tl_put_right:Nn \l_@@_cuam_hook_tl {#1} } , % \end{macrocode} % \end{macro} % % % % % % % % % % % % % % % % % % \begin{macro}{ % curef-add-forbidden-unit, % curef-remove-forbidden-unit, % curef-clear-forbidden-units % } % \begin{macrocode} curef-add-forbidden-unit .code:n = { \@@_add_forbidden_unit:n {#1} } , curef-add-forbidden-unit .default:n = { } , curef-remove-forbidden-unit .code:n = { \@@_remove_forbidden_unit:n {#1} } , curef-remove-forbidden-unit .default:n = { } , % curef-clear-forbidden-units .choice: , curef-clear-forbidden-units/true .code:n = { \@@_clear_forbidden_unit: } , curef-clear-forbidden-units/false .code:n = { } , curef-clear-forbidden-units .value_required:n = true, % \end{macrocode} % \end{macro} % % % % % % % % % % Ending the definition of keys. % \begin{macrocode} } % \end{macrocode} % \end{macro} % % % % % % % \subsection {Messages} % % Defining messages. % % \begin{macro} {Messages} % I do not allow fractions and ranges in the same input. Maybe I will % change this. % \begin{macrocode} \msg_new:nnnn { cooking-units } { fraction-not-allowed-with-range } { You \ cannot \ use \ '/' \ ( and \ '_' )\ in \ combination \ with \ '\l_@@_input_range_sign_tl' \ in \ '#1'. }{ You \ cannot \ use \ fractions \ with \ a \ range. \msg_see_documentation_text:n { cooking-units } } % \end{macrocode} % % Do not allow a \_ without a /. % \begin{macrocode} \msg_new:nnnn { cooking-units } { missing-slash } { You \ cannot \ use \ '_' \ without \ '/' \ in \ '#1'. }{ You \ cannot \ have \ a \ mixed \ fraction \ ('_') \ without \ a \ normal \ fraction \ ('/'). \msg_see_documentation_text:n { cooking-units } } \msg_new:nnnn { cooking-units } { fraction-wrong-order } { You \ cannot \ use \ '/' \ before \ '_' \ in \ '#1'. }{ You \ can \ only \ use \ '_' \ before \ '/'. \msg_see_documentation_text:n { cooking-units } } % \end{macrocode} % Error message if unit is not known to this package. % \begin{macrocode} \msg_new:nnnn { cooking-units } { unknown-unit } { The \ unit \ '#1' \ is \ not \ defined. \ Use \ \newcookingunit (or \ one \ of \ the \ others) \ to \ define \ new \ units. }{ Define \ units \ before \ using \ or \ check \ if \ the \ unit-key \ is \ written \ correctly. \msg_see_documentation_text:n { cooking-units } } % \end{macrocode} % Error if unit is already defined. % \begin{macrocode} \msg_new:nnnn { cooking-units } { unit-already-defined } { The\ unit \ '#1' \ is \ already \ defined. } { The \ unit-key \ is \ already \ defined. \ Please \ use \ a \ different \ key \ for \ a \ new \ unit. \msg_see_documentation_text:n {cooking-units} } % \end{macrocode} % % \begin{macrocode} \msg_new:nnnn { cooking-units } { character-not-allowed } { Unit-keys \ are \ not \ allowed \ to \ either \ contain \ ',' \ or \ '/' \ in \ '#1'. }{ The \ unit-key \ is \ not \ allowed \ to \ contain \ ',' \ or \ '/'. \ Due \ to \ internal \ reasons. \msg_see_documentation_text:n {cooking-units} } % \end{macrocode} % % Missing argument in \lstinline|\cudefinesymbols| (et all). % \begin{macrocode} \msg_new:nnnn { cooking-units } { missing-argument } { There \ is \ a \ missing \ argument. } { You \ probably \ have \ forgotten \ a \ curly-brace \ pair. \msg_see_documentation_text:n {cooking-units} } % \end{macrocode} % If fractions are evaluated division by zero is not allowed. % \begin{macrocode} \msg_new:nnnn { cooking-units } { Division-by-zero } { Division\ by \ zero \ is \ not \ allowed \ in \ '#1'. } { See \ a \ math \ book \ of \ your \ choice \ or \ for \ example \ Wikipedia. } % \end{macrocode} % Showing the not allowed token in the input. Hope this helps. % \begin{macrocode} \msg_new:nnnn { cooking-units } { Token-not-allowed } { The \ token \ '#1' \ is \ not \ allowed \ in \ '#2'. } { The \ command \ accepts \ only \ a \ fixed \ number \ of \ tokens. \msg_see_documentation_text:n {cooking-units} } % \end{macrocode} % A second decimal sign is not allowed (No na net). % \begin{macrocode} \msg_new:nnnn { cooking-units } { Second-decimal-sign-not-allowed } { A \ second \ decimal \ sign \ is \ not \ allowed \ in \ '#1'. } { Perhaps \ you \ didn't \ type \ it \ correctly. \msg_see_documentation_text:n {cooking-units} } % \end{macrocode} % % \begin{macrocode} \msg_new:nnnn { cooking-units } { Second-fraction-sign-not-allowed } { A \ second \ fraction \ sign \ is \ not \ allowed \ in \ '#1'. } { Perhaps \ you \ didn't \ type \ it \ correctly. \msg_see_documentation_text:n {cooking-units} } % \end{macrocode} % % \begin{macrocode} \msg_new:nnnn { cooking-units } { Second-mixed-fraction-sign-not-allowed } { A \ second \ mixed \ fraction \ sign \ is \ not \ allowed \ in \ '#1'. } { Perhaps \ you \ didn't \ type \ it \ correctly. \msg_see_documentation_text:n {cooking-units} } % \end{macrocode} % Error message for an undefined key. % \begin{macrocode} \msg_new:nnnn { cooking-units } { Key-not-defined } { The \ key \ '#1' \ is \ not \ defined. \ Use \ \cudefinekeys or \ \cudefinesinglekey to \ define \ keys. } { This \ key \ is \ not \ defined, \ perhaps \ you \ misspelled \ it. \msg_see_documentation_text:n {cooking-units} } % \end{macrocode} % % If the temperature is too low print this error message. % Now prints all units for which a zero-point is defined. % \begin{macrocode} \msg_new:nnnn { cooking-units } { Temperature-too-low } { The \ temperature \ '#1' \ is \ too \ low.\ It \ cannot \ be \ below \ the \ absolute \ zero - point \ of \ '#2'. \ Note \ that \ the \ temperatures \ '\@@_seq_use_msg:N \l_@@_temperatures_to_check_seq' \ are \ rounded \ to \ integers \ by \ default. \\\\ You \ can \ disable \ the \ option \ 'check-temperature' \ to \ disable \ this \ error. } { See \ for \ example \ Wikipedia. } % \end{macrocode} % If for an unit-key the value is wrong the following error message is shown. % \begin{macrocode} \msg_new:nnnn { cooking-units } { key-choice-unknown } { The \ key \ '#1' \ only \ accepts \ only \ '#3' \ as \ a \ set \ of \ choices \ and \ '#2' \ is \ non \ of \ these. }{ The \ key \ accepts \ only \ a \ fixed \ set \ of \ choices. \ You \ can \ add \ new \ choices \ via \ \token_to_str:N \cuaddkeys, ~ \token_to_str:N \cuaddsinglekeys ~ and \ \token_to_str:N \cuaddtokeys. \msg_see_documentation_text:n {cooking-units} } % \end{macrocode} % Adding a message for unit-groups. % \begin{macrocode} \msg_new:nnnn { cooking-units } { group-choice-not-allowed } { The \ group \ key \ '#1' \ accepts \ only \ '#3' \ as \ a \ set \ of \ choices \ and \ '#2' \ is \ non \ of \ these. }{ The \ key \ accepts\ only \ a \ fixed \ set \ of \ choices. \ You \ can \ add \ new \ choices \ via \ option \ 'add-unit-to-group'. \msg_see_documentation_text:n {cooking-units} } % \end{macrocode} % %\changes {v0.98a} {2016/06/11} {New option: 'value-not-known'.} %\changes {v0.99} {2016/06/12} {Renamed option: 'amount-not-known'.} % An info message for unknown messages. % \begin{macrocode} \msg_new:nnnn { cooking-units } { amount-not-known } { The \ amount \ '#1' \ is \ not \ known \ at \ line \ \msg_line_number: . }{ You \ used\ a\ special\ sign\ indicating\ that\ the\ true\ amount\ of\ the\ specific\ ingredient\ is\ (was) \ not\ known\ to\ you. This\ message\ reminds\ you\ about\ that\ fact. \msg_see_documentation_text:n {cooking-units} } % \end{macrocode} % % \begin{macrocode} \msg_new:nnnn { cooking-units } { group-key-unknown } { The \ group \ key \ '#1' \ is \ not \ defined. \ Perhaps \ you \ misspelled \ it? }{ The \ group \ key \ is \ not \ defined. \msg_see_documentation_text:n { cooking-units } } % \end{macrocode} % % If a load time option is not used as a package option, this % message is shown. % \begin{macrocode} \msg_new:nnnn { cooking-units } { load-time-option } { The \ option \ '#1' \ is \ only \ available \ as \ a \ load-time-option. \ Please \ set \ it \ as \ a \ package \ option. }{ You \ cannot \ set \ this \ option \ using \ \cusetup ~ but \ only \ as \ a \ package \ option. \msg_see_documentation_text:n { cooking-units } } % \end{macrocode} % % Messages for obsolete commands. % \begin{macrocode} \msg_new:nnnn { cooking-units } { obsolete-command } { Command \ #1 is \ obsolete. \ Please \ use \ #2 instead. }{ Don't \ use \ this \ old \ command \ ... \msg_see_documentation_text:n { cooking-units } } % \end{macrocode} % % \begin{macrocode} \msg_new:nnnn { cooking-units } { No-Value-given } { Please \ input \ a \ value \ for \ the \ key-value \ list \ in \ '#1' }{ Each \ element \ of \ the \ list \ needs \ a \ value. \msg_see_documentation_text:n { cooking-units } } % \end{macrocode} % % \begin{macrocode} \msg_new:nnnn { cooking-units } { Value-not-allowed } { The \ key-list \ in \ '#1' \ does \ not \ take \ a \ value. }{ This \ key-list \ does \ not \ take \ a \ value. \ The \ given \ value \ will \ be \ ignored. \msg_see_documentation_text:n { cooking-units } } % \end{macrocode} % % Error message if a zero-point temperature is already defined. % \begin{macrocode} \msg_new:nnnn { cooking-units } { Minimum-already-defined } { A \ minimum \ for \ '#1' \ has \ already \ been \ defined. }{ You \ cannot \ redefine \ it. \msg_see_documentation_text:n { cooking-units } } % \end{macrocode} % % Using the key version of \mycs{culabel} one needs to give the number of % people the recipe is for after a \enquote{*}. % \begin{macrocode} \msg_new:nnnn { cooking-units } { Number-of-persons-missing } { Please \ add \ the \ number \ of \ persons \ this \ recipe \ is \ for \ in \ '#1'. \ Note \ that\ the \ number \ must \ be \ given \ after \ a \ '*'. }{ Write \ 'Schweinsbraten*4' \ to \ create \ the \ label \ 'Schweinsbraten' \ which \ is \ initially \ for \ 4 \ persons. \msg_see_documentation_text:n { cooking-units } } % \end{macrocode} % % The number of persons, must be an integer \dots\ % \begin{macrocode} \msg_new:nnnn { cooking-units } { Number-of-persons-is-not-an-integer } { The \ number \ of \ persons \ the \ recipe \ is \ for \ must \ be \ an \ integer. \ '#1' \ is \ not \ allowed. }{ The \ number \ '#1' \ is \ not \ allowed. \msg_see_documentation_text:n { cooking-units } } % \end{macrocode} % % Each label defined by \mycs{culabel} needs to be new. % \begin{macrocode} \msg_new:nnnn { cooking-units } { label-already-defined } { The \ label \ '#1' \ has \ already \ been \ defined. }{ Each \ label \ must \ be \ unique. \msg_see_documentation_text:n { cooking-units } } % \end{macrocode} % % Message if a label is not defined. % \begin{macrocode} \msg_new:nnnn { cooking-units } { label-not-defined } { The \ label \ '#1' \ is \ not \ defined. \ Please \ note \ that \ a \ label \ has \ to \ defined \ before \ it \ is \ referenced. }{ Define \ the \ label \ before \ using \ it. \msg_see_documentation_text:n { cooking-units } } % \end{macrocode} % % If an unit is already defined and redefined by an \mycs{declarecookingunit}. % \begin{macrocode} \msg_new:nnnn { cooking-units } { redefine-unit } { The \ unit \ '#1' \ is \ redefined \ by \ \declarecookingunit ~ at \ \msg_line_context: . }{ \msg_see_documentation_text:n { cooking-units } } % \end{macrocode} % % A \enquote{phrase} must be an integer. % \begin{macrocode} \msg_new:nnnn { cooking-units } { phrase-unit-not-an-integer } { A \ phrase \ must \ be \ an \ integer, \ '#1' \ is \ not \ allowed. }{ You \ can \ only \ use \ integers. \msg_see_documentation_text:n { cooking-units } } % \end{macrocode} % % A translation for \cs{cutext} or \cs{Cutext} is not available. For this case % -- instead of printing the key-name (see \pkg{translations}) -- we fall back % to \cs{cunum}. % \begin{macrocode} \msg_new:nnnn { cooking-units } { cutext-no-translation-available } { For \ the \ unit \ '#1' \ there \ exists \ no \ translation \ to \ be \ used \ for \ \cutext ~ and \ \token_to_str:N \Cutext. \ You \ can \ define \ new \ translations \ for \ a \ given \ language \ using \ \cudefinename. }{ \cunum ~ is \ used \ instead. \msg_see_documentation_text:n { cooking-units } } % \end{macrocode} % % % \begin{macrocode} \msg_new:nnnn { cooking-units } { Translation-not-available } { The \ translation \ for \ #1 \ does \ not \ exist. Please \ define \ it \ using \ \token_to_str:N\cudefinename. }{ And \ you \ may \ send \ me \ the \ translation \ as \ it \ is \ not \ available \ yet. \msg_see_documentation_text:n { cooking-units } } % \end{macrocode} % % % \begin{macrocode} \msg_new:nnnn { cooking-units } { <-not-allowed-as-special-sign } { Currently \ (and \ probably \ forever) \ the \ sign \ '<' \ is \ not \ allowed \ to \ be \ used \ as \ a \ special \ sign. }{ I \ apologize \ for \ the \ inconvenience. \msg_see_documentation_text:n { cooking-units } } % \end{macrocode} % % % \begin{macrocode} \msg_new:nnnn { cooking-units } { unknown-gender } { '#1' \ is \ not \ allowed \ to \ be \ used \ as \ a \ gender-specification. Only \ 'm', \ 'f' \ or \ 'n' \ are \ allowed. }{ Please \ remove \ spaces \ if \ there \ are \ some. \msg_see_documentation_text:n { cooking-units } } % \end{macrocode} % % % \begin{macrocode} \msg_new:nnnn { cooking-units } { curef-not-inside-list } { '#1' \ cannot \ be \ removed \ from \ the \ 'forbidden \ unit' \ list \ because \ it \ is \ not \ inside \ the \ list. }{ Currently \ the \ list\ contains \ '#2'. \msg_see_documentation_text:n { cooking-units } } % \end{macrocode} % % % \begin{macrocode} \msg_new:nnnn { cooking-units } { curef-forbidden-unit } { The \ amount \ of \ '#1' \ cannot \ be \ changed \ using \ cooking-units` \ label \ and \ ref \ feature. }{ You \ can \ remove \ the \ unit \ using \ 'curef-remove-forbidden-unit'. \msg_see_documentation_text:n { cooking-units } } % \end{macrocode} % % \begin{macrocode} \msg_new:nnnn { cooking-units } { define-numeral-function } { You \ are \ using \ numerals \ (lowercase) \ without \ the \ load-time \ option \ 'use-fmtcount-numerals' \ as \ such \ you \ need \ to \ define \ which \ function \ is \ to \ be \ used \ for \ numerals. \ You \ can \ do \ that \ via \ 'numeral-function' \ and \ 'Numeral-function' }{ Please \ specify\ which \ function \ should \ be \ used \ to \ print \ numerals (lowercase \ and \ uppercase). \msg_see_documentation_text:n { cooking-units } } \msg_new:nnnn { cooking-units } { define-Numeral-function } { You \ are \ using \ numerals \ (capitalized) \ without \ the \ load-time \ option \ 'use-fmtcount-numerals' \ as \ such \ you \ need \ to \ define \ which \ function \ is \ to \ be \ used \ for \ numerals. \ You \ can \ do \ that \ via \ 'numeral-function' \ and \ 'Numeral-function' }{ Please \ specify\ which \ function \ should \ be \ used \ to \ print \ numerals (lowercase \ and \ uppercase). \msg_see_documentation_text:n { cooking-units } } % \end{macrocode} % % \begin{macrocode} \msg_new:nnnn { cooking-units } { 42-is-...-wrong? } { You \ requested \ to \ set \ 42 \ to \ 'false'. \ This \ doesn't \ make \ any \ sense! \ It \ cannot \ be \ 'false', \ it \ is \ the \ answer \ to \ the \ question \ of \ life, \ universe \ and \ everything. \ For \ the \ sake \ of \ the \ world \ I \ cannot \ allow \ you \ to \ set \ it \ to \ 'false', \ the \ universe \ might \ explode \ otherwise. \\ The \ run \ will \ be \ aborted. }{ Phew ... \ this \ might \ have \ ended \ disastrous. \msg_see_documentation_text:n { cooking-units } } % \end{macrocode} % % % \begin{macrocode} \msg_new:nnnn { cooking-units } { empty-amount } { The \ amount \ given \ is \ empty \ ( spaces \ are \ removed ). }{ The \ amount \ given \ is \ empty. \msg_see_documentation_text:n { cooking-units } } % \msg_new:nnnn { cooking-units } { unknown-option } { The \ option \ '#1' \ is \ not \ defined. }{ Perhaps \ you \ misspelled \ the \ option. \msg_see_documentation_text:n { cooking-units } } % \end{macrocode} % % % \begin{macrocode} \msg_new:nnnn { cooking-units } { internal-error } { This \ error \ shouldn't \ show. \ This \ means \ I \ (the \ package \ author) \ screwed \ up. \ The \ error \ code \ is \ '#1'. }{ Please \ send \ me \ a \ bug \ report. \msg_see_documentation_text:n { cooking-units } } % \end{macrocode} % \end{macro} % % \section {Helper Macros} % % The name says it all. % %\begin{macro} % { % \@@_error_if_unit_not_defined:n, % \@@_error_if_unit_not_defined:nTF, % \@@_error_if_unit_not_defined:VTF, % } % A little helper macro. Checks if the unit is defined, if not raise an error. % \begin{macrocode} \prg_new_protected_conditional:Npnn \@@_error_if_unit_not_defined:n #1 { TF, T, F } { \seq_if_in:NnTF \g_@@_list_of_defined_units_seq {#1} { \prg_return_false: } { \msg_error:nnn { cooking-units } { unknown-unit } {#1} \prg_return_true: } } \cs_new:Npn \@@_error_if_unit_not_defined:n #1 { \@@_error_if_unit_not_defined:nTF {#1} { } { } } \cs_generate_variant:Nn \@@_error_if_unit_not_defined:nTF { V } % \end{macrocode} %\end{macro} % % % \begin{macrocode} \cs_new:Npn \@@_seq_use_msg:N #1 { \seq_use:Nnnn #1 { ' , ~ ' } { ' , ~ ' } { ' ~ and ~ ' } } \cs_generate_variant:Nn \@@_seq_use_msg:N { c } % \end{macrocode} % % % % \begin{macro}{ \@@_if_integer:n } % Checking if the input consists only of numbers. % \begin{macrocode} \prg_new_protected_conditional:Npnn \@@_if_integer:n #1 { TF , F } { \tl_map_inline:nn {#1} { \tl_if_in:NnF \l_@@_input_digits_tl {##1} { \tl_map_break:n { \use_iii:nnn } } } \use_i:nn \prg_return_true: \prg_return_false: } \cs_generate_variant:Nn \@@_if_integer:nTF { V } \cs_generate_variant:Nn \@@_if_integer:nF { V } % \end{macrocode} % \end{macro} % % \begin{macro}{ \@@_if_integer:n } % Checking if the input consists only of numbers. % \begin{macrocode} \cs_new:Npn \@@_bool_set_if_integers:NNN #1#2#3 { \@@_if_integer:VTF #2 { \bool_set_true:N #1 } { \bool_set_false:N #1 } \bool_lazy_and:nnT { \l_@@_range_in_input_bool } {#1} { \@@_if_integer:VF #3 { \bool_set_false:N #1 } } } % \end{macrocode} % \end{macro} % % % % \begin{macro}[TF]{ \@@_fp_if_equal_one:n} % \begin{macro}[TF]{ \@@_int_if_equal_one:n} % \begin{macrocode} \prg_new_conditional:Npnn \@@_fp_if_equal_one:n #1 { TF } { \fp_compare:nNnTF {#1} = { 1.0 } { \prg_return_true: } { \prg_return_false: } } \prg_new_conditional:Npnn \@@_int_if_equal_one:n #1 { TF } { \int_compare:nNnTF {#1} = { 1 } { \prg_return_true: } { \prg_return_false: } } % \end{macrocode} % \end{macro} \end{macro} % % % % \begin{macro}{} % \begin{macrocode} \prg_new_conditional:Npnn \@@_change_cutext_to_cunum:n #1 { TF } { \keys_set_groups:nnn { cooking-units } { change-command } {#1} \bool_if:NTF \l_@@_cutext_to_cunum_bool { \prg_return_true: } { \prg_return_false: } } % \end{macrocode} % \end{macro} % % \begin{macro}{ \@@_check_if_correct_gender_input:n } % \begin{macrocode} \prg_new_conditional:Npnn \@@_if_gender_error:n #1 { TF } { \str_case:nnTF {#1} { { m } { } { f } { } { n } { } } { \prg_return_false: } { \msg_error:nnn { cooking-units } { unknown-gender } {#1} \prg_return_true: } } \cs_new:Npn \@@_check_if_correct_gender_input:n #1 { \str_case:nnF {#1} { { m } { } { f } { } { n } { } } { \msg_error:nnn { cooking-units } { unknown-gender } {#1} } } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_define_clear_unit_group:nn,\@@_add_to_unit_group_error:n,\@@_add_to_unit_group:nn} % \begin{macrocode} \cs_new:Npn \@@_define_clear_unit_group:nn #1#2 { \seq_clear_new:c { l_@@_group_ #1 _seq } \keys_define:nn { cooking-units } { #1 .code:n = { \@@_unit_group_convert_units:nn {#1} {##1} } , #1 .groups:n = { change-unit } , } } % \cs_new:Npn \@@_add_to_unit_group_error:n #1 { \msg_error:nnn { cooking-units } { No-Value-given } { add-unit-to-group } } % \cs_new:Npn \@@_add_to_unit_group:nn #1#2 { \@@_error_if_group_not_defined:nF {#1} { \clist_map_inline:nn {#2} { \@@_error_if_unit_not_defined:nF {##1} { \seq_if_in:cnF { l_@@_group_ #1 _seq } {##1} { \seq_put_right:cn { l_@@_group_ #1 _seq } {##1} } } } } } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_error_if_group_not_defined:n} % \begin{macrocode} \prg_new_conditional:Npnn \@@_error_if_group_not_defined:n #1 { F } { \seq_if_exist:cTF { l_@@_group_ #1 _seq } { \prg_return_false: } { \msg_error:nn { cooking-units} { group-key-unknown } \prg_return_true: } } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_unit_group_convert_units:nn} % Didn't feel like intending the groups, as such use |\use_none:nnnnn(nnn)|. % (Always wanted to use those |\use_none:|) % \begin{macrocode} \cs_new:Npn \@@_unit_group_convert_units:nn #1#2 { \@@_error_if_group_not_defined:nF {#1} { \@@_error_if_unit_not_defined:nF {#2} { \seq_if_in:cnTF { l_@@_group_ #1 _seq } {#2} { \seq_map_inline:cn { l_@@_group_ #1 _seq } { \@@_keys_set:nnn { cooking-units } {##1} {#2} } }{ \msg_error:nnxxx { cooking-units } { group-choice-not-allowed } {#1} {#2} { \@@_seq_use_msg:c { l_@@_group_ #1 _seq } } } } } } % \end{macrocode} % \end{macro} % % % \begin{macro}{\@@_convert_to_eV:} % Still work in progress. Will probably forever be. Changes all % predefined units into natural units (except for those who cannot % be changed, like |Msp.| for example). % % \begin{macrocode} \seq_new:N \g_@@_natural_units_seq \prop_new:N \g_@@_convert_to_eV_remember_prop \seq_gset_from_clist:Nn \g_@@_natural_units_seq { eV , eVc-2 , hbareV-1 , chbareV-1 , (chbareV-1)3 , } \cs_new:Npn \@@_keys_set:nnn #1#2#3 { \keys_set:nn {#1} { #2 = #3 } } \cs_generate_variant:Nn \@@_keys_set:nnn { nVV , nVn } \cs_new:Npn \@@_convert_to_eV: { \tl_set_eq:Nc \l_@@_tmp_unit_tl { l_@@_base_key_unit_ \l_@@_original_unit_tl _tl } \tl_if_empty:NF \l_@@_tmp_unit_tl { \prop_get:NVNTF \g_@@_convert_to_eV_remember_prop \l_@@_original_unit_tl \l_@@_tmpa_tl { \@@_keys_set:nVV { cooking-units } \l_@@_original_unit_tl \l_@@_tmpa_tl } { \prop_get:cnNTF { l_@@_cukeys_ \l_@@_tmp_unit_tl _prop } { Liste } \l_@@_tmpa_seq { \seq_map_inline:Nn \g_@@_natural_units_seq { \seq_if_in:NnT \l_@@_tmpa_seq {##1} { \prop_gput:NVn \g_@@_convert_to_eV_remember_prop \l_@@_original_unit_tl {##1} \@@_keys_set:nVn { cooking-units } \l_@@_original_unit_tl {##1} \seq_map_break: } } } { \msg_error:nnn { cooking-units } { internal-error } { convert-to-eV } } } } } % \end{macrocode} %\end{macro} % % % % % \begin{macro}{\@@_tl_eval:Nn} % I am using this construction often enough, so \dots\ yeah. % \begin{macrocode} \cs_new:Npn \@@_tl_eval:Nn #1#2 { \tl_set:Nf #1 { \fp_eval:n {#2} } } \cs_generate_variant:Nn \@@_tl_eval:Nn { Nv } % \end{macrocode} % \end{macro} % % % % \begin{macro}{ } % I am using this construction often enough, so \dots\ yeah. % Note that if the evaluation is |true|, the path taken is the |false| one. % \begin{macrocode} \prg_new_conditional:Npnn \@@_change_unit: { TF , T } { \bool_lazy_any:nTF { { \l_@@_lokal_fraction_bool } { \l_@@_special_sign_bool } { \l_@@_draft_bool } } { \prg_return_false: } { \prg_return_true: } } % \end{macrocode} % \end{macro} % % % \begin{macro}{\@@_temperature_to_check_print_error:n,\@@_temperatures_to_check_define:nn} % Commands used in the option \texttt{temperature-to-check}. % If no value is given (first command) it raises an error. If a value % is given the unit is added to a check-list and a new % constant is defined. % \begin{macrocode} \cs_new:Npn \@@_temperature_to_check_print_error:n #1 { \@@_error_if_unit_not_defined:n {#1} \msg_error:nnn { cooking-units } { No-Value-given } { add-temperature-to-check } } \cs_new:Npn \@@_temperatures_to_check_define:nn #1#2 { \@@_error_if_unit_not_defined:nF {#1} { \fp_if_exist:cTF { l_@@_ #1 _min_fp } { % \msg_warning:nnn { cooking-units } { Minimum-already-defined } {#1} \fp_set:cn { l_@@_ #1 _min_fp } {#2} }{ \seq_put_right:Nn \l_@@_temperatures_to_check_seq {#1} \fp_new:c { l_@@_ #1 _min_fp } \fp_set:cn { l_@@_ #1 _min_fp } {#2} } } } % \end{macrocode} % \end{macro} % % \begin{macro}{ \@@_set_options_for_error:n , \@@_set_options_for:nn } % \begin{macrocode} \cs_new:Npn \@@_set_options_for_error:n #1 { \@@_error_if_unit_not_defined:n {#1} \msg_error:nnn { cooking-units } { No-Value-given } { set-option-for } } \cs_new:Npn \@@_set_options_for:nn #1#2 { \cusetoptionfor {#1} {#2} } % \end{macrocode} % \end{macro} % % \begin{macro}{ \@@_add_options_for_error:n , \@@_add_options_for:nn } % \begin{macrocode} \cs_new:Npn \@@_add_options_for_error:n #1 { \@@_error_if_unit_not_defined:n {#1} \msg_error:nnn { cooking-units } { No-Value-given } { add-option-for } } \cs_new:Npn \@@_add_options_for:nn #1#2 { \cuaddoptionfor {#1} {#2} } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_rounding_function:n} % I think this definition is somewhat stupid, but I don't have a better idea. % \begin{macrocode} \cs_new:Npn \@@_rounding_function:n #1 { #1 , \l_@@_round_precision_int \bool_if:NT \l_@@_round_commercial_bool { , #1 } } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_label_and_persons:n} % \begin{macrocode} \cs_new:Npn \@@_label_and_persons:n #1 { \tl_if_in:nnTF {#1} { * } { \@@_label_and_persons_times_persons:ww #1 \q_stop }{ \msg_error:nnn { cooking-units} { Number-of-persons-missing } {#1} } } % \end{macrocode} % \end{macro} % % \begin{macrocode} \cs_new:Npn \@@_label_and_persons_times_persons:ww #1 * #2 \q_stop { \@@_culabel:nn {#1} {#2} } % \end{macrocode} % % \begin{macro}{ \@@_culabel:nn } % \begin{macrocode} \cs_new:Npn \@@_culabel:nn #1#2 { \int_if_exist:cTF { g_@@_number_of_persons_ #1 _int } { \msg_error:nnn { cooking-units } { label-already-defined } {#1} }{ \@@_if_integer:nTF {#2} { \int_new:c { g_@@_number_of_persons_ #1 _int } \int_gset:cn { g_@@_number_of_persons_ #1 _int } {#2} } { \msg_error:nnn { cooking-units } { Number-of-persons-is-not-an-integer } {#2} } } } % \end{macrocode} % \end{macro} % % \begin{macro}{ \@@_reference_label_and_persons:n } % \begin{macrocode} \cs_new:Npn \@@_reference_label_and_persons:n #1 { \int_if_exist:cTF { g_@@_number_of_persons_ #1 _int } { \bool_set_true:N \l_@@_calc_because_ref_was_given_bool \int_set_eq:Nc \l_@@_local_number_of_persons_int { g_@@_number_of_persons_ #1 _int } } { \msg_error:nnn { cooking-units } { label-not-defined } {#1} } } % \end{macrocode} % \end{macro} % % \begin{macro}{ \@@_curef:n } % \begin{macrocode} \cs_new:Npn \@@_curef:n #1 { \int_if_exist:cTF { g_@@_number_of_persons_ #1 _int } { \bool_if:NTF \l_@@_change_number_of_persons_bool { \int_use:N \l_@@_wanted_number_of_persons_int } { \int_use:c { g_@@_number_of_persons_ #1 _int } } }{ \msg_error:nnn { cooking-units } { label-not-defined } {#1} } } % \end{macrocode} % \end{macro} % % \begin{macro}{ \culabel , \curef } % \begin{macrocode} \NewDocumentCommand \culabel { m m } { \@@_culabel:nn {#1} {#2} } \NewExpandableDocumentCommand \curef { m } { \@@_curef:n {#1} } % \end{macrocode} % \end{macro} % % % % % \begin{macro}{ \@@_bool_reverse:N, \@@_check_minus_remove_and_reverse:NN } % Can probably optimize this as the sign is always at the first place % (this is done after cheking the input, so the assumption is safe), but yeah \dots % \begin{macrocode} \cs_new:Npn \@@_bool_reverse:N #1 { \bool_if:NTF #1 { \bool_set_false:N } { \bool_set_true:N } #1 } \cs_new:Npn \@@_check_minus_remove_and_reverse:NN #1#2 { \quark_if_nil:NF #2 { \tl_if_in:NnT #2 { - } { \tl_remove_once:Nn #2 { - } \@@_bool_reverse:N #1 } \@@_check_minus_remove_and_reverse:NN #1 } } % \end{macrocode} % \end{macro} % % % % \subsection{Language Macros} % % \begin{macrocode} \tl_const:Nn \c_@@_postfix_unit_tl { ( cu-unit ) } \tl_const:Nn \c_@@_postfix_unit_pl_tl { ( cu-unit-pl ) } \tl_const:Nn \c_@@_postfix_unitname_tl { ( cu-unitname ) } \tl_const:Nn \c_@@_postfix_unitname_pl_tl { ( cu-unitname-pl ) } \tl_const:Nn \c_@@_postfix_gender_tl { ( cu-unitgender ) } \tl_const:Nn \c_@@_postfix_phrase_tl { ( cu-unitphrase ) } % \end{macrocode} % % \begin{macro}{\@@_deftranslation_base:nnn, \@@_deftranslation_base:xVn } % \begin{macro}{\@@_deftranslation_to:nnnn , \@@_deftranslation_to:VxVv,\@@_deftranslation_to:VxVV,\@@_deftranslation_to:VxVn} % \begin{macrocode} \cs_new:Npn \@@_deftranslation_base:nnn #1#2#3 { \declaretranslationfallback { #1 #2 } {#3} } \cs_new:Npn \@@_deftranslation_to:nnnn #1#2#3#4 { \declaretranslation {#1} { #2 #3 } {#4} } \cs_generate_variant:Nn \@@_deftranslation_base:nnn { xV } \cs_generate_variant:Nn \@@_deftranslation_to:nnnn { VxVv, VxVV , VxVn } % \end{macrocode} % \end{macro} % \end{macro} % % % % \begin{macro}{\@@_newtranslation:xxn } % \begin{macro}{\@@_newtranslation:nxxn } % \begin{macrocode} \cs_new:Npn \@@_newtranslation_base:nnn #1#2#3 { \definetranslationfallback { #1 #2 } {#3} } \cs_new:Npn \@@_newtranslation_to:nnnn #1#2#3#4 { \definetranslation {#1} { #2 #3 } {#4} } \cs_generate_variant:Nn \@@_newtranslation_base:nnn { nVn } \cs_generate_variant:Nn \@@_newtranslation_to:nnnn { nnVn } % \end{macrocode} % \end{macro} % \end{macro} % % % \begin{macro}{\@@_translate:nn , \@@_translate:xV } % \begin{macro}{\@@_translate_let:Nnn , \@@_translate_let:NnV } % \begin{macro}{\@@_translate_let:nNnn , \@@_translate_let:VNnV } % \begin{macrocode} \cs_new:Npn \@@_translate:nn #1#2 { \GetTranslation { #1 #2 } } \cs_new:Npn \@@_translate_let:Nnn #1#2#3 { \SaveTranslation {#1} { #2 #3 } } \cs_new:Npn \@@_translate_let:nNnn #1#2#3#4 { \SaveTranslationFor {#2} {#1} { #3 #4 } } \cs_generate_variant:Nn \@@_translate:nn { VV, nV } \cs_generate_variant:Nn \@@_translate_let:Nnn { NnV } \cs_generate_variant:Nn \@@_translate_let:nNnn { VNnV, nNnV } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}[TF]{\@@_unitname_get:Nn,\@@_unitname_get:Nx } % \begin{macrocode} \prg_new_conditional:Npnn \@@_unitname_get:Nn #1#2 { F } { \@@_translate_let:NnV #1 {#2} \c_@@_postfix_unitname_tl \tl_if_eq:NNTF #1 \q_@@_no_translation { \prg_return_false: } { \prg_return_true: } } \cs_generate_variant:Nn \@@_unitname_get:NnF { Nx } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_translate_one_and_check_existance:Nx } % As |#2| is already going to be expanded, using |\@@_translate_let:NnV| is safe. % \begin{macrocode} \cs_new:Npn \@@_translate_one_and_check_existance:Nn #1#2 { \@@_translate_let:NnV #1 {#2} \c_@@_postfix_gender_tl \@@_unitname_get:NxF #1 { one (#1) } { \@@_translate_let:NnV #1 {#2} \c_@@_postfix_gender_tl \msg_error:nnn { cooking-units } { Translation-not-available } { one (#1) } } } \cs_generate_variant:Nn \@@_translate_one_and_check_existance:Nn { Nx } % \end{macrocode} % \end{macro} % % \begin{macro}{ decimal-mark, one(m), one(f), one(n) } % Defining the translation for the decimal-mark. Note that those % 'phrases' are stored inside % \verb|\g_@@_allowed_special_keys_seq|. % Furthermore some translations are defined. % \begin{macrocode} \seq_gset_from_clist:Nn \g_@@_allowed_special_keys_seq { decimal-mark , one (m) , one (f) , one (n) } % \end{macrocode} % \end{macro} % \begin{macrocode} \@@_newtranslation_base:nVn { decimal-mark } \c_@@_postfix_unitname_tl { . } \@@_newtranslation_base:nVn { decimal-mark } \c_@@_postfix_unitname_pl_tl { \q_@@_no_translation } \@@_newtranslation_to:nnVn { German } { decimal-mark } \c_@@_postfix_unitname_tl { , } % \end{macrocode} % Note that the plural versions just exist for completing the set. % \begin{macrocode} \@@_newtranslation_base:nVn { one (m) } \c_@@_postfix_unitname_tl { \q_@@_no_translation } \@@_newtranslation_base:nVn { one (f) } \c_@@_postfix_unitname_tl { \q_@@_no_translation } \@@_newtranslation_base:nVn { one (n) } \c_@@_postfix_unitname_tl { \q_@@_no_translation } \@@_newtranslation_base:nVn { one (m) } \c_@@_postfix_unitname_pl_tl { \q_@@_no_translation } \@@_newtranslation_base:nVn { one (f) } \c_@@_postfix_unitname_pl_tl { \q_@@_no_translation } \@@_newtranslation_base:nVn { one (n) } \c_@@_postfix_unitname_pl_tl { \q_@@_no_translation } % \end{macrocode} % \begin{macrocode} \@@_newtranslation_to:nnVn { English } { one (m) } \c_@@_postfix_unitname_tl { one } \@@_newtranslation_to:nnVn { English } { one (f) } \c_@@_postfix_unitname_tl { one } \@@_newtranslation_to:nnVn { English } { one (n) } \c_@@_postfix_unitname_tl { one } % \end{macrocode} % \begin{macrocode} \@@_newtranslation_to:nnVn { German } { one (m) } \c_@@_postfix_unitname_tl { ein } \@@_newtranslation_to:nnVn { German } { one (f) } \c_@@_postfix_unitname_tl { eine } \@@_newtranslation_to:nnVn { German } { one (n) } \c_@@_postfix_unitname_tl { ein } % \end{macrocode} % % \begin{macrocode} \@@_newtranslation_base:nVn { cutext-range-sign } \c_@@_postfix_unitname_tl { -- } \@@_newtranslation_base:nVn { cutext-range-sign } \c_@@_postfix_unitname_pl_tl { \q_@@_no_translation } \@@_newtranslation_to:nnVn { German } { cutext-range-sign } \c_@@_postfix_unitname_tl { ~bis~ } \@@_newtranslation_to:nnVn { English } { cutext-range-sign } \c_@@_postfix_unitname_tl { ~to~ } % \end{macrocode} % % % \section{General} % % This section collects commands which are used by all four main commands % (\mycs{cunum}, \cCutext, \mycs{cuam}), hence the name. % % % \begin{macro}{\@@_initialise_default:n , % \@@_initialise_unit_change:n , % \@@_initialise_after_unit_change:nn % } % Functions shared by all initialization functions: % \begin{macrocode} \cs_new_protected:Npn \@@_initialise_default:n #1 { \@@_set_unit:Nn \l_@@_original_unit_tl {#1} \bool_set_false:N \l_@@_error_bool \@@_error_if_unit_not_defined:VTF \l_@@_original_unit_tl { \bool_set_true:N \l_@@_unit_error_bool \cs_set_eq:NN \@@_print_correct_unit: \@@_print_default_unit: } { \bool_set_false:N \l_@@_unit_error_bool } \bool_set_false:N \l_@@_special_sign_bool \bool_set_false:N \l_@@_range_in_input_bool \bool_set_false:N \l_@@_lokal_fraction_bool \bool_set_false:N \l_@@_minus_bool } % \end{macrocode} % Some units have options added to them. To get those options it is first % needed to know which unit will be used at all. Therefore units will % be changed first and afterwards the other options are processed. % % |\l_@@_convert_to_eV_bool| must be checked after processing the keys % as the option \opt{convert-to-eV} is set during this process. % \begin{macrocode} \cs_new_protected:Npn \@@_initialise_unit_change:n #1 { \tl_if_empty:nF {#1} { \keys_set_groups:nnn { cooking-units } { change-unit } {#1} } \bool_if:NT \l_@@_convert_to_eV_bool { \@@_convert_to_eV: } \prop_get:NVNF \l_@@_change_unit_prop \l_@@_original_unit_tl \l_@@_option_unit_tl { \tl_set_eq:NN \l_@@_option_unit_tl \l_@@_original_unit_tl } } % \end{macrocode} % \begin{macrocode} \cs_new_protected:Npn \@@_initialise_after_unit_change:nn #1#2 { \IfNoValueF {#1} { \@@_reference_label_and_persons:n {#1} } \clist_if_empty:cF { l_@@_unit_option_ \l_@@_option_unit_tl _clist } { \keys_set_filter:nnv { cooking-units } { change-unit } { l_@@_unit_option_ \l_@@_option_unit_tl _clist } } \tl_if_empty:nF {#2} { \keys_set_filter:nnn { cooking-units } { change-unit } {#2} } \bool_lazy_and:nnTF { \l_@@_calc_because_ref_was_given_bool } { \l_@@_change_number_of_persons_bool } { \bool_set_true:N \l_@@_lokal_persons_bool } { \bool_set_false:N \l_@@_lokal_persons_bool } \bool_set_eq:NN \l_@@_lokal_numeral_bool \l_@@_print_numeral_bool } % \end{macrocode} % \end{macro} % % % \begin{macro}{ \@@_print_input:N , \@@_print_correct_unit: , % \@@_post_process_input:NN , \@@_pre_process_input:NN} % Wrapper macro for printing the (not)calculated output. Note that if no % calculation happens in \mycs{cutext} (and \mycs{Cutext}) \cs{l_@@_option_unit_tl} % is set to \cs{l_@@_original_unit_tl} (the unit given in the second argument of % \mycs{cutext} or \mycs{Cutext}) by default. % \begin{macrocode} \cs_new_protected:Npn \@@_print_input:N #1 { } \cs_new_protected:Npn \@@_print_correct_unit: { } \cs_new_protected:Npn \@@_do_not_process_input:NN #1#2 { } \cs_new_eq:NN \@@_pre_process_input:NN \@@_do_not_process_input:NN \cs_new_eq:NN \@@_post_process_input:NN \@@_do_not_process_input:NN % \end{macrocode} % \end{macro} % % \begin{macro} { \@@_set_process_and_print_for_cunum: , % \@@_set_process_and_print_for_cutext: , % \@@_set_process_and_print_for_cuam: % } % It is handy to set the \enquote{print} and \enquote{process} % command all in one go. It's also less messy to use. % \begin{macrocode} \cs_new_protected:Npn \@@_set_process_and_print_for_cunum: { \cs_set_eq:NN \@@_print_input:N \@@_print_numerical_input:N \cs_set_eq:NN \@@_print_correct_unit: \@@_cunum_print_correct_unit: \cs_set_eq:NN \@@_pre_process_input:NN \@@_do_not_process_input:NN \cs_set_eq:NN \@@_post_process_input:NN \@@_do_not_process_input:NN } \cs_new_protected:Npn \@@_set_process_and_print_for_cutext: { \cs_set_eq:NN \@@_print_input:N \@@_cutext_print_input:N \cs_set_eq:NN \@@_print_correct_unit: \@@_cutext_print_correct_unitname: \cs_set_eq:NN \@@_pre_process_input:NN \@@_cutext_pre_process_input:NN \cs_set_eq:NN \@@_post_process_input:NN \@@_cutext_post_process_input:NN } \cs_new_protected:Npn \@@_set_process_and_print_for_cuam: { \cs_set_eq:NN \@@_print_input:N \@@_cuam_print_numerical_input:N \cs_set_eq:NN \@@_print_correct_unit: \@@_cuam_print_correct_unitphrase: \cs_set_eq:NN \@@_pre_process_input:NN \@@_do_not_process_input:NN \cs_set_eq:NN \@@_post_process_input:NN \@@_cuam_post_process_input:NN } % \end{macrocode} % \end{macro} % % % % % % \begin{macro}{ \@@_print_numerical_input:N } % Prints the numerical output (if it is not a fraction). % % Changed \lstinline|\l_@@_tmpa_tl| by |\l_@@_translation_tmpa_tl|, it's better that way. % \begin{macrocode} \cs_new_protected:Npn \@@_print_numerical_input:N #1 { \tl_if_in:NnT #1 { . } { \@@_translate_let:NnV \l_@@_translation_tmpa_tl { decimal-mark } \c_@@_postfix_unitname_tl \tl_replace_once:Nnn #1 { . } { \l_@@_translation_tmpa_tl } } \tl_replace_once:Nnn #1 { - } \c_@@_minus_tl #1 } % \end{macrocode} % \end{macro} % % % \begin{macro}{ \@@_print_fractions:Nnn } % The name of this function is the name of the game: It prints fractions. % The minus sign is always put in front of the fraction. % % The first argument regards the mixed fraction part. It is either empty % or not empty. If empty, do nothing. Else insert and add space. % % The 2nd and 3rd argument are the nominator and denominator, they are % used in the fraction command directly. % % All three arguments are currently tl varables, but only the first is a dedicated % \enquote{can only take one token}. % % Since v.1.10(alpha) it also prints the minus sign (hopefully correct). % \begin{macrocode} \cs_new:Npn \@@_print_fractions:Nnn #1#2#3 { \bool_if:NT \l_@@_minus_bool { \c_@@_minus_tl } \tl_if_empty:NF #1 { #1 \skip_horizontal:N \l_@@_mixed_frac_dim } \@@_frac:nn {#2} {#3} } % \end{macrocode} % \end{macro} % % % \begin{macro}{ \@@_print_ranges:NN } % \begin{macrocode} \cs_new:Npn \@@_print_ranges:NN #1#2 { \@@_print_input:N #1 \bool_if:NTF \l_@@_using_cutext_bool { % \tl_use:N \l_@@_cutext_range_sign_tl \tl_if_empty:NTF \l_@@_cutext_range_sign_tl { \@@_translate:nV { cutext-range-sign } \c_@@_postfix_unitname_tl } { \tl_use:N \l_@@_cutext_range_sign_tl } \bool_set_false:N \l_@@_cutext_uppercase_word_bool } { \tl_use:N \l_@@_cunum_range_sign_tl } \@@_print_input:N #2 } % \end{macrocode} % \end{macro} % % % % % % \subsection {Parsing and checking numbers} % % This subsection contains macros for splitting an checking the input. % % \begin{macro}{\@@_create_error:n, \@@_create_error_and_stop:n , \@@_create_error:nn } % \begin{macrocode} \cs_new:Npn \@@_create_error:n #1 { \bool_set_true:N \l_@@_error_bool \msg_error:nnV { cooking-units } {#1} \l_@@_original_amount_tl } \cs_new:Npn \@@_create_error_and_stop:n #1 { \bool_set_true:N \l_@@_error_bool \msg_error:nnV { cooking-units } {#1} \l_@@_original_amount_tl \use_none_delimit_by_q_nil:w } \cs_new:Npn \@@_create_error:nn #1#2 { \bool_set_true:N \l_@@_error_bool \msg_error:nnnV { cooking-units } {#1} {#2} \l_@@_original_amount_tl } % \end{macrocode} % \end{macro} % % The following command is needed after the parsing. It further processes % the parsed input and prints. The actual parsing and printing process (|\@@_process_tmp|) % depends on the command (|\cunum|, etc.) used. % \begin{macrocode} \cs_new:Npn \@@_process_tmp: { } \cs_new:Npn \@@_process_and_print_input: { \bool_lazy_or:nnTF { \l_@@_error_bool } { \l_@@_unit_error_bool } { \l_@@_original_amount_tl } { \@@_process_tmp: } } % \end{macrocode} % If there is an error or there is a special case (like \opt{42=true}) these commands % are used. % \begin{macrocode} \cs_new:Npn \@@_process_default: { \l_@@_original_amount_tl } \cs_new:Npn \@@_print_default_unit: { \tl_if_empty:NF \l_@@_phantom_tl { \phantom { \l_@@_phantom_tl } } \,\l_@@_original_unit_tl } % \end{macrocode} % % \begin{macro}{ \@@_parse_input:n } % Rescans the input to get rid of spaces and to make \_ and ? inactive % (french with babel makes |?| active and changes the definition of it). % \lstinline|--| is replaced by \lstinline|\q_@@_range| and the input is parsed % (if not empty). Afterwards the units are printed. % \begin{macrocode} \cs_new:Npn \@@_parse_input:n #1 { \@@_set_amount:Nn \l_@@_original_amount_tl {#1} \tl_set_rescan:NnV \l_@@_original_amount_tl { \char_set_catcode_letter:N \_ % \char_set_catcode_ignore:N \ % \char_set_catcode_other:N ? % } \l_@@_original_amount_tl \bool_lazy_any:nTF { { \l_@@_fourty_two_bool } { \l_@@_draft_bool } { \tl_if_empty_p:N \l_@@_original_amount_tl } }{ \cs_set_eq:NN \@@_process_tmp: \@@_process_default: \tl_if_empty:NT \l_@@_original_amount_tl { \msg_error:nnV { cooking-units } { empty-amount } \l_@@_original_amount_tl } \bool_if:NT \l_@@_fourty_two_bool { \tl_set:Nn \l_@@_original_amount_tl { 42 } } }{ \tl_set_eq:NN \l_@@_tmpa_tl \l_@@_original_amount_tl \@@_split_input:N \l_@@_tmpa_tl } } % \end{macrocode} % \end{macro} % % \begin{macro}{ \@@_split_input:N , \@@_process_and_print_input: , \@@_process_tmp: } % I would need to check for |/| and |_| anyway. So let's do it here % and use the booleans for error-checking. % \begin{macrocode} \cs_new:Npn \@@_split_input:N #1 { \tl_if_in:NVT #1 \l_@@_input_range_sign_tl { \tl_replace_once:NVn #1 \l_@@_input_range_sign_tl { \q_@@_range } \bool_set_true:N \l_@@_range_in_input_bool } \tl_if_in:NnT #1 { / } { \bool_set_true:N \l_@@_lokal_fraction_bool \bool_if:NT \l_@@_range_in_input_bool { \@@_create_error_and_stop:n { fraction-not-allowed-with-range } } } \@@_split:N #1 \use_none_delimit_by_q_nil:w \q_nil } % \end{macrocode} % \end{macro} % % \begin{macro}{ \@@_split_input:} % Splits the input into fractions or ranges. % Errors are already checked at this point. % \begin{macrocode} \cs_new:Npn \@@_split:N #1 { \bool_if:NTF \l_@@_lokal_fraction_bool { \@@_split_fraction:V } { \bool_if:NTF \l_@@_range_in_input_bool { \@@_split_range:V } { \@@_split_number:V } } #1 } % \end{macrocode} % \begin{macrocode} \cs_new:Npn \@@_split_number:n #1 { \cs_set_eq:NN \@@_process_tmp: \@@_process_number_in_input: \@@_parse_input_and_safe_in:nN {#1} \l_@@_number_tmpa_tl } % \end{macrocode} % \begin{macrocode} \cs_new:Npn \@@_split_range:n #1 { \cs_set_eq:NN \@@_process_tmp: \@@_process_range_in_input: \@@_split_range_aux:ww #1 \q_stop } \cs_new:Npn \@@_split_range_aux:ww #1 \q_@@_range #2 \q_stop { \@@_parse_input_and_safe_in:nN {#1} \l_@@_number_tmpa_tl \@@_parse_input_and_safe_in:nN {#2} \l_@@_number_tmpb_tl } % \end{macrocode} % \begin{macrocode} \cs_new:Npn \@@_split_fraction:n #1 { \cs_set_eq:NN \@@_process_tmp: \@@_process_generel_fraction_in_input: \@@_split_fraction_mixed:ww #1 \q_stop / \q_recursion_tail _ \q_nil \q_stop \q_recursion_stop % \end{macrocode} % At this point we have all information we need to determine whatever or not % the fractions should be evaluated or if the units should be changed. % \begin{macrocode} \bool_lazy_or:nnT { \l_@@_lokal_persons_bool }{ \l_@@_eval_fractions_bool } { \bool_set_false:N \l_@@_lokal_fraction_bool } \bool_if:NT \l_@@_convert_fractions_bool { \tl_if_eq:NNF \l_@@_original_unit_tl \l_@@_option_unit_tl { \bool_set_false:N \l_@@_lokal_fraction_bool } } } % \cs_new:Npn \@@_split_fraction_mixed:ww #1 _ #2 \q_stop { \quark_if_nil:nTF {#2} { \tl_clear:N \l_@@_mixed_fraction_tl \@@_split_fraction_frac:ww #1 \q_stop }{ \@@_parse_input_and_safe_in:nN {#1} \l_@@_mixed_fraction_tl \@@_split_fraction_frac:ww #2 \q_stop } } \cs_new:Npn \@@_split_fraction_frac:ww #1 / #2 \q_stop { \quark_if_recursion_tail_stop_do:nn {#2} { \@@_create_error:n { fraction-wrong-order } } \@@_parse_input_and_safe_in:nN {#1} \l_@@_number_tmpa_tl \@@_parse_input_and_safe_in:nN {#2} \l_@@_number_tmpb_tl \use_none_delimit_by_q_recursion_stop:w } % \end{macrocode} % \begin{macrocode} \cs_generate_variant:Nn \@@_split_number:n { V } \cs_generate_variant:Nn \@@_split_range:n { V } \cs_generate_variant:Nn \@@_split_fraction:n { V } % \end{macrocode} % \end{macro} % % \begin{macro}{ \@@_parse_input_and_safe_in:nN } % Used to check the input. \lstinline|\l_@@_tmpa_tl| is cleared % at the beginning. At first it checks if the first token % is a sign or not. The parsed input is stored into \lstinline|\l_@@_tmpa_tl|. % \begin{macrocode} \cs_new:Npn \@@_parse_input_and_safe_in:nN #1 #2 { \tl_clear:N \l_@@_tmpa_tl \bool_set_false:N \l_@@_check_decimal_bool \cs_set_eq:NN \@@_parse:N \@@_start_loop:N \tl_map_function:nN {#1} \@@_parse:N \bool_if:NTF \l_@@_error_bool { } { \tl_set_eq:NN #2 \l_@@_tmpa_tl } } % \end{macrocode} % \end{macro} % % \begin{macro}{ \@@_start_loop:Nw } % This function seperates the input into two parts with the first % part being the first token. This token is checked whetever or not % it is a sign. If it is a sign it is put into % \lstinline|\l_@@_tmpa_tl|, if not it is checked normally by % \lstinline|\@@_parse_input_loop_aux:N|. \#2 (the other % tokens) is then given to \lstinline|\tl_map_function:nN|. This % also works if the input only conists of one token with \#2 being % empty (hopefully). % \begin{macrocode} \cs_new:Npn \@@_start_loop:N #1 { \cs_set_eq:NN \@@_parse:N \@@_parse_input_loop_aux:N \tl_if_in:NnTF \l_@@_input_value_signs_tl {#1} { \tl_put_right:Nn \l_@@_tmpa_tl {#1} } { \tl_map_function:nN {#1} \@@_parse:N } } % \end{macrocode} % \end{macro} % % \begin{macro}{ \@@_parse_input_loop_aux:N } % Parses the input. It also is more or less (more less then more) copied from % \texttt{siunitx}. Checks if the input consists only of numbers, % one decimal-sign and the allowed special input. If an allowed % token is found the boolean \lstinline|\l_@@_special_sign_bool| is % set to true. % \begin{macrocode} \cs_new:Npn \@@_parse_input_loop_aux:N #1 { \tl_if_in:NnTF \l_@@_input_digits_tl {#1} { \tl_put_right:Nn \l_@@_tmpa_tl {#1} } { \tl_if_in:NnTF \l_@@_input_decimal_mark_tl {#1} { \@@_check_repitition:N \l_@@_check_decimal_bool \tl_put_right:Nn \l_@@_tmpa_tl { . } }{ \tl_if_in:NnTF \l_@@_input_allowed_special_signs_tl {#1} { \bool_set_true:N \l_@@_special_sign_bool \tl_put_right:Nn \l_@@_tmpa_tl {#1} }{ \bool_set_true:N \l_@@_error_bool \@@_check_error:n {#1} } } } } % \end{macrocode} % The idea behind this error checking is the following: % At this point I already split the input. This means, a fraction % is already split into nominator and denominator and as such, all allowed % |/| in the input are already removed. The same goes for |_| (an error message % for |_| without |/| would happen before parsing starts). Therefore % all |/| and |_| in the input \emph{must} (hopefully) be inside a second time. % \begin{macrocode} \cs_new:Npn \@@_check_error:n #1 { \tl_if_in:NnTF \l_@@_input_fraction_sign_tl {#1} { \@@_create_error:n { Second-fraction-sign-not-allowed } } { \tl_if_in:NnTF \l_@@_input_mixed_fraction_sign_tl {#1} { \bool_if:NTF \l_@@_lokal_fraction_bool { \@@_create_error:n { Second-mixed-fraction-sign-not-allowed } } { \@@_create_error:n { missing-slash } } } { \@@_create_error:nn { Token-not-allowed } {#1} } } } % \end{macrocode} % \begin{macrocode} \cs_new:Npn \@@_check_repitition:N #1 { \bool_if:NTF #1 { \@@_create_error:n { Second-decimal-sign-not-allowed } } { \bool_set_true:N #1 } } % \end{macrocode} % \end{macro} % % % \begin{macro}{\@@_process_number_in_input:} % If no fractions and ranges are used this macro activated. % It just checks the input, stores the checked (and a bit % changed) input into a macro. This macro is given to another % function to calculate the input and print it. % \begin{macrocode} \cs_new:Npn \@@_process_number_in_input: { \@@_process_and_print_number_in_input:N \l_@@_number_tmpa_tl } \cs_new:Npn \@@_process_and_print_number_in_input:N #1 { \@@_pre_process_input:NN #1 \q_no_value \@@_calculate_and_store_in:N #1 \@@_post_process_input:NN #1 \q_no_value \@@_print_input:N #1 } % \end{macrocode} % \end{macro} % % \begin{macro}{ \@@_process_range_in_input: } % Is used if a \lstinline|\q_@@_range| is found inside the input. % Seperates the input, checks it and prints it (after calculating % it). Furthermore a boolean is set to true, is used to check for % errors (ergo if fractions are used). % % Set |\l_@@_cutext_uppercase_word_bool| to false % so that the second numeral is not capitalized. % \begin{macrocode} \cs_new:Npn \@@_process_range_in_input: { \@@_pre_process_input:NN \l_@@_number_tmpa_tl \l_@@_number_tmpb_tl \@@_calculate_and_store_in:N \l_@@_number_tmpa_tl \@@_calculate_and_store_in:N \l_@@_number_tmpb_tl \@@_post_process_input:NN \l_@@_number_tmpa_tl \l_@@_number_tmpb_tl \@@_print_ranges:NN \l_@@_number_tmpa_tl \l_@@_number_tmpb_tl } % \end{macrocode} % \end{macro} % % \begin{macro}{ \@@_process_generel_fraction_in_input: } % This function prints both mixed and normal fractions. Those was done % by two functions beforehand, but they shared mostly the same code, so I % managed to fuse them. % % The first part removes the minus sign. It cycles through the variables % (|\l_@@_mixed_fraction_tl| can be emtpy) and removes the minus signs. % It furthermore saves how many minuses are used by reversing a bool. % If a minus sign is found, the bool is reversed to true (from false). Another % minus: minus and minus is plus, reverse bool again (to false this time), etc. % % Afterwards: Is a fraciton printed, or is the input evaluated. Printing is % straight forward. % % Due to how mixed fractions are evaluated, one can just evaluate the % absolute values of the inputs and add a minus sign on the left side afterwards % (if necessary). % \begin{align} % \cuam{1_2/3} &= 1 + 2/3 \\ % \cuam{-1_2/3} &= -1 - 2/3 = - ( 1 + 2/3 ) % \end{align} % % If |\l_@@_mixed_fraction_tl| is empty the calculation just evaluates to % |+\l_@@_number_tmpa_tl / \l_@@_number_tmpb_tl|, which is also valid. % % \begin{macrocode} \cs_new:Npn \@@_process_generel_fraction_in_input: { \@@_check_minus_remove_and_reverse:NN \l_@@_mixed_fraction_tl \l_@@_number_tmpa_tl \l_@@_number_tmpb_tl \q_nil \bool_lazy_or:nnTF { \l_@@_lokal_fraction_bool } { \l_@@_special_sign_bool } { \bool_if:NT \l_@@_special_sign_bool { \msg_warning:nnV { cooking-units } { amount-not-known } \l_@@_original_amount_tl } \@@_print_fractions:Nnn \l_@@_mixed_fraction_tl { \l_@@_number_tmpa_tl } { \l_@@_number_tmpb_tl } }{ \fp_compare:nNnT { \l_@@_number_tmpb_tl } = { 0 } { \msg_error:nnV { cooking-units } { Division-by-zero } \l_@@_original_amount_tl } \@@_tl_eval:Nn \l_@@_number_tmpa_tl { \l_@@_mixed_fraction_tl + \l_@@_number_tmpa_tl / \l_@@_number_tmpb_tl } \bool_if:NT \l_@@_minus_bool { \tl_put_left:Nn \l_@@_number_tmpa_tl { - } } \@@_process_and_print_number_in_input:N \l_@@_number_tmpa_tl } } % \end{macrocode} % \end{macro} % % % % % % % \subsection {Formatiere \& Calculiere} % % \begin{macro}{ \@@_calculate_and_store_in:N } % % \changes {v0.98a} {2016/06/11} {Added warning to show if an unknown value is used.} % % After parsing the input, it is given to this function. If a not % allowed token is found (and \lstinline|\l_@@_error_bool| is set to % true) it just prints the input. Otherwise it checks if a allowed sign was % found. If so it is just stored inside \lstinline|\l_@@_tmpa_tl|, % otherwise it is calulcated and stored in \lstinline|\l_@@_tmpa_tl|. The input % \#1 can be either a token or a number. % \begin{macrocode} \cs_new:Npn \@@_calculate_and_store_in:N #1 { \bool_if:NTF \l_@@_special_sign_bool { \msg_warning:nnV { cooking-units } { amount-not-known } #1 }{ \bool_lazy_and:nnTF { \l_@@_using_cutext_bool } { \l_@@_cutext_keep_unit_bool } { \tl_set_eq:NN \l_@@_tmpa_tl #1 } { \@@_calculate_input_and_store_in:nN {#1} \l_@@_tmpa_tl } \@@_calc_references:NN \l_@@_tmpa_tl \l_@@_tmpa_tl \@@_round_calculated_input:NV \l_@@_tmpa_tl \l_@@_tmpa_tl \@@_check_temperature_limit:N \l_@@_tmpa_tl \tl_set_eq:NN #1 \l_@@_tmpa_tl } } % \end{macrocode} % \end{macro} % % \begin{macro}{ \@@_calculate_input_and_store_in:nN } % Well \dots\ this function calculates the input. First checks if the % wanted conversion contains a \lstinline|\l_@@_tmpa_fp| (ergo a \#1 in % the key definition). If true the conversion token (which already has % \lstinline|\l_@@_tmpa_fp| in its input) is executed, else the input % number is multiplicated with the conversion token. % \begin{macrocode} \cs_new:Npn \@@_calculate_input_and_store_in:nN #1#2 { \fp_set:Nn \l_@@_tmpa_fp {#1} \tl_if_in:cnTF { l_@@_unit_change_ \l_@@_original_unit_tl _tl } { \l_@@_tmpa_fp } { \@@_tl_eval:Nv #2 { l_@@_unit_change_ \l_@@_original_unit_tl _tl } }{ \@@_tl_eval:Nn #2 { \l_@@_tmpa_fp * \tl_use:c { l_@@_unit_change_ \l_@@_original_unit_tl _tl } } } } % \end{macrocode} % \end{macro} % % \begin{macro}{ \@@_calc_references:NN,\@@_calc_references_aux:NN } % As comparing integers is faster then checking if something is inside % the sequence, first (after the boolean) check if there needs to be a calculation % at all. % \begin{macrocode} \cs_new:Npn \@@_calc_references:NN #1#2 { \bool_if:NT \l_@@_lokal_persons_bool { \int_compare:nNnF { \l_@@_wanted_number_of_persons_int } = { \l_@@_local_number_of_persons_int } { \tl_set_eq:NN \l_@@_tmpb_tl \l_@@_original_unit_tl \seq_if_in:NVTF \l_@@_curef_do_not_change_seq \l_@@_tmpb_tl { \msg_error:nnV { cooking-units } { curef-forbidden-unit } \l_@@_tmpb_tl } { \@@_calc_references_aux:NN #1 #2 } } } } % \end{macrocode} % I hope that by putting |#2| to the front of the calculation, it will increase the % precision of the calculation (not that it is necessary). I don't really know if this % makes sense, but \dots\ eh. % \begin{macrocode} \cs_new:Npn \@@_calc_references_aux:NN #1#2 { \@@_tl_eval:Nn #1 { #2 * \l_@@_wanted_number_of_persons_int / \l_@@_local_number_of_persons_int } } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_check_number_for_rounding:n,\@@_check_number_after_dot_aux:ww} % Check if rounding is needed. The auxilary function splits the number into % the integer and non-integer part ($12.45$ to $12$ and $45$). % % If the non-integer part exists its number of digits $n$ are counted checked % if it is smaller then $a$, which depends on |\l_@@_round_to_int_bool|. % % \begin{macrocode} \cs_new:Npn \@@_check_number_for_rounding:n #1 { \bool_set_false:N \l_@@_round_number_bool \@@_check_number_after_dot_aux:ww #1 . \q_recursion_tail . \q_recursion_stop } \cs_new:Npn \@@_check_number_after_dot_aux:ww #1 . #2 . { \quark_if_recursion_tail_stop_do:nn {#2} { \bool_if:NT \l_@@_round_precision_negative_bool { \bool_set_true:N \l_@@_round_number_bool } } \int_compare:nNnT { \tl_count:n {#2} } > { \l_@@_round_precision_int } { \bool_set_true:N \l_@@_round_number_bool } \use_none_delimit_by_q_recursion_stop:w } % \end{macrocode} % \end{macro} % % \begin{macro}{ \@@_round_calculated_input:Nn,\@@_round_calculated_input:NV } % After calculating the numbers are rounded (if needed, safed inside \cs{l_tmpa_bool}). % We test at first if % the input needs to be rounded by comparing the number of tokens after the % decimal with the round precision. Afterwards the % input is expanded and stored in \#1. If rounding needs to be done it happens now. % \begin{macrocode} \cs_new:Npn \@@_round_calculated_input:Nn #1#2 { \@@_check_number_for_rounding:n {#2} \bool_if:NTF \l_@@_round_number_bool { \@@_tl_eval:Nn #1 { round ( \@@_rounding_function:n {#2} ) } } { \tl_set:Nn #1 {#2} } } \cs_generate_variant:Nn \@@_round_calculated_input:Nn { NV } % \end{macrocode} % \end{macro} % % % % % % % % % \begin{macro}{\@@_check_temperature_limit:N} % If \lstinline|check_temperature_bool| is set to true it now checks % if the value is below the absolute temperature. \lstinline|\clist_if_in:nVT| % is needed due to \myunit{Re}, a \lstinline|\tl_if_in:nVT| would also check for \myunit{R} % and \myunit{e} instead of only \myunit{Re}. % \begin{macrocode} \cs_new:Npn \@@_check_temperature_limit:N #1 { \bool_if:NT \l_@@_check_temperature_bool { \seq_if_in:NVT \l_@@_temperatures_to_check_seq \l_@@_option_unit_tl { \fp_compare:vNnT { l_@@_ \l_@@_option_unit_tl _min_fp } > {#1} { \msg_error:nnxx { cooking-units } { Temperature-too-low } { #1 \space \l_@@_option_unit_tl } { \fp_use:c { l_@@_ \l_@@_option_unit_tl _min_fp } \space \l_@@_option_unit_tl } } } } } % \end{macrocode} % \end{macro} % % % % % % % % % % % % % \begin{macrocode} \cs_new_nopar:Npn \@@_grab_arrows_for_safety_do_afterwards:nN #1#2 { \str_if_eq:nnTF {#2} { > } { \tl_put_right:Nx \l_@@_tmpa_tl { \tl_to_str:N > } \exp_last_unbraced:NV #1 \l_@@_tmpa_tl }{ \tl_put_right:Nn \l_@@_tmpa_tl {#2} \@@_grab_arrows_for_safety_do_afterwards:nN {#1} } } \cs_new_nopar:Npn \@@_if_arrow_grab_until_close_do:nnTF #1#2#3#4 { \str_if_eq:nnTF {#1} { < } { \tl_if_in:NoT \l_@@_input_allowed_special_signs_tl { < } { \msg_error:nn { cooking-units } { <-not-allowed-as-special-sign } } \tl_clear:N \l_@@_tmpa_tl \tl_put_right:Nx \l_@@_tmpa_tl { \tl_to_str:N < } \@@_grab_arrows_for_safety_do_afterwards:nN {#3} #2 } {#4} } % \end{macrocode} % % % % \subsection {\mycs{cunum}} % % % \begin{macro}{ \cunum } % The main command of this package. % \begin{macrocode} \NewDocumentCommand \cunum { d<> O{} m O{} m } { \@@_if_arrow_grab_until_close_do:nnTF {#3} {#5} { \cunum } { \group_begin: \@@_cunum:nnnnn {#1} {#2} {#3} {#4} {#5} \group_end: } } % \end{macrocode} % \end{macro} % % % \begin{macro}{ \@@_cunum:nnnnn } % \begin{macrocode} \cs_new:Npn \@@_cunum:nnnnn #1#2#3#4#5 { \@@_cunum_initialise:nnnnn {#1} {#2} {#3} {#4} {#5} \l_@@_cunum_hook_tl \@@_parse_input:n {#3} \@@_process_and_print_input: \@@_print_correct_unit: } % \end{macrocode} % \end{macro} % % % \begin{macro}{ \@@_cunum_initialise:nnnn } % Lots of things to do in this function. It checks if the unit is defined or not, % sets the keys for converting the unit and sets the optional unit (the unit % our input is converted to) accordingly, sets the options again (to get the % option-specific options) and \dots\ yeah. % % First parses the change of unit ('set groups'), afterwards set % the predefined options for the new unit. Afterwards % set the 'normal' options given by the optional argument. % % \begin{macrocode} \cs_new_protected:Npn \@@_cunum_initialise:nnnnn #1#2#3#4#5 { \@@_set_process_and_print_for_cunum: \tl_set:Nn \l_@@_phantom_tl {#4} \@@_initialise_default:n {#5} \@@_initialise_unit_change:n {#2} \@@_initialise_after_unit_change:nn {#1} {#2} } % \end{macrocode} % \end{macro} % % % % % \begin{macro}{ \@@_cunum_print_correct_unit: } % The invisible space is added by a \lstinline|\phantom|, afterwards % \lstinline|value_unit_space_tl| is used (which is set to % \lstinline|\thinspace| by default) and if either special signs or % fractions are parsed the input-unit is printed else the converted % unit is. % \begin{macrocode} \cs_new:Npn \@@_cunum_print_correct_unit: { \tl_if_empty:NF \l_@@_phantom_tl { \phantom { \l_@@_phantom_tl } } \tl_use:N \l_@@_value_unit_space_tl \@@_change_unit:TF { \@@_translate:VV \l_@@_option_unit_tl \c_@@_postfix_unit_tl } { \@@_translate:VV \l_@@_original_unit_tl \c_@@_postfix_unit_tl } } % \end{macrocode} % \end{macro} % % % \section { cutext \& Cutext } % % % A better implemantation of \opt{cutext-to-cunum}, but % sufficient for now. % \begin{macrocode} \NewDocumentCommand \cutext { d<> O{} m m } { \@@_if_arrow_grab_until_close_do:nnTF {#3} {#4} { \cutext } { \group_begin: \@@_change_cutext_to_cunum:nTF {#2} { \@@_cunum:nnnnn {#1} {#2} {#3} { } {#4} } { \bool_set_false:N \l_@@_cutext_uppercase_word_bool \@@_cutext:nnnn {#1} {#2} {#3} {#4} } \group_end: } } % \end{macrocode} % % \begin{macrocode} \NewDocumentCommand \Cutext { d<> O{} m m } { \@@_if_arrow_grab_until_close_do:nnTF {#3} {#4} { \Cutext } { \group_begin: \@@_change_cutext_to_cunum:nTF {#2} { \@@_cunum:nnnnn {#1} {#2} {#3} { } {#4} } { \bool_set_true:N \l_@@_cutext_uppercase_word_bool \@@_cutext:nnnn {#1} {#2} {#3} {#4} } \group_end: } } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \@@_cutext_initialise:nnn #1#2#3 { \bool_set_true:N \l_@@_using_cutext_bool \@@_set_process_and_print_for_cutext: \@@_initialise_default:n {#3} \@@_initialise_unit_change:n {#2} \bool_if:NT \l_@@_cutext_keep_unit_bool { \tl_set_eq:NN \l_@@_option_unit_tl \l_@@_original_unit_tl } \@@_initialise_after_unit_change:nn {#1} {#2} \bool_if:NT \l_@@_fourty_two_bool { \tl_set:Nn \l_@@_cutext_last_value_tl { 42 } } } % \end{macrocode} % %^^A #1: label, #2: Options, #3: Values, #4: unit % \begin{macrocode} \cs_new:Npn \@@_cutext:nnnn #1#2#3#4 { \@@_cutext_initialise:nnn {#1} {#2} {#4} \bool_if:NTF \l_@@_cutext_uppercase_word_bool { \l_@@_Cutext_hook_tl } { \l_@@_cutext_hook_tl } \bool_if:NTF \l_@@_cutext_old_bool { \@@_old_cutext:nnn {#2} {#3} {#4} } { \@@_parse_input:n {#3} \@@_process_and_print_input: } \@@_print_correct_unit: } % \end{macrocode} % % % % \begin{macro} {\@@_cutext_print_input:Nn , \@@_cutext_print_input:NV} % \changes {2016/06/11} {0.99} {New.} % % % \begin{macrocode} \cs_new_protected:Npn \@@_cutext_print_input:Nn #1#2 { \bool_if:NTF \l_@@_lokal_numeral_bool { \@@_int_if_equal_one:nTF {#1} { \@@_translate_one_and_check_existance:Nx \l_@@_translation_tmpa_tl {#2} \bool_if:NTF \l_@@_cutext_uppercase_word_bool { \exp_args:Nx \tl_upper_case:n { \tl_head:V \l_@@_translation_tmpa_tl } \tl_tail:V \l_@@_translation_tmpa_tl } { \l_@@_translation_tmpa_tl } }{ \bool_if:NTF \l_@@_cutext_uppercase_word_bool { \@@_print_Numeral:n {#1} } { \@@_print_numeral:n {#1} } } } { \@@_print_numerical_input:N #1 } } \cs_generate_variant:Nn \@@_cutext_print_input:Nn { NV } \cs_new_protected:Npn \@@_cutext_print_input:N #1 { \@@_change_unit:TF { \@@_cutext_print_input:NV #1 \l_@@_option_unit_tl } { \@@_cutext_print_input:NV #1 \l_@@_original_unit_tl } } % \end{macrocode} % \end{macro} % % \begin{macrocode} \cs_new:Npn \@@_cutext_print_correct_unitname: { \l_@@_cutext_space_tl \@@_change_unit:TF { \@@_fp_if_equal_one:nTF { \l_@@_cutext_last_value_tl } { \@@_translate:VV \l_@@_option_unit_tl \c_@@_postfix_unitname_tl } { \@@_translate:VV \l_@@_option_unit_tl \c_@@_postfix_unitname_pl_tl } } { \@@_translate:VV \l_@@_original_unit_tl \c_@@_postfix_unitname_pl_tl } } % \end{macrocode} % % \begin{macrocode} \cs_new:Npn \@@_cutext_pre_process_input:NN #1#2 { \@@_change_unit:TF { \tl_set_eq:NN \l_@@_tmpb_tl \l_@@_option_unit_tl } { \tl_set_eq:NN \l_@@_tmpb_tl \l_@@_original_unit_tl } \@@_unitname_get:NxF \l_@@_tmpa_tl \l_@@_tmpb_tl { \msg_warning:nnx { cooking-units } { cutext-no-translation-available } \l_@@_tmpb_tl \bool_set_false:N \l_@@_using_cutext_bool \@@_set_process_and_print_for_cunum: } } % \end{macrocode} % % % % \begin{macrocode} \cs_new:Npn \@@_cutext_post_process_input:NN #1#2 { \bool_if:NF \l_@@_special_sign_bool { \@@_cutext_post_process_input_aux:NN #1#2 } } % \end{macrocode} % \begin{macrocode} \cs_new:Npn \@@_cutext_post_process_input_aux:NN #1#2 { \bool_if:NTF \l_@@_range_in_input_bool { \tl_set_eq:NN \l_@@_cutext_last_value_tl #2 } { \tl_set_eq:NN \l_@@_cutext_last_value_tl #1 } \bool_if:NT \l_@@_lokal_numeral_bool { \@@_cutext_post_process_input_numerals:NN #1#2 } } \cs_new:Npn \@@_cutext_post_process_input_numerals:NN #1#2 { \@@_bool_set_if_integers:NNN \l_@@_tmpa_bool #1 #2 \bool_if:NTF \l_@@_tmpa_bool { \bool_if:NTF \l_@@_range_in_input_bool { \bool_lazy_and:nnF { \int_compare_p:nNn {#1} < { \l_@@_print_numerals_below_int } } { \int_compare_p:nNn {#2} < { \l_@@_print_numerals_below_int } } { \bool_set_false:N \l_@@_lokal_numeral_bool } }{ \int_compare:nNnF {#1} < { \l_@@_print_numerals_below_int } { \bool_set_false:N \l_@@_lokal_numeral_bool } } } { \bool_set_false:N \l_@@_lokal_numeral_bool } } % \end{macrocode} % % % % % % % % % % \section{cuam} % % \begin{macrocode} \tl_const:Nn \c_@@_cuam_marker_tl { @@_cunum } \tl_new:c { l_@@_unit_change_ \c_@@_cuam_marker_tl _tl } \tl_set:cn { l_@@_unit_change_ \c_@@_cuam_marker_tl _tl } { 1.0 } \clist_new:c { l_@@_unit_option_ \c_@@_cuam_marker_tl _clist } % \end{macrocode} % % Replaces and extends \mycs{cufrac}. % \begin{macro}{\cuam} % \begin{macrocode} \NewDocumentCommand \cuam { d<> O{} m } { \@@_if_arrow_grab_until_close_do:nnTF {#3} { } { \cuam } { \group_begin: \@@_cuam:nnn {#1} {#2} {#3} \group_end: } } % \end{macrocode} % \end{macro} % % \begin{macrocode} \cs_new:Npn \@@_cuam:nnn #1#2#3 { \@@_cuam_initialise:nn {#1} {#2} \l_@@_cuam_hook_tl \bool_if:NTF \l_@@_cuam_old_bool { \@@_cuam_old:n {#3} } { \@@_parse_input:n {#3} \@@_process_and_print_input: \@@_print_correct_unit: } } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \@@_cuam_initialise:nn #1#2 { \@@_set_process_and_print_for_cuam: \tl_set_eq:NN \l_@@_original_unit_tl \c_@@_cuam_marker_tl \tl_set_eq:NN \l_@@_option_unit_tl \c_@@_cuam_marker_tl \bool_set_false:N \l_@@_lokal_phrase_bool \@@_initialise_after_unit_change:nn {#1} {#2} } % \end{macrocode} % % Important thing is: This whole process must not acticate if a % special sign is in the input. This is due to mathematical comparisons. % \begin{macrocode} \cs_new_protected:Npn \@@_cuam_post_process_input:NN #1#2 { \bool_if:NF \l_@@_special_sign_bool { \@@_cuam_post_process_input_aux:NN #1 #2 } } % \end{macrocode} % % Just a helper macro to tidy up the main macro. The first thing to % do is to check if the nummerical input consits of integers. This % is done both both numerical values (if a range exists). % Afterwards check if phrases are used and can be used at all. This needs % to be done before the numeral check as it can change the input. % \begin{macrocode} \cs_new:Npn \@@_cuam_post_process_input_aux:NN #1#2 { \@@_bool_set_if_integers:NNN \l_@@_tmpa_bool #1 #2 \bool_lazy_and:nnT { \l_@@_use_phrases_bool } { \l_@@_tmpa_bool } { \@@_cuam_post_process_input_phrases:NN #1#2 } \bool_if:NT \l_@@_lokal_numeral_bool { \@@_cuam_post_process_input_numerals:NN #1#2 } } % \end{macrocode} % % This command is more or less straightforward. Does a list of phrases exist % for the current language? If yes, parse the input and check if phrases are used. % It is important for ranges to check both values and then decide if phrases % are used or not. % \begin{macrocode} \cs_new:Npn \@@_cuam_post_process_input_phrases:NN #1#2 { \@@_get_phrase_for_current_langauge:NNT \l_@@_phrase_prop \l_@@_phrase_numbers_seq { \@@_cuam_post_process_input_phrases_aux:NNN #1 \l_@@_tmpa_int \l_@@_phrase_number_tl \bool_if:NT \l_@@_lokal_phrase_bool { \bool_if:NTF \l_@@_range_in_input_bool { \bool_if:NF \l_@@_phrase_negative_bool { \@@_cuam_post_process_input_phrases_range:NN #2 \l_@@_tmpb_int \bool_if:NT \l_@@_lokal_phrase_bool { \tl_set:NV #1 \l_@@_tmpa_int \tl_set:NV #2 \l_@@_tmpb_int \@@_cuam_get_phrase_name:NVN \l_@@_phrase_phrase_tl \l_@@_phrase_number_tl \l_@@_tmpb_int } } }{ \tl_set:NV #1 \l_@@_tmpa_int \@@_cuam_get_phrase_name:NVN \l_@@_phrase_phrase_tl \l_@@_phrase_number_tl \l_@@_tmpa_int } } } } % \end{macrocode} % \begin{macrocode} \cs_new:Npn \@@_cuam_post_process_input_phrases_aux:NNN #1#2#3 { \bool_set_false:N \l_@@_lokal_phrase_bool \seq_map_inline:Nn \l_@@_phrase_numbers_seq { \int_compare:nNnF { \int_abs:n {##1} } > {#1} { \int_compare:nNnTF {##1} < { 0 } { \bool_set_true:N \l_@@_phrase_negative_bool \int_set:Nn \l_tmpa_int { 1 } } { \int_set:Nn \l_tmpa_int { \int_div_truncate:nn {#1} {##1} } } \int_compare:nNnT { \int_abs:n {##1} * \l_tmpa_int } = {#1} { \int_set_eq:NN #2 \l_tmpa_int \tl_set:Nn #3 {##1} \bool_set_true:N \l_@@_lokal_phrase_bool \seq_map_break: } } } } \cs_new:Npn \@@_cuam_post_process_input_phrases_range:NN #1#2 { \int_set:Nn \l_tmpa_int { \int_div_truncate:nn {#1} { \l_@@_phrase_number_tl } } \int_compare:nNnTF { \l_@@_phrase_number_tl * \l_tmpa_int } = {#1} { \int_set_eq:NN #2 \l_tmpa_int \bool_set_true:N \l_@@_lokal_phrase_bool }{ \bool_set_false:N \l_@@_lokal_phrase_bool } } \cs_new:Npn \@@_cuam_get_phrase_name:NnN #1#2#3 { \@@_int_if_equal_one:nTF {#3} { \prop_get:NnN \l_@@_phrase_prop {#2} #1 } { \prop_get:NnN \l_@@_phrase_prop { #2-pl } #1 } } \cs_generate_variant:Nn \@@_cuam_get_phrase_name:NnN { NVN } % \end{macrocode} % % % Processing numerals. This function only happens if numerals are used % and because numerals have to be integers I can set the numeral boolean % false if there is no integer. % % Furthermore, due to knowing that we have integers we can use % |\int_compare_p:nNn| instead of the |fp|-equivalent. % \begin{macrocode} \cs_new:Npn \@@_cuam_post_process_input_numerals:NN #1#2 { \bool_if:NTF \l_@@_tmpa_bool { \bool_if:NTF \l_@@_range_in_input_bool { \bool_lazy_and:nnF { \int_compare_p:nNn {#1} < { \l_@@_print_numerals_below_int } } { \int_compare_p:nNn {#2} < { \l_@@_print_numerals_below_int } } { \bool_set_false:N \l_@@_lokal_numeral_bool } }{ \int_compare:nNnF {#1} < { \l_@@_print_numerals_below_int } { \bool_set_false:N \l_@@_lokal_numeral_bool } } } { \bool_set_false:N \l_@@_lokal_numeral_bool } } % \end{macrocode} % % % Note: This command checks if \emph{both} a phrase and a numeral is % used to decide whetever or not to print numerals. This is due to % the $1$ being dependent (in some languages) depending on the gender % of the following word. Currently testing only |\l_@@_lokal_numeral_bool| doesn't % work due to the $1$ having a special parsing. % \begin{macrocode} \cs_new_protected:Npn \@@_cuam_print_numerical_input:N #1 { \bool_lazy_and:nnTF { \l_@@_lokal_phrase_bool } { \l_@@_lokal_numeral_bool } { \@@_int_if_equal_one:nTF {#1} { \@@_translate_one_and_check_existance:Nx \l_@@_translation_tmpa_tl { \l_@@_phrase_number_tl -phrase-gender } \l_@@_translation_tmpa_tl } { \exp_args:NV \@@_print_numeral:n #1 } }{ \@@_print_numerical_input:N #1 } } % \end{macrocode} % % \begin{macrocode} \cs_new:Npn \@@_cuam_print_correct_unitphrase: { \bool_if:NT \l_@@_lokal_phrase_bool { \l_@@_cuphrase_space_tl \l_@@_phrase_phrase_tl } } % \end{macrocode} % % % % % % % \section {cukeys} % % \subsection {Define Keys} % % \begin{macro}{ \cudefinekeys } % Defining keys. % \begin{macrocode} \NewDocumentCommand \cudefinekeys { m m } { \bool_set_false:N \l_@@_single_key_bool \@@_cukeys_define_keys_and_single_keys:nn {#1} {#2} } % \end{macrocode} % \end{macro} % % \begin{macro}{ \cudefinesinglekey } % Again, but with the boolean set to true. % \begin{macrocode} \NewDocumentCommand \cudefinesinglekey { m m } { \bool_set_true:N \l_@@_single_key_bool \@@_cukeys_define_keys_and_single_keys:nn {#1} {#2} } % \end{macrocode} % \end{macro} % % \begin{macro}{ \@@_cukeys_define_keys_and_single_keys:nn } % First checks whetever the unit is defined or not, then clears some macros % which are needed later. Further procession depends on the boolean. % If more than one key is created, the value \lstinline|\l_@@_tmpa_fp| is set to one. % This is important for adding keys where \lstinline|\l_@@_tmpa_fp| is changed accordingly. % \begin{macrocode} \cs_new:Npn \@@_cukeys_define_keys_and_single_keys:nn #1#2 { \@@_error_if_unit_not_defined:nTF {#1} { \bool_set_true:N } { \bool_set_false:N } \l_@@_unit_error_bool \tl_if_blank:nF {#2} { \prop_gclear:N \g_@@_master_changer_prop \prop_gclear:N \g_@@_convert_to_eV_remember_prop \seq_clear:N \l_@@_tmpa_seq \prop_clear:N \l_@@_tmpa_prop \prop_clear_new:c { l_@@_cukeys_ #1 _prop } \bool_if:NTF \l_@@_single_key_bool { \@@_cukeys_parse_and_create_single_key:nn {#1} {#2} }{ \fp_set:Nn \l_@@_tmpa_fp { 1.0 } \tl_set:Nn \l_@@_original_unit_tl {#1} \@@_cukeys_parse_and_create_keys:nn {#1} { {#1} { 1.0 } #2 } } } } % \end{macrocode} % \end{macro} % % \begin{macro}{ \@@_cukeys_parse_and_create_keys:nn } % A simple parsing function using quarks (which are pretty handy). % At first parses the input, then creates the property lists for each key % (containing all the values) and at last defines the keys. % \begin{macrocode} \cs_new:Npn \@@_cukeys_parse_and_create_keys:nn #1#2 { \@@_cukeys_parse_input:nn #2 \q_recursion_tail \q_recursion_tail \q_recursion_stop \bool_if:NF \l_@@_unit_error_bool { \@@_cukeys_create_key_prop:n {#1} \clist_set_from_seq:NN \l_@@_tmpa_clist \l_@@_tmpa_seq \@@_cukeys_define_keys:V \l_@@_tmpa_clist } } \cs_generate_variant:Nn \@@_cukeys_parse_and_create_keys:nn { Vn } % \end{macrocode} % \end{macro} % % \begin{macro}{ \@@_cukeys_parse_input:nn } % Yeah \dots\ \lstinline|\l_@@_tmpa_clist| stores all the used unit-keys, while % the property list saves the relation to each other. This cycle is repeated until an % recursion tail is found. If you define a new key, \verb|\l_@@_tmpa_fp| is set to % 1 and changed later if a new key is added. % \begin{macrocode} \cs_new:Npn \@@_cukeys_parse_input:nn #1#2 { \quark_if_recursion_tail_stop:n {#1} \quark_if_recursion_tail_stop_do:nn {#2} { \msg_error:nn { cooking-units } { missing-argument } } \@@_error_if_unit_not_defined:nF {#1} { \seq_if_in:NnF \l_@@_tmpa_seq {#1} { \seq_put_right:Nn \l_@@_tmpa_seq {#1} } \prop_put:Nnx \l_@@_tmpa_prop {#1} { \fp_eval:n { (#2) * \l_@@_tmpa_fp } } } \@@_cukeys_parse_input:nn } % \end{macrocode} % \end{macro} % % \begin{macro}{ \@@_cukeys_create_key_prop:n } % % \changes {2016/09/22} {1.02f} {Save 'Liste', 'prop' and 'Erstes Ding' to \cs{l_tmpb_prop} and set the unit-prop lists equal to \cs{l_tmpb_prop}.} % \changes {2016/09/22} {1.02g} {Do not need \cs{tl_clear_new:c} as token list is already defined.} % % All linked unit-keys are stored within \lstinline|\l_@@_tmpa_clist| and are mapped % one after another. At first a property list is created (or cleared), this property list % stores the units linked to this unit, saves the created property list which contains the % numerical relation of each unit. \lstinline|Erstes Ding| (firsth thing) stores % the first unit used for defining the keys, it is needed later for adding keys. % % For each unit the other units are added in the cleared or newly created property list % as keys with their value being the correct numerical relation. For example: % % \begin{align*} % \SI{1}{\kg}&= \SI{1}{\kg} \\ % \SI{1}{\kg}&= \SI{100}{\deka\gram} \\ % \SI{1}{\kg}&= \SI{1000}{\g} \\ % \SI{1}{\kg}&= \SI{35.27399}{oz} % \end{align*} % % Therefore the property list for \lstinline|kg| contains the keys and values: % \myunit{kg}=\myunit{1} % \myunit{dag}=\myunit{100}, \myunit{g}=\myunit{1000} and \myunit{oz}= \myunit{35.27399}. % % For the next unit (\myunit{dag} in this case) a new property list is created, relation above % stored inside etc. The condition now is that \myunit{dag}=\texttt{1}, therefore every number % is divided the the number \texttt{100}: % % \begin{align*} % \SI{1}{\deka\gram}&= \SI{0.01}{\kg} \\ % \SI{1}{\deka\gram}&= \SI{1}{\deka\gram} \\ % \SI{1}{\deka\gram}&= \SI{10}{\g} \\ % \SI{1}{\deka\gram}&= \SI{0.3527399}{\oz} % \end{align*} % % Same for \myunit{g}: % % \begin{align*} % \SI{1}{\g}&= \SI{0.001}{\kg} \\ % \SI{1}{\g}&= \SI{0.1}{\deka\gram} \\ % \SI{1}{\g}&= \SI{1}{\g} \\ % \SI{1}{\g}&= \SI{0.03527399}{oz} % \end{align*} % % and \myunit{oz} % % \begin{align*} % \SI{1}{oz}&= \SI{0.0283495}{\kg} \\ % \SI{1}{oz}&= \SI{2.83495}{\deka\gram} \\ % \SI{1}{oz}&= \SI{28.3495}{\g} \\ % \SI{1}{oz}&= \SI{1}{oz} % \end{align*} % % \begin{macrocode} \cs_new:Npn \@@_cukeys_create_key_prop:n #1 { \prop_set_eq:cN { l_@@_cukeys_ #1 _prop } \l_@@_tmpa_prop \prop_put:cnV { l_@@_cukeys_ #1 _prop } { Liste } \l_@@_tmpa_seq \seq_map_inline:Nn \l_@@_tmpa_seq { \tl_set_eq:cN { l_@@_base_key_unit_ ##1 _tl } \l_@@_original_unit_tl \tl_set:cn { l_@@_unit_change_ ##1 _tl } { 1.0 } } } % \end{macrocode} % \end{macro} % % \begin{macro}{ \@@_cukeys_define_keys:n , \@@_cukeys_define_keys:V } % Defining the keys: It maps through the list of unit-keys and creates a % unit-key respectively. % \begin{macrocode} \cs_new:Npn \@@_cukeys_define_keys:n #1 { \seq_map_inline:Nn \l_@@_tmpa_seq { \@@_cukeys_keys_define:nn {##1} {#1} } } \cs_new:Npn \@@_cukeys_keys_define:nn #1#2 { \seq_if_in:NnF \l_@@_list_of_defined_keys_seq {#1} { \seq_put_right:Nn \l_@@_list_of_defined_keys_seq {#1} } \keys_define:nn { cooking-units } { #1 .choices:nn = {#2} { \@@_cukeys_define_keys_and_single_key_aux:n {#1} } , #1 / unknown .code:n= { \seq_set_split:Nnn \l_tmpa_seq { , } {#2} \msg_error:nnxxx { cooking-units } { key-choice-unknown } {#1} {##1} { \@@_seq_use_msg:N \l_tmpa_seq } } , #1 .default:n = {#1} , #1 .groups:n = { change-unit } } } \cs_generate_variant:Nn \@@_cukeys_define_keys:n { V } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_cukeys_define_keys_and_single_key_aux:n} %^^A << % \begin{macrocode} \prg_new_conditional:Npnn \@@_prop_get_master:nnN #1#2#3 { F } { \prop_get:NnNTF \g_@@_master_changer_prop { #1 ~->~ #2 } #3 { \prg_return_true: } { \prg_return_false: } } \cs_generate_variant:Nn \@@_prop_get_master:nnNF { nVc } % \cs_new:Npn \@@_prop_gput_master:nnn #1#2#3 { \prop_gput:Nnn \g_@@_master_changer_prop { #1 ~->~ #2 } {#3} } \cs_generate_variant:Nn \@@_prop_gput_master:nnn { nVV, nVv } % \cs_new:Npn \@@_cukeys_define_keys_and_single_key_aux:n #1 { \@@_prop_get_master:nVcF {#1} \l_keys_choice_tl { l_@@_unit_change_ #1_tl } { \prop_if_exist:cTF { l_@@_cukeys_ #1 _prop } { \prop_get:cVc { l_@@_cukeys_ #1 _prop } \l_keys_choice_tl { l_@@_unit_change_ #1_tl } \@@_prop_gput_master:nVv {#1} \l_keys_choice_tl { l_@@_unit_change_ #1_tl } }{ \tl_set_eq:Nc \l_@@_tmpa_tl { l_@@_base_key_unit_ #1 _tl } \prop_set_eq:Nc \l_@@_tmpa_prop { l_@@_cukeys_ \l_@@_tmpa_tl _prop } \@@_tl_eval:Nn \l_@@_tmpb_tl { (\exp_args:NNV\prop_item:Nn \l_@@_tmpa_prop \l_keys_choice_tl) / (\prop_item:Nn \l_@@_tmpa_prop {#1}) } \@@_prop_gput_master:nVV {#1} \l_keys_choice_tl \l_@@_tmpb_tl \tl_set:cV { l_@@_unit_change_ #1 _tl } \l_@@_tmpb_tl } } \prop_put:NnV \l_@@_change_unit_prop {#1} \l_keys_choice_tl } % \end{macrocode} % \end{macro} % % % \begin{macrocode} \cs_new:Npn \@@_cukeys_parse_and_create_single_key:nn #1#2 { \tl_set_rescan:Nnn \l_@@_tmpa_tl { \char_set_catcode_letter:N \# % \char_set_catcode_ignore:N\ % } { {#1} { 1.0 } #2 } \@@_cusinglekeys_parse_input:V \l_@@_tmpa_tl \bool_if:NF \l_@@_unit_error_bool { \@@_cusinglekeys_create_key_prop:n {#1} \clist_set_from_seq:NN \l_@@_tmpa_clist \l_@@_tmpa_seq \@@_cukeys_define_singlekey:nV {#1} \l_@@_tmpa_clist } } % \end{macrocode} % % \begin{macrocode} \cs_new:Npn \@@_cusinglekeys_parse_input:n #1 { \@@_cusinglekeys_parse_input_aux:nn #1 \q_recursion_tail \q_recursion_tail \q_recursion_stop } \cs_generate_variant:Nn \@@_cusinglekeys_parse_input:n { V } % \cs_new:Npn \@@_cusinglekeys_parse_input_aux:nn #1#2 { \quark_if_recursion_tail_stop:n {#1} \quark_if_recursion_tail_stop_do:nn {#2} { \msg_error:nn { cooking-units } { missing-argument } } \@@_error_if_unit_not_defined:nF {#1} { \seq_if_in:NnF \l_@@_tmpa_seq {#1} { \seq_put_right:Nn \l_@@_tmpa_seq {#1} } \tl_set:Nn \l_@@_tmpa_tl {#2} \tl_replace_all:NVn \l_@@_tmpa_tl \g_@@_input_str_hash_one_tl { \l_@@_tmpa_fp } \prop_put:NnV \l_@@_tmpa_prop {#1} \l_@@_tmpa_tl } \@@_cusinglekeys_parse_input_aux:nn } % \end{macrocode} % % \begin{macrocode} \cs_new:Npn \@@_cusinglekeys_create_key_prop:n #1 { \tl_set:cn { l_@@_unit_change_ #1 _tl } { 1.0 } \tl_set:cn { l_@@_base_key_unit_ #1 _tl } {#1} \prop_set_eq:cN { l_@@_cukeys_ #1 _prop } \l_@@_tmpa_prop \prop_put:cnV { l_@@_cukeys_ #1 _prop } { Liste } \l_@@_tmpa_seq } % \end{macrocode} % % \begin{macrocode} \cs_new:Npn \@@_cukeys_define_singlekey:nn #1#2 { \@@_cukeys_keys_define:nn {#1} {#2} } \cs_generate_variant:Nn \@@_cukeys_define_singlekey:nn { nV } % \end{macrocode} % % % \section {Adding Keys} % % \begin{macrocode} \NewDocumentCommand \cuaddkeys { m m } { \bool_set_false:N \l_@@_single_key_bool \@@_cukeys_add_keys_or_single_keys:nn {#1} {#2} } % \end{macrocode} % % \begin{macrocode} \NewDocumentCommand \cuaddsinglekeys { m m } { \bool_set_true:N \l_@@_single_key_bool \@@_cukeys_add_keys_or_single_keys:nn {#1} {#2} } % \end{macrocode} % % \begin{macrocode} \NewDocumentCommand \cuaddtokeys { m m m } { \bool_set_false:N \l_@@_single_key_bool \tl_set:Nn \l_@@_tmpb_tl { {#2} { \fp_eval:n { 1.0 / (#3) } } } \@@_cukeys_add_keys_or_single_keys:nV {#1} \l_@@_tmpb_tl } % \end{macrocode} % % % % \begin{macrocode} \cs_new:Npn \@@_cukeys_add_keys_or_single_keys:nn #1#2 { \@@_error_if_unit_not_defined:nF {#1} { \seq_if_in:NnF \l_@@_list_of_defined_keys_seq {#1} { \msg_error:nnn { cooking-units } { Key-not-defined } {#1} } \tl_if_blank:nF {#2} { \prop_gclear:N \g_@@_master_changer_prop \@@_cukeys_add_keys_and_single_key_aux:n {#1} \bool_if:NTF \l_@@_single_key_bool { \@@_cukeys_parse_and_create_single_key:nn {#1} {#2} } { \@@_cukeys_parse_and_create_keys:Vn \l_@@_original_unit_tl {#2} } } } } \cs_generate_variant:Nn \@@_cukeys_add_keys_or_single_keys:nn { nV } % \end{macrocode} % %^^A (((( % Now this does the following: 1) get the \enquote{original unit} (the unit used % in the first argument of |\cudefinekeys|) 2) Get the list of units already in the % list (It is important that the units are alway in the same order and one cannot % rely on the order of the property-lists 3) Get the property list of the % \enquote{original unit}. In the old code I simply stored the whole property list inside % another property list, but this shouldn't be done this way. So \dots\ simply % copy the original one. 4) As there is a unit added the unit it is added to % might not be the \enquote{original unit}. As such we need the conversion factor. % \begin{macrocode} \cs_new:Npn \@@_cukeys_add_keys_and_single_key_aux:n #1 { \tl_set_eq:Nc \l_@@_original_unit_tl { l_@@_base_key_unit_ #1 _tl } \prop_set_eq:Nc \l_@@_tmpa_prop { l_@@_cukeys_ \l_@@_original_unit_tl _prop } \prop_get:NnN\l_@@_tmpa_prop { Liste } \l_@@_tmpa_seq \prop_get:NnN \l_@@_tmpa_prop {#1} \l_@@_tmpa_fp } % \end{macrocode} % % % \section {Creating New Units} % % %\begin{macro}{ \declarecookingunit , \newcookingunit , \providecookingunit } % \begin{macrocode} \NewDocumentCommand \declarecookingunit { o m } { \seq_if_in:NnTF \g_@@_list_of_defined_units_seq {#2} { \msg_info:nnn { cooking-units } { redefine-unit } {#2} } { \@@_new_cooking_unit:nn {#1} {#2} } \@@_set_cooking_unit:nn {#1} {#2} } \NewDocumentCommand \newcookingunit { o m } { \@@_new_cooking_unit:nn {#1} {#2} \@@_set_cooking_unit:nn {#1} {#2} } \NewDocumentCommand \providecookingunit { o m } { \seq_if_in:NnF \g_@@_list_of_defined_units_seq {#2} { \@@_new_cooking_unit:nn {#1} {#2} \@@_set_cooking_unit:nn {#1} {#2} } } % \end{macrocode} %\end{macro} % % \begin{macrocode} \cs_new:Npn \@@_new_cooking_unit:nn #1#2 { \seq_if_in:NnTF \g_@@_list_of_defined_units_seq {#2} { \msg_error:nnn { cooking-units } { unit-already-defined } {#2} } { \tl_map_inline:nn {#2} { \tl_if_in:NnT \l_@@_unit_letter_not_allowed_tl {##1} { \msg_error:nnn { cooking-units } { character-not-allowed } {#2} } } \seq_gput_right:Nn \g_@@_list_of_defined_units_seq {#2} \tl_new:c { l_@@_unit_change_ #2 _tl } \tl_set:cn { l_@@_unit_change_ #2 _tl } { 1.0 } \clist_new:c { l_@@_unit_option_ #2 _clist } \keys_define:nn { cooking-units } { set-option-for-#2 .code:n = { \cusetoptionfor {#2} {##1} } , add-option-for-#2 .code:n = { \cuaddoptionfor {#2} {##1} }, } \tl_new:c { l_@@_base_key_unit_ #2 _tl } \tl_new:c { l_@@_default_unit_ #2 _tl } } } \cs_new:Npn \@@_set_cooking_unit:nn #1#2 { \IfNoValueTF {#1} { \tl_set:cn { l_@@_default_unit_ #2 _tl } {#2} \@@_deftranslation_base:xVn {#2} \c_@@_postfix_unit_tl {#2} }{ \tl_set:cn { l_@@_default_unit_ #2 _tl } {#1} \@@_deftranslation_base:xVn {#2} \c_@@_postfix_unit_tl {#1} } \@@_deftranslation_base:xVn {#2} \c_@@_postfix_unitname_tl { \q_@@_no_translation } \@@_deftranslation_base:xVn {#2} \c_@@_postfix_unitname_pl_tl { \q_@@_no_translation } \@@_deftranslation_base:xVn {#2} \c_@@_postfix_gender_tl { m } } % \end{macrocode} % % % % \begin{macro}{\declarecookingderivatives} % Now this is an experimental command. The idea is simple: Combine units % (like meter and second giving meter per second or in any way possible). % The first argument contains a list of the units that should be connected, one of every type is enough. % Second is the unit-key, containing |#1|, \dots\ |#(number of units in first argument)|. % Third is the calculation. The formula for the new unit should be written in here. % And last, but not least: The last argument contains the unit-symbol. % % Now this command simply defines a bunch of units, declaring them makes things easier. % \begin{macrocode} \NewDocumentCommand \declarecookingderivatives { m m m m } { \@@_declare_cooking_derivative:nnnn {#1} {#2} {#3} {#4} } % \end{macrocode} % \end{macro} % % The idea is the following. The relation between the units are given as % |(#1)/(#2)| (e.g.). The idea is the following: % \begin{enumerate} % \item The derivative contains two units. % \item The mathematical relationship is given by |(#1)/(#2)| % \item Define |\@@_tmp:w| to be |(#1)/(#2)|. % \item Parse through all values and store them in a list (e.g. |\l_tmpa_t|) as | {value-1}{value-2} | % \item Use |\exp_after:wN \@@_tmp:w \l_tmpa_t | to expand to |\@@_tmp:w {value-1} {value-2} | % \item Let |\@@_tmp:w| do its job. % \end{enumerate} % % \begin{macro}{\@@_tl_set_list:Nnn, \@@_tl_set_list:NnV, \@@_tl_set_list:NVV, \@@_tl_set_list_aux:Nnnnnnnnn } % The following argument creates the list. I am a bit lazy here and don't quite know how % to do it \enquote{correctly}. And I know, there are too many |\q_nil|. % \begin{macrocode} \cs_new:Npn \@@_tl_set_list:Nnn #1#2#3 { \@@_tl_set_list_aux:Nnnnnnnnn #1 {#2} #3 \q_nil \q_nil \q_nil \q_nil \q_nil \q_nil \q_nil \q_nil \q_nil \q_recursion_stop } \cs_generate_variant:Nn \@@_tl_set_list:Nnn { NnV, NVV } \cs_new:Npn \@@_tl_set_list_aux:Nnnnnnnnn #1#2#3#4#5#6#7#8#9 { \tl_set:Nf #1 { \int_case:nn { \l_@@_curr_depth_int } { { 1 } { } { 2 } { {#3} } { 3 } { {#3}{#4} } { 4 } { {#3}{#4}{#5} } { 5 } { {#3}{#4}{#5}{#6} } { 6 } { {#3}{#4}{#5}{#6}{#7} } { 7 } { {#3}{#4}{#5}{#6}{#7}{#8} } { 8 } { {#3}{#4}{#5}{#6}{#7}{#8}{#9} } } {#2} } \use_none_delimit_by_q_recursion_stop:w } % \end{macrocode} % \end{macro} % \begin{macro} { \@@_declare_cooking_derivative:nnnn } % This command has the following parts: % \begin{enumerate} % \item Get list of units in |#1|, count their number and store in |\l_@@_max_depth_int| % \item Use |\cs_generate_from_arg_count:NNnn| to create the commands % \item Define lists |l_@@_tmp_ 1 ... \l_@@_max_depth_int |, same for prop. I know % that there is a better way to do it, but this \emph{is} experimental. In the end, it % safes a bit of brain-power for me. % \item The main part: Map trough all units in the |l_@@_cukeys_ _prop| lists. % \item Create key-porperty and define keys. % \end{enumerate} % \begin{macrocode} \cs_new:Npn \@@_declare_cooking_derivative:nnnn #1#2#3#4 { \prop_gclear:N \g_@@_master_changer_prop \seq_set_from_clist:Nn \l_@@_tmpa_seq {#1} \seq_clear:N \l_@@_number_of_iterations_seq \seq_clear:N \l_@@_derivative_unit_list_seq \seq_clear:N \l_@@_derivative_symbol_list_seq \seq_clear:N \l_@@_derivative_value_list_seq \int_set:Nn \l_@@_max_depth_int { \seq_count:N \l_@@_tmpa_seq } \int_set:Nn \l_@@_curr_depth_int { 1 } % \end{macrocode} % \begin{macrocode} \cs_generate_from_arg_count:NNnn \@@_tmp_unit_and_symbol_list:w \cs_set:Npn { \l_@@_max_depth_int } { \seq_put_right:Nn \l_@@_derivative_unit_list_seq {#2} \seq_put_right:Nn \l_@@_derivative_symbol_list_seq {#4} } \cs_generate_from_arg_count:NNnn \@@_tmp_value_list:w \cs_set:Npn { \l_@@_max_depth_int } { \seq_put_right:Nx \l_@@_derivative_value_list_seq { \fp_eval:n {#3} } } % \end{macrocode} % \begin{macrocode} \int_step_inline:nn { \l_@@_max_depth_int } { \tl_set_eq:Nc \l_@@_original_unit_tl { l_@@_base_key_unit_ \seq_item:Nn \l_@@_tmpa_seq {##1} _tl } \prop_set_eq:Nc \l_@@_tmpa_prop { l_@@_cukeys_ \l_@@_original_unit_tl _prop } \prop_get:NnN \l_@@_tmpa_prop { Liste } \l_@@_tmpb_seq \int_set:Nn \l_@@_tmpa_int { \seq_count:N \l_@@_tmpb_seq } % \end{macrocode} % \begin{macrocode} \seq_put_right:NV \l_@@_number_of_iterations_seq \l_@@_tmpa_int \seq_clear_new:c { l_@@_tmp_ ##1 _seq } \prop_clear_new:c { l_@@_tmp_ ##1 _prop } \seq_set_eq:cN { l_@@_tmp_ ##1 _seq } \l_@@_tmpb_seq \prop_set_eq:cN { l_@@_tmp_ ##1 _prop } \l_@@_tmpa_prop } % \end{macrocode} % \begin{macrocode} \seq_map_function:cN { l_@@_tmp_ \int_use:N \l_@@_curr_depth_int _seq } \@@_seq_step_function:n % \end{macrocode} % \begin{macrocode} \seq_get_left:NN \l_@@_derivative_unit_list_seq \l_@@_original_unit_tl \prop_clear_new:c { l_@@_cukeys_ \l_@@_original_unit_tl _prop } % \end{macrocode} % \begin{macrocode} \int_zero:N \l_@@_tmpa_int \clist_set_from_seq:NN \l_@@_tmpa_clist \l_@@_derivative_unit_list_seq \seq_map_inline:Nn \l_@@_derivative_unit_list_seq { \int_incr:N \l_@@_tmpa_int \tl_set:Nx \l_@@_tmpa_tl { \seq_item:Nn \l_@@_derivative_symbol_list_seq { \l_@@_tmpa_int } } \exp_after:wN \declarecookingunit \exp_after:wN [ \l_@@_tmpa_tl ] {##1} \prop_put:cnx { l_@@_cukeys_ \l_@@_original_unit_tl _prop } {##1} { \seq_item:Nn \l_@@_derivative_value_list_seq { \l_@@_tmpa_int } } \tl_clear_new:c { l_@@_base_key_unit_ ##1 _tl } \tl_set_eq:cN { l_@@_base_key_unit_ ##1 _tl } \l_@@_original_unit_tl \exp_args:NnV \@@_cukeys_keys_define:nn {##1} \l_@@_tmpa_clist } } % \end{macrocode} % \end{macro} % % \begin{macrocode} \cs_new:Npn \@@_seq_step_function:n #1 { \@@_tl_set_list:NnV \l_@@_list_of_units_tl {#1} \l_@@_list_of_units_tl \prop_get:cnN { l_@@_tmp_ \int_use:N \l_@@_curr_depth_int _prop } {#1} \l_@@_tmpa_tl \@@_tl_set_list:NVV \l_@@_list_of_values_tl \l_@@_tmpa_tl \l_@@_list_of_values_tl \int_compare:nNnTF { \l_@@_curr_depth_int } = { \l_@@_max_depth_int } { \exp_after:wN \@@_tmp_unit_and_symbol_list:w \l_@@_list_of_units_tl \exp_after:wN \@@_tmp_value_list:w \l_@@_list_of_values_tl }{ \int_incr:N \l_@@_curr_depth_int \seq_map_function:cN { l_@@_tmp_ \int_use:N \l_@@_curr_depth_int _seq } \@@_seq_step_function:n \int_decr:N \l_@@_curr_depth_int } } % \end{macrocode} % % % % % % % % % \section {Names} % % Stolen from \pkg{l3keys.dtx} % \begin{macrocode} \tl_new:N \l_@@_sanitise_tl \cs_new_protected:Npn \@@_sanitise_aux:w #1 \q_mark { \tl_set:Nn \l_@@_sanitise_tl {#1} } \group_begin: \char_set_catcode_active:n { `\< } \char_set_catcode_active:n { `\> } \cs_new:Npn \@@_sanitize_open_arrow: { \exp_after:wN \@@_sanitize_open_arrow_auxi:w \l_@@_sanitise_tl \q_mark < \q_nil < \exp_after:wN \@@_sanitise_aux:w \l_@@_sanitise_tl } \cs_new_protected:Npn \@@_sanitize_open_arrow_auxi:w #1 < { \tl_set:Nn \l_@@_sanitise_tl {#1} \@@_sanitize_open_arrow_auxii:w } \cs_new_protected:Npn \@@_sanitize_open_arrow_auxii:w #1 < { \quark_if_nil:nF {#1} { \tl_set:Nx \l_@@_sanitise_tl { \exp_not:V \l_@@_sanitise_tl \token_to_str:N < \exp_not:n {#1} } \exp_after:wN \@@_sanitize_open_arrow_auxii:w } } \cs_new:Npn \@@_sanitize_close_arrow: { \exp_after:wN \@@_sanitize_close_arrow_auxi:w \l_@@_sanitise_tl \q_mark > \q_nil > \exp_after:wN \@@_sanitise_aux:w \l_@@_sanitise_tl } \cs_new_protected:Npn \@@_sanitize_close_arrow_auxi:w #1 > { \tl_set:Nn \l_@@_sanitise_tl {#1} \@@_sanitize_close_arrow_auxii:w } \cs_new_protected:Npn \@@_sanitize_close_arrow_auxii:w #1 > { \quark_if_nil:nF {#1} { \tl_set:Nx \l_@@_sanitise_tl { \exp_not:V \l_@@_sanitise_tl \token_to_str:N > \exp_not:n {#1} } \exp_after:wN \@@_sanitize_close_arrow_auxii:w } } \group_end: \cs_new_protected:Npn \@@_sanitize_arrows:n #1 { \tl_set:Nn \l_@@_sanitise_tl {#1} \@@_sanitize_open_arrow: \@@_sanitize_close_arrow: } % \end{macrocode} % % % \begin{macrocode} \NewDocumentCommand \cudefinename { m m } { \tl_set:Nn \l_@@_language_tl {#1} \@@_sanitize_arrows:n {#2} \exp_last_unbraced:NV \@@_cuname_parse_input:n \l_@@_sanitise_tl \q_recursion_tail \q_recursion_tail \q_recursion_stop } % \end{macrocode} % % % \begin{macrocode} \cs_new:Npn \@@_cuname_parse_input:n #1 { \peek_meaning_ignore_spaces:NTF [ { \@@_cuname_parse_unit_symbol:nw {#1} }{ \seq_if_in:NnTF \g_@@_allowed_special_keys_seq {#1} { \@@_cuname_parse_input_aux:nn {#1} } { \@@_cuname_parse_unit_symbol:nw {#1} [ \q_no_value ] } } } % \end{macrocode} % % \begin{macrocode} \cs_new:Npn \@@_cuname_parse_unit_symbol:nw #1 [#2] { \quark_if_recursion_tail_stop:n {#1} \quark_if_recursion_tail_stop_do:nn {#2} { \msg_error:nn { cooking-units } { missing-argument } } \@@_error_if_unit_not_defined:nT {#1} { \use_none_delimit_by_q_recursion_stop:w } \quark_if_no_value:nTF {#2} { \@@_deftranslation_to:VxVv \l_@@_language_tl {#1} \c_@@_postfix_unit_tl { l_@@_default_unit_ #1 _tl } }{ \@@_deftranslation_to:VxVn \l_@@_language_tl {#1} \c_@@_postfix_unit_tl {#2} } \@@_cuname_parse_input_aux:nn {#1} } % \end{macrocode} % % % \begin{macrocode} \cs_new:Npn \@@_cuname_parse_input_aux:nn #1#2 { \quark_if_recursion_tail_stop:n {#1} \quark_if_recursion_tail_stop_do:nn {#2} { \msg_error:nn { cooking-units } { missing-argument } } \seq_if_in:NnF \g_@@_allowed_special_keys_seq {#1} { \@@_error_if_unit_not_defined:nT {#1} { \use_none_delimit_by_q_recursion_stop:w } } \@@_deftranslation_to:VxVn \l_@@_language_tl {#1} \c_@@_postfix_unitname_tl {#2} \peek_meaning_ignore_spaces:NTF [ { \@@_cuname_parse_bracket:nw {#1} } { \@@_cuname_parse_bracket:nw {#1} [#2] } } % \end{macrocode} % % \begin{macrocode} \cs_new:Npn \@@_cuname_parse_bracket:nw #1 [#2] { \seq_if_in:NnF \g_@@_allowed_special_keys_seq {#1} { \@@_deftranslation_to:VxVn \l_@@_language_tl {#1} \c_@@_postfix_unitname_pl_tl {#2} } \peek_meaning_ignore_spaces:NTF < { \@@_cuname_parse_gender:nw {#1} } { \@@_cuname_parse_gender:nw {#1} } } % \end{macrocode} % % \begin{macrocode} \cs_new:Npn \@@_cuname_parse_gender:nw #1 <#2> { % \@@_check_if_correct_gender_input:n {#2} % \@@_deftranslation_to:VxVn % \l_@@_language_tl {#1} % \c_@@_postfix_gender_tl {#2} \@@_if_gender_error:nTF {#2} { \@@_deftranslation_to:VxVn \l_@@_language_tl {#1} \c_@@_postfix_gender_tl { m } }{ \@@_deftranslation_to:VxVn \l_@@_language_tl {#1} \c_@@_postfix_gender_tl {#2} } \@@_cuname_parse_input:n } % \end{macrocode} % % % % \subsection {cudefinesymbol} % % % \begin{macrocode} \NewDocumentCommand \cudefinesymbol { m m } { \tl_set:Nn \l_@@_language_tl {#1} \@@_cuprint_define_printed_unit:nn #2 \q_recursion_tail \q_recursion_tail \q_recursion_stop } % \end{macrocode} % % \begin{macrocode} \cs_new:Npn \@@_cuprint_define_printed_unit:nn #1#2 { \quark_if_recursion_tail_stop:n {#1} \quark_if_recursion_tail_stop_do:nn {#2} { \msg_error:nn { cooking-units } { missing-argument } } \seq_if_in:NnTF \g_@@_allowed_special_keys_seq {#1} { \@@_deftranslation_to:VxVn \l_@@_language_tl {#1} \c_@@_postfix_unitname_tl {#2} }{ \@@_error_if_unit_not_defined:nF {#1} { \@@_deftranslation_to:VxVn \l_@@_language_tl {#1} \c_@@_postfix_unit_tl {#2} } } \@@_cuprint_define_printed_unit:nn } % \end{macrocode} % % % % \subsection {Phrases} % % % \begin{macrocode} \@@_newtranslation_base:nVn { phrase-prop } \c_@@_postfix_phrase_tl { \q_@@_no_translation } % \end{macrocode} % % \begin{macrocode} \prg_new_conditional:Npnn \@@_phrase_list_get_for:NN #1#2 { TF } { \@@_translate_let:VNnV #2 #1 { phrase-prop } \c_@@_postfix_phrase_tl \tl_if_eq:NNTF #1 \q_@@_no_translation { \prg_return_false: } { \prg_return_true: } } \prg_new_conditional:Npnn \@@_get_phrase_for_current_langauge:NN #1#2 { T } { \@@_translate_let:NnV #1 { phrase-prop } \c_@@_postfix_phrase_tl \tl_if_eq:NNTF #1 \q_@@_no_translation { \prg_return_false: } { \@@_translate_let:NnV #2 { phrase-clist } \c_@@_postfix_phrase_tl \prg_return_true: } } % \end{macrocode} % \begin{macrocode} \NewDocumentCommand \cudefinephrase { m m } { \@@_cuphrase:nn {#1} {#2} } \cs_new:Npn \@@_cuphrase:nn #1#2 { \tl_set:Nn \l_@@_language_tl {#1} % \end{macrocode} % \begin{macrocode} \@@_phrase_list_get_for:NNTF \l_@@_phrase_prop \l_@@_language_tl { \@@_translate_let:VNnV \l_@@_language_tl \l_@@_phrase_numbers_seq { phrase-clist } \c_@@_postfix_phrase_tl }{ \prop_clear:N \l_@@_phrase_prop \seq_clear:N \l_@@_phrase_numbers_seq } % \end{macrocode} % \begin{macrocode} \@@_sanitize_arrows:n {#2} \exp_last_unbraced:NV \@@_cuphrase_parse:n \l_@@_sanitise_tl \q_recursion_tail \q_recursion_tail \q_recursion_stop % \end{macrocode} % \begin{macrocode} \seq_sort:Nn \l_@@_phrase_numbers_seq { \int_compare:nNnTF { \int_abs:n {##1} } < { \int_abs:n {##2} } { \sort_return_swapped: } { \int_compare:nNnTF { \int_abs:n {##1} } = { \int_abs:n {##2} } { \int_compare:nNnTF {##1} < {##2} { \sort_return_same: } { \sort_return_swapped: } }{ \sort_return_same: } } } % \end{macrocode} % \begin{macrocode} \@@_deftranslation_to:VxVV \l_@@_language_tl { phrase-prop } \c_@@_postfix_phrase_tl \l_@@_phrase_prop \@@_deftranslation_to:VxVV \l_@@_language_tl { phrase-clist } \c_@@_postfix_phrase_tl \l_@@_phrase_numbers_seq } % \end{macrocode} % % % \begin{macrocode} \cs_new:Npn \@@_cuphrase_parse:n #1 { \quark_if_recursion_tail_stop:n {#1} \@@_if_integer:nF {#1} { \msg_error:nnn { cooking-units} { phrase-unit-not-an-integer } {#1} } \peek_meaning_remove_ignore_spaces:NTF * { \int_set:Nn \l_@@_tmpa_int {-#1} \@@_cuphrase_parse_normal:Vn \l_@@_tmpa_int }{ \int_set:Nn \l_@@_tmpa_int {#1} \@@_cuphrase_parse_normal:Vn \l_@@_tmpa_int } } % \end{macrocode} % % \begin{macrocode} \cs_new:Npn \@@_cuphrase_parse_normal:nn #1#2 { \quark_if_recursion_tail_stop_do:nn {#2} { \msg_error:nn { cooking-units } { missing-argument } } \prop_put:Nnn \l_@@_phrase_prop {#1} {#2} \seq_if_in:NnF \l_@@_phrase_numbers_seq {#1} { \seq_push:Nn \l_@@_phrase_numbers_seq {#1} } \peek_meaning_ignore_spaces:NTF [ { \@@_chuphrase_parse_plural:nw {#1} }{ \@@_chuphrase_parse_plural:nw {#1} [#2] } } \cs_generate_variant:Nn \@@_cuphrase_parse_normal:nn { V } % \end{macrocode} % % \begin{macrocode} \cs_new:Npn \@@_chuphrase_parse_plural:nw #1 [#2] { \prop_put:Nnn \l_@@_phrase_prop { #1-pl } {#2} \peek_meaning_ignore_spaces:NTF < { \@@_chuphrase_parse_gender:nw {#1} }{ \@@_chuphrase_parse_gender:nw {#1} < m > } } % \end{macrocode} % % \begin{macrocode} \cs_new:Npn \@@_chuphrase_parse_gender:nw #1 <#2> { \@@_if_gender_error:nTF {#2} { \@@_deftranslation_to:VxVn \l_@@_language_tl { #1-phrase-gender } \c_@@_postfix_gender_tl { m } }{ \@@_deftranslation_to:VxVn \l_@@_language_tl { #1-phrase-gender } \c_@@_postfix_gender_tl {#2} } \@@_cuphrase_parse:n } % \end{macrocode} % % % % % \subsection{Old stuff} % % \begin{macro} { } % \begin{macrocode} \cs_new:Npn \@@_old_cutext:nnn #1#2#3 { \tl_set_eq:NN \l_@@_option_unit_tl \l_@@_original_unit_tl \@@_old_cutext_default:nnn {#1} {#2} {#3} } % \end{macrocode} % \end{macro} % % % % \begin{macro} { \@@_old_cutext_default:nnn } % \changes {2016/06/11} {0.98a} { New command } % \begin{macrocode} \cs_new:Npn \@@_old_cutext_default:nnn #1#2#3 { \bool_if:NTF \l_@@_draft_bool {#2} { \tl_set:Nn \l_@@_cutext_last_value_tl {#2} \tl_if_in:NVTF \l_@@_cutext_last_value_tl \l_@@_input_range_sign_tl { \tl_replace_once:NVn \l_@@_cutext_last_value_tl \l_@@_input_range_sign_tl { \q_@@_range } \@@_old_cutext_parse_range:Vn \l_@@_cutext_last_value_tl {#3} }{ \@@_old_cutext_print_input:Nn \l_@@_cutext_last_value_tl {#3} } } } % \end{macrocode} % \begin{macrocode} \cs_new_protected:Npn \@@_old_cutext_print_input:Nn #1#2 { \@@_old_cutext_if_numeral_is_int_and_parse_and_smaller_then_print_numerals:NTF #1 { \@@_int_if_equal_one:nTF {#1} { \@@_translate_one_and_check_existance:Nx \l_@@_translation_tmpa_tl {#2} \bool_if:NTF \l_@@_cutext_uppercase_word_bool { \exp_args:Nx \tl_upper_case:n { \tl_head:V \l_@@_translation_tmpa_tl } \tl_tail:V \l_@@_translation_tmpa_tl } { \l_@@_translation_tmpa_tl } }{ \bool_if:NTF \l_@@_cutext_uppercase_word_bool { \@@_print_Numeral:n {#1} } { \@@_print_numeral:n {#1} } } } { \@@_print_numerical_input:N #1 } } % \end{macrocode} % \end{macro} % % \begin{macro} {\@@_old_cutext_if_numeral_is_int_and_parse_and_smaller_then_print_numerals:N} % \begin{macrocode} \prg_new_conditional:Npnn \@@_old_cutext_if_numeral_is_int_and_parse_and_smaller_then_print_numerals:N #1 { TF } { \bool_if:NTF \l_@@_lokal_numeral_bool { \@@_if_integer:VTF #1 { \int_compare:nNnTF {#1} < { \l_@@_print_numerals_below_int } { \prg_return_true: } { \prg_return_false: } }{ \prg_return_false: } }{ \prg_return_false: } } % \end{macrocode} % \end{macro} % % \begin{macrocode} \cs_new:Npn \@@_old_cutext_parse_range:nn #1 #2 { \@@_old_cutext_parse_range_aux:nww {#2} #1 \q_stop } \cs_generate_variant:Nn \@@_old_cutext_parse_range:nn { V } \cs_new:Npn \@@_old_cutext_parse_range_aux:nww #1 #2 \q_@@_range #3 \q_stop { \tl_set:Nn \l_@@_tmpa_tl {#2} \tl_set:Nn \l_@@_cutext_last_value_tl {#3} \@@_old_cutext_print_input:Nn \l_@@_tmpa_tl {#1} \tl_use:N \l_@@_cutext_range_sign_tl \@@_old_cutext_print_input:Nn \l_@@_cutext_last_value_tl {#1} } % \end{macrocode} % % % \begin{macro}{\@@_cuam_old:n} % \begin{macrocode} \cs_new:Npn \@@_cuam_old:n #1 { \tl_set_rescan:Nnn \l_@@_tmpa_tl { \char_set_catcode_letter:N \_ % \char_set_catcode_ignore:N\ % } {#1} \bool_if:NTF \l_@@_draft_bool { \l_@@_tmpa_tl } { \@@_cuam_old_parse:V \l_@@_tmpa_tl } } % \end{macrocode} % \end{macro} % % \begin{macrocode} \cs_new_protected:Npn \@@_cuam_old_parse:n #1 { \tl_if_in:nVTF {#1} \l_@@_input_range_sign_tl { \tl_set:Nn \l_@@_tmpa_tl {#1} \tl_replace_once:NVn \l_@@_tmpa_tl \l_@@_input_range_sign_tl { \q_@@_range } \@@_cuam_old_parse_range:V \l_@@_tmpa_tl }{ \tl_if_in:nnTF {#1} { / } { \tl_if_in:nnTF {#1} { _ } { \@@_cuam_old_parse_mixed_frac:www #1 \q_stop } { \@@_cuam_old_parse_frac:ww #1 \q_stop } }{ \tl_if_in:nnTF {#1} { _ } { \msg_error:nnn { cooking-units } { missing-slash } {#1} } { \@@_cuam_old_parse_scale:n {#1} } } } } \cs_generate_variant:Nn \@@_cuam_old_parse:n { V } % \end{macrocode} % % \begin{macrocode} \cs_new:Npn \@@_cuam_old_parse_range:n #1 { \@@_cuam_old_parse_range_aux:ww #1 \q_nil } \cs_generate_variant:Nn \@@_cuam_old_parse_range:n { V } \cs_new:Npn \@@_cuam_old_parse_range_aux:ww #1 \q_@@_range #2 \q_nil { #1 \l_@@_cunum_range_sign_tl #2 } % \end{macrocode} % % % \begin{macrocode} \cs_new:Npn \@@_cuam_old_parse_scale:n #1 {#1} % \end{macrocode} % % \begin{macrocode} \cs_new:Npn \@@_cuam_old_parse_frac:ww #1/#2 \q_stop { \@@_frac:nn {#1} {#2} } % \end{macrocode} % % \begin{macrocode} \cs_new:Npn \@@_cuam_old_parse_mixed_frac:www #1_#2/#3 \q_stop { #1 \skip_horizontal:N \l_@@_mixed_frac_dim \@@_frac:nn {#2} {#3} } % \end{macrocode} % % % \subsubsection {cufrac} % % Obsolete. % \begin{macrocode} \NewDocumentCommand \cufrac { O{} m } { \msg_error:nnnn { cooking-units } { obsolete-command } { \cufrac } { \cuam } \group_begin: \tl_if_empty:nF {#1} { \keys_set:nn { cooking-units } {#1} } \@@_cufrac:n {#2} \group_end: } \cs_new:Npn \@@_cufrac:n #1 { \tl_set_rescan:Nnn \l_@@_tmpa_tl { \char_set_catcode_letter:N \_ % \char_set_catcode_ignore:N\ % } {#1} \@@_cufrac_parse:V \l_@@_tmpa_tl } \cs_new:Npn \@@_cufrac_parse:n #1 { \tl_if_in:nnTF {#1} { / } { \tl_if_in:nnTF {#1} { _ } { \@@_cufrac_parse_mixed_frac:www #1 \q_stop } { \@@_cufrac_parse_frac:ww #1 \q_stop } }{ \tl_if_in:nnTF {#1} { _ } { \msg_error:nnn { cooking-units } { missing-slash } {#1} } { \@@_cufrac_parse_scale:n {#1} } } } \cs_generate_variant:Nn \@@_cufrac_parse:n { V } \cs_new:Npn \@@_cufrac_parse_scale:n #1 {#1} \cs_new:Npn \@@_cufrac_parse_frac:ww #1/#2 \q_stop { \@@_frac:nn {#1} {#2} } \cs_new:Npn \@@_cufrac_parse_mixed_frac:www #1_#2/#3 \q_stop { #1 \skip_horizontal:N \l_@@_mixed_frac_dim \@@_frac:nn {#2} {#3} } % \end{macrocode} % % % % % \begin{macrocode} \cs_new:Npn \@@_add_forbidden_unit:n #1 { \seq_set_from_clist:Nn \l_@@_tmpa_seq {#1} \seq_map_inline:Nn \l_@@_tmpa_seq { \@@_error_if_unit_not_defined:nF {##1} { \seq_if_in:NnF \l_@@_curef_do_not_change_seq {##1} { \seq_put_right:Nn \l_@@_curef_do_not_change_seq {##1} } } } } \cs_new:Npn \@@_remove_forbidden_unit:n #1 { \seq_set_from_clist:Nn \l_@@_tmpa_seq {#1} \seq_map_inline:Nn \l_@@_tmpa_seq { \@@_error_if_unit_not_defined:nF {##1} { \seq_if_in:NnTF \l_@@_curef_do_not_change_seq {##1} { \seq_remove_all:Nn \l_@@_curef_do_not_change_seq {##1} } { \msg_warning:nnnn { cooking-units } { curef-not-inside-list } {##1} { \@@_seq_use_msg:N \l_@@_curef_do_not_change_seq } } } } } \cs_new:Npn \@@_clear_forbidden_unit: { \seq_clear:N \l_@@_curef_do_not_change_seq } % \end{macrocode} % % % % % % % \begin{macrocode} \NewDocumentCommand \cudeclareunitgroup { m m } { \@@_define_clear_unit_group:nn {#1} {#2} \@@_add_to_unit_group:nn {#1} {#2} } \NewDocumentCommand \cuaddtounitgroup { m m } { \@@_add_to_unit_group:nn {#1} {#2} } \NewDocumentCommand \cuclearunitgroup { m } { \@@_error_if_group_not_defined:nF {#1} { \@@_define_clear_unit_group:nn {#1} { } } } % \end{macrocode} % % % % % % % % % % % % Works better now. % \begin{macrocode} \NewDocumentCommand \cusetoptionfor { m m } { \@@_map_trough_valid_unit_options:nnn {#1} {#2} { \clist_set:cn { l_@@_unit_option_ ##1 _clist } {##2} } } \NewDocumentCommand \cuaddoptionfor { m m } { \@@_map_trough_valid_unit_options:nnn {#1} {#2} { \clist_put_right:cn { l_@@_unit_option_ ##1 _clist } {##2} } } \NewDocumentCommand \cuclearoptionfor { m } { \@@_map_trough_valid_unit_options:nnn {#1} { } { \clist_clear:c { l_@@_unit_option_ ##1 _clist } } } % \end{macrocode} % The reason I map trough the units twice is simply: I think it makes more % sense if an \enquote{unknown unit} error is shown before an % \enquote{unknown option} error (at least for me). % It is kinda stupid, but this is not really a heavily used function, so \dots\ yeah. % % Note: I cannot check if |\l_@@_tmpa_clist| is empty because one could % use |\cusetoptionfor{F,C,Re,K}{}| to clear the options of the given units. % \begin{macrocode} \cs_new:Npn \@@_tmp:w { } \cs_new:Npn \@@_map_trough_valid_unit_options:nnn #1#2 #3 { \seq_clear:N \l_@@_tmpa_seq \clist_clear:N \l_@@_tmpa_clist \cs_set:Npn \@@_tmp:w ##1##2 {#3} \clist_map_inline:nn {#1} { \@@_error_if_unit_not_defined:nF {##1} { \seq_put_right:Nn \l_@@_tmpa_seq {##1} } } \tl_if_empty:nF {#2} { \@@_unit_options_check_validity:n {#2} } \seq_map_inline:Nn \l_@@_tmpa_seq { \exp_args:NnV \@@_tmp:w {##1} \l_@@_tmpa_clist } } \cs_new:Npn \@@_unit_options_check_validity:n #1 { \keyval_parse:NNn \@@_unit_options_check_validity_aux_i:n \@@_unit_options_check_validity_aux_ii:nn {#1} } \cs_new:Npn \@@_unit_options_check_validity_aux_i:n #1 { \keys_if_exist:nnTF { cooking-units } {#1} { \clist_put_right:Nn \l_@@_tmpa_clist {#1} } { \msg_error:nnn { cooking-units } { unknown-option } {#1} } } \cs_new:Npn \@@_unit_options_check_validity_aux_ii:nn #1#2 { \keys_if_exist:nnTF { cooking-units } {#1} { \clist_put_right:Nn \l_@@_tmpa_clist { #1={#2} } } { \msg_error:nnn { cooking-units } { unknown-option } {#1} } } % \end{macrocode} % % % % % % % % \subsection {cusetup} % % \begin{macrocode} \NewDocumentCommand \cusetup { m } { \keys_set:nn { cooking-units } {#1} } % \end{macrocode} % % % % \subsection{Definitions et all} % % Plase note that at his point we are still inside the Expl3 \enquote{Environment} % and that spaces are ignored! % % \begin{macrocode} \newcookingunit { kg } \newcookingunit { dag } \newcookingunit { g } \newcookingunit { oz } \newcookingunit { lb } \newcookingunit { stick } \newcookingunit [ \ensuremath{ \@@_frac:nn { eV } { c^2 } } ] { eVc-2 } % \end{macrocode} % % \begin{macrocode} \newcookingunit { K } \newcookingunit [ \ensuremath{ {} ^ { \circ } } \kern-\scriptspace C ] { C } \newcookingunit [ \ensuremath{ {} ^ { \circ } } \kern-\scriptspace F ] { F } \newcookingunit [ \ensuremath{ {} ^ { \circ } } \kern-\scriptspace R\'{e} ] { Re } % \end{macrocode} % % \begin{macrocode} \newcookingunit { d } \newcookingunit { h } \newcookingunit { min } \newcookingunit { s } \newcookingunit [ \ensuremath{ \@@_frac:nn { \hbar } { eV } } ] { hbareV-1 } % \end{macrocode} % % \begin{macrocode} \newcookingunit { m } \newcookingunit { cm } \newcookingunit { dm } \newcookingunit { mm } \newcookingunit { in } \newcookingunit [ \ensuremath{ \@@_frac:nn { c\hbar } { eV } } ] { chbareV-1 } % \end{macrocode} % % \begin{macrocode} \newcookingunit { l } \newcookingunit { dl } \newcookingunit { cl } \newcookingunit { ml } \newcookingunit [ \ensuremath { \@@_frac:nn { c^3 \hbar^3 } { eV^3 } } ] { (chbareV-1)3 } % \end{macrocode} % % \begin{macrocode} \newcookingunit { cal } \newcookingunit { kcal } \newcookingunit { J } \newcookingunit { kJ } \newcookingunit { eV } % \end{macrocode} % % \begin{macrocode} \newcookingunit [ pinch ] { pn } \newcookingunit { EL } \newcookingunit { TL } \newcookingunit [ ssp. ] { ssp } %% saltspoonful \newcookingunit [ csp. ] { csp } %% coffeespoonful \newcookingunit [ dsp. ] { dsp } \newcookingunit [ Msp. ] { Msp } % \end{macrocode} % % \begin{macrocode} \DeclareLanguageAlias { AmericanEnglish } { American } % \end{macrocode} % % \begin{macrocode} \cudefinename { German } { { kg } { Kilogramm } < n > { dag } { Dekagramm } < n > { g } { Gramm } < n > { oz } { Unze } < f > { lb } { Pfund } < n > % \end{macrocode} % \begin{macrocode} { d } { Tag } [ Tage ] { h } { Stunde } [ Stunden ] < f > { min } { Minute } [ Minuten ] < f > { s } { Sekunde } [ Sekunden ] < f > % \end{macrocode} % \begin{macrocode} { C } { Grad \space Celsius } { K } { Kelvin } < n > { F } { Grad \space Fahrenheit } { Re } { Grad \space R\'{e}amur } % \end{macrocode} % \begin{macrocode} { m } { Meter } < n > { dm } { Dezimeter } < n > { cm } { Centimeter } < n > { mm } { Millimeter } < n > { in } { Zoll } % \end{macrocode} % \begin{macrocode} { l } [ l ] { Liter } { dl } { Deziliter } { cl } { Centiliter } { ml } { Milliliter } % \end{macrocode} % \begin{macrocode} { cal } { Kalorie } [ Kalorien ] < f > { kcal } { Kilokalorie } [ Kilokalorien ] < f > { J } { Joule } { kJ } { Kilojoule } { eV } { Elektronenvolt } < n > % \end{macrocode} % \begin{macrocode} { Msp } [ Msp. ] { Messerspitze } [ Messerspitzen ] < f > { pn } [ Prise ] { Prise } [ Prisen ] < f > { EL } [ EL ] { Essl{\"o}ffel } { TL } [ TL ] { Teel{\"o}ffel } { csp } [ KL ] { Mokkal{\"o}ffel } % \end{macrocode} % \begin{macrocode} { decimal-mark } { , } { one (m) } { ein } { one (f) } { eine } { one (n) } { ein } } % \end{macrocode} % % % \begin{macrocode} \cudefinename { English } { { kg } { kilogramme } { dag } { decagramme } { g } { gramme } { oz } { ounce } { lb } { pound } [ pounds ] { stick } { stick } [ sticks ] % \end{macrocode} % \begin{macrocode} { d } { day } [ days ] { h } { hour } [ hours ] { min } { minute } [ minutes ] { s } { second } [ seconds ] % \end{macrocode} % \begin{macrocode} { C } { degree \space Celsius } [ degrees \space Celsius ] { F } { degree \space Fahrenheit } [ degrees \space Fahrenheit ] { K } { kelvin } { Re } { degree \space R\'{e}aumur } [ degrees \space R\'{e}aumur ] % \end{macrocode} % \begin{macrocode} { m } { metre } [ metres ] { dm } { decimetre } [ decimetres ] { cm } { centimetre } [ centimetres ] { mm } { millimitre } [ millimitres ] { in } { inch } [ inches ] % \end{macrocode} % \begin{macrocode} { l } [ \ensuremath { \ell } ] { litre } [ litres ] { dl } { decilitre } [ decilitres ] { cl } { centilitre } [ centilitres ] { ml } { millilitre } [ millilitres ] % \end{macrocode} % \begin{macrocode} { cal } { calorie } [ calories ] { kcal } { kilocalorie } [ kilocalories ] { J } { joule } [ joules ] { kJ } { kilojoule } [ kilojoules ] { eV } { electron \space volt } % \end{macrocode} % \begin{macrocode} % { Msp } [ pinch ] { pinch } [ pinches ] % { Msp } { Messerspitze } [ Messerspitzen ] { pn } [ pinch ] { pinch } [ pinches ] { EL } [ tbsp. ] { tablespoon } [ tablespoons ] { TL } [ tsp. ] { teaspoon } [ teaspoons ] { dsp } { dessertspoonful } { csp } { coffeespoonful } { ssp } { saltspoonful } % \end{macrocode} % \begin{macrocode} { decimal-mark } { . } { one (m) } { one } { one (f) } { one } { one (n) } { one } } % \end{macrocode} % % \begin{macrocode} \cudefinename { AmericanEnglish } { { kg } { kilogram } { dag } { decagram } { g } { gram } { oz } { ounce } % \end{macrocode} % \begin{macrocode} { m } { meter } [ meters ] { dm } { decimeter } [ decimeters ] { cm } { centimeter } [ centimeters ] { mm } { millimiter } [ millimiters ] { in } { inch } [ inches ] % \end{macrocode} % \begin{macrocode} { l } [ \ensuremath { \ell } ] { liter } [ liters ] { dl } { deciliter } [ deciliters ] { cl } { centiliter } [ centiliters ] { ml } { milliliter } [ milliliters ] % \end{macrocode} % \begin{macrocode} % { Msp } { Messerspitze } [ Messerspitzen ] { pn } [ pn. ] { pinch } [ pinches ] } % \end{macrocode} % % % \begin{macrocode} \cudefinename { French } { { kg } { kilogramme } [ kilogrammes ] { dag } { d\'{e}cagramme } [ d\'{e}cagrammes] { g } { gramme } [ gramme ] { oz } { once } < f > { lb } { livre } [ livres ] < f > % \end{macrocode} % \begin{macrocode} { d } { jour } [ jours ] { h } { heure } [ heures ] < f > { min } { minute } [ minutes ] < f > { s } { seconde } [ secondes ] < f > % \end{macrocode} % \begin{macrocode} { C } { degr\'{e} \space Celsius } [ degr\'{e}s \space Celsius ] { K } { degr\'{e} \space Fahrenheit } [ degr\'{e}s \space Fahrenheit ] { F } { kelvin } [ kelvins ] { Re } { \'{e}chelle \space R\'{e}aumur } [ degr\'{e}s \space R\'{e}aumur ] % \end{macrocode} % \begin{macrocode} { m } { m\`{e}tre } [ m\`{e}tres ] { dm } { d\'{e}cim\`{e}tre } [ d\'{e}cim\`{e}tres ] { cm } { centim\`{e}tre } [ centim\`{e}tres ] { mm } { millim\`{e}tre } [ millim\`{e}tres ] { in } [ po ] { pouce } [ pouces ] % \end{macrocode} % \begin{macrocode} { l } [ L ] { litre } [ litres ] { dl } [ dL ] { d\'{e}cilitre } [ d\'{e}cilitres ] { cl } [ cL ] { centilitre } [ centilitres ] { ml } [ mL ] { millilitre } [ millilitres ] % \end{macrocode} % \begin{macrocode} { cal } { calorie } [ calorie ] { kcal } { kilocalorie } [ kilocalories ] { J } { joule } [ joules ] { kJ } { kilojoule } [ kilojoules ] { eV } { \'{e}lectron-volt } [ \'{e}lectron-volts ] % \end{macrocode} % \begin{macrocode} { pn } { pinc\'{e}e } < f > { EL } [c.\`{a}.s.] { cuill\`{e}re \space \`{a} \space soupe } < f > { TL } [c.\`{a}.c.] { cuill\`{e}re \space \`{a} \space caf\'{e} } < f > % \end{macrocode} % \begin{macrocode} { decimal-mark } { . } { one (m) } { un } { one (f) } { une } { one (n) } { un } } % \end{macrocode} % % % % \begin{macrocode} \cudefinekeys { kg } { { dag }{ 100 } { g } { 1000 } { lb } { 1/0.45359237 } { oz } { 16/0.45359237 } { stick } { 4/0.45359237 } { eVc-2 } { 560958865.0e+27 } %% 560958865.0 +- 3.5 e+27 } % \end{macrocode} % \begin{macrocode} \cudefinekeys { d } { { h } { 24 } { min }{ 1440 } { s } { 86400 } { hbareV-1 } { 151926746.1e+7 * 86400 } %% 151926746.1 +- 2.1 e+7 } %\cuaddtokeys { s } { hbareV-1 } { 6.582119514e-16 } % \end{macrocode} % \begin{macrocode} \cudefinekeys { m } { { dm } { 10 } { cm } { 100 } { mm } { 1000 } { in } { 36/0.9144 } { chbareV-1 } { 5067730.759 } %% 5067730.759 +- 0.070 } %\cuaddtokeys { m } { chbareV-1 } { 1.97326972e-7 } % \end{macrocode} % \begin{macrocode} \cudefinekeys { l } { { dl } { 10 } { cl } { 100 } { ml }{ 1000 } { (chbareV-1)3 } { 130148929.5e+12 * 1e-3 } %% (130148929.5 +- 5.4 e+12)*1e-3 } % \end{macrocode} % \begin{macrocode} \cudefinekeys { J } { { kJ }{ 1e-3 } { cal }{ 0.2388459 } { kcal }{ 0.2388459e-3 } { eV }{ 624150912.6e+10 } %% 624150912.6 +- 3.9 e+10 } %\cuaddtokeys { J } { eV } { 1.6021766208e-19 } % \end{macrocode} % \begin{macrocode} \fp_const:Nn \c_@@_kb_eV_fp { 8.617 330 3 e-5 } \cudefinesinglekey { C } { { K } { #1 + 273.15 } { F } { #1 * 1.8 + 32 } { Re } { #1 * 0.8 } { eV } { ( #1 + 273.15 ) * \c_@@_kb_eV_fp } } \cudefinesinglekey { F } { { C } { ( #1 - 32 ) * 5/9 } { K } { ( #1 + 459.67 ) * 5/9 } { Re } { ( #1 - 32 ) * 4/9 } { eV } {( #1 + 459.67 ) * 5/9 * \c_@@_kb_eV_fp } } \cudefinesinglekey { K } { { C } { #1 - 273.15 } { F } { #1 * 1.8 - 459.67 } { Re } { ( #1 - 273.15 ) * 0.8 } { eV } { #1 * \c_@@_kb_eV_fp } } \cudefinesinglekey { Re } { { K } { #1 * 1.25 + 273.15 } { C } { #1 * 1.25 } { F } { #1 * 2.25 + 32 } { eV } { ( #1 * 1.25 + 273.15 ) * \c_@@_kb_eV_fp } } % \end{macrocode} % % % \begin{macrocode} \cudefinephrase { German } { % { 6 } * { halbes \ Dutzend } < n > % { 6 } { efkjwefjkl \ Dutzend } < n > { 12 } { Dutzend } < n > % { 60 } { Schock } < n > % { 1728 } { Gro{\ss}gros } < n > % { 144 } { Gros } < n > } % \end{macrocode} % % % \subsection{Finish} % % \begin{macrocode} \cudeclareunitgroup { weight } { kg , dag, g, oz, lb, stick } \cudeclareunitgroup { length } { m , dm , cm , mm , in } \cudeclareunitgroup { volume } { l , dl , cl , ml } \cudeclareunitgroup { temperature } { C , F , K , Re } \cudeclareunitgroup { energy } { cal, kcal , J , kJ , eV } \cudeclareunitgroup { time } { d , h , min , s } \cusetoptionfor { F , C , K , Re } { round-precision = 0 } \cusetup { curef-add-forbidden-unit = { F , C , K , Re } , add-temperature-to-check = { K = 0, C = -273.15 , F = -459.67 , Re = -218.52 } , round-precision = 2 , } % \end{macrocode} % % % % % % % % % % % \begin{macrocode} % % \end{macrocode} % % \end{implementation} % % % % \begin{thebibliography}{} % \bibitem{Gattopardo} % Guiseppe Tomasi di Lampedusa, \emph{Der Gattopardo}, % Piper, Volume~8 (2018), ISBN~978-3-492-24586-9 % % \bibitem{Sh:3} % Sir Arthur Conan Doyle, \emph{Sherlock Holmes The Complete Novels and Stories Volume~II}, % Bantam Books % % \bibitem{Nist2008} \emph{Guide for the Use of the International System of Units (SI)}, % NIST Special Publication 811, 2008 Edition, Ambler Thompson and Barry N. Taylor % % \bibitem{Nist2006} \emph{The International System of Units (SI) – Conversion Factors % for General Use}, NIST Special Publication 1038, May 2006, % Kenneth Butcher, Linda Crown and Elizabeth J. Gentry % % \bibitem{WM1985} \emph{Weights and Measures Act 1985}, % \url{https://www.legislation.gov.uk/ukpga/1985/72} % % \bibitem{StickSource} \url{https://cooking.stackexchange.com/questions/784/translating-cooking-terms-between-us-uk-au-ca-nz} % % \end{thebibliography} % % % % \endinput % % % % % Local Variables: % mode: doctex % TeX-master: t % End: