diff options
Diffstat (limited to 'Master/texmf-dist/tex/context/base/mkiv/syst-aux.mkxl')
-rw-r--r-- | Master/texmf-dist/tex/context/base/mkiv/syst-aux.mkxl | 6587 |
1 files changed, 0 insertions, 6587 deletions
diff --git a/Master/texmf-dist/tex/context/base/mkiv/syst-aux.mkxl b/Master/texmf-dist/tex/context/base/mkiv/syst-aux.mkxl deleted file mode 100644 index 7ade250d970..00000000000 --- a/Master/texmf-dist/tex/context/base/mkiv/syst-aux.mkxl +++ /dev/null @@ -1,6587 +0,0 @@ -%D \module -%D [ file=syst-aux, % merge of syst-gen cum suis -%D version=1996.03.20, -%D title=\CONTEXT\ System Macros, -%D subtitle=General, -%D author=Hans Hagen, -%D date=\currentdate, -%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] -%C -%C This module is part of the \CONTEXT\ macro||package and is -%C therefore copyrighted by \PRAGMA. See mreadme.pdf for -%C details. - -\registerctxluafile{syst-aux}{} - -%D This fils is a follow up in \type {syst-aux.mkii} and \type {syst-aux.mkiv} -%D where you can find some more pure \TEX\ or \LUATEX| variants. - -\unprotect - -%D \macros -%D {unexpanded} -%D -%D Because we use this module only in \MKIV, we have removed the old protection -%D code. -%D -%D \starttyping -%D \unexpanded\def\somecommand{... ... ...} -%D \stoptyping -%D -%D This overloads the \ETEX\ primitive but as we already had an \MKII\ solution we -%D keep the same name for a similar mechanism. - -\let\unexpanded\normalprotected - -\ifcase\contextlmtxmode - - \def\startlmtxmode#1\stoplmtxmode{} - \let\stoplmtxmode \relax - \let\startmkivmode\relax - \let\stopmkivmode \relax - -\else - - \let\startlmtxmode\relax - \let\stoplmtxmode \relax - \def\startmkivmode#1\stopmkivmode{} - \let\stopmkivmode \relax - -\fi - -%D As we don't have namespace definers yet, we use a special one: - -\ifdefined\c_syst_helpers_n_of_namespaces - - % lets plug in a better error message - -\else - - \newcount\c_syst_helpers_n_of_namespaces \c_syst_helpers_n_of_namespaces\pluseight % 1-8 reserved for catcodes - - \def\v_interfaces_prefix_template_system{\number \c_syst_helpers_n_of_namespaces>>} - %def\v_interfaces_prefix_template_system{\characters\c_syst_helpers_n_of_namespaces>>} % no \characters yet - -\fi - -\unexpanded\def\installsystemnamespace#1% maybe move this to syst-ini - {\ifcsname ??#1\endcsname - \writestatus\m!system{duplicate system namespace '#1'}\wait - \else - \global\advance\c_syst_helpers_n_of_namespaces\plusone - \expandafter\edef\csname ??#1\endcsname{\v_interfaces_prefix_template_system}% - \fi} - -%D \macros -%D {normalspace} -%D -%D There is already \type{\space} but just to be sure we also provide: - -\def\normalspace{ } - -%D \macros -%D {!!count, !!toks, !!dimen, !!box, -%D !!width, !!height, !!depth, !!string, !!done} -%D -%D We define some more \COUNTERS\ and \DIMENSIONS. We also define some shortcuts to -%D the local scatchregisters~0, 2, 4, 6 and~8. - -\newcount\!!counta \newtoks\!!toksa \newdimen\!!dimena \newbox\!!boxa -\newcount\!!countb \newtoks\!!toksb \newdimen\!!dimenb \newbox\!!boxb -\newcount\!!countc \newtoks\!!toksc \newdimen\!!dimenc \newbox\!!boxc -\newcount\!!countd \newtoks\!!toksd \newdimen\!!dimend \newbox\!!boxd -\newcount\!!counte \newtoks\!!tokse \newdimen\!!dimene \newbox\!!boxe -\newcount\!!countf \newtoks\!!toksf \newdimen\!!dimenf \newbox\!!boxf - \newdimen\!!dimeng - \newdimen\!!dimenh - \newdimen\!!dimeni - \newdimen\!!dimenj - \newdimen\!!dimenk - -\let\!!stringa\empty \let\!!stringb\empty \let\!!stringc\empty -\let\!!stringd\empty \let\!!stringe\empty \let\!!stringf\empty - -\newdimen\!!widtha \newdimen\!!heighta \newdimen\!!deptha -\newdimen\!!widthb \newdimen\!!heightb \newdimen\!!depthb -\newdimen\!!widthc \newdimen\!!heightc \newdimen\!!depthc -\newdimen\!!widthd \newdimen\!!heightd \newdimen\!!depthd - -\newif\if!!donea \newif\if!!doneb \newif\if!!donec -\newif\if!!doned \newif\if!!donee \newif\if!!donef - -\def\!!zerocount {0} % alongside \zerocount -\def\!!minusone {-1} % ... -\def\!!plusone {1} % ... -\def\!!plustwo {2} % ... -\def\!!plusthree {3} % ... -\def\!!plusfour {4} % ... -\def\!!plusfive {5} % ... -\def\!!plussix {6} % ... -\def\!!plusseven {7} % ... -\def\!!pluseight {8} % ... -\def\!!plusnine {9} % alongside \plusnine - -\setnewconstant \uprotationangle 0 -\setnewconstant\rightrotationangle 90 -\setnewconstant \downrotationangle 180 -\setnewconstant \leftrotationangle 270 - -\ifdefined\data \else \let\data \relax \fi % dep checker - -%D \macros -%D {s!,c!,e!,p!,v!,@@,??} -%D -%D To save memory, we use constants (sometimes called variables). Redefining these -%D constants can have disastrous results. - -\def\v!prefix! {v!} -\def\c!prefix! {c!} -\def\s!prefix! {s!} - -\def\s!next {next} -\def\s!default {default} -\def\s!dummy {dummy} -\def\s!unknown {unknown} - -\def\s!do {do} -\def\s!dodo {dodo} - -\def\s!complex {complex} -\def\s!start {start} -\def\s!simple {simple} -\def\s!stop {stop} - -\def\s!empty {empty} - -%D Sometimes we pass macros as arguments to commands that don't expand them -%D before interpretation. Such commands can be enclosed with \type {\expanded}, -%D like: -%D -%D \starttyping -%D \expanded{\setupsomething[\alfa]} -%D \stoptyping -%D -%D Such situations occur for instance when \type{\alfa} is a commalist or when data -%D stored in macros is fed to index of list commands. If needed, one should use -%D \type{\noexpand} inside the argument. Later on we will meet some more clever -%D alternatives to this command. Beware, only the simple one has \type {\noexpand} -%D before its argument. - -\let\m_syst_helpers_expanded\empty - -\unexpanded\def\expanded#1% - {\xdef\m_syst_helpers_expanded{\noexpand#1}\m_syst_helpers_expanded} - -\unexpanded\def\startexpanded#1\stopexpanded - {\xdef\m_syst_helpers_expanded{#1}\m_syst_helpers_expanded} - -\let\stopexpanded\relax - -%D Recent \TEX\ engines have a primitive \type {\expanded} and we will use that when -%D possible. After all, we can make not expandable macros now. - -% We cannot use the next variant as first we need to adapt \type {##}'s in callers: -% -% \def\expanded#1% -% {\normalexpanded{\noexpand#1}} -% -% \def\startexpanded#1\stopexpanded -% {\normalexpanded{#1}} - -%D \macros -%D {gobbleoneargument,gobble...arguments} -%D -%D The next set of macros just do nothing, except that they get rid of a number of -%D arguments. - -\def\gobbleoneargument #1{} -\def\gobbletwoarguments #1#2{} -\def\gobblethreearguments#1#2#3{} -\def\gobblefourarguments #1#2#3#4{} -\def\gobblefivearguments #1#2#3#4#5{} -\def\gobblesixarguments #1#2#3#4#5#6{} -\def\gobblesevenarguments#1#2#3#4#5#6#7{} -\def\gobbleeightarguments#1#2#3#4#5#6#7#8{} -\def\gobbleninearguments #1#2#3#4#5#6#7#8#9{} -\def\gobbletenarguments #1{\gobbleninearguments} - -\def\gobbleoneoptional [#1]{} -\def\gobbletwooptionals [#1][#2]{} -\def\gobblethreeoptionals[#1][#2][#3]{} -\def\gobblefouroptionals [#1][#2][#3][#4]{} -\def\gobblefiveoptionals [#1][#2][#3][#4][#5]{} - -%D Reserved macros for tests: - -\let\donothing\empty - -\let\m_syst_string_one \empty -\let\m_syst_string_two \empty -\let\m_syst_string_three\empty -\let\m_syst_string_four \empty - -\let\m_syst_action_yes \empty -\let\m_syst_action_nop \empty - -%D \macros -%D {doifnextcharelse} -%D -%D When we started using \TEX\ in the late eighties, our first experiences with -%D programming concerned a simple shell around \LATEX. The commands probably use -%D most at \PRAGMA, are the itemizing ones. One of those few shell commands took -%D care of an optional argument, that enabled us to specify what kind of item symbol -%D we wanted. Without understanding anything we were able to locate a \LATEX\ macro -%D that could be used to inspect the next character. -%D -%D It's this macro that the ancester of the next one presented here. It executes one -%D of two actions, dependant of the next character. Disturbing spaces and line -%D endings, which are normally interpreted as spaces too, are skipped. -%D -%D \starttyping -%D \doifnextcharelse {karakter} {then ...} {else ...} -%D \stoptyping -%D -%D This macro differs from the original in the use of \type {\localnext} because we -%D don't want clashes with \type {\next}. - -\let\next \relax -\let\nextnext \relax -\let\nextnextnext \relax -\let\nexttoken \relax -\let\charactertoken\relax - -\let\m_syst_action_yes\relax -\let\m_syst_action_nop\relax - -% \def\syst_helpers_inspect_next_character -% {\ifx\nexttoken\blankspace -% \expandafter\syst_helpers_reinspect_next_character -% \else -% \expandafter\syst_helpers_inspect_next_character_indeed -% \fi} -% -% \def\syst_helpers_inspect_next_character_indeed -% {\ifx\nexttoken\charactertoken -% \expandafter\m_syst_action_yes -% \else -% \expandafter\m_syst_action_nop -% \fi} - -\unexpanded\def\doifelsenextchar#1#2#3% #1 should not be {} ! - {\def\m_syst_action_yes{#2}% - \def\m_syst_action_nop{#3}% - \futureexpandis#1\m_syst_action_yes\m_syst_action_nop} - -\unexpanded\def\doifelsenextcharcs % #1#2#3% #1 should not be {} ! - {\futureexpandis} - -\let\doifnextcharelse \doifelsenextchar -\let\doifnextcharcselse\doifelsenextcharcs - -%D Because we will mostly use this macro for testing if the next character is \type -%D {[}, we also make a slightly faster variant as it is not uncommon to have tens of -%D thousands of calls to this test in a run. Of course it also is more convenient to -%D read a trace then. - -% \newif\if_next_blank_space_token - -% \let\syst_helpers_next_optional_character_token=[ -% -% \def\syst_helpers_inspect_next_optional_character -% {\ifx\nexttoken\blankspace -% \expandafter\syst_helpers_reinspect_next_optional_character -% \else -% \expandafter\syst_helpers_inspect_next_optional_character_indeed -% \fi} -% -% \def\syst_helpers_inspect_next_optional_character_indeed -% {\ifx\nexttoken\syst_helpers_next_optional_character_token -% \expandafter\m_syst_action_yes -% \else -% \expandafter\m_syst_action_nop -% \fi} - -\unexpanded\def\doifelsenextoptional#1#2% - {\def\m_syst_action_yes{#1}% - \def\m_syst_action_nop{#2}% - \futureexpandis[\m_syst_action_yes\m_syst_action_nop} - -\unexpanded\def\doifelsenextoptionalcs - {\futureexpandis[} - -\let\doifnextoptionalelse \doifelsenextoptional -\let\doifnextoptionalcselse\doifelsenextoptionalcs - -% \let\syst_helpers_next_bgroup_character_token\bgroup -% -% \def\syst_helpers_inspect_next_bgroup_character -% {\ifx\nexttoken\blankspace -% \expandafter\syst_helpers_reinspect_next_bgroup_character -% \else -% \expandafter\syst_helpers_inspect_next_bgroup_character_indeed -% \fi} -% -% \def\syst_helpers_inspect_next_bgroup_character_indeed -% {\ifx\nexttoken\syst_helpers_next_bgroup_character_token -% \expandafter\m_syst_action_yes -% \else -% \expandafter\m_syst_action_nop -% \fi} - -\unexpanded\def\doifelsenextbgroup#1#2% - {\def\m_syst_action_yes{#1}% - \def\m_syst_action_nop{#2}% - \futureexpandis\bgroup\m_syst_action_yes\m_syst_action_nop} - -\unexpanded\def\doifelsenextbgroupcs % #1#2 - {\futureexpandis\bgroup} - -\let\doifnextbgroupelse \doifelsenextbgroup -\let\doifnextbgroupcselse\doifelsenextbgroupcs - -% \let\syst_helpers_next_parenthesis_character_token( -% -% \def\syst_helpers_inspect_next_parenthesis_character -% {\ifx\nexttoken\blankspace -% \expandafter\syst_helpers_reinspect_next_parenthesis_character -% \else -% \expandafter\syst_helpers_inspect_next_parenthesis_character_indeed -% \fi} -% -% \def\syst_helpers_inspect_next_parenthesis_character_indeed -% {\ifx\nexttoken\syst_helpers_next_parenthesis_character_token -% \expandafter\m_syst_action_yes -% \else -% \expandafter\m_syst_action_nop -% \fi} - -\unexpanded\def\doifelsenextparenthesis#1#2% - {\def\m_syst_action_yes{#1}% - \def\m_syst_action_nop{#2}% - \futureexpandis(\m_syst_action_yes\m_syst_action_nop} - -\let\doifnextparenthesiselse\doifelsenextparenthesis - -%D The next one is handy in predictable situations: - -\def\syst_helpers_do_if_fast_optional_check_else - {\ifx\nexttoken\syst_helpers_next_optional_character_token - \expandafter\m_syst_action_yes - \else - \expandafter\m_syst_action_nop - \fi} - -\unexpanded\def\doifelsefastoptionalcheck#1#2% - {\def\m_syst_action_yes{#1}% - \def\m_syst_action_nop{#2}% - \futureexpandis[\m_syst_action_yes\m_syst_action_nop} - -\unexpanded\def\doifelsefastoptionalcheckcs - {\futureexpandis[} - -\let\doiffastoptionalcheckelse \doifelsefastoptionalcheck -\let\doiffastoptionalcheckcselse\doifelsefastoptionalcheckcs - -%D Here's one for skipping spaces and pars, handy for: -%D -%D \starttyping -%D \hbox -%D -%D {a few lines later} -%D \stoptyping -%D -%D like: -%D -%D \starttyping -%D \def\somecommand{\dowithnextbox{\box\nextbox}\ruledhbox} -%D -%D \assumelongusagecs\somecommand -%D -%D \bgroup -%D oeps -%D \egroup -%D \stoptyping - -%D The cumbersome original: - -% \unexpanded\def\assumelongusagecs#1% -% {\let\m_syst_action#1% -% \futurelet\nexttoken\syst_helpers_ignore_spacing} -% -% \def\syst_helpers_ignore_spacing -% {\ifx\nexttoken\blankspace -% \expandafter\syst_helpers_ignore_spacing_blankspace -% \orelse\ifx\nexttoken\par -% \expandafter\syst_helpers_ignore_spacing_partoken -% \else -% \expandafter\m_syst_action -% \fi} -% -% \def\syst_helpers_ignore_spacing_partoken\par -% {\futurelet\nexttoken\syst_helpers_ignore_spacing} - -%D A bit less tracing noise: - -% \def\assume_long_usage_cs -% {\futureexpandis\par\assume_long_usage_par\m_syst_action} -% -% \def\assume_long_usage_par\par% -% {\assume_long_usage_cs} -% -% \unexpanded\def\assumelongusagecs#1{\let\m_syst_action#1\assume_long_usage_cs} - -%D Ok, using \type {\futureexpandisap} is maybe feature creep but I'd like to experiment -%D with more tolerant user input. It might go away in which case we use the above. - -\unexpanded\def\assumelongusagecs#1% - {\futureexpandisap\relax#1#1} - -% D These macros use some auxiliary macros. Although we were able to program quite -% D complicated things, I only understood these after rereading the \TEX book. The -% D trick is in using a command with a one character name. Such commands differ from -% D the longer ones in the fact that trailing spaces are {\em not} skipped. This -% D enables us to indirectly define a long named macro that gobbles a space. In the -% D first line we define \type {\blankspace}. Next we make \type {\:} equivalent to -% D \type {\reinspect...}. This one||character command is expanded before the next -% D \type {\def} comes into action. This way the space after \type {\:} becomes a -% D delimiter of the longer named \type {\reinspectnextcharacter}. - -\let\next\: - -\def\:{\let\blankspace= } \: - -% \def\:{\syst_helpers_reinspect_next_character} -% \expandafter\def\: {\let\if_next_blank_space_token\iftrue\futurelet\nexttoken\syst_helpers_inspect_next_character} -% -% \def\:{\syst_helpers_reinspect_next_optional_character} -% \expandafter\def\: {\let\if_next_blank_space_token\iftrue\futurelet\nexttoken\syst_helpers_inspect_next_optional_character} -% -% \def\:{\syst_helpers_reinspect_next_bgroup_character} -% \expandafter\def\: {\let\if_next_blank_space_token\iftrue\futurelet\nexttoken\syst_helpers_inspect_next_bgroup_character} -% -% \def\:{\syst_helpers_reinspect_next_parenthesis_character} -% \expandafter\def\: {\let\if_next_blank_space_token\iftrue\futurelet\nexttoken\syst_helpers_inspect_next_parenthesis_character} -% -% \def\:{\syst_helpers_ignore_spacing_blankspace} -% \expandafter\def\: {\futurelet\nexttoken\syst_helpers_ignore_spacing} - -\let\:\next - -%D \macros -%D {setvalue,setgvalue,setevalue,setxvalue, -%D letvalue,letgvalue,getvalue,resetvalue, -%D undefinevalue,ignorevalue} -%D -%D \TEX's primitive \type {\csname} can be used to construct all kind of commands -%D that cannot be defined with \type {\def} and \type {\let}. Every macro programmer -%D sooner or later wants macros like these. -%D -%D \starttyping -%D \setvalue {name}{...} = \def\name{...} -%D \setgvalue {name}{...} = \gdef\name{...} -%D \setevalue {name}{...} = \edef\name{...} -%D \setxvalue {name}{...} = \xdef\name{...} -%D \letvalue {name}=\... = \let\name=\... -%D \letgvalue {name}=\... = \glet\name=\... -%D \getvalue {name} = \name -%D \resetvalue {name} = \def\name{} -%D \stoptyping -%D -%D As we will see, \CONTEXT\ uses these commands many times, which is mainly due to -%D its object oriented and parameter driven character. - -\def\setvalue #1{\expandafter\def \csname#1\endcsname} -\def\setgvalue #1{\expandafter\gdef\csname#1\endcsname} -\def\setevalue #1{\expandafter\edef\csname#1\endcsname} -\def\setxvalue #1{\expandafter\xdef\csname#1\endcsname} -\def\getvalue #1{\csname#1\endcsname} % maybe: \begincsname#1\endcsname -\def\letvalue #1{\expandafter\let \csname#1\endcsname} -\def\letgvalue #1{\expandafter\glet\csname#1\endcsname} -\def\resetvalue #1{\expandafter\let \csname#1\endcsname\empty} -\def\undefinevalue#1{\expandafter\let \csname#1\endcsname\undefined} -\def\ignorevalue#1#2{\expandafter\let \csname#1\endcsname\empty} - -\def\setuvalue #1{\normalprotected\expandafter \def\csname#1\endcsname} -\def\setuevalue #1{\normalprotected\expandafter\edef\csname#1\endcsname} -\def\setugvalue #1{\normalprotected\expandafter\gdef\csname#1\endcsname} -\def\setuxvalue #1{\normalprotected\expandafter\xdef\csname#1\endcsname} - -\unexpanded\def\getuvalue#1{\csname#1\endcsname} - -%D \macros -%D {globallet,glet} -%D -%D In \CONTEXT\ of May 2000 using \type {\globallet} instead of the two tokens will -%D save us some $300\times4=1200$ bytes of format file on a 32~bit system. Not that -%D it matters much today. This shortcut is already defined: - -\let\globallet\glet - -%D \macros -%D {doifundefined,doifdefined, -%D doifundefinedelse,doifdefinedelse, -%D doifalldefinedelse} -%D -%D The standard way of testing if a macro is defined is comparing its meaning with -%D another undefined one, usually \type{\undefined}. To garantee correct working of -%D the next set of macros, \type{\undefined} may never be defined! -%D -%D \starttyping -%D \doifundefined {string} {...} -%D \doifdefined {string} {...} -%D \doifundefinedelse {string} {then ...} {else ...} -%D \doifdefinedelse {string} {then ...} {else ...} -%D \doifalldefinedelse {commalist} {then ...} {else ...} -%D \stoptyping -%D -%D Every macroname that \TEX\ builds gets an entry in the hash table, which is of -%D limited size. It is expected that \ETEX\ will offer a less memory||consuming -%D alternative. - -%D Although it will probably never be a big problem, it is good to be aware of the -%D difference between testing on a macro name to be build by using \type{\csname} and -%D \type{\endcsname} and testing the \type{\name} directly. -%D -%D \starttyping -%D \expandafter\ifx\csname NameA\endcsname\relax ... \else ... \fi -%D -%D \ifundefined\NameB ... \else ... \fi -%D \stoptyping - -% \suppressifcsnameerror\plusone % already set - -\def\doifelseundefined#1% - {\ifcsname#1\endcsname - \expandafter\secondoftwoarguments\else\expandafter\firstoftwoarguments - \fi} - -\def\doifelsedefined#1% - {\ifcsname#1\endcsname - \expandafter\firstoftwoarguments\else\expandafter\secondoftwoarguments - \fi} - -\def\doifundefined#1% - {\ifcsname#1\endcsname - \expandafter\gobbleoneargument\else\expandafter\firstofoneargument - \fi} - -\def\doifdefined#1% - {\ifcsname#1\endcsname - \expandafter\firstofoneargument\else\expandafter\gobbleoneargument - \fi} - -\let\doifundefinedelse\doifelseundefined -\let\doifdefinedelse \doifelsedefined - -%D \macros -%D {letbeundefined} -%D -%D Testing for being undefined comes down to testing on \type {\relax} when we use -%D \type {\csname}, but when using \type {\ifx}, we test on being \type -%D {\undefined}! In \ETEX\ we have \type {\ifcsname} and that way of testing on -%D existance is not the same as the one described here. Therefore we introduce: - -\unexpanded\def\letbeundefined#1% potential stack buildup when used \global - {\expandafter\let\csname#1\endcsname\undefined} % or use \undefinevalue to match \setvalue - -\unexpanded\def\localundefine#1% conditional - {\ifcsname#1\endcsname\expandafter\let\csname#1\endcsname\undefined\fi} - -\unexpanded\def\globalundefine#1% conditional - {\ifcsname#1\endcsname\expandafter\glet\csname#1\endcsname\undefined\fi} - -%D Beware, being \type {\undefined} in \ETEX\ means that the macro {\em is} defined! -%D -%D When we were developing the scientific units module, we encountered different -%D behavior in text and math mode, which was due to this grouping subtilities. We -%D therefore decided to use \type{\begingroup} instead of \type{\bgroup}. - -\unexpanded\def\doifelsealldefined#1% - {\begingroup - \donetrue % we could use a reserved one and avoid the group - \processcommalist[#1]\syst_helpers_do_if_all_defined_else - \ifdone - \endgroup\expandafter\firstoftwoarguments - \else - \endgroup\expandafter\secondoftwoarguments - \fi} - -\let\doifalldefinedelse\doifelsealldefined - -\def\syst_helpers_do_if_all_defined_else#1% - {\ifcsname#1\endcsname\else - \donefalse - \expandafter\quitcommalist % added - \fi} - -%D \macros -%D {doif,doifelse,doifnot} -%D -%D Programming in \TEX\ differs from programming in procedural languages like -%D \MODULA. This means that one --- well, let me speek for myself --- tries to do -%D the things in the well known way. Therefore the next set of \type{\ifthenelse} -%D commands were between the first ones we needed. A few years later, the opposite -%D became true: when programming in \MODULA, I sometimes miss handy things like -%D grouping, runtime redefinition, expansion etc. While \MODULA\ taught me to -%D structure, \TEX\ taught me to think recursive. -%D -%D \starttyping -%D \doif {string1} {string2} {...} -%D \doifnot {string1} {string2} {...} -%D \doifelse {string1} {string2} {then ...}{else ...} -%D \stoptyping - -\unexpanded\def\doifelse#1#2% - {\iftok{#1}{#2}% - \expandafter\firstoftwoarguments - \else - \expandafter\secondoftwoarguments - \fi} - -\unexpanded\def\doif#1#2% - {\iftok{#1}{#2}% - \expandafter\firstofoneargument - \else - \expandafter\gobbleoneargument - \fi} - -\unexpanded\def\doifnot#1#2% - {\iftok{#1}{#2}% - \expandafter\gobbleoneargument - \else - \expandafter\firstofoneargument - \fi} - -%D \macros -%D {doifempty,doifemptyelse,doifnotempty} -%D -%D We complete our set of conditionals with: -%D -%D \starttyping -%D \doifempty {string} {...} -%D \doifnotempty {string} {...} -%D \doifemptyelse {string} {then ...} {else ...} -%D \stoptyping -%D -%D This time, the string is not expanded. - -\unexpanded\def\doifelseempty#1% - {\def\m_syst_string_one{#1}% - \ifx\m_syst_string_one\empty - \expandafter\firstoftwoarguments - \else - \expandafter\secondoftwoarguments - \fi} - -\let\doifemptyelse\doifelseempty - -\unexpanded\def\doifempty#1% - {\def\m_syst_string_one{#1}% - \ifx\m_syst_string_one\empty - \expandafter\firstofoneargument - \else - \expandafter\gobbleoneargument - \fi} - -\unexpanded\def\doifnotempty#1% - {\def\m_syst_string_one{#1}% - \ifx\m_syst_string_one\empty - \expandafter\gobbleoneargument - \else - \expandafter\firstofoneargument - \fi} - -%D \macros -%D {doifinset,doifnotinset,doifinsetelse} -%D -%D We can check if a string is present in a comma separated set of strings. -%D Depending on the result, some action is taken. -%D -%D \starttyping -%D \doifinset {string} {string,...} {...} -%D \doifnotinset {string} {string,...} {...} -%D \doifinsetelse {string} {string,...} {then ...} {else ...} -%D \stoptyping - -% !0nop=\doifinsetelse{ccc}{,}{yes}{nop} -% !0nop=\doifinsetelse{ccc}{,,}{yes}{nop} -% !0nop=\doifinsetelse{ccc}{,,,}{yes}{nop} - -% !1nop=\doifinsetelse{}{}{yes}{nop} -% !2yes=\doifinsetelse{aaa}{bbb,ccc,ddd,aaa,eee}{yes}{nop} -% !3nop=\doifinsetelse{aaa}{bbb}{yes}{nop} -% !4yes=\doifinsetelse{aaa}{aaa}{yes}{nop} -% !5nop=\doifinsetelse{aaaa}{bbb,ccc,ddd,aaa,eee}{yes}{nop} -% !6nop=\doifinsetelse{}{}{yes}{nop} -% !7nop=\doifinsetelse{}{aaa}{yes}{nop} -% !8nop=\doifinsetelse{aaa}{}{yes}{nop} - -% !1=\doifinset{}{}{yes} -% !2yes=\doifinset{aaa}{bbb,ccc,ddd,aaa,eee}{yes} -% !3=\doifinset{aaa}{bbb}{yes} -% !4yes=\doifinset{aaa}{aaa}{yes} -% !5=\doifinset{}{}{yes} -% !6=\doifinset{aaa}{}{yes} - -% !1yes=\doifnotinset{}{}{yes} -% !2=\doifnotinset{aaa}{bbb,ccc,ddd,aaa,eee}{yes} -% !3yes=\doifnotinset{aaa}{bbb}{yes} -% !4=\doifnotinset{aaa}{aaa}{yes} -% !5yes=\doifnotinset{}{}{yes} -% !6yes=\doifnotinset{aaa}{}{yes} - -\unexpanded\def\doifelseinset#1#2{\clf_doifelseinset{#1}{#2}} -\unexpanded\def\doifinset #1#2{\clf_doifinset {#1}{#2}} -\unexpanded\def\doifnotinset #1#2{\clf_doifnotinset {#1}{#2}} - % \let\firstinset \clf_firstinset - -\let\doifinsetelse\doifelseinset - -%D \macros -%D {doifcommon,doifnotcommon,doifcommonelse} -%D -%D Probably the most time consuming tests are those that test for overlap in sets -%D of strings. -%D -%D \starttyping -%D \doifcommon {string,...} {string,...} {...} -%D \doifnotcommon {string,...} {string,...} {...} -%D \doifcommonelse {string,...} {string,...} {then ...} {else ...} -%D \stoptyping - -% !1yes=\doifcommonelse{aaa,bbb,ccc}{aaa,bbb,ccc}{yes}{nop} -% !2nop=\doifcommonelse{aaa,bbb,ccc}{ddd,eee,fff}{yes}{nop} -% !3nop=\doifcommonelse{aaa}{ddd,eee,fff}{yes}{nop} -% !4yes=\doifcommonelse{aaa}{aaa}{yes}{nop} -% !5nop=\doifcommonelse{bbb}{aaa}{yes}{nop} -% !6nop=\doifcommonelse{}{aaa,bbb,ccc}{yes}{nop} -% !7nop=\doifcommonelse{aaa,bbb,ccc}{}{yes}{nop} -% !8nop=\doifcommonelse{}{}{yes}{nop} - -% !9nop=\doifcommonelse{,,}{,,}{yes}{nop} -% !9yes=\doifcommonelse{,a,}{,a,}{yes}{nop} -% !9yes=\doifcommonelse{,,a,}{,a,}{yes}{nop} -% !9yes=\doifcommonelse{,a,}{,,a,}{yes}{nop} -% !9yes=\doifcommonelse{,a,}{,,,a,}{yes}{nop} -% !9yes=\doifcommonelse{,,a,}{,,,a,}{yes}{nop} - -\unexpanded\def\doifelsecommon#1#2{\clf_doifelsecommon{#1}{#2}} -\unexpanded\def\doifcommon #1#2{\clf_doifcommon {#1}{#2}} -\unexpanded\def\doifnotcommon #1#2{\clf_doifnotcommon {#1}{#2}} - -\let\doifcommonelse\doifelsecommon - -%D \macros -%D {processcommalist,processcommacommand,quitcommalist, -%D processcommalistwithparameters} -%D -%D We've already seen some macros that take care of comma separated lists. Such -%D list can be processed with -%D -%D \starttyping -%D \processcommalist[string,string,...]\commando -%D \stoptyping -%D -%D The user supplied command \type{\commando} receives one argument: the string. -%D This command permits nesting and spaces after commas are skipped. Empty sets -%D are no problem. -%D -%D \startbuffer -%D \def\dosomething#1{(#1)} -%D -%D 1: \processcommalist [\hbox{$a,b,c,d,e,f$}] \dosomething \par -%D 2: \processcommalist [{a,b,c,d,e,f}] \dosomething \par -%D 3: \processcommalist [{a,b,c},d,e,f] \dosomething \par -%D 4: \processcommalist [a,b,{c,d,e},f] \dosomething \par -%D 5: \processcommalist [a{b,c},d,e,f] \dosomething \par -%D 6: \processcommalist [{a,b}c,d,e,f] \dosomething \par -%D 7: \processcommalist [] \dosomething \par -%D 8: \processcommalist [{[}] \dosomething \par -%D \stopbuffer -%D -%D \typebuffer -%D -%D Before we show the result, we present the macro's: - -\newcount\commalevel - -\installsystemnamespace{nextcommalevel} - -\def\syst_helpers_do_do_do_process_comma_item - {\csname\??nextcommalevel\the\commalevel\endcsname} - -% \ifcase\contextlmtxmode - - \def\syst_helpers_do_process_comma_item - {\futurelet\nexttoken\syst_helpers_do_do_process_comma_item} - - \def\syst_helpers_do_do_process_comma_item - {\ifx\nexttoken\blankspace - \expandafter\syst_helpers_re_do_process_comma_item - \else - \expandafter\syst_helpers_do_do_process_comma_item_indeed - \fi} - - \def\syst_helpers_do_do_process_comma_item_indeed - {\ifx\nexttoken]% - \expandafter\gobbleoneargument - \else - \expandafter\syst_helpers_do_do_do_process_comma_item - \fi} - -% \else -% -% \def\syst_helpers_do_process_comma_item -% {\futureexpandis]\gobbleoneargument\syst_helpers_do_do_do_process_comma_item} -% -% \fi - -%D Empty arguments are not processed. Empty items (\type {,,}) however are -%D treated. We have to check for the special case \type {[{a,b,c}]}. - -\unexpanded\def\processcommalist[% - {\futurelet\nexttoken\syst_helpers_do_check_comma_item} - -\def\syst_helpers_do_check_comma_item - {\ifx\nexttoken]% - \expandafter\gobblethreearguments - \else - \expandafter\syst_helpers_do_process_comma_list - \fi - \relax} % this one preserved the next {} - -\def\syst_helpers_do_process_comma_list#1]#2% - {\global\advance\commalevel \plusone - \expandafter\def\csname\??nextcommalevel\the\commalevel\endcsname##1,% - {#2{##1}\syst_helpers_do_process_comma_item}% - \syst_helpers_do_do_process_comma_item_gobble#1,]\relax - \global\advance\commalevel \minusone } - -\def\syst_helpers_do_do_process_comma_item_gobble#1{\syst_helpers_do_do_process_comma_item} - -%D One way of quitting a commalist halfway is: - -\unexpanded\def\quitcommalist - {\begingroup\let\syst_helpers_do_process_comma_item\syst_helpers_do_quit_comma_list} - -\def\syst_helpers_do_quit_comma_list#1]% - {\endgroup} - -\unexpanded\def\quitprevcommalist - {\begingroup\let\syst_helpers_do_process_comma_item\syst_helpers_do_quit_prev_comma_list} - -\def\syst_helpers_do_quit_prev_comma_list#1]% - {\let\syst_helpers_do_process_comma_item\syst_helpers_do_quit_comma_list} - -%D The hack we used for checking the next character \type {\doifnextcharelse} -%D is also used here. - -% \ifcase\contextlmtxmode - - \let\next\: - - \def\:{\syst_helpers_re_do_process_comma_item} % \:not saved ? - - \expandafter\def\: {\futurelet\nexttoken\syst_helpers_do_do_process_comma_item} - - \let\:\next - -% \fi - -%D The previous examples lead to: -%D -%D \getbuffer - -%D When a list is saved in a macro, we can use a construction like: -%D -%D \starttyping -%D \expandafter\processcommalist\expandafter[\list]\command -%D \stoptyping -%D -%D Such solutions suit most situations, but we wanted a bit more. -%D -%D \starttyping -%D \processcommacommand[string,\stringset,string]\commando -%D \stoptyping -%D -%D where \type{\stringset} is a predefined set, like: -%D -%D \starttyping -%D \def\first{aap,noot,mies} -%D \def\second{laatste} -%D -%D \processcommacommand[\first]\message -%D \processcommacommand[\first,second,third]\message -%D \processcommacommand[\first,between,\second]\message -%D \stoptyping -%D -%D Commands that are part of the list are expanded, so the use of this macro has its -%D limits. - -\unexpanded\def\processcommacommand[#1]% - {\normalexpanded{\processcommalist[#1]}} - -%D The argument to \type{\command} is not delimited. Because we often use \type {[]} -%D as delimiters, we also have: -%D -%D \starttyping -%D \processcommalistwithparameters[string,string,...]\command -%D \stoptyping -%D -%D where \type{\command} looks like: -%D -%D \starttyping -%D \def\command[#1]{... #1 ...} -%D \stoptyping - -\unexpanded\def\processcommalistwithparameters[#1]#2% - {\def\syst_helpers_do_process_comma_list_with_parameters##1{#2[##1]}% - \processcommalist[#1]\syst_helpers_do_process_comma_list_with_parameters} - -%D \macros -%D {startprocesscommalist,startprocesscommacommand} -%D -%D Two more: - -\let\syst_helpers_comma_list_step\relax - -\unexpanded\def\startprocesscommalist[#1]#2\stopprocesscommalist - {\def\syst_helpers_comma_list_step##1{\def\currentcommalistitem{##1}#2}% - \processcommalist[#1]\syst_helpers_comma_list_step} - -\unexpanded\def\startprocesscommacommand[#1]#2\stopprocesscommacommand - {\def\syst_helpers_comma_list_step##1{\def\currentcommalistitem{##1}#2}% - \normalexpanded{\processcommalist[#1]}\syst_helpers_comma_list_step} - -\let\stopprocesscommalist \relax -\let\stopprocesscommacommand\relax - -%D \macros -%D {processaction, -%D processfirstactioninset, -%D processallactionsinset} -%D -%D \CONTEXT\ makes extensive use of a sort of case or switch command. Depending of -%D the presence of one or more provided items, some actions is taken. These macros -%D can be nested without problems. -%D -%D \starttyping -%D \processaction [x] [a=>\a,b=>\b,c=>\c] -%D \processfirstactioninset [x,y,z] [a=>\a,b=>\b,c=>\c] -%D \processallactionsinset [x,y,z] [a=>\a,b=>\b,c=>\c] -%D \stoptyping -%D -%D We can supply both a \type {default} action and an action to be undertaken when -%D an \type {unknown} value is met: -%D -%D \starttyping -%D \processallactionsinset -%D [x,y,z] -%D [ a=>\a, -%D b=>\b, -%D c=>\c, -%D default=>\default, -%D unknown=>\unknown{... \commalistelement ...}] -%D \stoptyping -%D -%D When \type {#1} is empty, this macro scans list \type {#2} for the keyword \type -%D {default} and executed the related action if present. When \type {#1} is non -%D empty and not in the list, the action related to \type {unknown} is executed. -%D Both keywords must be at the end of list \type{#2}. Afterwards, the actually -%D found keyword is available in \type {\commalistelement}. An advanced example of -%D the use of this macro can be found in \PPCHTEX, where we completely rely on \TEX\ -%D for interpreting user supplied keywords like \type {SB}, \type {SB1..6}, \type -%D {SB125} etc. - -\newcount\processlevel - -\unexpanded\def\syst_helpers_do_compare_process_action_a[#1=>#2][#3]% - {\edef\m_syst_string_two{#1}% - \ifx\m_syst_string_two\s!default - \let\commalistelement\empty - #2% - \fi} - -% met \quitcommalist tot meer dan 25\% sneller - -\unexpanded\def\syst_helpers_do_compare_process_action_b[#1=>#2][#3]% - {\edef\m_syst_string_two{#1}% - \ifx\m_syst_string_one\m_syst_string_two - \def\commalistelement{#3}% - #2% - \expandafter\quitcommalist - \orelse\ifx\m_syst_string_two\s!unknown - \def\commalistelement{#3}% beware of loops - #2% - \fi} - -\unexpanded\def\processaction[#1]#2[% - {\edef\m_syst_string_one{#1}% - \ifx\m_syst_string_one\empty - \let\syst_helpers_do_compare_process_action\syst_helpers_do_compare_process_action_a - \else - \let\syst_helpers_do_compare_process_action\syst_helpers_do_compare_process_action_b - \fi - \edef\syst_helpers_do_process_action##1{\syst_helpers_do_compare_process_action[##1][#1]}% expands #1 - \processnextcommalist\relax\relax\syst_helpers_do_process_action[} - -\unexpanded\def\syst_helpers_do_compare_process_action_c[#1=>#2][#3]% - {\edef\m_syst_string_one{#1}% - \edef\m_syst_string_two{#3}% - \ifx\m_syst_string_one\m_syst_string_two - \def\commalistelement{#3}% - #2% - \expandafter\quitprevcommalist - \else - \edef\m_syst_string_one{#1}% - \ifx\m_syst_string_one\s!unknown - \def\commalistelement{#3}% - #2% - \fi - \fi} - -\unexpanded\def\processfirstactioninset[#1]% - {\edef\m_syst_string_one{#1}% - \ifx\m_syst_string_one\empty - \expandafter\processaction - \else - \expandafter\syst_helpers_process_first_action_in_set_indeed - \fi - [#1]} - -\unexpanded\def\syst_helpers_process_first_action_in_set_indeed[#1]#2[#3]% - {\def\syst_helpers_do_process_action##1% - {\def\syst_helpers_do_do_process_action####1{\syst_helpers_do_compare_process_action_c[####1][##1]}% - \processcommalist[#3]\syst_helpers_do_do_process_action}% - \normalexpanded{\processcommalist[#1]}\syst_helpers_do_process_action} - -\unexpanded\def\syst_helpers_do_compare_process_action_d[#1=>#2][#3]% - {\edef\m_syst_string_one{#1}% - \edef\m_syst_string_two{#3}% - \ifx\m_syst_string_one\m_syst_string_two - \def\commalistelement{#3}% - #2% - \expandafter\quitcommalist - \else - \edef\m_syst_string_one{#1}% - \ifx\m_syst_string_one\s!unknown - \def\commalistelement{#3}% - #2% - \fi - \fi} - -\installsystemnamespace{nextactionlevel} - -\unexpanded\def\syst_helpers_do_process_all_actions_in_set - {\csname\??nextactionlevel\the\processlevel\endcsname} - -\unexpanded\def\processallactionsinset[#1]% - {\edef\m_syst_string_one{#1}% - \ifx\m_syst_string_one\empty - \expandafter\processaction - \else - \expandafter\syst_helpers_process_all_actions_in_set_indeed - \fi - [#1]} - -\unexpanded\def\syst_helpers_process_all_actions_in_set_indeed[#1]#2[#3]% - {\advance\processlevel \plusone - \expandafter\def\csname\??nextactionlevel\the\processlevel\endcsname##1% - {\def\syst_helpers_do_do_process_action####1{\syst_helpers_do_compare_process_action_d[####1][##1]}% - \processcommalist[#3]\syst_helpers_do_do_process_action}% - \normalexpanded{\processcommalist[#1]}\syst_helpers_do_process_all_actions_in_set - \advance\processlevel\minusone} - -%D These macros use: - -\unexpanded\def\processnextcommalist#1#2#3[#4#5]% - {#1% - \let\nexttoken#4% - \global\advance\commalevel \plusone - \expandafter\def\csname\??nextcommalevel\the\commalevel\endcsname##1,% - {#3{##1}\syst_helpers_do_process_comma_item}% - \syst_helpers_do_do_process_comma_item#4#5,]\relax - \global\advance\commalevel\minusone - #2} - -%D \macros -%D {getfirstcharacter, firstcharacter, remainingcharacters, doiffirstcharacter} -%D -%D Sometimes the action to be undertaken depends on the next character. This macro -%D get this character and puts it in \type {\firstcharacter}. -%D -%D \starttyping -%D \getfirstcharacter {string} -%D \stoptyping -%D -%D A two step expansion is used to prevent problems with complicated arguments, for -%D instance arguments that consist of two or more expandable tokens. - -\let\firstcharacter \empty -\let\remainingcharacters\empty - -\unexpanded\def\getfirstcharacter #1{\clf_getfirstcharacter{#1}} -\unexpanded\def\doifelsefirstchar #1#2{\clf_doifelsefirstchar{#1}{#2}} -\unexpanded\def\thefirstcharacter #1{\clf_thefirstcharacter{#1}} -\unexpanded\def\theremainingcharacters#1{\clf_theremainingcharacters{#1}} - -\let\doiffirstcharelse\doifelsefirstchar - -%D \macros -%D {doifinstringelse, doifincsnameelse} -%D -%D We can check for the presence of a substring in a given sequence of characters. -%D -%D \starttyping -%D \doifinsetelse {substring} {string} {then ...} {else ...} -%D \stoptyping - -\let\m_syst_sub_string\empty - -\unexpanded\def\doifelseinstring#1% - {\edef\m_syst_sub_string{#1}% expand #1 here - \ifx\m_syst_sub_string\empty - \expandafter\thirdofthreearguments - \else - \expandafter\syst_helpers_do_if_in_string_else_indeed - \fi} - -\let\doifinstringelse\doifelseinstring - -\unexpanded\def\syst_helpers_do_if_in_string_else_indeed#1% - {\syst_helpers_do_if_in_string_else\m_syst_sub_string{#1}% - \expandafter\firstoftwoarguments - \else - \expandafter\secondoftwoarguments - \fi} - -\unexpanded\def\doifinstring#1%% - {\edef\m_syst_sub_string{#1}% expand #1 here - \ifx\m_syst_sub_string\empty - \expandafter\gobbletwoarguments - \else - \expandafter\syst_helpers_do_if_in_string_indeed - \fi} - -\unexpanded\def\syst_helpers_do_if_in_string_indeed#1% - {\syst_helpers_do_if_in_string_else\m_syst_sub_string{#1}% - \expandafter\firstofoneargument - \else - \expandafter\gobbleoneargument - \fi} - -\unexpanded\def\doifnotinstring#1%% - {\edef\m_syst_sub_string{#1}% expand #1 here - \ifx\m_syst_sub_string\empty - \expandafter\gobbletwoarguments - \else - \expandafter\syst_helpers_do_if_not_in_string_indeed - \fi} - -\unexpanded\def\syst_helpers_do_if_not_in_string_indeed#1% - {\syst_helpers_do_if_in_string_else\m_syst_sub_string{#1}% - \expandafter\gobbleoneargument - \else - \expandafter\firstofoneargument - \fi} - -% replaces prev - -\unexpanded\def\syst_helpers_do_if_in_string_else#1#2% ##2 can be {abc} - {\expandafter\def\expandafter\syst_helpers_do_do_if_in_string_else - \expandafter##\expandafter1#1##2##3^^^^0004{\unless\if##2@}% expand #1 here - \expandafter\syst_helpers_do_do_if_in_string_else\normalexpanded{#2#1}@@^^^^0004} % expand #2 here - -%D The next alternative proved to be upto twice as fast on tasks like checking -%D reserved words in pretty verbatim typesetting! This is mainly due to the fact -%D that passing (expanded) strings is much slower that passing a macro. -%D -%D \starttyping -%D \doifincsnameelse {substring} {\string} {then ...} {else ...} -%D \stoptyping -%D -%D Where \type {\doifinstringelse} does as much expansion as possible, the latter -%D alternative does minimal (one level) expansion. - -\unexpanded\def\syst_helpers_do_if_in_csname_else#1#2% - {\def\syst_helpers_do_do_if_in_csname_else##1#1##2##3^^^^0004% - {\unless\if##2@}% - \expandafter\syst_helpers_do_do_if_in_csname_else#2#1@@^^^^0004} - -\unexpanded\def\doifelseincsname#1#2% - {\normalexpanded{\syst_helpers_do_if_in_csname_else{#1}}{#2}% - \expandafter\firstoftwoarguments - \else - \expandafter\secondoftwoarguments - \fi} - -\let\doifincsnameelse\doifelseincsname - -%D \macros -%D {doifnumberelse,doifnumber,doifnotnumber} -%D -%D The next macro executes a command depending of the outcome of a test on numerals. -%D This is probably one of the fastest test possible, exept from a less robust -%D 10||step \type {\if}||ladder or some tricky \type {\lcode} checking. -%D -%D \starttyping -%D \doifnumberelse {string} {then ...} {else ...} -%D \stoptyping -%D -%D The macro accepts \type {123}, \type {abc}, \type {{}}, \type {\getal} and \type -%D {\the\count...}. This macro is a rather dirty one. - -\def\doifelsenumber#1% - {\ifchknum#1\or - \expandafter\firstoftwoarguments - \else - \expandafter\secondoftwoarguments - \fi} - -\def\doifnumber#1% - {\ifchknum#1\or - \expandafter\firstoftwoarguments - \else - \expandafter\gobbleoneargument - \fi} - -\def\doifnotnumber#1% - {\ifchknum#1\or - \expandafter\gobbleoneargument - \else - \expandafter\firstofoneargument - \fi} - -\let\doifnumberelse\doifelsenumber - -%D \macros -%D {setpercentdimen} -%D -%D \starttyping -%D \scratchdimen=100pt \setpercentdimen\scratchdimen{10\letterpercent} -%D \scratchdimen=100pt \setpercentdimen\scratchdimen{5pt} -%D \scratchdimen \percentdimen \hsize {10\letterpercent} -%D \stoptyping - -\def\percentdimen#1#2% dimen percentage (with %) - {\dimexpr\clf_percentageof{#2}\dimexpr#1\relax} - -\unexpanded\def\setpercentdimen#1#2% dimen percentage (with %) - {#1=\clf_percentageof{#2}\dimexpr#1\relax} - -%D \macros -%D {makerawcommalist, -%D rawdoinsetelse, -%D rawprocesscommalist, -%D rawprocessaction} -%D -%D Some of the commands mentioned earlier are effective but slow. When one is -%D desperately in need of faster alternatives and when the conditions are -%D predictable safe, the \type {\raw} alternatives come into focus. A major drawback -%D is that they do not take \type {\c!constants} into account, simply because no -%D expansion is done. This is no problem with \type {\rawprocesscommalist}, because -%D this macro does not compare anything. Expandable macros are permitted as search -%D string. -%D -%D \starttyping -%D \makerawcommalist[string,string,...]\stringlist -%D \rawdoifelseinset{string}{string,...}{...}{...} -%D \rawprocesscommalist[string,string,...]\commando -%D \rawprocessaction[x][a=>\a,b=>\b,c=>\c] -%D \stoptyping -%D -%D Spaces embedded in the list, for instance after commas, spoil the search process. -%D The gain in speed depends on the length of the argument (the longer the argument, -%D the less we gain). - -\unexpanded\def\makerawcommalist[#1]#2% use \processnext ... here - {\def\syst_helpers_do_make_raw_comma_list##1% we don't expand ##1 - {\ifx#2\empty - \def#2{##1}% - \else - \expandafter\def\expandafter#2\expandafter{#2,##1}% - \fi}% - \let#2\empty - \processcommalist[#1]\syst_helpers_do_make_raw_comma_list} - -\def\syst_helpers_raw_process_comma_item#1,#2% #2 eats up preceding space - {\if]#1\else - \csname\??nextcommalevel\the\commalevel\endcsname{#1}% - \expandafter\syst_helpers_raw_process_comma_item - \fi#2} - -\unexpanded\def\rawprocesscommalist[#1]#2% accepteert ook [\cs] - {\global\advance\commalevel \plusone - \expandafter\let\csname\??nextcommalevel\the\commalevel\endcsname#2% - \expandafter\syst_helpers_raw_process_comma_item#1,],% \relax - \global\advance\commalevel \minusone } - -\unexpanded\def\rawprocesscommacommand[#1]% not really needed - {\normalexpanded{\rawprocesscommalist[#1]}} - -%D Here is one without nesting: - -\unexpanded\def\syst_helpers_fast_process_comma_item#1,#2% #2 eats up preceding space - {\if]#1\else - \syst_helpers_fast_process_comma_command{#1}% - \expandafter\syst_helpers_fast_process_comma_item - \fi#2} - -\unexpanded\def\fastprocesscommalist[#1]#2% accepteert ook [\cs] - {\let\syst_helpers_fast_process_comma_command#2% - \expandafter\syst_helpers_fast_process_comma_item#1,],}% \relax - -\unexpanded\def\fastprocesscommacommand[#1]#2% accepteert ook [\cs] - {\let\syst_helpers_fast_process_comma_command#2% - \normalexpanded{\syst_helpers_fast_process_comma_item#1},],}% \relax - -% \def\rawdoifelseinset#1#2{\doifinstringelse{,#1,}{,#2,}} -% \def\rawdoifinset #1#2{\doifinstring {,#1,}{,#2,}} - -\def\m_syst_two_commas{,,} - -\unexpanded\def\rawdoifelseinset#1% - {\edef\m_syst_sub_string{,#1,}% expand #1 here - \ifx\m_syst_sub_string\m_syst_two_commas - \expandafter\thirdofthreearguments - \else - \expandafter\syst_helpers_raw_do_if_in_set_else - \fi} - -\let\rawdoifinsetelse\rawdoifinsetelse - -\unexpanded\def\syst_helpers_raw_do_if_in_set_else#1% - {\syst_helpers_do_if_in_string_else\m_syst_sub_string{,#1,}% - \expandafter\firstoftwoarguments - \else - \expandafter\secondoftwoarguments - \fi} - -\unexpanded\def\rawdoifinset#1% - {\edef\m_syst_sub_string{,#1,}% expand #1 here - \ifx\m_syst_sub_string\m_syst_two_commas - \expandafter\gobbletwoarguments - \else - \expandafter\syst_helpers_raw_do_if_in_set - \fi} - -\unexpanded\def\syst_helpers_raw_do_if_in_set#1%% - {\syst_helpers_do_if_in_string_else\m_syst_sub_string{,#1,}% - \expandafter\firstofoneargument - \else - \expandafter\gobbleoneargument - \fi} - -%D Some more raw material: - -\def\syst_helpers_do_raw_process_action[#1][#2]% - {\def\syst_helpers_do_do_raw_process_action##1,#1=>##2,##3^^^^0004% - {\if##3@\else - \def\m_syst_helpers_process_action{##2}% - \fi}% - \syst_helpers_do_do_raw_process_action,#2,#1=>,@^^^^0004} - -\unexpanded\def\rawprocessaction[#1]#2[#3]% - {\edef\m_syst_string_one{#1}% - \edef\m_syst_string_two{undefined}% better \!!undefined - \let\m_syst_helpers_process_action\m_syst_string_two - \ifx\m_syst_string_one\empty - \expandafter\syst_helpers_do_raw_process_action\expandafter[\s!default][#3]% - \else - \expandafter\syst_helpers_do_raw_process_action\expandafter[\m_syst_string_one][#3]% - \ifx\m_syst_helpers_process_action\m_syst_string_two - \expandafter\syst_helpers_do_raw_process_action\expandafter[\s!unknown][#3]% - \fi - \fi - \ifx\m_syst_helpers_process_action\m_syst_string_two - \else - \m_syst_helpers_process_action - \fi} - -%D When we process the list \type {a,b,c,d,e}, the raw routine takes over 30\% less -%D time, when we feed $20+$ character strings we gain about 20\%. Alternatives which -%D use \type {\futurelet} perform worse. Part of the speedup is due to the \type -%D {\let} and \type {\expandafter} in the test. -%D -%D \macros -%D {dosetvalue,dosetevalue,dosetgvalue,docopyvalue,doresetvalue, -%D dogetvalue} -%D -%D When we are going to do assignments, we have to take multi||linguality into account. -%D For the moment we keep things simple and single||lingual. -%D -%D \starttyping -%D \dosetvalue {label} {variable} {value} -%D \dosetevalue {label} {variable} {value} -%D \dosetgvalue {label} {variable} {value} -%D \docopyvalue {to label} {from label} {variable} -%D \doresetvalue {label} {variable} -%D \stoptyping -%D -%D These macros are in fact auxiliary ones and are not meant for use outside the -%D assignment macros. - -\def\dosetvalue#1#2% #3 - {\expandafter\def\csname#1#2\endcsname} % {#3}} - -\def\dosetevalue#1#2% #3 - {\expandafter\edef\csname#1#2\endcsname} % {#3}} - -\def\dosetgvalue#1#2% #3 - {\expandafter\gdef\csname#1#2\endcsname} % {#3}} - -\def\doresetvalue#1#2% - {\expandafter\let\csname#1#2\endcsname\empty} - -\def\doignorevalue#1#2#3% - {\expandafter\let\csname#1#2\endcsname\empty} - -\def\docopyvalue#1#2#3% - {\expandafter\def\csname#1#3\endcsname{\csname#2#3\endcsname}} - -%D \macros -%D {doassign,undoassign,doassignempty} -%D -%D Assignments are the backbone of \CONTEXT. Abhorred by the concept of style file -%D hacking, we took a considerable effort in building a parameterized system. -%D Unfortunately there is a price to pay in terms of speed. Compared to other -%D packages and taking the functionality of \CONTEXT\ into account, the total size -%D of the format file is still very acceptable. Now how are these assignments done. -%D -%D Assignments can be realized with: -%D -%D \starttyping -%D \doassign[label][variable=value] -%D \undoassign[label][variable=value] -%D \stoptyping -%D -%D and: -%D -%D \starttyping -%D \doassignempty[label][variable=value] -%D \stoptyping -%D -%D Assignments like \type{\doassign} are compatible with: -%D -%D \starttyping -%D \def\labelvariable{value} -%D \stoptyping -%D -%D We do check for the presence of an \type{=} and loudly complain of it's missed. We -%D will redefine this macro later on, when a more advanced message mechanism is -%D implemented. - -\unexpanded\def\showassignerror#1#2% - {\writestatus{setup}{missing or ungrouped '=' after '#1' in line #2}} - -\unexpanded\def\doassignempty[#1][#2=#3]% - {\ifcsname#1#2\endcsname\else\dosetvalue{#1}{#2}{#3}\fi} - -%D \macros -%D {getparameters,geteparameters,getgparameters, -%D forgetparameters} -%D -%D Using the assignment commands directly is not our ideal of user friendly interfacing, -%D so we take some further steps. -%D -%D \starttyping -%D \getparameters [label] [...=...,...=...] -%D \forgetparameters [label] [...=...,...=...] -%D \stoptyping -%D -%D Again, the label identifies the category a variable belongs to. The second argument -%D can be a comma separated list of assignments. -%D -%D \starttyping -%D \getparameters -%D [demo] -%D [alfa=1, -%D beta=2] -%D \stoptyping -%D -%D is equivalent to -%D -%D \starttyping -%D \def\demoalfa{1} -%D \def\demobeta{2} -%D \stoptyping -%D -%D -%D In the pre||multi||lingual stadium \CONTEXT\ took the next approach. With -%D -%D \starttyping -%D \def\??demo {@@demo} -%D \def\!!alfa {alfa} -%D \def\!!beta {beta} -%D \stoptyping -%D -%D calling -%D -%D \starttyping -%D \getparameters -%D [\??demo] -%D [\!!alfa=1, -%D \!!beta=2] -%D \stoptyping -%D -%D lead to: -%D -%D \starttyping -%D \def\@@demoalfa{1} -%D \def\@@demobeta{2} -%D \stoptyping -%D -%D Because we want to be able to distinguish the \type{!!} pre||tagged user supplied -%D variables from internal counterparts, we will introduce a slightly different tag -%D in the multi||lingual modules. There we will use \type{c!} or \type{v!}, -%D depending on the context. -%D -%D By calling \type{doassign} directly, we save ourselves some argument passing -%D and gain some speed. Whatever optimizations we do, this command will always be -%D one of the bigger bottlenecks. The alternative \type{\geteparameters} --- it's -%D funny to see that this alternative saw the light so lately --- can be used to do -%D expanded assigments. - -\let\currentvalue\empty - -\unexpanded\def\getparameters {\dogetparameters\dosetvalue} -\unexpanded\def\geteparameters {\dogetparameters\dosetevalue} -\unexpanded\def\getgparameters {\dogetparameters\dosetgvalue} -\unexpanded\def\getxparameters {\dogetparameters\dosetxvalue} -\unexpanded\def\forgetparameters{\dogetparameters\doignorevalue} - -\let\getexpandedparameters\geteparameters - -\unexpanded\def\dogetparameters#1[#2]#3[#4% - {\if\noexpand#4]% - \expandafter\gobbleoneargument - \else - \let\setsomevalue#1% - \def\syst_helpers_get_parameters_assign{\syst_helpers_get_parameters_assign_indeed#2}% - \expandafter\syst_helpers_get_parameters - \fi#4} - -\def\syst_helpers_get_parameters#1]% - {\xprocesscommaitem#1,],^^^^0004} - -\def\syst_helpers_process_comma_item#1,#2% #2 takes space before , - {\if,#1,% dirty trick for testing #1=empty - \expandafter\syst_helpers_process_comma_item - \orelse\if]#1% - \expandafter\gobbleoneargument - \else - \syst_helpers_get_parameters_assign^^^^0004#1==\empty^^^^0004% - \expandafter\syst_helpers_process_comma_item - \fi#2} - -\def\syst_helpers_assign_error#1#2#3% - {\showassignerror{#2}{\the\inputlineno\space(#1)}} - -\def\syst_helpers_get_parameters_assign_normal#1^^^^0004#2=#3=#4#5^^^^0004% - {\ifx\empty#2\empty - \expandafter\syst_helpers_assign_error - \orelse\ifx#4\empty - \expandafter\syst_helpers_assign_error - \else - \expandafter\setsomevalue - \fi - {#1}{#2}{#3}} - -\def\syst_helpers_get_parameters_assign_error#1^^^^0004#2=#3=#4#5^^^^0004% - {\ifx\empty#2\empty - \expandafter\syst_helpers_assign_error - \orelse\ifx#4\empty - \expandafter\syst_helpers_assign_error - \orelse\ifcsname#1#2\endcsname - \expandafter\let\expandafter\currentvalue\csname#1#2\endcsname - \expandafter\setsomevalue - \else - \let\currentvalue\empty - \expandafter\setsomevalue - \fi - {#1}{#2}{#3}} - -\let\syst_helpers_get_parameters_assign_indeed\syst_helpers_get_parameters_assign_normal - -\unexpanded\def\doassign [#1][#2]{\let\setsomevalue\dosetvalue \syst_helpers_get_parameters_assign_indeed#1^^^^0004#2==\empty^^^^0004} -\unexpanded\def\doeassign [#1][#2]{\let\setsomevalue\dosetevalue \syst_helpers_get_parameters_assign_indeed#1^^^^0004#2==\empty^^^^0004} -\unexpanded\def\undoassign[#1][#2]{\let\setsomevalue\doresetvalue\syst_helpers_get_parameters_assign_indeed#1^^^^0004#2==\empty^^^^0004} - -%D \macros -%D {processassignmentlist,processassignmentcommand, -%D startprocessassignmentlist,startprocessassignmentcommand} -%D -%D For Wolfgang: -%D -%D \starttyping -%D \def\showpair#1#2{key:#1, value:#2\par} -%D \processassignmentlist[a=1,b=2]\showpair -%D \stoptyping -%D -%D We can optimize this one if needed but it's not a core macro so hardly worth the -%D trouble and tokens. - -\unexpanded\def\processassignmentlist[#1]#2% #2 == \command{key}{value] - {\def\syst_helpers_process_assignment_entry##1{#2}% {##2}{##3} % namespace is ignored - \dogetparameters\syst_helpers_process_assignment_entry[][#1]} - -\unexpanded\def\processassignmentcommand[#1]% - {\normalexpanded{\processassignmentlist[#1]}} - -\unexpanded\def\startprocessassignmentlist[#1]#2\stopprocessassignmentlist - {\def\currentassignmentlistcommand##1##2{\def\currentassignmentlistkey{##1}\def\currentassignmentlistvalue{##2}#2}% - \processassignmentlist[#1]\currentassignmentlistcommand} - -\unexpanded\def\startprocessassignmentcommand[#1]#2\stopprocessassignmentcommand - {\def\currentassignmentlistcommand##1##2{\def\currentassignmentlistkey{##1}\def\currentassignmentlistvalue{##2}#2}% - \normalexpanded{\processassignmentlist[#1]}\currentassignmentlistcommand} - -%D \macros{currentvalue} -%D -%D Just in case a \type{\getparameter} argument itself ends up inside a \type -%D {\write} or other expandable location, our new macro needs a default value. -%D -%D \starttyping -%D \getparameters[xxx][aaa=bbb]\par -%D \getparameters[xxx][=bbb]\par -%D \getparameters[xxx][aaa=]\par -%D \getparameters[xxx][=]\par -%D \getparameters[xxx][aaa]\par -%D \stoptyping - -%D \macros -%D {expandparameters} -%D -%D Example usage: -%D -%D \startbuffer -%D \getparameters[taco][name=taco] -%D \convertcommand\taconame\to\ascii \ascii -%D \expandparameters \getparameters[taco][name=\currentvalue\space hoekwater] -%D \convertcommand\taconame\to\ascii \ascii -%D \getparameters[taco][name=\currentvalue\space hoekwater] -%D \convertcommand\taconame\to\ascii \ascii -%D \stopbuffer -%D -%D \typebuffer -%D \startlines -%D \getbuffer -%D \stoplines -%D -%D Here we hook in the code (beware, this is the optimized get **): - -\def\syst_helpers_get_parameters_normal#1]% - {\syst_helpers_process_comma_item#1,],^^^^0004} - -\def\syst_helpers_get_parameters_expanded#1]% - {\let\dosetnvalue\setsomevalue - \let\setsomevalue\dosetevalue - \let\syst_helpers_get_parameters_assign_indeed\syst_helpers_get_parameters_assign_error - \let\setsomevalue\dosetevalue - \syst_helpers_process_comma_item#1,],^^^^0004% - \let\syst_helpers_get_parameters_assign_indeed\syst_helpers_get_parameters_assign_normal - \let\setsomevalue\dosetnvalue - \let\syst_helpers_get_parameters\syst_helpers_get_parameters_normal - \let\currentvalue\empty} - -\let\syst_helpers_get_parameters\syst_helpers_get_parameters_normal % ** - -\unexpanded\def\expandparameters - {\let\syst_helpers_get_parameters\syst_helpers_get_parameters_expanded} - -%D \macros -%D {getemptyparameters} -%D -%D Sometimes we explicitly want variables to default to an empty string, so we -%D welcome: -%D -%D \starttyping -%D \getemptyparameters [label] [...=...,...=...] -%D \stoptyping - -\unexpanded\def\getemptyparameters[#1]#2[#3]% - {\def\syst_helpers_get_empty_parameters##1{\doassignempty[#1][##1]}% - \processcommalist[#3]\syst_helpers_get_empty_parameters} - -%D \macros -%D {copyparameters} -%D -%D Some \CONTEXT\ commands take their default setups from others. All commands that -%D are able to provide backgounds or rules around some content, for instance default -%D to the standard command for ruled boxes. Is situations like this we can use: -%D -%D \starttyping -%D \copyparameters [to-label] [from-label] [name1,name2,...] -%D \stoptyping -%D -%D For instance -%D -%D \starttyping -%D \copyparameters -%D [internal][external] -%D [alfa,beta] -%D \stoptyping -%D -%D Leads to: -%D -%D \starttyping -%D \def\internalalfa {\externalalfa} -%D \def\internalbeta {\externalbeta} -%D \stoptyping -%D -%D By using \type {\docopyvalue} we've prepared this command for use in a -%D multi||lingual environment. - -\unexpanded\def\copyparameters[#1]#2[#3]#4[#5]% - {\doifnot{#1}{#3} - {\def\syst_helpers_copy_parameter{\docopyvalue{#1}{#3}}% ##1 - \processcommalist[#5]\syst_helpers_copy_parameter}} - -%D \macros -%D {ifparameters,checkparameters} -%D -%D A slightly different one is \type {\checkparameters}, which also checks on the -%D presence of a~\type {=}. -%D -%D The boolean \type {\ifparameters} can be used afterwards. Combining both in one -%D \type {\if}||macro would lead to problems with nested \type {\if}'s. -%D -%D \starttyping -%D \checkparameters[argument] -%D \stoptyping - -\newif\ifparameters - -\def\syst_helpers_check_parameters#1=#2#3^^^^0004% - {\if#2^^^^0003\parametersfalse\else\parameterstrue\fi} - -\unexpanded\def\checkparameters[#1]% - {\syst_helpers_check_parameters#1=^^^^0003^^^^0003^^^^0004} - -%D \macros -%D {getfromcommalist,getfromcommacommand, -%D commalistelement, -%D getcommalistsize,getcommacommandsize} -%D -%D It's possible to get an element from a commalist or a command representing -%D a commalist. -%D -%D \starttyping -%D \getfromcommalist [string] [n] -%D \getfromcommacommand [string,\strings,string,...] [n] -%D \stoptyping -%D -%D The difference betwee the two of them is the same as the difference between -%D \type {\processcomma...}. The found string is stored in \type -%D {\commalistelement}. -%D -%D We can calculate the size of a comma separated list by using: -%D -%D \starttyping -%D \getcommalistsize [string,string,...] -%D \getcommacommandsize [string,\strings,string,...] -%D \stoptyping -%D -%D Afterwards, the length is available in the macro \type {\commalistsize} -%D (not a \COUNTER). - -\newcount\commalistcounter - -\def\commalistsize{0} - -\def\syst_helpers_get_comma_list_size#1% - {\advance\commalistcounter\plusone} - -\unexpanded\def\getcommalistsize#1]% don't loose [{#1}] - {\commalistcounter\zerocount - \processcommalist#1]\syst_helpers_get_comma_list_size % was [{#1}] - \edef\commalistsize{\the\commalistcounter}} - -% \def\getcommacommandsize[#1]% -% {\edef\commacommand{#1}% -% \scratchtoks\expandafter{\expandafter[\commacommand]}% -% \expandafter\getcommalistsize\the\scratchtoks } - -\unexpanded\def\getcommacommandsize[#1]% - {\normalexpanded{\getcommalistsize[#1]}} - -\def\syst_helpers_get_from_comma_list#1% - {\advance\commalistcounter \minusone - \ifcase\commalistcounter - \def\commalistelement{#1}% - \expandafter\quitcommalist - \fi} - -\unexpanded\def\getfromcommalist[#1]#2[#3]% - {\let\commalistelement\empty - \commalistcounter#3\relax - \processcommalist[#1]\syst_helpers_get_from_comma_list} - -\unexpanded\def\getfromcommacommand[#1]% - {\normalexpanded{\getfromcommalist[#1]}} - -%D Watertight (and efficient) solutions are hard to find, due to the handling of -%D braces during parameters passing and scanning. Nevertheless: -%D -%D \startbuffer -%D \def\dosomething#1{(#1=\commalistsize) } -%D -%D \getcommalistsize [\hbox{$a,b,c,d,e,f$}] \dosomething 1 -%D \getcommalistsize [{a,b,c,d,e,f}] \dosomething 1 -%D \getcommalistsize [{a,b,c},d,e,f] \dosomething 4 -%D \getcommalistsize [a,b,{c,d,e},f] \dosomething 4 -%D \getcommalistsize [a{b,c},d,e,f] \dosomething 4 -%D \getcommalistsize [{a,b}c,d,e,f] \dosomething 4 -%D \getcommalistsize [] \dosomething 0 -%D \getcommalistsize [{[}] \dosomething 1 -%D \stopbuffer -%D -%D \typebuffer -%D -%D reports: -%D -%D \getbuffer - -%D \macros -%D {dogetcommalistelement,dogetcommacommandelement} -%D -%D For low level (fast) purposes, we can also use the next alternative, which can -%D handle 8~elements at most. -%D -%D \starttyping -%D \dogetcommalistelement1\from a,b,c\to\commalistelement -%D \stoptyping - -\def\syst_helpers_get_comma_list_element#1\from#2,#3,#4,#5,#6,#7,#8\to#9% - {\edef#9{\ifcase#1\relax\or#2\or#3\or#4\or#5\or#6\or#7\or#8\fi}} - -\def\dogetcommacommandelement#1\from#2\to% - {\expandafter\syst_helpers_get_comma_list_element\expandafter#1\expandafter\from#2,,,,,,\to} - -%D \macros -%D {dosingleargument,dodoubleargument,dotripleargument, -%D doquadrupleargument,doquintupleargument,dosixtupleargument, -%D doseventupleargument} -%D -%D When working with delimited arguments, spaces and lineendings can interfere. The -%D next set of macros uses \TEX' internal scanner for grabbing everything between -%D arguments. Forgive me the funny names. -%D -%D \starttyping -%D \dosingleargument\commando = \commando[#1] -%D \dodoubleargument\commando = \commando[#1][#2] -%D \dotripleargument\commando = \commando[#1][#2][#3] -%D \doquadrupleargument\commando = \commando[#1][#2][#3][#4] -%D \doquintupleargument\commando = \commando[#1][#2][#3][#4][#5] -%D \dosixtupleargument\commando = \commando[#1][#2][#3][#4][#5][#6] -%D \doseventupleargument\command = \commando[#1][#2][#3][#4][#5][#6][#7] -%D \stoptyping -%D -%D These macros are used in the following way: -%D -%D \starttyping -%D \def\dosetupsomething[#1][#2]% -%D {... #1 ... #2 ...} -%D -%D \unexpanded\def\setupsomething -%D {\dodoubleargument\dosetupsomething} -%D \stoptyping -%D -%D The implementation can be surprisingly simple and needs no -%D further explanation, like: -%D -%D \starttyping -%D \def\dosingleargument#1[#2]% -%D {#1[#2]} -%D \def\dotripleargument#1[#2]#3[#4]#5[#6]% -%D {#1[#2][#4][#6]} -%D \def\doquintupleargument#1% -%D {\def\dodoquintupleargument[##1]##2[##3]##4[##5]##6[##7]##8[##9]% -%D {#1[##1][##3][##5][##7][##9]}% -%D \dodoquintupleargument} -%D \stoptyping -%D -%D Because \TEX\ accepts 9~arguments at most, we have to use two||step solution when -%D getting five or more arguments. -%D -%D When developing more and more of the real \CONTEXT, we started using some -%D alternatives that provided empty arguments (in fact optional ones) whenever the -%D user failed to supply them. Because this more complicated macros enable us to do -%D some checking, we reimplemented the non||empty ones. - -%D \macros -%D {iffirstagument,ifsecondargument,ifthirdargument, -%D iffourthargument,iffifthargument,ifsixthargument, -%D ifseventhargument} -%D -%D We use some signals for telling the calling macros if all wanted arguments are -%D indeed supplied by the user. - -\newif\iffirstargument -\newif\ifsecondargument -\newif\ifthirdargument -\newif\iffourthargument -\newif\iffifthargument -\newif\ifsixthargument -\newif\ifseventhargument - -%D \macros -%D {dosingleempty,dodoubleempty,dotripleempty, -%D doquadrupleempty,doquintupleempty,dosixtupeempty, -%D doseventupleempty} -%D -%D The empty argument supplying macros mentioned before, look like: -%D -%D \starttyping -%D \dosingleempty \command -%D \dodoubleempty \command -%D \dotripleempty \command -%D \doquadrupleempty \command -%D \doquintupleempty \command -%D \dosixtuple_empty \command -%D \doseventupleempty\command -%D \stoptyping -%D -%D So \type{\dodoubleempty} leads to: -%D -%D \starttyping -%D \command[#1][#2] -%D \command[#1][] -%D \command[][] -%D \stoptyping -%D -%D Depending of the generousity of the user. Afterwards one can use the \type -%D {\if...argument} boolean. For novice: watch the stepwise doubling of \type {#}'s. - -%D Common: - -\newtoks\t_syst_aux - -\def\syst_helpers_single_empty_one_yes {\firstargumenttrue \the\t_syst_aux} -\def\syst_helpers_double_empty_two_yes {\secondargumenttrue \the\t_syst_aux} -\def\syst_helpers_triple_empty_three_yes {\thirdargumenttrue \the\t_syst_aux} -\def\syst_helpers_quadruple_empty_four_yes {\fourthargumenttrue \the\t_syst_aux} -\def\syst_helpers_quintuple_empty_five_yes {\fifthargumenttrue \the\t_syst_aux} -\def\syst_helpers_sixtuple_empty_six_yes {\sixthargumenttrue \the\t_syst_aux} -\def\syst_helpers_seventuple_empty_seven_yes{\seventhargumenttrue\the\t_syst_aux} - -%D Single: - -\unexpanded\def\dosingleempty#1% - {%syst_helpers_argument_reset - \t_syst_aux{#1}% - \futureexpand[\syst_helpers_single_empty_one_yes\syst_helpers_single_empty_one_nop} - -\def\syst_helpers_single_empty_one_nop - {\firstargumentfalse - \the\t_syst_aux[]} - -%D Double - -\unexpanded\def\dodoubleempty#1% - {%syst_helpers_argument_reset - \t_syst_aux{#1}% - \futureexpand[\syst_helpers_double_empty_one_yes\syst_helpers_double_empty_one_nop} - -\def\syst_helpers_double_empty_one_yes[#1]% - {\firstargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \futureexpand[\syst_helpers_double_empty_two_yes\syst_helpers_double_empty_two_nop} - -\def\syst_helpers_double_empty_one_nop - {\firstargumentfalse - \secondargumentfalse - \the\t_syst_aux[][]} - -\def\syst_helpers_double_empty_two_nop - {\secondargumentfalse - \the\t_syst_aux[]} - -% Triple - -\unexpanded\def\dotripleempty#1% - {%syst_helpers_argument_reset - \t_syst_aux{#1}% - \futureexpand[\syst_helpers_triple_empty_one_yes\syst_helpers_triple_empty_one_nop} - -\def\syst_helpers_triple_empty_one_yes[#1]% - {\firstargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \futureexpand[\syst_helpers_triple_empty_two_yes\syst_helpers_triple_empty_two_nop} - -\def\syst_helpers_triple_empty_two_yes[#1]% - {\secondargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \futureexpand[\syst_helpers_triple_empty_three_yes\syst_helpers_triple_empty_three_nop} - -\def\syst_helpers_triple_empty_one_nop - {\firstargumentfalse - \secondargumentfalse - \thirdargumentfalse - \the\t_syst_aux[][][]} - -\def\syst_helpers_triple_empty_two_nop - {\secondargumentfalse - \thirdargumentfalse - \the\t_syst_aux[][]} - -\def\syst_helpers_triple_empty_three_nop - {\thirdargumentfalse - \the\t_syst_aux[]} - -%D Quadruple: - -\unexpanded\def\doquadrupleempty#1% - {%syst_helpers_argument_reset - \t_syst_aux{#1}% - \futureexpand[\syst_helpers_quadruple_empty_one_yes\syst_helpers_quadruple_empty_one_nop} - -\def\syst_helpers_quadruple_empty_one_yes[#1]% - {\firstargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \futureexpand[\syst_helpers_quadruple_empty_two_yes\syst_helpers_quadruple_empty_two_nop} - -\def\syst_helpers_quadruple_empty_two_yes[#1]% - {\secondargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \futureexpand[\syst_helpers_quadruple_empty_three_yes\syst_helpers_quadruple_empty_three_nop} - -\def\syst_helpers_quadruple_empty_three_yes[#1]% - {\thirdargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \futureexpand[\syst_helpers_quadruple_empty_four_yes\syst_helpers_quadruple_empty_four_nop} - -\def\syst_helpers_quadruple_empty_one_nop - {\firstargumentfalse - \secondargumentfalse - \thirdargumentfalse - \fourthargumentfalse - \the\t_syst_aux[][][][]} - -\def\syst_helpers_quadruple_empty_two_nop - {\secondargumentfalse - \thirdargumentfalse - \fourthargumentfalse - \the\t_syst_aux[][][]} - -\def\syst_helpers_quadruple_empty_three_nop - {\thirdargumentfalse - \fourthargumentfalse - \the\t_syst_aux[][]} - -\def\syst_helpers_quadruple_empty_four_nop - {\fourthargumentfalse - \the\t_syst_aux[]} - -%D Quintuple: - -\unexpanded\def\doquintupleempty#1% - {%syst_helpers_argument_reset - \t_syst_aux{#1}% - \futureexpand[\syst_helpers_quintuple_empty_one_yes\syst_helpers_quintuple_empty_one_nop} - -\def\syst_helpers_quintuple_empty_one_yes[#1]% - {\firstargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \futureexpand[\syst_helpers_quintuple_empty_two_yes\syst_helpers_quintuple_empty_two_nop} - -\def\syst_helpers_quintuple_empty_two_yes[#1]% - {\secondargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \futureexpand[\syst_helpers_quintuple_empty_three_yes\syst_helpers_quintuple_empty_three_nop} - -\def\syst_helpers_quintuple_empty_three_yes[#1]% - {\thirdargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \futureexpand[\syst_helpers_quintuple_empty_four_yes\syst_helpers_quintuple_empty_four_nop} - -\def\syst_helpers_quintuple_empty_four_yes[#1]% - {\fourthargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \futureexpand[\syst_helpers_quintuple_empty_five_yes\syst_helpers_quintuple_empty_five_nop} - -\def\syst_helpers_quintuple_empty_one_nop - {\firstargumentfalse - \secondargumentfalse - \thirdargumentfalse - \fourthargumentfalse - \fifthargumentfalse - \the\t_syst_aux[][][][][]} - -\def\syst_helpers_quintuple_empty_two_nop - {\secondargumentfalse - \thirdargumentfalse - \fourthargumentfalse - \fifthargumentfalse - \the\t_syst_aux[][][][]} - -\def\syst_helpers_quintuple_empty_three_nop - {\thirdargumentfalse - \fourthargumentfalse - \fifthargumentfalse - \the\t_syst_aux[][][]} - -\def\syst_helpers_quintuple_empty_four_nop - {\fourthargumentfalse - \fifthargumentfalse - \the\t_syst_aux[][]} - -\def\syst_helpers_quintuple_empty_five_nop - {\fifthargumentfalse - \the\t_syst_aux[]} - -%D Sixtuple: - -\unexpanded\def\dosixtupleempty#1% - {%syst_helpers_argument_reset - \t_syst_aux{#1}% - \futureexpand[\syst_helpers_sixtuple_empty_one_yes\syst_helpers_sixtuple_empty_one_nop} - -\def\syst_helpers_sixtuple_empty_one_yes[#1]% - {\firstargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \futureexpand[\syst_helpers_sixtuple_empty_two_yes\syst_helpers_sixtuple_empty_two_nop} - -\def\syst_helpers_sixtuple_empty_two_yes[#1]% - {\secondargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \futureexpand[\syst_helpers_sixtuple_empty_three_yes\syst_helpers_sixtuple_empty_three_nop} - -\def\syst_helpers_sixtuple_empty_three_yes[#1]% - {\thirdargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \futureexpand[\syst_helpers_sixtuple_empty_four_yes\syst_helpers_sixtuple_empty_four_nop} - -\def\syst_helpers_sixtuple_empty_four_yes[#1]% - {\fourthargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \futureexpand[\syst_helpers_sixtuple_empty_five_yes\syst_helpers_sixtuple_empty_five_nop} - -\def\syst_helpers_sixtuple_empty_five_yes[#1]% - {\fifthargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \futureexpand[\syst_helpers_sixtuple_empty_six_yes\syst_helpers_sixtuple_empty_six_nop} - -\def\syst_helpers_sixtuple_empty_one_nop - {\firstargumentfalse - \secondargumentfalse - \thirdargumentfalse - \fourthargumentfalse - \fifthargumentfalse - \sixthargumentfalse - \the\t_syst_aux[][][][][][]} - -\def\syst_helpers_sixtuple_empty_two_nop - {\secondargumentfalse - \thirdargumentfalse - \fourthargumentfalse - \fifthargumentfalse - \sixthargumentfalse - \the\t_syst_aux[][][][][]} - -\def\syst_helpers_sixtuple_empty_three_nop - {\thirdargumentfalse - \fourthargumentfalse - \fifthargumentfalse - \sixthargumentfalse - \the\t_syst_aux[][][][]} - -\def\syst_helpers_sixtuple_empty_four_nop - {\fourthargumentfalse - \fifthargumentfalse - \sixthargumentfalse - \the\t_syst_aux[][][]} - -\def\syst_helpers_sixtuple_empty_five_nop - {\fifthargumentfalse - \sixthargumentfalse - \the\t_syst_aux[][]} - -\def\syst_helpers_sixtuple_empty_six_nop - {\sixthargumentfalse - \the\t_syst_aux[]} - -%D Seventuple: - -\unexpanded\def\doseventupleempty#1% - {%syst_helpers_argument_reset - \t_syst_aux{#1}% - \futureexpand[\syst_helpers_seventuple_empty_one_yes\syst_helpers_seventuple_empty_one_nop} - -\def\syst_helpers_seventuple_empty_one_yes[#1]% - {\firstargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \futureexpand[\syst_helpers_seventuple_empty_two_yes\syst_helpers_seventuple_empty_two_nop} - -\def\syst_helpers_seventuple_empty_two_yes[#1]% - {\secondargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \futureexpand[\syst_helpers_seventuple_empty_three_yes\syst_helpers_seventuple_empty_three_nop} - -\def\syst_helpers_seventuple_empty_three_yes[#1]% - {\thirdargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \futureexpand[\syst_helpers_seventuple_empty_four_yes\syst_helpers_seventuple_empty_four_nop} - -\def\syst_helpers_seventuple_empty_four_yes[#1]% - {\fourthargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \futureexpand[\syst_helpers_seventuple_empty_five_yes\syst_helpers_seventuple_empty_five_nop} - -\def\syst_helpers_seventuple_empty_five_yes[#1]% - {\fifthargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \futureexpand[\syst_helpers_seventuple_empty_six_yes\syst_helpers_seventuple_empty_six_nop} - -\def\syst_helpers_seventuple_empty_six_yes[#1]% - {\sixthargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \futureexpand[\syst_helpers_seventuple_empty_seven_yes\syst_helpers_seventuple_empty_seven_nop} - -\def\syst_helpers_seventuple_empty_one_nop - {\firstargumentfalse - \secondargumentfalse - \thirdargumentfalse - \fourthargumentfalse - \fifthargumentfalse - \sixthargumentfalse - \seventhargumentfalse - \the\t_syst_aux[][][][][][][]} - -\def\syst_helpers_seventuple_empty_two_nop - {\secondargumentfalse - \thirdargumentfalse - \fourthargumentfalse - \fifthargumentfalse - \sixthargumentfalse - \seventhargumentfalse - \the\t_syst_aux[][][][][][]} - -\def\syst_helpers_seventuple_empty_three_nop - {\thirdargumentfalse - \fourthargumentfalse - \fifthargumentfalse - \sixthargumentfalse - \seventhargumentfalse - \the\t_syst_aux[][][][][]} - -\def\syst_helpers_seventuple_empty_four_nop - {\fourthargumentfalse - \fifthargumentfalse - \sixthargumentfalse - \seventhargumentfalse - \the\t_syst_aux[][][][]} - -\def\syst_helpers_seventuple_empty_five_nop - {\fifthargumentfalse - \sixthargumentfalse - \seventhargumentfalse - \the\t_syst_aux[][][]} - -\def\syst_helpers_seventuple_empty_six_nop - {\sixthargumentfalse - \seventhargumentfalse - \the\t_syst_aux[][]} - -\def\syst_helpers_seventuple_empty_seven_nop - {\seventhargumentfalse - \the\t_syst_aux[]} - -%D Aliases: - -\let\dosingleargument \dosingleempty -\let\dodoubleargument \dodoubleempty -\let\dotripleargument \dotripleempty -\let\doquadrupleargument \doquadrupleempty -\let\doquintupleargument \doquintupleempty -\let\dosixtupleargument \dosixtupleempty -\let\doseventupleargument\doseventupleempty - -%D \macros -%D {strippedcsname} -%D -%D The next macro can be very useful when using \type{\csname} like in: -%D -%D \starttyping -%D \csname if\strippedcsname\something\endcsname -%D \stoptyping -%D -%D This expands to \type{\ifsomething}. - -% \def\strippedcsname -% {\expandafter\gobbleoneargument\string} - -\let\strippedcsname\csstring - -%D \macros -%D {complexorsimple,complexorsimpleempty} -%D -%D Setups can be optional. A command expecting a setup is prefixed by \type -%D {\complex}, a command without one gets the prefix \type {\simple}. Commands like -%D this can be defined by: -%D -%D \starttyping -%D \complexorsimple\command -%D \stoptyping -%D -%D When \type{\command} is followed by a \type{[setup]}, then -%D -%D \starttyping -%D \complexcommand [setup] -%D \stoptyping -%D -%D executes, else we get -%D -%D \starttyping -%D \simplecommand -%D \stoptyping -%D -%D An alternative for \type{\complexorsimple} is: -%D -%D \starttyping -%D \complexorsimpleempty {command} -%D \stoptyping -%D -%D Depending on the presence of \type{[setup]}, this one leads to one of: -%D -%D \starttyping -%D \complexcommando [setup] -%D \complexcommando [] -%D \stoptyping -%D -%D Many \CONTEXT\ commands started as complex or simple ones, but changed into more -%D versatile (more object oriented) ones using the \type {\get..argument} commands. - -\unexpanded\def\complexorsimple#1% - {% \relax % prevents lookahead, brrr - \doifelsenextoptional - {\firstargumenttrue \csname\s!complex\csstring#1\endcsname} - {\firstargumentfalse\csname\s!simple \csstring#1\endcsname}} - -\unexpanded\def\complexorsimpleempty#1% - {% \relax % prevents lookahead, brrr - \doifelsenextoptional - {\firstargumenttrue \csname\s!complex\csstring#1\endcsname} - {\firstargumentfalse\csname\s!complex\csstring#1\endcsname[]}} - -%D \macros -%D {definecomplexorsimple,definecomplexorsimpleempty} -%D -%D The previous commands are used that often that we found it worthwile to offer two -%D more alternatives. Watch the build in protection. - -\unexpanded\def\syst_helpers_complex_or_simple#1#2% - {\doifelsenextoptional{\firstargumenttrue#1}{\firstargumentfalse#2}} - -\unexpanded\def\syst_helpers_complex_or_simple_empty#1% - {\doifelsenextoptional{\firstargumenttrue#1}{\firstargumentfalse#1[]}} - -\unexpanded\def\definecomplexorsimple#1% - {\unexpanded\edef#1{\syst_helpers_complex_or_simple - \expandafter\noexpand\csname\s!complex\csstring#1\endcsname - \expandafter\noexpand\csname\s!simple \csstring#1\endcsname}} - -\unexpanded\def\definecomplexorsimpleempty#1% - {\unexpanded\edef#1{\syst_helpers_complex_or_simple_empty - \expandafter\noexpand\csname\s!complex\csstring#1\endcsname}} - -%D These commands are called as: -%D -%D \starttyping -%D \definecomplexorsimple\command -%D \stoptyping -%D -%D Of course, we must have available -%D -%D \starttyping -%D \def\complexcommand[#1]{...} -%D \def\simplecommand {...} -%D \stoptyping -%D -%D Using this construction saves a few string now and then. - -%D \macros -%D {dosinglegroupempty,dodoublegroupempty,dotriplegroupempty, -%D doquadruplegroupempty, doquintuplegroupempty} -%D -%D We've already seen some commands that take care of -%D optional arguments between \type{[]}. The next two commands -%D handle the ones with \type{{}}. They are called as: -%D -%D \starttyping -%D \dosinglegroupempty \ineedONEargument -%D \dodoublegroupempty \ineedTWOarguments -%D \dotriplegroupempty \ineedTHREEarguments -%D \doquadruplegroupempty \ineedFOURarguments -%D \doquintuplegroupempty \ineedFIVEarguments -%D \stoptyping -%D -%D We can add additional definitions later when we have defined \type {\appendtoks}. - -\newconditional\c_syst_helpers_permit_spaces_between_groups - -\unexpanded\def \permitspacesbetweengroups{\settrue \c_syst_helpers_permit_spaces_between_groups} -\unexpanded\def\dontpermitspacesbetweengroups{\setfalse\c_syst_helpers_permit_spaces_between_groups} - -\dontpermitspacesbetweengroups - -%D We can avoid the nasty if handling in \type {syst-gen} by splitting the lot in -%D pieces so that we have no nested \type {\nextarguments} potentially being an -%D \type {conditional} token. Okay, these macros are not called that often but it -%D saves crap when tracing. - -\unexpanded\def\dosinglegroupempty#1% - {\t_syst_aux{#1}% - \futureexpand\bgroup\syst_helpers_single_empty_one_yes\syst_helpers_single_group_empty_one_nop} - -\def\syst_helpers_single_group_empty_one_nop - {\firstargumentfalse - \the\t_syst_aux{}} - -\unexpanded\def\dodoublegroupempty#1% - {\t_syst_aux{#1}% - \futureexpand\bgroup\syst_helpers_group_double_empty_one_yes\syst_helpers_group_double_empty_one_nop} - -\def\syst_helpers_group_double_empty_one_yes#1% - {\firstargumenttrue - \toksapp\t_syst_aux{{#1}}% - \futureexpand\bgroup\syst_helpers_double_empty_two_yes\syst_helpers_group_double_empty_two_nop} - -\def\syst_helpers_group_double_empty_one_nop - {\firstargumentfalse - \secondargumentfalse - \the\t_syst_aux{}{}} - -\def\syst_helpers_group_double_empty_two_nop - {\secondargumentfalse - \the\t_syst_aux{}} - -\unexpanded\def\dotriplegroupempty#1% - {\t_syst_aux{#1}% - \futureexpand\bgroup\syst_helpers_group_triple_empty_one_yes\syst_helpers_group_triple_empty_one_nop} - -\def\syst_helpers_group_triple_empty_one_yes#1% - {\firstargumenttrue - \toksapp\t_syst_aux{{#1}}% - \futureexpand\bgroup\syst_helpers_group_triple_empty_two_yes\syst_helpers_group_triple_empty_two_nop} - -\def\syst_helpers_group_triple_empty_two_yes#1% - {\secondargumenttrue - \toksapp\t_syst_aux{{#1}}% - \futureexpand\bgroup\syst_helpers_triple_empty_three_yes\syst_helpers_group_triple_empty_three_nop} - -\def\syst_helpers_group_triple_empty_one_nop - {\firstargumentfalse - \secondargumentfalse - \thirdargumentfalse - \the\t_syst_aux{}{}{}} - -\def\syst_helpers_group_triple_empty_two_nop - {\secondargumentfalse - \thirdargumentfalse - \the\t_syst_aux{}{}} - -\def\syst_helpers_group_triple_empty_three_nop - {\thirdargumentfalse - \the\t_syst_aux{}} - -\unexpanded\def\doquadruplegroupempty#1% - {\t_syst_aux{#1}% - \futureexpand\bgroup\syst_helpers_group_quadruple_empty_one_yes\syst_helpers_group_quadruple_empty_one_nop} - -\def\syst_helpers_group_quadruple_empty_one_yes#1% - {\firstargumenttrue - \toksapp\t_syst_aux{{#1}}% - \futureexpand\bgroup\syst_helpers_group_quadruple_empty_two_yes\syst_helpers_group_quadruple_empty_two_nop} - -\def\syst_helpers_group_quadruple_empty_two_yes#1% - {\secondargumenttrue - \toksapp\t_syst_aux{{#1}}% - \futureexpand\bgroup\syst_helpers_group_quadruple_empty_three_yes\syst_helpers_group_quadruple_empty_three_nop} - -\def\syst_helpers_group_quadruple_empty_three_yes#1% - {\thirdargumenttrue - \toksapp\t_syst_aux{{#1}}% - \futureexpand\bgroup\syst_helpers_quadruple_empty_four_yes\syst_helpers_group_quadruple_empty_four_nop} - -\def\syst_helpers_group_quadruple_empty_one_nop - {\firstargumentfalse - \secondargumentfalse - \thirdargumentfalse - \fourthargumentfalse - \the\t_syst_aux{}{}{}{}} - -\def\syst_helpers_group_quadruple_empty_two_nop - {\secondargumentfalse - \thirdargumentfalse - \fourthargumentfalse - \the\t_syst_aux{}{}{}} - -\def\syst_helpers_group_quadruple_empty_three_nop - {\thirdargumentfalse - \fourthargumentfalse - \the\t_syst_aux{}{}} - -\def\syst_helpers_group_quadruple_empty_four_nop - {\fourthargumentfalse - \the\t_syst_aux{}} - -\unexpanded\def\doquintuplegroupempty#1% - {\t_syst_aux{#1}% - \futureexpand\bgroup\syst_helpers_group_quintuple_empty_one_yes\syst_helpers_group_quintuple_empty_one_nop} - -\def\syst_helpers_group_quintuple_empty_one_yes#1% - {\firstargumenttrue - \toksapp\t_syst_aux{{#1}}% - \futureexpand\bgroup\syst_helpers_group_quintuple_empty_two_yes\syst_helpers_group_quintuple_empty_two_nop} - -\def\syst_helpers_group_quintuple_empty_two_yes#1% - {\secondargumenttrue - \toksapp\t_syst_aux{{#1}}% - \futureexpand\bgroup\syst_helpers_group_quintuple_empty_three_yes\syst_helpers_group_quintuple_empty_three_nop} - -\def\syst_helpers_group_quintuple_empty_three_yes#1% - {\thirdargumenttrue - \toksapp\t_syst_aux{{#1}}% - \futureexpand\bgroup\syst_helpers_group_quintuple_empty_four_yes\syst_helpers_group_quintuple_empty_four_nop} - -\def\syst_helpers_group_quintuple_empty_four_yes#1% - {\fourthargumenttrue - \toksapp\t_syst_aux{{#1}}% - \futureexpand\bgroup\syst_helpers_quintuple_empty_five_yes\syst_helpers_group_quintuple_empty_five_nop} - -\def\syst_helpers_group_quintuple_empty_one_nop - {\firstargumentfalse - \secondargumentfalse - \thirdargumentfalse - \fourthargumentfalse - \fifthargumentfalse - \the\t_syst_aux{}{}{}{}{}} - -\def\syst_helpers_group_quintuple_empty_two_nop - {\secondargumentfalse - \thirdargumentfalse - \fourthargumentfalse - \fifthargumentfalse - \the\t_syst_aux{}{}{}{}} - -\def\syst_helpers_group_quintuple_empty_three_nop - {\thirdargumentfalse - \fourthargumentfalse - \fifthargumentfalse - \the\t_syst_aux{}{}{}} - -\def\syst_helpers_group_quintuple_empty_four_nop - {\fourthargumentfalse - \fifthargumentfalse - \the\t_syst_aux{}{}} - -\def\syst_helpers_group_quintuple_empty_five_nop - {\fifthargumentfalse - \the\t_syst_aux{}} - -%D These macros can explictly take care of spaces, which means that the next -%D definition and calls are valid: -%D -%D \starttyping -%D \def\test#1#2#3{[#1#2#3]} -%D -%D \dotriplegroupempty\test {a}{b}{c} -%D \dotriplegroupempty\test {a}{b} -%D \dotriplegroupempty\test {a} -%D \dotriplegroupempty\test -%D \dotriplegroupempty\test {a} {b} {c} -%D \dotriplegroupempty\test {a} {b} -%D \dotriplegroupempty\test -%D {a} -%D {b} -%D \stoptyping -%D -%D And alike. - -%D \macros -%D {firstofoneargument, firstoftwoarguments, firstofthreearguments -%D secondoftwoarguments, secondofthreearguments, -%D thirdofthreearguments} -%D -%D The next six macros (dedicated to Taco) can conveniently used to select -%D arguments. Their names explain their functionality. - -\def\firstofoneargument #1{#1} - -\def\firstoftwoarguments #1#2{#1} -\def\secondoftwoarguments #1#2{#2} - -\def\firstofthreearguments #1#2#3{#1} -\def\secondofthreearguments #1#2#3{#2} -\def\thirdofthreearguments #1#2#3{#3} - -\def\firstoffourarguments #1#2#3#4{#1} -\def\secondoffourarguments #1#2#3#4{#2} -\def\thirdoffourarguments #1#2#3#4{#3} -\def\fourthoffourarguments #1#2#3#4{#4} - -\def\firstoffivearguments #1#2#3#4#5{#1} -\def\secondoffivearguments #1#2#3#4#5{#2} -\def\thirdoffivearguments #1#2#3#4#5{#3} -\def\fourthoffivearguments #1#2#3#4#5{#4} -\def\fifthoffivearguments #1#2#3#4#5{#5} - -\def\firstofsixarguments #1#2#3#4#5#6{#1} -\def\secondofsixarguments#1#2#3#4#5#6{#2} -\def\thirdofsixarguments #1#2#3#4#5#6{#3} -\def\fourthofsixarguments#1#2#3#4#5#6{#4} -\def\fifthofsixarguments #1#2#3#4#5#6{#5} -\def\sixthofsixarguments #1#2#3#4#5#6{#6} - -\unexpanded\def\firstofoneunexpanded #1{#1} - -\unexpanded\def\firstoftwounexpanded #1#2{#1} -\unexpanded\def\secondoftwounexpanded #1#2{#2} - -\unexpanded\def\firstofthreeunexpanded #1#2#3{#1} -\unexpanded\def\secondofthreeunexpanded#1#2#3{#2} -\unexpanded\def\thirdofthreeunexpanded #1#2#3{#3} - -%D \macros -%D {globalletempty,letempty, -%D letvalueempty,letgvalueempty, -%D letvaluerelax,letgvaluerelax} -%D -%D Trivial: - -\unexpanded\def\letempty #1{\let #1\empty} -\unexpanded\def\globalletempty#1{\glet#1\empty} - -\unexpanded\def\letvalueempty #1{\expandafter\let \csname#1\endcsname\empty} -\unexpanded\def\letgvalueempty#1{\expandafter\glet\csname#1\endcsname\empty} -\unexpanded\def\letvaluerelax #1{\expandafter\let \csname#1\endcsname\relax} -\unexpanded\def\letgvalurelax #1{\expandafter\glet\csname#1\endcsname\relax} - -\unexpanded\def\relaxvalueifundefined#1% - {\ifcsname#1\endcsname \else - \expandafter\let\csname#1\endcsname\relax - \fi} - -%D \macros -%D {wait} -%D -%D The next macro hardly needs explanation. Because no nesting is to be expected, we -%D can reuse \type {\wait} within \type {\wait} itself. - -\unexpanded\def\wait - {\begingroup - \read16 to \wait - \endgroup} - -%D \macros -%D {writestring,writeline, -%D writestatus,statuswidth,normalwritestatus} -%D -%D Maybe one didn't notice, but we've already introduced a macro for showing -%D messages. In the multi||lingual modules, we will also introduce a mechanism for -%D message passing. For the moment we stick to the core macros: -%D -%D \starttyping -%D \writestring {string} -%D \writeline -%D \writestatus {category} {message} -%D \stoptyping -%D -%D Messages are formatted. One can provide the maximum with of the identification -%D string with the macro \type {\statuswidth}. - -\setnewconstant\statuswidth 15 -\setnewconstant\statuswrite 128 % \pluscxxviii - -\ifdefined\writestring \else - - \unexpanded\def\writestring{\immediate\write\statuswrite} - \unexpanded\def\writeline {\writestring{}} - -\fi - -\unexpanded\def\normalwritestatus#1#2% - {\writestring{\expandafter\syst_helpers_split_status_yes\expandafter\statuswidth#1% - \space\space\space\space\space\space\space - \space\space\space\space\space\space\space - \space\space\space\space\space\space\end - \space:\space#2}} - -\def\syst_helpers_split_status_yes#1#2% - {\ifcase#1 \expandafter\syst_helpers_split_status_nop\fi#2% - \expandafter\syst_helpers_split_status_yes\expandafter{\the\numexpr#1+\minusone\relax}} - -\def\syst_helpers_split_status_nop#1\end - {} - -%D \macros -%D {immediatemessage} -%D -%D A fully expandable message: - -\let\immediatemessage\clf_immediatemessage % {} mandate - -%D \macros -%D {rawgetparameters} -%D -%D A raw and dirty alternative for \type {\getparameters}; no checking is done! - -\unexpanded\def\rawsetparameter#1=#2,% - {\if]#1\else - \expandafter\def\csname\rawparameterprefix#1\endcsname{#2}% - \expandafter\rawsetparameter - \fi} - -\unexpanded\def\rawgetparameters[#1][#2% some 5-10% faster - {\ifx#2]% test is needed, else bomb on [#1][] - \expandafter\gobbleoneargument - \else - \def\rawparameterprefix{#1}% - \expandafter\dorawgetparameters - \fi#2} - -\def\dorawgetparameters#1]% - {\expandafter\rawsetparameter#1,]=,} - -%D \macros -%D {doglobal, -%D redoglobal,dodoglobal,resetglobal} -%D -%D The two macros \type {\redoglobal} and \type{\dodoglobal} are used in this and -%D some other modules to enforce a user specified \type {\doglobal} action. The last -%D and often only global assignment in a macro is done with \type {\dodoglobal}, but -%D all preceding ones with \type {\redoglobal}. When using only alternatives, one -%D can reset this mechanism with \type {\resetglobal}. - -\unexpanded\def\resetglobal - {\let\redoglobal\relax - \let\dodoglobal\relax} - -\resetglobal - -\unexpanded\def\doglobal - {\ifx\redoglobal\relax - \let\redoglobal\global - \let\dodoglobal\syst_helpers_dodo_global - \fi} - -\def\syst_helpers_dodo_global - {\resetglobal\global} - -\def\saveglobal - {\let\syst_helpers_dodo_global\dodoglobal - \let\syst_helpers_redo_global\redoglobal} - -\def\restoreglobal - {\let\redoglobal\syst_helpers_redo_global - \let\dodoglobal\syst_helpers_dodo_global} - -%D A very useful application of this macro is \type {\newif}, \TEX's fake boolean -%D type. Not being a primitive, \type {\global} hopelessly fails here. But a slight -%D adaption of Knuth's original macro permits: -%D -%D \starttyping -%D \doglobal\newif\iftest -%D \stoptyping -%D -%D Of course one can still say: -%D -%D \starttyping -%D \global\testtrue -%D \global\testfalse -%D \stoptyping -%D -%D Apart from the prefixes, a few more \type {\expandafters} are needed: - -% \unexpanded\def\newif#1% uses the original plain \@if -% {\privatescratchcounter\escapechar -% \escapechar\minusone -% \expandafter\expandafter\expandafter -% \redoglobal\expandafter\expandafter\expandafter -% \edef\@if#1{true}{\let\noexpand#1\noexpand\iftrue}% -% \expandafter\expandafter\expandafter -% \redoglobal\expandafter\expandafter\expandafter -% \edef\@if#1{false}{\let\noexpand#1\noexpand\iffalse}% -% \dodoglobal\@if#1{false}% -% \escapechar\privatescratchcounter} - -\normalprotected\def\newif#1% see syst-ini.mkiv - {\let\new_if_saved\newif - \let\newif\new_if_check - \expandafter\redoglobal\expandafter\def\csname\expandafter\newif\csstring#1true\endcsname {\let#1\iftrue }% - \expandafter\redoglobal\expandafter\def\csname\expandafter\newif\csstring#1false\endcsname{\let#1\iffalse}% - \dodoglobal\csname\expandafter\newif\csstring#1false\endcsname - \let\newif\new_if_saved} - -%D Also new: - -\unexpanded\def\define#1% - {\ifdefined#1% - \message{[\noexpand#1is already defined]}% - \unexpanded\expandafter\def\expandafter\gobbleddefinition - \else - \unexpanded\expandafter\def - \fi#1} - -\unexpanded\def\redefine#1% - {\ifdefined#1% - \message{[\noexpand#1is redefined]}% - \fi - \unexpanded\def#1} - -\unexpanded\def\definemacro#1% - {\ifdefined#1% - \message{[\noexpand#1is already defined]}% - \unexpanded\expandafter\def\expandafter\gobbleddefinition - \else - \unexpanded\expandafter\def - \fi#1} - -% \define\hans{hans} -% \redefine\hans{hans} -% \define\hans#1[]#2#3{hans} - -%D The next variant fits nicely in the setups syntax: -%D -%D \starttyping -%D \starttexdefinition bagger [#1] #2 -%D oeps -%D #1 -%D oeps -%D \stoptexdefinition -%D -%D \bagger [a] {b} -%D \stoptyping - -% \starttexdefinition test -% oeps -% \stoptexdefinition -% -% [\test] - -\def\s!unexpanded{unexpanded} - -\bgroup \obeylines - -\glet\stoptexdefinition\relax - -\unexpanded\gdef\starttexdefinition% - {\bgroup% - \obeylines% - \syst_helpers_start_tex_definition} - -\gdef\syst_helpers_start_tex_definition#1 - {\catcode\endoflineasciicode\ignorecatcode% - \clf_texdefinition_one{#1}} - -\gdef\dostarttexdefinition#1\stoptexdefinition% - {\egroup% - \clf_texdefinition_two{#1}} - -\egroup - -% \unexpanded\def\texdefinition#1{\csname\ifcsname#1\endcsname#1\else donothing\fi\endcsname} % todo: a nop cs: char 0 or some corenamespace - -\unexpanded\def\texdefinition#1{\begincsname#1\endcsname} - -% This is a first variant, more might be added: - -\unexpanded\def\starttexcode{\unprotect} -\unexpanded\def\stoptexcode {\protect} - -%D \macros -%D {newcounter, -%D increment,decrement} -%D -%D Unfortunately the number of \COUNTERS\ in \TEX\ is limited, but fortunately we -%D can store numbers in a macro. We can increment such pseudo \COUNTERS\ with \type -%D {\increment}. -%D -%D \starttyping -%D \increment(\counter,20) -%D \increment(\counter,-4) -%D \increment(\counter) -%D \increment\counter -%D \stoptyping -%D -%D After this sequence of commands, the value of \type {\counter} is 20, 16, 17 -%D and~18. Of course there is also the complementary command \type {\decrement}. -%D -%D Global assignments are possible too, using \type{\doglobal}: -%D -%D \starttyping -%D \doglobal\increment\counter -%D \stoptyping -%D -%D When \type {\counter} is undefined, it's value is initialized at~0. It is -%D nevertheless better to define a \COUNTER\ explicitly. One reason could be that -%D the \COUNTER\ can be part of a test with \type {\ifnum} and this conditional does -%D not accept undefined macro's. The \COUNTER\ in our example can for instance be -%D defined with: -%D -%D \starttyping -%D \newcounter\counter -%D \stoptyping -%D -%D The command \type {\newcounter} must not be confused with \type {\newcount}! Of -%D course this mechanism is much slower than using \TEX's \COUNTERS\ directly. In -%D practice \COUNTERS\ (and therefore our pseudo counters too) are seldom the -%D bottleneck in the processing of a text. Apart from some other incompatilities we -%D want to mention a pitfal when using \type {\ifnum}. -%D -%D \starttyping -%D \ifnum\normalcounter=\pseudocounter \doif \else \doelse \fi -%D \ifnum\pseudocounter=\normalcounter \doif \else \doelse \fi -%D \stoptyping -%D -%D In the first test, \TEX\ continues it's search for the second number after -%D reading \type {\pseudocounter}, while in the second test, it stops reading after -%D having encountered a real one. Tests like the first one therefore can give -%D unexpected results, for instance execution of \type {\doif} even if both numbers -%D are unequal. - -\def\zerocountervalue{0} - -\unexpanded\def\newcounter#1% - {\dodoglobal\let#1\zerocountervalue} - -%D Nowadays we don't mind a few more tokens if we can gain a bit of speed. - -\def\syst_helpers_do_increment#1{\dodoglobal\edef#1{\the\numexpr\ifdefined#1\ifx#1\relax\else#1\fi\fi+\plusone \relax}} -\def\syst_helpers_do_decrement#1{\dodoglobal\edef#1{\the\numexpr\ifdefined#1\ifx#1\relax\else#1\fi\fi+\minusone\relax}} - -\def\syst_helpers_do_do_do_increment#1,#2){\dodoglobal\edef#1{\the\numexpr\ifdefined#1\ifx#1\relax\else#1\fi\fi+#2\relax}} -\def\syst_helpers_do_do_do_decrement#1,#2){\dodoglobal\edef#1{\the\numexpr\ifdefined#1\ifx#1\relax\else#1\fi\fi-#2\relax}} - -\def\syst_helpers_do_do_increment(#1% - {\def\m_syst_action_yes{\syst_helpers_do_do_do_increment#1}% - \def\m_syst_action_nop{\syst_helpers_do_do_do_increment#1,\plusone}% - \doifelsenextcharcs,\m_syst_action_yes\m_syst_action_nop} - -\def\syst_helpers_do_do_decrement(#1% - {\def\m_syst_action_yes{\syst_helpers_do_do_do_decrement#1}% - \def\m_syst_action_nop{\syst_helpers_do_do_do_decrement#1,\plusone}% - \doifelsenextcharcs,\m_syst_action_yes\m_syst_action_nop} - -\unexpanded\def\increment{\doifelsenextcharcs(\syst_helpers_do_do_increment\syst_helpers_do_increment} -\unexpanded\def\decrement{\doifelsenextcharcs(\syst_helpers_do_do_decrement\syst_helpers_do_decrement} - -\unexpanded\def\fastincrement#1{\dodoglobal\edef#1{\the\numexpr#1+\plusone \relax}} -\unexpanded\def\fastdecrement#1{\dodoglobal\edef#1{\the\numexpr#1+\minusone\relax}} - -\unexpanded\def\incrementvalue#1{\expandafter\increment\csname#1\endcsname} -\unexpanded\def\decrementvalue#1{\expandafter\decrement\csname#1\endcsname} - -%D \macros -%D {newsignal} -%D -%D When writing advanced macros, we cannot do without signaling. A signal is a small -%D (invisible) kern or penalty that signals the next macro that something just -%D happened. This macro can take any action depending on the previous signal. -%D Signals must be unique and the next macro takes care of that. -%D -%D \starttyping -%D \newsignal\somesignal -%D \stoptyping -%D -%D Signals old dimensions and can be used in skips, kerns and tests like \type -%D {\ifdim}. - -\newdimen\maximumsignal % step is about 0.00025pt - -\unexpanded\def\newsignal#1% - {\ifdefined#1\else - \advance\maximumsignal 2\scaledpoint % to be save in rounding - \edef#1{\the\maximumsignal}% - \fi} - -%D \macros -%D {strippedcsname} -%D -%D The next macro can be very useful when using \type {\csname} like in: -%D -%D \starttyping -%D \csname if\strippedcsname\something\endcsname -%D \stoptyping - -\let\checkedstrippedcsname\csstring - -%D \macros -%D {savenormalmeaning} -%D -%D We will use this one in: - -\unexpanded\def\savenormalmeaning#1% - {\ifcsname normal\csstring#1\endcsname \else - \expandafter\let\csname normal\csstring#1\endcsname#1% - \fi} - -%D \macros -%D {dorecurse,recurselevel,recursedepth, -%D dostepwiserecurse} -%D -%D \TEX\ does not offer us powerfull for||loop mechanisms. On the other hand its -%D recursion engine is quite unique. We therefore identify the for||looping macros -%D by this method. The most simple alternative is the one that only needs a number. -%D -%D \starttyping -%D \dorecurse {n} {whatever we want} -%D \stoptyping -%D -%D This macro can be nested without problems and therefore be used in situations -%D where \PLAIN\ \TEX's \type {\loop} macro ungracefully fails. The current value of -%D the counter is available in \type {\recurselevel}, before as well as after the -%D \typ {whatever we wat} stuff. -%D -%D \starttyping -%D \dorecurse % inner loop -%D {10} -%D {\recurselevel: % outer value -%D \dorecurse % inner loop -%D {\recurselevel} % outer value -%D {\recurselevel} % inner value -%D \dorecurse % inner loop -%D {\recurselevel} % outer value -%D {\recurselevel} % inner value -%D \endgraf} -%D \stoptyping -%D -%D In this example the first, second and fourth \type {\recurselevel} concern the -%D outer loop, while the third and fifth one concern the inner loop. The depth of -%D the nesting is available for inspection in \type {\recursedepth}. -%D -%D Both \type {\recurselevel} and \type {\recursedepth} are macros. The real -%D \COUNTERS\ are hidden from the user because we don't want any interference. - -\newcount\outerrecurse -\newcount\innerrecurse - -\def\recursedepth{\the\outerrecurse} -\def\recurselevel{0} - -\let\syst_helpers_stepwise_next\relax - -\installsystemnamespace{recurseindex} -\installsystemnamespace{recurseaction} - -\unexpanded\def\dostepwiserecurse#1#2#3#4% can be made faster by postponing #4 - {\global\advance\outerrecurse \plusone - \expandafter\gdef\csname\??recurseaction\the\outerrecurse\endcsname{#4}% - \expandafter\glet\csname\??recurseindex \the\outerrecurse\endcsname\recurselevel - \ifnum#3>\zerocount\relax - \ifnum#2<#1\relax - \let\syst_helpers_stepwise_next\syst_helpers_stepwise_exit - \else - \let\syst_helpers_stepwise_next\syst_helpers_stepwise_recurse - \fi - \orelse\ifnum#3<\zerocount\relax - \ifnum#1<#2\relax - \let\syst_helpers_stepwise_next\syst_helpers_stepwise_exit - \else - \let\syst_helpers_stepwise_next\syst_helpers_stepwise_reverse - \fi - \else - \let\syst_helpers_stepwise_next\syst_helpers_stepwise_exit - \fi\normalexpanded{\syst_helpers_stepwise_next{\number#1}{\number#2}{\number#3}}} - -\unexpanded\def\syst_helpers_stepwise_recurse#1#2#3% from to step - {\ifnum#1>#2\relax - \expandafter\syst_helpers_stepwise_recurse_nop - \else - \def\recurselevel{#1}% - \doubleexpandafter\syst_helpers_stepwise_recurse_yes\expandafter - \fi\expandafter{\the\numexpr\recurselevel+#3\relax}{#2}{#3}} - -\unexpanded\def\syst_helpers_recurse_content - {\csname\??recurseaction\the\outerrecurse\endcsname} - -\unexpanded\def\syst_helpers_stepwise_recurse_yes - {\syst_helpers_recurse_content - \syst_helpers_stepwise_recurse} - -\unexpanded\def\syst_helpers_stepwise_reverse#1#2#3% from to step - {\ifnum#1<#2\relax - \expandafter\syst_helpers_stepwise_recurse_nop - \else - \def\recurselevel{#1}% - \innerrecurse#1\relax - \advance\innerrecurse#3\relax - \doubleexpandafter\syst_helpers_stepwise_reverse_yes\expandafter - \fi\expandafter{\the\innerrecurse}{#2}{#3}} - -\unexpanded\def\syst_helpers_stepwise_reverse_yes - {\syst_helpers_recurse_content - \syst_helpers_stepwise_reverse} - -\unexpanded\def\syst_helpers_stepwise_exit - {\syst_helpers_stepwise_recurse_nop\relax} - -\unexpanded\def\syst_helpers_stepwise_recurse_nop#1#2#3#4% - {\expandafter\let\expandafter\recurselevel\csname\??recurseindex\the\outerrecurse\endcsname - \global\advance\outerrecurse\minusone} - -\unexpanded\def\dorecurse#1% - {\dostepwiserecurse\plusone{#1}\plusone} - -\def\doexpandedrecurse#1#2% user macro (also was \doxprecurse) - {\ifnum#1>\zerocount - #2\expandafter\doexpandedrecurse\expandafter{\the\numexpr#1-\plusone\relax}{#2}% - \fi} - -%D As we can see here, the simple command \type{\dorecurse} is a special case of the -%D more general: -%D -%D \starttyping -%D \dostepwiserecurse {from} {to} {step} {action} -%D \stoptyping -%D -%D This commands accepts positive and negative steps. Illegal values are handles as -%D good as possible and the macro accepts numbers and \COUNTERS. -%D -%D \starttyping -%D \dostepwiserecurse {1} {10} {2} {...} -%D \dostepwiserecurse {10} {1} {-2} {...} -%D \stoptyping -%D -%D Because the simple case is used often, we implement it more efficiently: - -\unexpanded\def\dorecurse#1% - {\ifcase#1\relax - \expandafter\gobbletwoarguments - \or - \expandafter\syst_helpers_recurse_y - \else - \expandafter\syst_helpers_recurse_x - \fi{#1}} - -\unexpanded\def\syst_helpers_recurse_x#1#2% - {\global\advance\outerrecurse \plusone - \expandafter\gdef\csname\??recurseaction\the\outerrecurse\endcsname{#2}% - \expandafter\glet\csname\??recurseindex \the\outerrecurse\endcsname\recurselevel - \expandafter\syst_helpers_recurse_indeed\expandafter1\expandafter{\number#1}} - -\unexpanded\def\syst_helpers_recurse_y#1#2% - {\global\advance\outerrecurse \plusone - \expandafter\glet\csname\??recurseindex\the\outerrecurse\endcsname\recurselevel - \let\recurselevel\!!plusone - #2% - \expandafter\let\expandafter\recurselevel\csname\??recurseindex\the\outerrecurse\endcsname - \global\advance\outerrecurse \minusone} - -\unexpanded\def\syst_helpers_recurse_indeed#1#2% from to - {\ifnum#1>#2\relax - \expandafter\syst_helpers_recurse_indeed_nop - \else - \def\recurselevel{#1}% - \doubleexpandafter\syst_helpers_recurse_indeed_yes - \fi\expandafter{\the\numexpr\recurselevel+\plusone\relax}{#2}} - -\unexpanded\def\syst_helpers_recurse_indeed#1#2% from to - {\ifnum#1>#2\relax - \expandafter\syst_helpers_recurse_indeed_nop - \else - \def\recurselevel{#1}% - \innerrecurse#1\advance\innerrecurse\plusone - \doubleexpandafter\syst_helpers_recurse_indeed_yes - \fi\expandafter{\the\innerrecurse}{#2}} - -\unexpanded\def\syst_helpers_recurse_indeed_yes - {\syst_helpers_recurse_content - \syst_helpers_recurse_indeed} - -\unexpanded\def\syst_helpers_recurse_indeed_nop#1#2#3% - {\expandafter\let\expandafter\recurselevel\csname\??recurseindex\the\outerrecurse\endcsname - \global\advance\outerrecurse \minusone } - -%D \macros -%D {dowith} -%D -%D Here's a loop over whatever is in a list: -%D -%D \starttyping -%D \dowith{a,b,c}{[#1]} -%D \stoptyping - -\unexpanded\def\dowith#1#2% - {\def\syst_helpers_with##1{#2}% - \normalexpanded{\processcommalist[#1]}\syst_helpers_with} - -%D \macros -%D {doloop,exitloop} -%D -%D Sometimes loops are not determined by counters, but by (a combinations of) -%D conditions. We therefore implement a straightforward loop, which can only be left -%D when we explictly exit it. Nesting is supported. First we present a more -%D extensive alternative. -%D -%D \starttyping -%D \doloop -%D {Some kind of typesetting punishment \par -%D \ifnum\pageno>100 \exitloop \fi} -%D \stoptyping -%D -%D When needed, one can call for \type {\looplevel} and \type {\loopdepth}. - -\let\endofloop\donothing % maybe \syst_helpers_loop_end - -\unexpanded\def\doloop#1% - {\global\advance\outerrecurse \plusone - \expandafter\gdef\csname\??recurseaction\the\outerrecurse\endcsname{#1}% - \expandafter\glet\csname\??recurseindex \the\outerrecurse\endcsname\recurselevel - \let\endofloop\syst_helpers_loop - \syst_helpers_loop1} % no \plusone else \recurselevel wrong - -\unexpanded\def\syst_helpers_loop#1% - {\def\recurselevel{#1}% - \expandafter\syst_helpers_loop_yes\expandafter{\the\numexpr\recurselevel+\plusone\relax}} - -\unexpanded\def\syst_helpers_loop_yes - {\syst_helpers_recurse_content - \endofloop} - -\unexpanded\def\syst_helpers_loop_nop#1% - {\let\endofloop\syst_helpers_loop % new, permits nested \doloop's - \expandafter\let\expandafter\recurselevel\csname\??recurseindex\the\outerrecurse\endcsname - \global\advance\outerrecurse\minusone} - -\unexpanded\def\exitloop % \exitloop quits at end - {\let\endofloop\syst_helpers_loop_nop} - -\unexpanded\def\exitloopnow#1\endofloop % \exitloopnow quits directly - {\syst_helpers_loop_nop} - -%D The loop is executed at least once, so beware of situations -%D like: -%D -%D \starttyping -%D \doloop {\exitloop some commands} -%D \stoptyping -%D -%D It's just a matter of putting the text into the \type {\if} statement that should -%D be there anyway, like in: -%D -%D \starttyping -%D \doloop {\ifwhatever \exitloop \else some commands\fi} -%D \stoptyping -%D -%D You can also quit a loop immediately, by using \type -%D {\exitloopnow} instead. Beware, this is more sensitive -%D for conditional errors. - -%D Krzysztof Leszczynski suggested to provide access to the level by means of a -%D \type {#1}. I decided to pass the more frequently used level as \type {#1} and -%D the less favoured depth as \type {#2}. The intended usage is: -%D -%D \starttyping -%D \dorecurse{3}{\definesymbol[test-#1][xx-#1]} -%D -%D \def\test{\dorecurse{3}{\definesymbol[test-##1][xx-##1]}} \test -%D -%D \symbol[test-1]\quad\symbol[test-2]\quad\symbol[test-3] -%D \stoptyping -%D -%D Since the hashed arguments are expanded, we don't need tricky expansion here. -%D -%D \starttyping -%D \dorecurse{3}{\expanded{\definesymbol[test-\recurselevel][xx-\recurselevel]}} -%D \stoptyping - -\def\syst_helpers_recurse_content - {\csname\??recurseaction\the\outerrecurse\expandafter\expandafter\expandafter\endcsname - \expandafter\expandafter\expandafter{\expandafter\recurselevel\expandafter}\expandafter{\the\outerrecurse}} - -\unexpanded\def\syst_helpers_recurse_x#1#2% - {\global\advance\outerrecurse \plusone - \expandafter\gdef\csname\??recurseaction\the\outerrecurse\endcsname##1##2{#2}% - \expandafter\glet\csname\??recurseindex \the\outerrecurse\endcsname\recurselevel - \expandafter\syst_helpers_recurse_indeed\expandafter1\expandafter{\number#1}} - -\unexpanded\def\syst_helpers_recurse_y#1#2% - {\global\advance\outerrecurse \plusone - \expandafter\glet\csname\??recurseindex \the\outerrecurse\endcsname\recurselevel - \let\recurselevel\!!plusone - \expandafter\gdef\csname\??recurseaction\the\outerrecurse\endcsname##1##2{#2}% - \syst_helpers_recurse_content - \expandafter\let\expandafter\recurselevel\csname\??recurseindex\the\outerrecurse\endcsname - \global\advance\outerrecurse \minusone} - -\unexpanded\def\doloop#1% - {\global\advance\outerrecurse \plusone - \expandafter\gdef\csname\??recurseaction\the\outerrecurse\endcsname##1##2{#1}% - \expandafter\glet\csname\??recurseindex \the\outerrecurse\endcsname\recurselevel - \let\endofloop\syst_helpers_loop - \syst_helpers_loop1} % no \plusone else \recurselevel wrong - -\installsystemnamespace{recursestepwise} - -\unexpanded\def\dostepwiserecurse#1#2#3#4% can be made faster by postponing #4 - {\global\advance\outerrecurse \plusone - \expandafter\gdef\csname\??recurseaction\the\outerrecurse\endcsname##1##2{#4}% - \expandafter\glet\csname\??recurseindex \the\outerrecurse\endcsname\recurselevel - \csname\??recursestepwise - % we need the x in order to avoid the \relax that tex adds - \ifnum#3>\zerocount - \ifnum#2<#1x\else d\fi - \orelse\ifnum#3<\zerocount - \ifnum#1<#2x\else r\fi - \fi - \expandafter\endcsname\normalexpanded{{\number#1}{\number#2}{\number#3}}} - % \expandafter\endcsname\expandafter{\number#1\expandafter}\expandafter{\number#2\expandafter}\expandafter{\number#3}} - -\letvalue{\??recursestepwise x}\syst_helpers_stepwise_exit -\letvalue{\??recursestepwise d}\syst_helpers_stepwise_recurse -\letvalue{\??recursestepwise r}\syst_helpers_stepwise_reverse - -\newcount\fastloopindex -\newcount\fastloopfinal - -\let\m_syst_helpers_fast_loop_cs\relax - -\unexpanded\def\dofastloopcs#1% - {\fastloopfinal#1\relax - \ifcase\fastloopfinal - \expandafter\gobbleoneargument - \else - \expandafter\syst_helpers_fast_loop_cs - \fi} - -\unexpanded\def\syst_helpers_fast_loop_cs#1% - {\let\m_syst_helpers_fast_loop_cs#1% - \fastloopindex\plusone - \syst_helpers_fast_loop_cs_step} - -\unexpanded\def\syst_helpers_fast_loop_cs_step - {\ifnum\fastloopindex>\fastloopfinal - \let\m_syst_helpers_fast_loop_cs\relax - \else - \m_syst_helpers_fast_loop_cs - \advance\fastloopindex\plusone - \expandafter\syst_helpers_fast_loop_cs_step - \fi} - -% Helper: - -\unexpanded\def\resetrecurselevel{\let\recurselevel\!!zerocount} - -\let\recurselevel\!!zerocount - -% \appendtoks \resetrecurselevel \to \everydump - -%D \macros -%D {doloopoverlist} -%D -%D \starttyping -%D \doloopoverlist {red,green,blue} { -%D \setuppalet[\recursestring] -%D \doloopoverlist {light,normal,dark} { -%D \blackrule[color=\recursestring,width=20cm,height=2cm,depth=0cm]\par -%D } -%D } -%D \stoptyping -%D -%D or: -%D -%D \starttyping -%D \doloopoverlist {red,green,blue} { -%D \setuppalet[#1] -%D \doloopoverlist {light,normal,dark} { -%D \blackrule[color=##1,width=20cm,height=2cm,depth=0cm]\par -%D } -%D } -%D \stoptyping - -\unexpanded\def\doloopoverlist#1#2% - {\global\advance\outerrecurse\plusone - \expandafter\gdef\csname\??recurseaction\the\outerrecurse\endcsname##1{\edef\recursestring{##1}#2}% - \expandafter\glet\csname\??recurseindex \the\outerrecurse\endcsname\recursestring - \normalexpanded{\processcommalist[#1]{\expandafter\noexpand\csname\??recurseaction\the\outerrecurse\endcsname}}% - \expandafter\let\expandafter\recursestring\csname\??recurseindex\the\outerrecurse\endcsname - \global\advance\outerrecurse\minusone} - -%D \macros -%D {newevery,everyline,EveryLine,EveryPar} -%D -%D Lets skip to something quite different. It's common use to use \type {\everypar} -%D for special purposes. In \CONTEXT\ we use this primitive for locating sidefloats. -%D This means that when user assignments to \type {\everypar} can interfere with -%D those of the package. We therefore introduce \type {\EveryPar}. -%D -%D The same goes for \type {\EveryLine}. Because \TEX\ offers no \type {\everyline} -%D primitive, we have to call for \type {\everyline} when we are working on a line -%D by line basis. Just by calling \type {\EveryPar{}} and \type {\EveryLine{}} we -%D restore the old situation. - -% \dorecurse{2}{ -% \expanded{\everypar{before \recurselevel\space}} -% \EveryPar{x } [before \recurselevel\space x] \par -% \EveryPar{y } [before \recurselevel\space y] \par -% \EveryPar{} [before \recurselevel] \par -% \EveryPar{x } \EveryPar{y } \EveryPar{} [before \recurselevel] \par -% \EveryPar{y } \everypar{before } [before] \par -% } - -\installsystemnamespace{extraevery} - -\unexpanded\def\newevery#1#2% - {\ifx#1\everypar\else\newtoks#1\fi% we test for redefinition elsewhere - \ifx#2\relax\orelse\ifdefined#2\else - \expandafter\newtoks\csname\??extraevery\csstring#1\endcsname - \edef#2{\syst_helpers_every#1\csname\??extraevery\csstring#1\endcsname}% - \fi} - -\unexpanded\def\syst_helpers_every#1#2% - {\removetoks\the#2\from#1% - \appendtoks\the#2\to #1% - #2} - -%D This one permits definitions like: - -\newevery \everypar \EveryPar % we get a warning which is ok -\newevery \everyline \EveryLine - -%D and how about: - -\newtoks \neverypar - -\unexpanded\def\forgeteverypar - {\everypar{\the\neverypar}} - -%D Which we're going to use indeed! When the second argument equals \type {\relax}, -%D the first token list is created unless it is already defined. -%D -%D Technically spoken we could have used the method we are going to present in the -%D visual debugger. First we save the primitive \type{\everypar}: -%D -%D \starttyping -%D \let\normaleverypar=\everypar -%D \stoptyping -%D -%D Next we allocate a \TOKENLIST\ named \type{\everypar}, which means that -%D \type{\everypar} is no longer a primitive but something like \type{\toks44}. -%D -%D \starttyping -%D \newtoks\everypar -%D \stoptyping -%D -%D Because \TEX\ now executes \type{\normaleverypar} instead of \type{\everypar}, we -%D are ready to assign some tokens to this internally known and used \TOKENLIST. -%D -%D \starttyping -%D \normaleverypar={all the things the system wants to do \the\everypar} -%D \stoptyping -%D -%D Where the user can provide his own tokens to be expanded every time he expects -%D them to expand. -%D -%D \starttyping -%D \everypar={something the user wants to do} -%D \stoptyping -%D -%D We don't use this method because it undoubtly leads to confusing situations, -%D especially when other packages are used, but it's this kind of tricks that make -%D \TEX\ so powerful. - -%D \macros -%D {convertargument,convertcommand,convertvalue} -%D -%D Some persistent experimenting led us to the next macro. This macro converts a -%D parameter or an expanded macro to it's textual meaning. -%D -%D \starttyping -%D \convertargument ... \to \command -%D \stoptyping -%D -%D For example, -%D -%D \starttyping -%D \convertargument{one \two \three{four}}\to\ascii -%D \stoptyping -%D -%D The resulting macro \type{\ascii} can be written to a file or the terminal -%D without problems. In \CONTEXT\ we use this macro for generating registers and -%D tables of contents. -%D -%D The second conversion alternative accepts a command: -%D -%D \starttyping -%D \convertcommand\command\to\ascii -%D \stoptyping -%D -%D Both commands accept the prefix \type{\doglobal} for global assignments. - -\unexpanded\def\convertvalue#1\to - {\expandafter\convertcommand\csname#1\endcsname\to} - -\unexpanded\def\defconvertedvalue#1#2% less sensitive for \to - {\expandafter\defconvertedcommand\expandafter#1\csname#2\endcsname} - -%D \macros -%D {doifassignmentelse} -%D -%D A lot of \CONTEXT\ commands take optional arguments, for instance: -%D -%D \starttyping -%D \dothisorthat[alfa,beta] -%D \dothisorthat[first=foo,second=bar] -%D \dothisorthat[alfa,beta][first=foo,second=bar] -%D \stoptyping -%D -%D Although a combined solution is possible, we prefer a seperation. The next -%D command takes care of propper handling of such multi||faced commands. -%D -%D \starttyping -%D \doifassignmentelse {...} {then ...} {else ...} -%D \stoptyping - -\def\syst_helpers_check_if_assignment_else#1=#2#3^^^^0004{\if#2^^^^0003}% -\def\syst_helpers_check_else_assignment_if#1=#2#3^^^^0004{\unless\if#2^^^^0003}% - -\unexpanded\def\doifelseassignment#1% - {\expandafter\syst_helpers_check_if_assignment_else\detokenize{#1}=^^^^0003^^^^0003^^^^0004% - \expandafter\secondoftwoarguments - \else - \expandafter\firstoftwoarguments - \fi} - -\unexpanded\def\doifelseassignmentcs#1#2#3% - {\expandafter\syst_helpers_check_if_assignment_else\detokenize{#1}=^^^^0003^^^^0003^^^^0004% - \expandafter#3% - \else - \expandafter#2% - \fi} - -\let\doifassignmentelse \doifelseassignment -\let\doifassignmentelsecs\doifelseassignmentcs - -\newif\ifassignment - -\unexpanded\def\docheckassignment#1% - {\expandafter\syst_helpers_check_if_assignment_else\detokenize{#1}=^^^^0003^^^^0003^^^^0004% - \assignmentfalse - \else - \assignmenttrue - \fi} - -%D These can be used for cases where we want less tracing noise. - -\unexpanded\def\validassignment#1% - {\expandafter\syst_helpers_check_else_assignment_if\detokenize{#1}=^^^^0003^^^^0003^^^^0004} - -\unexpanded\def\novalidassignment#1% - {\expandafter\syst_helpers_check_if_assignment_else\detokenize{#1}=^^^^0003^^^^0003^^^^0004} - -%D In \ETEX\ we can use \type {\detokenize} and gain some speed, but in general far -%D less that 1\% for \type {\convertargument} and nil for \type {\convertcommand}. -%D This macro is more robust than the pure \TEX\ one, something I found out when -%D primitives like \type {\jobname} were fed (or something undefined). - -\unexpanded\def\convertargument#1\to#2{\dodoglobal\edef#2{\detokenize{#1}}} -\unexpanded\def\convertcommand #1\to#2{\dodoglobal\edef#2{\expandafter\detokenize\expandafter{#1}}} % hm, only second is also ok - -\unexpanded\def\defconvertedargument #1#2{\edef#1{\detokenize{#2}}} -\unexpanded\def\defconvertedcommand #1#2{\edef#1{\detokenize\expandafter{#2}}} -\unexpanded\def\edefconvertedargument#1#2{\edef#1{#2}% - \edef#1{\detokenize\expandafter{#1}}} -\unexpanded\def\gdefconvertedargument#1#2{\xdef#1{\detokenize{#2}}} -\unexpanded\def\gdefconvertedcommand #1#2{\xdef#1{\detokenize\expandafter{#2}}} -\unexpanded\def\xdefconvertedargument#1#2{\xdef#1{#2}% - \xdef#1{\detokenize\expandafter{#1}}} - -%D When you try to convert a primitive command, you'll find out that the \ETEX\ -%D method fails on for instance \type {\jobname} in the sense that it returns the -%D filename instead of just \type {\jobname}. So far this does not give real -%D problems. - -%D This is typically a macro that one comes to after reading the \TEX book -%D carefully. Even then, the definite solution was found after rereading the \TEX -%D book. The first implementation was: -%D -%D \starttyping -%D \def\doconvertargument#1->#2\\\\{#2} -%D \stoptyping -%D -%D The \type {-}, the delimiter \type {\\\\} and the the second argument are -%D completely redundant. - -%D \macros -%D {showvalue} -%D -%D Ahandy macro, for testing purposes only: - -\unexpanded\def\showvalue#1% - {\ifcsname#1\endcsname - \expandafter\show\csname#1\endcsname - \else - \show\undefined - \fi} - -%D \macros -%D {doifmeaningelse} -%D -%D We can use both commands in testing, but alas, not all meanings expand to -%D something \type {->}. This is no problem in the \ETEX\ implementation, but since -%D we want compatibility, we need: -%D -%D \starttyping -%D \doifmeaningelse {\next} {\something} {true} {false} -%D \stoptyping -%D -%D Watch the one level expansion of the second argument. - -\unexpanded\def\doifelsemeaning#1#2% - {\edef\m_syst_string_one{\normalmeaning#1}% - \def \m_syst_string_two{#2}% - \edef\m_syst_string_two{\normalmeaning\m_syst_string_two}% - \ifx\m_syst_string_one\m_syst_string_two - \expandafter\firstoftwoarguments - \else - \expandafter\secondoftwoarguments - \fi} - -\let\doifmeaningelse\doifelsemeaning - -%D \macros -%D {doifsamestringselse,doifsamestring,doifnotsamestring} -%D -%D The next comparison macro converts the arguments into expanded strings. This -%D command can be used to compare for instance \type {\jobname} with a name stored -%D in a macro. -%D -%D \starttyping -%D \doifelse {\jobname}{oeps}{YES}{NO} -%D \doifsamestringelse{\jobname}{oeps}{YES}{NO} -%D \stoptyping - -\def\syst_helpers_if_samestring_else#1#2#3#4% - {\edef\m_syst_string_one{\detokenize\expandafter{\normalexpanded{#3}}}% - \edef\m_syst_string_two{\detokenize\expandafter{\normalexpanded{#4}}}% - \ifx\m_syst_string_one\m_syst_string_two\expandafter#1\else\expandafter#2\fi} - -\unexpanded\def\doifelsesamestring{\syst_helpers_if_samestring_else\firstoftwoarguments\secondoftwoarguments} -\unexpanded\def\doifsamestring {\syst_helpers_if_samestring_else\firstofoneargument \gobbleoneargument } -\unexpanded\def\doifnotsamestring {\syst_helpers_if_samestring_else\gobbleoneargument \firstofoneargument } - -\let\doifsamestringelse\doifelsesamestring - -%D \macros -%D {ConvertToConstant,ConvertConstantAfter} -%D -%D When comparing arguments with a constant, we can get into trouble when this -%D argument consists of tricky expandable commands. One solution for this is -%D converting the argument to a string of unexpandable characters. To make -%D comparison possible, we have to convert the constant too. -%D -%D \starttyping -%D \ConvertToConstant\doifelse {...} {...} {then ...} {else ...} -%D \stoptyping -%D -%D This construction is only needed when the first argument can give troubles. -%D Misuse can slow down processing. -%D -%D \starttyping -%D \ConvertToConstant\doifelse{\c!alfa} {\c!alfa}{...}{...} -%D \ConvertToConstant\doifelse{alfa} {\c!alfa}{...}{...} -%D \ConvertToConstant\doifelse{alfa} {alfa} {...}{...} -%D \ConvertToConstant\doifelse{alfa \alfa test}{\c!alfa}{...}{...} -%D \stoptyping -%D -%D In examples~2 and~3 both arguments equal, in~1 and~4 they differ. - -\unexpanded\def\ConvertToConstant#1#2#3% - {\edef\m_syst_string_one{\expandafter\detokenize\expandafter{#2}}% - \edef\m_syst_string_two{\expandafter\detokenize\expandafter{#3}}% - #1{\m_syst_string_one}{\m_syst_string_two}} - -%D When the argument \type{#1} consists of commands, we had better use -%D -%D \starttyping -%D \ConvertConstantAfter\processaction[#1][...] -%D \ConvertConstantAfter\doifelse{#1}{\v!something}{}{} -%D \stoptyping -%D -%D This commands accepts things like: -%D -%D \starttyping -%D \v!constant -%D constant -%D \hbox to \hsize{\rubish} -%D \stoptyping -%D -%D As we will see in the core modules, this macro permits constructions like: -%D -%D \starttyping -%D \setupfootertexts[...][...] -%D \setupfootertexts[margin][...][...] -%D \setupfootertexts[\v!margin][...][...] -%D \stoptyping -%D -%D where \type {...} can be anything legally \TEX. - -\unexpanded\def\CheckConstantAfter#1#2% - {\expandafter\convertargument\v!prefix!\to\ascii - \convertargument#1\to#2\relax - \doifelseinstring\ascii{#2} - {\expandafter\convertargument#1\to#2} - {}} - -\unexpanded\def\ConvertConstantAfter#1#2#3% - {\CheckConstantAfter{#2}\asciia - \CheckConstantAfter{#3}\asciib - #1{\asciia}{\asciib}} - -%D \macros -%D {assignifempty} -%D -%D We can assign a default value to an empty macro using: -%D -%D \starttyping -%D \assignifempty \macros {default value} -%D \stoptyping -%D -%D We don't explicitly test if the macro is defined. - -\unexpanded\def\assignifempty#1#2% can be sped up - {\doifsomething{#1}{\def#1{#2}}} % {\doifnot{#1}{}{\def#1{#2}}} - -%D \macros -%D {gobbleuntil,grabuntil,gobbleuntilrelax, -%D processbetween,processuntil} -%D -%D In \TEX\ gobbling usually stand for skipping arguments, so here are our gobbling -%D macros. -%D -%D In \CONTEXT\ we use a lot of \type {\start}||\type {\stop} like constructions. -%D Sometimes, the \type {\stop} is used as a hard coded delimiter like in: %D -%D \starttyping -%D \unexpanded\def\startcommand#1\stopcommand% -%D {... #1 ...} -%D \stoptyping -%D -%D In many cases the \type {\start}||\type {\stop} pair is defined at format -%D generation time or during a job. This means that we cannot hardcode the \type -%D {\stop} criterium. Only after completely understanding \type {\csname} and \type -%D {\expandafter} I was able to to implement a solution, starting with: -%D -%D \starttyping -%D \grabuntil{stop}\command -%D \stoptyping -%D -%D This commands executes, after having encountered \type {\stop} the command \type -%D {\command}. This command receives as argument the text preceding the \type -%D {\stop}. This means that: -%D -%D \starttyping -%D \unexpanded\def\starthello% -%D {\grabuntil{stophello}\message} -%D -%D \starthello Hello world!\stophello -%D \stoptyping -%D -%D results in: \type{\message{Hello world!}}. - -\let\syst_helpers_grab_indeed\relax - -\unexpanded\def\syst_helpers_grab#1#2% - {\def\syst_helpers_grab_indeed##1#1{#2{##1}}\syst_helpers_grab_indeed} - -\unexpanded\def\grabuntil#1% - {\expandafter\syst_helpers_grab\expandafter{\csname#1\endcsname}} - -%D The next command build on this mechanism: -%D -%D \starttyping -%D \processbetween{string}\command -%D \stoptyping -%D -%D Here: -%D -%D \starttyping -%D \processbetween{hello}\message -%D \starthello Hello again!\stophello -%D \stoptyping -%D -%D leads to: \type{\message{Hello again!}}. The command -%D -%D \starttyping -%D \gobbleuntil{sequence} -%D \stoptyping -%D -%D is related to these commands. This one simply throws away -%D everything preceding \type{\command}. - -\let\syst_helpers_gobble_indeed\relax - -\unexpanded\def\processbetween#1#2% - {\setvalue{\s!start#1}{\grabuntil{\s!stop#1}{#2}}} - -\unexpanded\def\gobbleuntil#1% - {\def\syst_helpers_gobble_indeed##1#1{}\syst_helpers_gobble_indeed} - -\unexpanded\def\gobbleuntilrelax#1\relax - {} - -%D The next one simply expands the pickup up tokens. -%D -%D \starttyping -%D \processuntil{sequence} -%D \stoptyping - -\let\syst_helpers_until_indeed\relax - -\unexpanded\def\processuntil#1% - {\def\syst_helpers_until_indeed##1#1{##1}\syst_helpers_until_indeed} - -%D \macros -%D {groupedcommand} -%D -%D Commands often manipulate argument as in: -%D -%D \starttyping -%D \def\doezomaarwat#1{....#1....} -%D \stoptyping -%D -%D A disadvantage of this approach is that the tokens that form \type{#1} are fixed -%D the the moment the argument is read in. Normally this is no problem, but for -%D instance verbatim environments adapt the \CATCODES\ of characters and therefore -%D are not always happy with already fixed tokens. -%D -%D Another problem arises when the argument is grouped not by \type {{}} but by -%D \type {\bgroup} and \type {\egroup}. Such an argument fails, because the \type -%D {\bgroup} is een as the argument (which is quite normal). -%D -%D The next macro offers a solution for both unwanted situations: -%D -%D \starttyping -%D \groupedcommand {before} {after} -%D \stoptyping -%D -%D Which can be used like: -%D -%D \starttyping -%D \def\cite% -%D {\groupedcommand{\rightquote\rightquote}{\leftquote\leftquote}} -%D \stoptyping -%D -%D This command is equivalent to, but more 'robust' than: -%D -%D \starttyping -%D \def\cite#1% -%D {\rightquote\rightquote#1\leftquote\leftquote} -%D \stoptyping -%D -%D \starttyping -%D \def\rightword% -%D {\groupedcommand{\hfill\hbox}{\parfillskip\zeropoint}} -%D -%D .......... \rightword{the right way} -%D \stoptyping -%D -%D Here \TEX\ typesets \type {\bf the right way} unbreakable at the end of the line. -%D The solution mentioned before does not work here. We also handle -%D -%D \starttyping -%D to be \bold{bold} or not, that's the question -%D \stoptyping -%D -%D and -%D -%D \starttyping -%D to be {\bold bold} or not, that's the question -%D \stoptyping -%D -%D This alternative checks for a \type {\bgroup} token first. The internal -%D alternative does not accept the box handling mentioned before, but further -%D nesting works all right. The extra \type {\bgroup}||\type {\egroup} is needed to -%D keep \type {\m_syst_helpers_handle_group_after} both into sight and local. - -\let\m_syst_helpers_handle_group_after \relax -\let\m_syst_helpers_handle_group_before\relax - -\unexpanded\def\syst_helpers_handle_group_nop - {\ifnum\currentgrouptype=\semisimplegroupcode - \expandafter\syst_helpers_handle_group_nop_a - \else - \expandafter\syst_helpers_handle_group_nop_b - \fi} - -\def\syst_helpers_handle_group_nop_a - {\begingroup - \aftergroup\m_syst_helpers_handle_group_a - \aftergroup\endgroup - \m_syst_helpers_handle_group_b} - -\def\syst_helpers_handle_group_nop_b - {\bgroup - \aftergroup\m_syst_helpers_handle_group_a - \aftergroup\egroup - \m_syst_helpers_handle_group_b} - -\unexpanded\def\syst_helpers_handle_group_normal - {\bgroup - \afterassignment\m_syst_helpers_handle_group_normal_before - \let\next=} - -\def\m_syst_helpers_handle_group_normal_before - {\bgroup - \m_syst_helpers_handle_group_b - \bgroup - \aftergroup\m_syst_helpers_handle_group_a - \aftergroup\egroup - \aftergroup\egroup} - -\unexpanded\def\syst_helpers_handle_group_simple% no inner group (so no kerning interference) - {\bgroup - \afterassignment\m_syst_helpers_handle_group_simple_before - \let\next=} - -\def\m_syst_helpers_handle_group_simple_before - {\bgroup - \aftergroup\m_syst_helpers_handle_group_simple_after - \m_syst_helpers_handle_group_b} - -\def\m_syst_helpers_handle_group_simple_after - {\m_syst_helpers_handle_group_a - \egroup}% - -\unexpanded\def\syst_helpers_handle_group_pickup% no inner group (so no kerning interference) - {\bgroup - \afterassignment\m_syst_helpers_handle_group_pickup_before - \let\next=} - -\def\m_syst_helpers_handle_group_pickup_before - {\bgroup - \aftergroup\m_syst_helpers_handle_group_a - \aftergroup\egroup - \aftergroup\m_syst_helpers_handle_group_p - \m_syst_helpers_handle_group_b} - -\unexpanded\def\syst_helpers_handle_group_nop_x - {\ifnum\currentgrouptype=\semisimplegroupcode - \begingroup - \aftergroup\endgroup - \else - \bgroup - \aftergroup\egroup - \fi - \m_syst_helpers_handle_group_b} - -\unexpanded\def\syst_helpers_handle_group_normal_x - {\bgroup - \afterassignment\m_syst_helpers_handle_group_normal_before_x - \let\next=} - -\def\m_syst_helpers_handle_group_normal_before_x - {\bgroup - \m_syst_helpers_handle_group_b - \bgroup - \aftergroup\egroup - \aftergroup\egroup} - -%D I considered it a nuisance that -%D -%D \starttyping -%D \color[green] -%D {as grass} -%D \stoptyping -%D -%D was not interpreted as one would expect. This is due to the fact that \type -%D {\futurelet} obeys blank spaces, and a line||ending token is treated as a blank -%D space. So the final implementation became: - -\unexpanded\def\groupedcommand#1#2% - {\def\m_syst_helpers_handle_group_b{#1}% - \def\m_syst_helpers_handle_group_a{#2}% - \futureexpandis\bgroup\syst_helpers_handle_group_normal\syst_helpers_handle_group_nop} - -\unexpanded\def\groupedcommandcs#1#2% - {\let\m_syst_helpers_handle_group_b#1% - \let\m_syst_helpers_handle_group_a#2% - \futureexpandis\bgroup\syst_helpers_handle_group_normal\syst_helpers_handle_group_nop} - -\unexpanded\def\simplegroupedcommand#1#2% - {\def\m_syst_helpers_handle_group_b{#1}% - \def\m_syst_helpers_handle_group_a{#2}% - \futureexpandis\bgroup\syst_helpers_handle_group_simple\syst_helpers_handle_group_nop} - -\unexpanded\def\pickupgroupedcommand#1#2#3% - {\def\m_syst_helpers_handle_group_b{#1}% - \def\m_syst_helpers_handle_group_a{#2}% - \def\m_syst_helpers_handle_group_p{#3}% - \futureexpandis\bgroup\syst_helpers_handle_group_pickup\syst_helpers_handle_group_nop} - -\unexpanded\def\triggergroupedcommand#1% - {\def\m_syst_helpers_handle_group_b{#1}% - \futureexpandis\bgroup\syst_helpers_handle_group_normal_x\syst_helpers_handle_group_nop_x} - -\unexpanded\def\triggergroupedcommandcs#1% - {\let\m_syst_helpers_handle_group_b#1% - \futureexpandis\bgroup\syst_helpers_handle_group_normal_x\syst_helpers_handle_group_nop_x} - -%D Users should be aware of the fact that grouping can interfere with ones paragraph -%D settings that are executed after the paragraph is closed. One should therefore -%D explictly close the paragraph with \type {\par}, else the settings will be -%D forgotten and not applied. So it's: -%D -%D \starttyping -%D \def\BoldRaggedCenter% -%D {\groupedcommand{\raggedcenter\bf}{\par}} -%D \stoptyping - -%D \macros -%D {checkdefined} -%D -%D The bigger the system, the greater the change that user defined commands collide -%D with those that are part of the system. The next macro gives a warning when a -%D command is already defined. We considered blocking the definition, but this is -%D not always what we want. -%D -%D \starttyping -%D \checkdefined {category} {class} {command} -%D \stoptyping -%D -%D The user is warned with the suggestion to use \type {CAPITALS}. This suggestion -%D is feasible, because \CONTEXT only defines lowcased macros. - -\unexpanded\def\showdefinederror#1#2% - {\writestatus\m!system{#1 #2 replaces a macro, use CAPITALS!}} - -\unexpanded\def\checkdefined#1#2#3% - {\doifdefined{#3}{\showdefinederror{#2}{#3}}} - -%D \macros -%D {GotoPar,GetPar} -%D -%D Typesetting a paragraph in a special way can be done by first grabbing the -%D contents of the paragraph and processing this contents grouped. The next macro -%D for instance typesets a paragraph in boldface. -%D -%D \starttyping -%D \def\remark#1\par% -%D {\bgroup\bf#1\egroup} -%D \stoptyping -%D -%D This macro has to be called like -%D -%D \starttyping -%D \remark some text ... ending with \par -%D \stoptyping -%D -%D Instead of \type {\par} we can of course use an empty line. When we started -%D typesetting with \TEX, we already had produced lots of text in plain \ASCII. In -%D producing such simple formatted texts, we adopted an open layout, and when -%D switching to \TEX, we continued this open habit. Although \TEX\ permits a cramped -%D and badly formatted source, it adds to confusion and sometimes introduces errors. -%D So we prefer: -%D -%D \starttyping -%D \remark -%D -%D some text ... ending with an empty line -%D \stoptyping -%D -%D We are going to implement a mechanism that allows such open specifications. The -%D definition of the macro handling \type {\remark} becomes: -%D -%D \starttyping -%D \def\remark% -%D {\BeforePar{\bgroup\bf}% -%D \AfterPar{\egroup}% -%D \GetPar} -%D \stoptyping -%D -%D A macro like \type {\GetPar} can be defined in several ways. The recent version, -%D the fourth one in a row, originally was far more complicated, but some -%D functionality has been moved to other macros. -%D -%D We start with the more simple but in some cases more appropriate alternative is -%D \type {\GotoPar}. This one leaves \type {\par} unchanged and is therefore more -%D robust. On the other hand, \type {\AfterPar} is not supported. - -\newtoks\BeforePar -\newtoks\AfterPar - -\def\redowithpar\par - {\doifelsenextchar\par\redowithpar\dodowithpar}% - -\def\dowithpar#1#2% - {\def\dodowithpar##1\par{#1##1#2}% - \redowithpar\par} - -\def\redogotopar\par - {\doifelsenextchar\par\redogotopar\dodogotopar}% - -\def\dogotopar#1% - {\def\dodogotopar{#1}% - \redogotopar\par} - -\def\dogotoparcs#1% - {\let\dodogotopar#1% - \redogotopar\par} - -\unexpanded\def\GetPar - {\expanded - {\dowithpar - {\the\BeforePar - \BeforePar\emptytoks} - {\the\AfterPar - \BeforePar\emptytoks - \AfterPar\emptytoks}}} - -\unexpanded\def\GotoPar - {\expanded - {\dogotopar - {\the\BeforePar - \BeforePar\emptytoks}}} - -%D \macros -%D {dowithpargument,dowithwargument} -%D -%D The next macros are a variation on \type {\GetPar}. When macros expect an -%D argument, it interprets a grouped sequence of characters a one token. While this -%D adds to robustness and less ambiguous situations, we sometimes want to be a bit -%D more flexible, or at least want to be a bit more tolerant to user input. -%D -%D We start with a commands that acts on paragraphs. This -%D command is called as: -%D -%D \starttyping -%D \dowithpargument\command -%D \dowithpargument{\command ... } -%D \stoptyping -%D -%D In \CONTEXT\ we use this one to read in the titles of chapters, sections etc. The -%D commands responsible for these activities accept several alternative ways of -%D argument passing. In these examples, the \type {\par} can be omitted when an -%D empty line is present. -%D -%D \starttyping -%D \command{...} -%D \command ... \par -%D \command -%D {...} -%D \command -%D ... \par -%D \stoptyping - -\let\syst_helpers_next_par\relax -\let\syst_helpers_next_arg\relax - -\unexpanded\def\dowithpargument#1% - {\def\syst_helpers_next_par##1 \par{#1{##1}}% - \def\syst_helpers_next_arg##1{#1{##1}}% - \doifelsenextbgroup\syst_helpers_next_arg{\doifelsenextchar\par{#1{}}\syst_helpers_next_par}} - -%D The \type {p} in the previous command stands for paragraph. When we want to act -%D upon words we can use the \type{w} alternative. -%D -%D \starttyping -%D \dowithwargument\command -%D \dowithwargument{... \command ...} -%D \stoptyping -%D -%D The main difference bwteen two alternatives is in the handling of \type {\par}'s. -%D This time the space token acts as a delimiter. -%D -%D \starttyping -%D \command{...} -%D \command ... -%D \command -%D {...} -%D \command -%D ... -%D \stoptyping - -\let\syst_helpers_next_war\relax -\let\syst_helpers_next_arg\relax - -\unexpanded\def\dowithwargument#1% - {\def\syst_helpers_next_war##1 {#1{##1}}% - \def\syst_helpers_next_arg##1{#1{##1}}% - \doifelsenextbgroup\syst_helpers_next_arg\syst_helpers_next_war} - -%D \macros -%D {dorepeat,dorepeatwithcommand} -%D -%D When doing repetitive tasks, we stromgly advice to use \type {\dorecurse}. The -%D next alternative however, suits better some of the \CONTEXT\ interface commands. -%D -%D \starttyping -%D \dorepeat[n*\command] -%D \stoptyping -%D -%D The value of the used \COUNTER\ can be called within -%D \type{\command} by \type{\repeater}. -%D -%D A slightly different alternative is: -%D -%D \starttyping -%D \dorepeatwithcommand[n*{...}]\command -%D \stoptyping -%D -%D When we call for something like: -%D -%D \starttyping -%D \dorepeatwithcommand[3*{Hello}]\message -%D \stoptyping -%D -%D we get ourselves three \type {\message{Hello}} messages in a row. In both -%D commands, the \type {n*} is optional. When this specification is missing, the -%D command executes once. - -\unexpanded\def\dorepeatwithcommand[#1]% - {\syst_helpers_repeat_with_command#1*\empty*\relax} - -\def\syst_helpers_repeat_with_command#1*#2#3*#4\relax#5% - {\ifx#2\empty\syst_helpers_repeat_with_command_again[#1]#5\else\syst_helpers_repeat_with_command_indeed{#1}{#2}{#3}#5\fi} - -\def\syst_helpers_repeat_with_command_indeed#1#2#3#4% - {\ifx#2\empty % redundant but gives cleaner extensions - #4{#1}% - \orelse\ifnum#1<\zerocount - %\normalexpanded{\dorecurse{\number-\number#1}}{#4{-#2#3}}% - \dorecurse{-#1}{#4{-#2#3}}% - \orelse\ifx#2+% - \dorecurse{#1}{#4{#3}}% - \else - \dorecurse{#1}{#4{#2#3}}% - \fi} - -\def\syst_helpers_repeat_with_command_again[#1]#2% - {#2{#1}} - -%D The extension hook permits something like: -%D -%D \starttyping -%D \bgroup -%D -%D \catcode`\*=\superscriptcatcode -%D -%D \gdef\syst_helpers_repeat_with_command_again[#1]% -%D {\redodorepeatwithcommand#1*\empty*\relax} -%D -%D \gdef\redodorepeatwithcommand#1*#2#3*#4\relax#5% -%D {\syst_helpers_repeat_with_command_indeed{#1}{#2}{#3}#5} -%D -%D \egroup -%D \stoptyping -%D -%D although one may wonder if changing the catcode of \type {*} is wise. - -%D \macros -%D {doifstringinstringelse} -%D -%D The next macro is meant for situations where both strings are macros. This save -%D some unneeded expansion. -%D -%D \starttyping -%D \def\doifstringinstringelse#1#2% -%D {\syst_helpers_do_if_in_string_else#1#2% -%D \expandafter\firstoftwoarguments -%D \else -%D \expandafter\secondoftwoarguments -%D \fi} -%D \stoptyping -%D -%D A bit faster is: - -\def\syst_helpers_if_instring_else_indeed#1% - {\if#1@% - \expandafter\secondoftwoarguments - \else - \expandafter\firstoftwoarguments - \fi} - -\def\doifelsestringinstring#1#2% - {\expandafter\def\expandafter\syst_helpers_if_instring_else\expandafter##\expandafter1#1##2##3^^^^0004% - {\syst_helpers_if_instring_else_indeed##2}% - \expandafter\expandafter\expandafter\syst_helpers_if_instring_else\expandafter#2#1@@^^^^0004} - -\let\doifstringinstringelse\doifelsestringinstring - -%D \macros -%D {appendtoks,prependtoks,appendtoksonce,prependtoksonce, -%D doifintokselse,flushtoks,dotoks} -%D -%D We use tokenlists sparsely within \CONTEXT, because the comma separated lists are -%D more suitable for the user interface. Nevertheless we have: -%D -%D \starttyping -%D (\doglobal) \appendtoks ... \to\tokenlist -%D (\doglobal) \prependtoks ... \to\tokenlist -%D (\doglobal) \flushtoks\tokenlist -%D \dotoks\tokenlist -%D \stoptyping -%D -%D These macros are clones of the ones implemented in page~378 of Knuth's \TEX book. - -\newtoks\t_syst_helpers_scratch -\let \m_syst_helpers_scratch\empty - -\unexpanded\def\appendtoks#1\to#2% - {\ifx\dodoglobal\relax - \expandafter\toksapp - \else - \resetglobal - \expandafter\gtoksapp - \fi#2{#1}} - -\unexpanded\def\prependtoks#1\to#2% - {\ifx\dodoglobal\relax - \expandafter\tokspre - \else - \resetglobal - \expandafter\gtokspre - \fi#2{#1}} - -\def\syst_helpers_append_toks_indeed - {\ifx\dodoglobal\relax - \expandafter\toksapp - \else - \resetglobal - \expandafter\gtoksapp - \fi\m_syst_helpers_scratch\t_syst_helpers_scratch} - -\def\syst_helpers_prepend_toks_indeed - {\ifx\dodoglobal\relax - \expandafter\tokspre - \else - \resetglobal - \expandafter\gtokspre - \fi\m_syst_helpers_scratch\t_syst_helpers_scratch} - -\unexpanded\def\appendtoksonce#1\to#2% - {\let\m_syst_helpers_scratch#2% - \t_syst_helpers_scratch{#1}% - \doifelseintoks\t_syst_helpers_scratch\m_syst_helpers_scratch - \donothing - \syst_helpers_append_toks_indeed} - -\unexpanded\def\prependtoksonce#1\to#2% - {\let\m_syst_helpers_scratch#2% - \t_syst_helpers_scratch{#1}% - \doifelseintoks\t_syst_helpers_scratch\m_syst_helpers_scratch - \donothing - \syst_helpers_prepend_toks_indeed} - -%D The test macro: - -\unexpanded\def\doifelseintoks#1#2% #1 en #2 zijn toks - {\edef\asciia{\detokenize\expandafter{\the#1}}% - \edef\asciib{\detokenize\expandafter{\the#2}}% - \doifelsestringinstring\asciia\asciib} - -\let\doifintokselse\doifelseintoks - -%D Moved from \type {lxml-ini.tex} to here. This one is for generators that collect -%D stuff piecewise, which is sometimes hard on mechanisms that grab content using -%D delimiters: -%D -%D \starttyping -%D \startcollecting -%D \startcollect \bTABLE \stopcollect -%D \startcollect \bTR \stopcollect -%D \startcollect \bTD \stopcollect -%D \startcollect foo\stopcollect -%D \startcollect \eTD \stopcollect -%D \startcollect \bTD \stopcollect -%D \startcollect bar\stopcollect -%D \startcollect \eTD \stopcollect -%D \startcollect \eTR \stopcollect -%D \startcollect \eTABLE \stopcollect -%D \stopcollecting -%D \stoptyping - -\newtoks \collectingtoks - -\unexpanded\def\startcollect #1\stopcollect {\toksapp \collectingtoks{#1}} -\unexpanded\def\startexpandedcollect#1\stopexpandedcollect{\etoksapp\collectingtoks{#1}} - -\unexpanded\def\startcollecting{\collectingtoks\emptytoks} -\unexpanded\def\stopcollecting {\the\collectingtoks} - -\unexpanded\def\collect {\toksapp \collectingtoks} -\unexpanded\def\collectexpanded{\etoksapp\collectingtoks} - -%D A nice one too: - -% {\scratchtoks{abc} \removetoks b\from\scratchtoks [\the\scratchtoks]} -% {\scratchtoks{abc} \removetoks x\from\scratchtoks [\the\scratchtoks]} -% {\scratchtoks{} \removetoks x\from\scratchtoks [\the\scratchtoks]} -% {\scratchtoks{xaa} \removetoks x\from\scratchtoks [\the\scratchtoks]} -% {\scratchtoks{a\relax b} \removetoks \relax\from\scratchtoks [\showthe\scratchtoks]} - -\unexpanded\def\removetoks#1\from#2% - {\def\syst_helpers_remove_toks##1#1##2\empty\empty\empty##3^^^^0004% - {\def\m_syst_string_one{##3}% - \ifx\m_syst_string_one\empty#2{##1}\else#2{##1##2}\fi}% - \expandafter\syst_helpers_remove_toks\the#2\empty\empty\empty#1\empty\empty\empty^^^^0004} - -%D Also: - -\unexpanded\def\appendetoks#1\to#2% - {\ifx\dodoglobal\relax - \expandafter\etoksapp - \else - \resetglobal - \expandafter\xtoksapp - \fi#2{#1}} - -\unexpanded\def\prependetoks#1\to#2% - {\ifx\dodoglobal\relax - \expandafter\etokspre - \else - \resetglobal - \expandafter\xtokspre - \fi#2{#1}} - -%D Hm. - -\unexpanded\def\flushtoks#1% nb: can reassign to #1 again, hence the indirectness - {\t_syst_helpers_scratch#1\relax - \dodoglobal#1\emptytoks - \the\t_syst_helpers_scratch\relax} - -\let\dotoks\the - -%D \macros -%D {beforesplitstring,aftersplitstring} -%D -%D These both commands split a string at a given point in two -%D parts, so \type{x.y} becomes \type{x} or \type{y}. -%D -%D \starttyping -%D \beforesplitstring test.tex\at.\to\filename -%D \aftersplitstring test.tex\at.\to\extension -%D \stoptyping -%D -%D The first routine looks (and is indeed) a bit simpler than the second one. The -%D alternative looking more or less like the first one did not always give the -%D results we needed. Both implementations show some insight in the manipulation of -%D arguments. - -\let\syst_helpers_split_string\relax - -\unexpanded\def\beforesplitstring#1\at#2\to#3% - {\def\syst_helpers_split_string##1#2##2#2##3\\% - {\def#3{##1}}% - \expandafter\syst_helpers_split_string#1#2#2\\} - -\unexpanded\def\aftersplitstring#1\at#2\to#3% - {\def\syst_helpers_split_string##1#2##2@@@##3\\% - {\def#3{##2}}% - \expandafter\syst_helpers_split_string#1@@@#2@@@\\} - -%D \macros -%D {splitstring,greedysplitstring} -%D -%D A bonus macro. - -\unexpanded\def\splitstring#1\at#2\to#3\and#4% - {\def\syst_helpers_split_string##1#2##2\empty\empty\empty##3\\% - {\def#3{##1}% - \def\syst_helpers_split_string{##3}% - \ifx\syst_helpers_split_string\empty - \let#4\empty - \else - \def#4{##2}% - \fi}% - \expandafter\syst_helpers_split_string#1\empty\empty\empty#2\empty\empty\empty\\} - -\unexpanded\def\greedysplitstring#1\at#2\to#3\and#4% - {\edef\asciib{#1}% - \let\asciic\asciib - \let#3\empty - \let#4\empty - \doloop - {\expandafter\splitstring\asciib\at#2\to\asciia\and\asciib - \ifx\asciib\empty - \exitloop - \else - % not \edef#3{\ifx#3\empty\else#3#2\fi\asciia} else - % /root/path fails because then #3==empty - \edef#3{\ifcase\recurselevel\or\else#3#2\fi\asciia}% - \let#4\asciib - \fi}% - \ifx#3\empty\let#3\asciic\fi} - -%D \macros -%D {beforetestandsplitstring, -%D aftertestandsplitstring, -%D testandsplitstring} - -\unexpanded\def\beforetestandsplitstring#1\at#2\to#3% - {\def\syst_helpers_split_string##1#2##2#2##3##4\\% - {\ifx##3\empty\let#3\empty\else\def#3{##1}\fi}% - \expandafter\syst_helpers_split_string#1#2#2\empty\\} - -\unexpanded\def\aftertestandsplitstring#1\at#2\to#3% - {\def\syst_helpers_split_string ##1#2##2@@@##3##4\\% - {\ifx##3\empty\let#3\empty\else\def#3{##2}\fi}% - \expandafter\syst_helpers_split_string #1@@@#2@@@\empty\\} - -\def\testandsplitstring#1\at#2\to#3\and#4% - {\def\syst_helpers_split_string##1#2##2#2##3##4\\% - {\ifx##3\empty\let#3\empty\let#4\empty\else\def#3{##1}\def#4{##2}\fi}% - \expandafter\syst_helpers_split_string#1#2#2\empty\\} - -%D \macros -%D {splitatperiod, -%D {splitatcomma, -%D splitatasterisk, -%D splitatcolon, -%D splitatcolons} - -\unexpanded\def\splitatperiod #1{\normalexpanded{\syst_helpers_splitatperiod #1}..\relax} -\unexpanded\def\splitatcomma #1{\normalexpanded{\syst_helpers_splitatcomma #1},,\relax} % not at ", " -\unexpanded\def\splitatasterisk#1{\normalexpanded{\syst_helpers_splitatasterisk#1}**\relax} -\unexpanded\def\splitatcolon #1{\normalexpanded{\syst_helpers_splitatcolon #1}::\relax} -\unexpanded\def\splitatcolons #1{\normalexpanded{\syst_helpers_splitatcolons #1}::::\relax} - -\unexpanded\def\syst_helpers_splitatperiod #1.#2.#3\relax#4#5{\def#4{#1}\def#5{#2}} -\unexpanded\def\syst_helpers_splitatcomma #1,#2,#3\relax#4#5{\def#4{#1}\def#5{#2}} -\unexpanded\def\syst_helpers_splitatasterisk #1*#2*#3\relax#4#5{\def#4{#1}\def#5{#2}} -\unexpanded\def\syst_helpers_splitatcolon #1:#2:#3\relax#4#5{\def#4{#1}\def#5{#2}} -\unexpanded\def\syst_helpers_splitatcolons #1::#2::#3\relax#4#5{\edef#4{#1}\edef#5{#2}} - -%D \macros -%D {removesubstring} -%D -%D A first application of the two routines defined above is: -%D -%D \starttyping -%D \removesubstring-\from first-last\to\nothyphenated -%D \stoptyping -%D -%D Which in terms of \TEX\ looks like: - -\unexpanded\def\removesubstring#1\from#2\to#3% - {\splitstring#2\to\m_syst_string_one\and\m_syst_string_two - \dodoglobal#3{\m_syst_string_one\m_syst_string_two}} - -%D \macros -%D {appendtocommalist,prependtocommalist, -%D addtocommalist,removefromcommalist} -%D -%D When working with comma separated lists, one sooner or later want the tools to -%D append or remove items from such a list. When we add an item, we first check if -%D it's already there. This means that every item in the list is unique. -%D -%D \starttyping -%D \addtocommalist {alfa} \name -%D \addtocommalist {beta} \name -%D \addtocommalist {gamma} \name -%D \removefromcommalist {beta} \name -%D \stoptyping -%D -%D These commands can be prefixed with \type {\doglobal}. The implementation of the -%D second command is more complecated, because we have to take leading spaces into -%D account. Keep in mind that users may provide lists with spaces after the commas. -%D When one item is left, we also have to get rid of trailing spaces. -%D -%D \starttyping -%D \def\words{alfa, beta, gamma, delta} -%D \def\words{alfa,beta,gamma,delta} -%D \stoptyping -%D -%D Removing an item takes more time than adding one. A fast appending alternative, -%D without any testing, is also provided: -%D -%D \starttyping -%D \appendtocommalist {something} \name -%D \prependtocommalist {something} \name -%D \stoptyping -%D -%D This can be implemented as follows: -%D -%D \starttyping -%D \def\appendtocommalist#1#2% -%D {\ifx#2\empty -%D \dodoglobal\edef#2{#1}% -%D \else % no test on empty -%D \dodoglobal\edef#2{#2,#1}% -%D \fi} -%D -%D \def\prependtocommalist#1#2% -%D {\ifx#2\empty -%D \dodoglobal\edef#2{#1}% -%D \else % no test on empty -%D \dodoglobal\edef#2{#1,#2}% -%D \fi} -%D \stoptyping -%D -%D The faster alternatives are: - -\unexpanded\def\appendtocommalist#1#2% - {\dodoglobal\edef#2{\ifx#2\empty\else#2,\fi#1}} - -\unexpanded\def\prependtocommalist#1#2% - {\dodoglobal\edef#2{#1\ifx#2\empty\else,#2\fi}} - -\unexpanded\def\addtocommalist#1#2% {item} \cs - {\rawdoifelseinset{#1}#2\resetglobal - {\dodoglobal\edef#2{\ifx#2\empty\else#2,\fi#1}}} - -\unexpanded\def\pretocommalist#1#2% {item} \cs - {\rawdoifelseinset{#1}#2\resetglobal - {\dodoglobal\edef#2{#1\ifx#2\empty\else,#2\fi}}} - -\unexpanded\def\robustdoifelseinset#1#2% - {\edef\m_syst_string_one{\detokenize\expandafter{\normalexpanded{#1}}}% - \edef\m_syst_string_two{\detokenize\expandafter{\normalexpanded{#2}}}% - \rawdoifelseinset\m_syst_string_one\m_syst_string_two} - -\let\robustdoifinsetelse\robustdoifelseinset - -\unexpanded\def\robustaddtocommalist#1#2% {item} \cs - {\robustdoifelseinset{#1}#2\resetglobal - {\dodoglobal\edef#2{\ifx#2\empty\else#2,\fi#1}}} - -\unexpanded\def\robustpretocommalist#1#2% {item} \cs - {\robustdoifelseinset{#1}#2\resetglobal - {\dodoglobal\edef#2{#1\ifx#2\empty\else,#2\fi}}} - -\unexpanded\def\xsplitstring#1#2% \cs {str} - {\def\syst_helpers_split_string##1,#2,##2,#2,##3\\% - {\edef\m_syst_string_one{\bcleanedupcommalist##1\empty\empty\relax}% - \edef\m_syst_string_two{\acleanedupcommalist##2,,\relax}}% - \expandafter\syst_helpers_split_string\expandafter,#1,,#2,,#2,\\} - -\def\bcleanedupcommalist#1#2#3\relax{\if#1,\else#1\fi\if#2,\else#2\fi#3} -\def\bcleanedupcommalist#1#2\relax{\if#1,\else#1\fi#2} -\def\acleanedupcommalist#1,,#2\relax{#1} - -\unexpanded\def\removefromcommalist#1#2% to be sped up - {\rawdoifelseinset{#1}#2% - {\normalexpanded{\xsplitstring\noexpand#2{#1}}% - \dodoglobal\edef#2% - {\ifx\m_syst_string_one\empty - \m_syst_string_two - \else - \m_syst_string_one\ifx\m_syst_string_two\empty\else,\m_syst_string_two\fi - \fi}} - \resetglobal} - -%D \macros -%D {substituteincommalist} -%D -%D Slow but seldom used, so for the moment we stick to this implementation. -%D -%D \starttyping -%D \substituteincommalist{old}{new}{list} -%D \stoptyping - -\def\syst_helpers_substitute_in_comma_list_step#1% - {\edef\m_syst_string_three{#1}% - \ifx\m_syst_string_one\m_syst_string_three - \ifx\m_syst_string_two\empty \else - \edef\m_syst_string_four{\ifx\m_syst_string_four\empty\else\m_syst_string_four,\fi\m_syst_string_two}% - \fi - \else - \edef\m_syst_string_four{\ifx\m_syst_string_four\empty\else\m_syst_string_four,\fi#1}% - \fi} - -\unexpanded\def\substituteincommalist#1#2#3% old, new, list (slooow) - {\edef\m_syst_string_one{#1}% - \edef\m_syst_string_two{#2}% - \let\m_syst_string_four\empty - \normalexpanded{\rawprocesscommacommand[#3]}\syst_helpers_substitute_in_comma_list_step - \let#3\m_syst_string_four} - -%D \macros -%D {replaceincommalist} -%D -%D The next macro can be used to replace an indexed element in a commalist: -%D -%D \starttyping -%D \replaceincommalist\MyList{2} -%D \stoptyping -%D -%D Element~2 will be replaced by the current meaning of the macro \type -%D {\newcommalistelement}. The old meaning is saved in \type {\commalistelement}. -%D The replacement honors grouped items, like in: -%D -%D \starttyping -%D \def\MyList{a,b,c,d,e,f} \replaceincommalist\MyList{3} -%D \def\MyList{a,b,c,d,e,f} \replaceincommalist\MyList{3} -%D \def\MyList{a,{b,c},d,e,f} \replaceincommalist\MyList{3} -%D \def\MyList{a,b,c,{d,e,f}} \replaceincommalist\MyList{3} -%D \stoptyping -%D -%D This macro was used in the bibtex code (and is probably no longer needed). - -\newcount\c_syst_helpers_comma_list_index -\let \m_syst_helpers_comma_list_target\empty - -\let\newcommalistelement\empty - -\def\syst_helpers_replace_in_comma_list_step#1% - {\ifnum\commalistcounter=\c_syst_helpers_comma_list_index\relax - \ifx\newcommalistelement\empty\else - \ifx\m_syst_helpers_comma_list_target\empty - \let\m_syst_helpers_comma_list_target\newcommalistelement - \else - \expandafter\expandafter\expandafter\def\expandafter\expandafter\expandafter - \m_syst_helpers_comma_list_target\expandafter\expandafter\expandafter - {\expandafter\m_syst_helpers_comma_list_target\expandafter,\newcommalistelement}% - \fi - \fi - \def\commalistelement{#1}% - \else - \ifx\m_syst_helpers_comma_list_target\empty - \ifx\nexttoken\bgroup % is known -) - \def\m_syst_helpers_comma_list_target{{#1}}% - \else - \def\m_syst_helpers_comma_list_target{#1}% - \fi - \else - \ifx\nexttoken\bgroup % is known -) - \expandafter\def\expandafter\m_syst_helpers_comma_list_target\expandafter{\m_syst_helpers_comma_list_target,{#1}}% - \else - \expandafter\def\expandafter\m_syst_helpers_comma_list_target\expandafter{\m_syst_helpers_comma_list_target,#1}% - \fi - \fi - \fi - \advance\commalistcounter\plusone} - -\unexpanded\def\replaceincommalist#1#2% #1 = commalistelement #2 = position starts at 1 - {\c_syst_helpers_comma_list_index#2\relax - \let\m_syst_helpers_comma_list_target\empty - \let\commalistelement\empty - \commalistcounter\plusone - \expandafter\processcommalist\expandafter[#1]\syst_helpers_replace_in_comma_list_step - \dodoglobal\let#1\m_syst_helpers_comma_list_target} - -%D \macros -%D {globalprocesscommalist} -%D -%D The commalist processing commands are characterized by the fact that the way they -%D handle expansion as well as the fact that they can be nested. This makes them -%D kind of useless for handling comma lists in alignments. In these situations the -%D next macro can be of use. - -\let\m_syst_helpers_comma_list_command_global\empty - -\def\syst_helpers_comma_list_command_global_step#1,% - {\if]#1\else - \m_syst_helpers_comma_list_command_global{#1}% - \expandafter\syst_helpers_comma_list_command_global_step - \fi} - -\unexpanded\def\globalprocesscommalist[#1]#2% - {\glet\m_syst_helpers_comma_list_command_global#2% - \expandafter\syst_helpers_comma_list_command_global_step#1,],} - -%D \macros -%D {withoutpt,PtToCm, -%D numberofpoints,dimensiontocount} -%D -%D We can convert point into centimeters with: -%D -%D \starttyping -%D \PtToCm{dimension} -%D \stoptyping - -{\catcode`\.=\othercatcode - \catcode`\p=\othercatcode - \catcode`\t=\othercatcode - \gdef\WITHOUTPT#1pt{#1}} - -\def\withoutpt#1% - {\expandafter\WITHOUTPT#1} - -%D The capitals are needed because \type {p} and \type {t} have catcode~12, while -%D macronames only permit tokens with the catcode~11. As a result we cannot use the -%D \type {.group} primitives. Those who want to know more about this kind of -%D manipulations, we advice to study the \TEX book in detail. Because this macro -%D does not do any assignment, we can use it in the following way too. - -\def\PtToCm#1% - {\withoutpt\the\dimexpr0.0351459804\dimexpr#1\relax\relax cm} - -%D We also support: -%D -%D \starttyping -%D \numberofpoints {dimension} -%D \dimensiontocount {dimension} {\count} -%D \stoptyping -%D -%D Both macros return a rounded number. - -% \dimensiontocount{10.49pt}\scratchcounter \the\scratchcounter / \numberofpoints{10.49pt} -% \dimensiontocount{10.51pt}\scratchcounter \the\scratchcounter / \numberofpoints{10.51pt} - -\def\dimensiontocount#1#2{#2\numexpr\dimexpr#1\relax/\maxcard\relax} -\def\numberofpoints #1{\the\numexpr\dimexpr#1\relax/\maxcard\relax} - -%D \macros -%D {swapdimens,swapcounts,swapmacros, -%D globalswapdimens,globalswapcounts,globalswapmacros} -%D -%D Simple but effective are the next two macros. There name exactly states their -%D purpose. - -\newdimen\d_syst_helpers_swapped -\newcount\c_syst_helpers_swapped -\let \m_syst_helpers_swapped\relax - -\unexpanded\def\swapdimens#1#2{\d_syst_helpers_swapped#1#1#2#2\d_syst_helpers_swapped} -\unexpanded\def\swapcounts#1#2{\c_syst_helpers_swapped#1#1#2#2\c_syst_helpers_swapped} -\unexpanded\def\swapmacros#1#2{\let\m_syst_helpers_swapped#1\let#1#2\let#2\m_syst_helpers_swapped} - -\unexpanded\def\globalswapdimens#1#2{\d_syst_helpers_swapped#1\global#1#2\global#2\d_syst_helpers_swapped} -\unexpanded\def\globalswapcounts#1#2{\c_syst_helpers_swapped#1\global#1#2\global#2\c_syst_helpers_swapped} -\unexpanded\def\globalswapmacros#1#2{\let\m_syst_helpers_swapped#1\glet#1#2\glet#2\m_syst_helpers_swapped} - -%D \macros -%D {pushmacro,popmacro} -%D -%D Premature and a bit of beta, we offer: -%D -%D \starttyping -%D \pushmacro\macro -%D \popmacro\macro -%D \stoptyping -%D -%D Beware: global! - -\installsystemnamespace{localpushedmacro} -\installsystemnamespace{globalpushedmacro} - -\let\m_syst_helpers_push_macro\empty - -\newcount\c_syst_helpers_pop_count - -\def\syst_helpers_push_macro_new_global - {\expandafter\newcount\csname\??globalpushedmacro\m_syst_helpers_push_macro\endcsname - \global\advance\csname\??globalpushedmacro\m_syst_helpers_push_macro\endcsname\plusone} - -\def\syst_helpers_push_macro_new_local - {\expandafter\newcount\csname\??localpushedmacro\m_syst_helpers_push_macro\endcsname - \global\advance\csname\??localpushedmacro\m_syst_helpers_push_macro\endcsname\plusone} - -\unexpanded\def\globalpushmacro#1% - {\xdef\m_syst_helpers_push_macro{\csstring#1}% - \ifcsname\??globalpushedmacro\m_syst_helpers_push_macro\endcsname - \global\advance\lastnamedcs\plusone - \else - \syst_helpers_push_macro_new_global - \fi - \expandafter\glet\csname\the\lastnamedcs\m_syst_helpers_push_macro\endcsname#1} - -\unexpanded\def\localpushmacro#1% this one can be used to push a value over an \egroup - {\xdef\m_syst_helpers_push_macro{\csstring#1}% - \ifcsname\??localpushedmacro\m_syst_helpers_push_macro\endcsname - \global\advance\lastnamedcs\plusone - \else - \syst_helpers_push_macro_new_local - \fi - \expandafter\glet\csname\the\lastnamedcs\m_syst_helpers_push_macro\endcsname#1} - -\unexpanded\def\globalpopmacro#1% - {\xdef\m_syst_helpers_push_macro{\csstring#1}% - \c_syst_helpers_pop_count\csname\??globalpushedmacro\m_syst_helpers_push_macro\endcsname - \global\advance\lastnamedcs \minusone - \expandafter\glet\expandafter#1\csname\the\c_syst_helpers_pop_count\m_syst_helpers_push_macro\endcsname} - -\unexpanded\def\localpopmacro#1% - {\xdef\m_syst_helpers_push_macro{\csstring#1}% - \c_syst_helpers_pop_count\csname\??localpushedmacro\m_syst_helpers_push_macro\endcsname - \global\advance\lastnamedcs \minusone - \expandafter\let\expandafter#1\csname\the\c_syst_helpers_pop_count\m_syst_helpers_push_macro\endcsname} - -\let\pushmacro\localpushmacro -\let\popmacro \localpopmacro - -%D \macros -%D {setlocalhsize,distributedhsize} -%D -%D Sometimes we need to work with the \type{ \hsize} that is corrected for -%D indentation and left and right skips. The corrected value is available in \type -%D {\localhsize}, which needs to be calculated with \type {\setlocalhsize} first. %D -%D -%D \starttyping -%D \setlocalhsize \hbox to \localhsize{...} -%D \setlocalhsize[-1em] \hbox to \localhsize{...} -%D \setlocalhsize[.5ex] \hbox to \localhsize{...} -%D \stoptyping -%D -%D These examples show us that an optional can be used. The value provided is added -%D to \type {\localhsize}. - -\newdimen\localhsize - -\unexpanded\def\setlocalhsize % don't change ! - {\doifelsenextoptional - \syst_helpers_set_local_hsize_yes - \syst_helpers_set_local_hsize_nop} - -\def\syst_helpers_set_local_hsize_nop - {\localhsize\availablehsize} - -\def\syst_helpers_set_local_hsize_yes[#1]% - {\syst_helpers_set_local_hsize_nop - \advance\localhsize#1\relax} - -\def\availablehsize - {\dimexpr - \hsize-\leftskip-\rightskip - \ifnum\hangafter<\zerocount - \ifdim\hangindent>\zeropoint-\else+\fi\hangindent - \fi - \relax} - -\def\distributedhsize#1#2#3% - {\dimexpr(#1-\numexpr#3-1\relax\dimexpr#2\relax)/#3\relax} - -\def\hsizefraction#1#2% - {\dimexpr#1/#2\relax} - -%D \macros -%D {doifvalue,doifnotvalue,doifelsevalue, -%D doifnothing,doifsomething,doifelsenothing, -%D doifvaluenothing,doifvaluesomething,doifelsevaluenothing} -%D -%D These \type {\if} commands can be used to access macros (or variables) that are -%D normally accessed by using \type {\getvalue}. Using these alternatives safes us -%D three tokens per call. Anyone familiar with the not||values ones, can derive -%D their meaning from the definitions. - -\unexpanded\def\doifvalue#1#2% - {\iftok{\csname#1\endcsname}{#2}% - \expandafter\firstofoneargument - \else - \expandafter\gobbleoneargument - \fi} - -\unexpanded\def\doifnotvalue#1#2% - {\iftok{\csname#1\endcsname}{#2}% - \expandafter\gobbleoneargument - \else - \expandafter\firstofoneargument - \fi} - -\unexpanded\def\doifelsevalue#1#2% - {\iftok{\csname#1\endcsname}{#2}% - \expandafter\firstoftwoarguments - \else - \expandafter\secondoftwoarguments - \fi} - -\unexpanded\def\doifnothing#1% - {\iftok{#1}\emptytoks - \expandafter\firstofoneargument - \else - \expandafter\gobbleoneargument - \fi} - -\unexpanded\def\doifsomething#1% - {\iftok{#1}\emptytoks - \expandafter\gobbleoneargument - \else - \expandafter\firstofoneargument - \fi} - -\unexpanded\def\doifelsenothing#1% - {\iftok{#1}\emptytoks - \expandafter\firstoftwoarguments - \else - \expandafter\secondoftwoarguments - \fi} - -\unexpanded\def\doifelsesomething#1% - {\iftok{#1}\emptytoks - \expandafter\secondoftwoarguments - \else - \expandafter\firstoftwoarguments - \fi} - -\unexpanded\def\doifvaluenothing#1% - {\iftok{\csname#1\endcsname}\emptytoks - \expandafter\firstofoneargument - \else - \expandafter\gobbleoneargument - \fi} - -\unexpanded\def\doifvaluesomething#1% - {\iftok{\csname#1\endcsname}\emptytoks - \expandafter\gobbleoneargument - \else - \expandafter\firstofoneargument - \fi} - -\unexpanded\def\doifelsevaluenothing#1% - {\iftok{\csname#1\endcsname}\emptytoks - \expandafter\firstoftwoarguments - \else - \expandafter\secondoftwoarguments - \fi} - -\let\doifvalueelse \doifelsevalue -\let\doifnothingelse \doifelsenothing -\let\doifsomethingelse \doifelsesomething -\let\doifvaluenothingelse\doifelsevaluenothing - -%D \macros -%D {doifemptyelsevalue, doifemptyvalue, doifnotemptyvalue} -%D -%D Also handy: - -\def\doifelseemptyvalue#1% - {\expandafter\ifx\csname#1\endcsname\empty - \expandafter\firstoftwoarguments - \else - \expandafter\secondoftwoarguments - \fi} - -\let\doifemptyvalueelse\doifelseemptyvalue - -\def\doifemptyvalue#1% - {\expandafter\ifx\csname#1\endcsname\empty - \expandafter\firstofoneargument - \else - \expandafter\gobbleoneargument - \fi} - -\def\doifnotemptyvalue#1% - {\expandafter\ifx\csname#1\endcsname\empty - \expandafter\gobbleoneargument - \else - \expandafter\firstofoneargument - \fi} - -%D \macros -%D {doifallcommonelse} -%D -%D A complete match of two sets can be tested with \type {\doifallcommonelse}, where -%D the first two arguments are sets. - -\def\syst_helpers_do_if_all_common_else#1#2#3#4% slow - {\def\syst_helpers_do_common_check_all##1% - {\doifnotinset{##1}{#4}\donefalse - \ifdone\else\expandafter\quitcommalist\fi}% - \donetrue - \processcommalist[#3]\syst_helpers_do_common_check_all - \ifdone\expandafter#1\else\expandafter#2\fi} - -\unexpanded\def\doifelseallcommon{\syst_helpers_do_if_all_common_else\firstoftwoarguments\secondoftwoarguments} -\unexpanded\def\doifallcommon {\syst_helpers_do_if_all_common_else\firstofonearguments\gobbleoneargument } -\unexpanded\def\doifnotallcommon {\syst_helpers_do_if_all_common_else\gobbleoneargument \firstofonearguments } - -\let\doifallcommonelse\doifelseallcommon - -%D \macros -%D {DOIF,DOIFELSE,DOIFNOT} -%D -%D \TEX\ is case sensitive. When comparing arguments, this feature sometimes is less -%D desirable, for instance when we compare filenames. The next three alternatives -%D upcase their arguments before comparing them. -%D -%D \starttyping -%D \DOIF {string1} {string2} {...} -%D \DOIFNOT {string1} {string2} {...} -%D \DOIFELSE {string1} {string2} {then ...}{else ...} -%D \stoptyping -%D -%D We have to use a two||step implementation, because the -%D expansion has to take place outside \type{\uppercase}. -%D -%D These might end up as \LUA based helpers (i.e. consider these -%D obsolete: - -\unexpanded\def\syst_helpers_do_IF#1#2% - {\uppercase{\syst_helpers_do_if_in_string_else{$#1$}{$#2$}}% - \expandafter\firstofoneargument - \else - \expandafter\gobbleoneargument - \fi} - -\unexpanded\def\syst_helpers_do_IF_NOT#1#2% - {\uppercase{\syst_helpers_do_if_in_string_else{$#1$}{$#2$}}% - \expandafter\gobbleoneargument - \else - \expandafter\firstofoneargument - \fi} - -\unexpanded\def\syst_helpers_do_IF_ELSE#1#2% - {\uppercase{\syst_helpers_do_if_in_string_else{$#1$}{$#2$}}% - \expandafter\firstoftwoarguments - \else - \expandafter\secondoftwoarguments - \fi} - -\unexpanded\def\syst_helpers_do_IF_INSTRING_ELSE#1#2% - {\uppercase{\syst_helpers_do_if_in_string_else{$#1$}{$#2$}}% - \expandafter\firstoftwoarguments - \else - \expandafter\secondoftwoarguments - \fi} - -\unexpanded\def\DOIF #1#2{\normalexpanded{\syst_helpers_do_IF {#1}{#2}}}% will become obsolete -\unexpanded\def\DOIFNOT #1#2{\normalexpanded{\syst_helpers_do_IF_NOT {#1}{#2}}}% will become obsolete -\unexpanded\def\DOIFELSE #1#2{\normalexpanded{\syst_helpers_do_IF_ELSE {#1}{#2}}}% will become obsolete -\unexpanded\def\DOIFINSTRINGELSE #1#2{\normalexpanded{\syst_helpers_do_IF_INSTRING_ELSE{#1}{#2}}}% will become obsolete - -%D \macros -%D {dosingleargumentwithset, -%D dodoubleargumentwithset,dodoubleemptywithset, -%D dotripleargumentwithset,dotripleemptywithset} -%D -%D These maybe too mysterious macros enable us to handle more than one setup at once. -%D -%D \starttyping -%D \dosingleargumentwithset \command[#1] -%D \dodoubleargumentwithset \command[#1][#2] -%D \dotripleargumentwithset \command[#1][#2][#3] -%D \dodoubleemptywithset \command[#1][#2] -%D \dotripleemptywithset \command[#1][#2][#3] -%D \stoptyping -%D -%D The first macro calls \type {\command[##1]} for each string in the set~\type -%D {#1}. The second one calls for \typ {\command [##1][#2]} and the third, well one -%D may guess. These commands support constructions like: -%D -%D \starttyping -%D \def\dodefinesomething[#1][#2]% -%D {\getparameters[\??xx#1][#2]} -%D -%D \unexpanded\def\definesomething% -%D {\dodoubleargumentwithset\dodefinesomething} -%D \stoptyping -%D -%D Which accepts calls like: -%D -%D \starttyping -%D \definesomething[alfa,beta,...][variable=...,...] -%D \stoptyping - -\let\m_syst_helpers_with_set_command\empty -\let\syst_helpers_with_set_step \relax - -\def\syst_helpers_with_set_double[#1][#2]% - {\doifsomething{#1}% - {\def\syst_helpers_with_set_step##1{\m_syst_helpers_with_set_command[##1][#2]}% - \processcommalist[#1]\syst_helpers_with_set_step}} - -\def\syst_helpers_with_set_triple[#1][#2][#3]% - {\doifsomething{#1}% - {\def\syst_helpers_with_set_step##1{\m_syst_helpers_with_set_command[##1][#2][#3]}% - \processcommalist[#1]\syst_helpers_with_set_step}} - -\def\dodoubleemptywithset #1{\let\m_syst_helpers_with_set_command#1\dodoubleempty \syst_helpers_with_set_double} % \command -\def\dodoubleargumentwithset#1{\let\m_syst_helpers_with_set_command#1\dodoubleargument\syst_helpers_with_set_double} % \command - -\def\dotripleemptywithset #1{\let\m_syst_helpers_with_set_command#1\dotripleempty \syst_helpers_with_set_triple} % \command -\def\dotripleargumentwithset#1{\let\m_syst_helpers_with_set_command#1\dotripleargument\syst_helpers_with_set_triple} % \command - -%D \macros -%D {stripcharacters,stripspaces} -%D -%D The next command was needed first when we implemented the \CONTEXT\ interactivity -%D macros. When we use labeled destinations, we often cannot use all the characters -%D we want. We therefore strip some of the troublemakers, like spaces, from the -%D labels before we write them to the \DVI||file, which passes them to for instance -%D a \POSTSCRIPT\ file. -%D -%D \starttyping -%D \stripspaces\from\one\to\two -%D \stoptyping -%D -%D Both the old string \type{\one} and the new one \type{\two} -%D are expanded. This command is a special case of: -%D -%D \starttyping -%D \stripcharacter\char\from\one\to\two -%D \stoptyping -%D -%D As we can see below, spaces following a control sequence are to enclosed in \type -%D {{}}. - -\let\m_syst_helpers_strip_character\empty - -\unexpanded\def\stripcharacter#1\from#2\to#3% - {\def\syst_helpers_strip_character##1#1##2\end - {\edef\m_syst_helpers_strip_character{\m_syst_helpers_strip_character##1}% - \doifnotempty{##2}{\syst_helpers_strip_character##2\end}}% - \let\m_syst_helpers_strip_character\empty - \edef\m_syst_string_one{#2}% - \expandafter\syst_helpers_strip_character\m_syst_string_one#1\end - \dodoglobal\let#3\m_syst_helpers_strip_character} - -\unexpanded\def\stripspaces\from#1\to#2% will become \unspacestring#1\from#2 - {\stripcharacter{ }\from#1\to#2} - -%D \macros -%D {unspacestring} -%D -%D The next macro does the same but is more compatible with other macros, like \type -%D {\convert...}. - -\unexpanded\def\unspacestring#1\to#2% - {\stripcharacter{ }\from#1\to#2} - -%D \macros -%D {executeifdefined} -%D -%D \CONTEXT\ uses one auxiliary file for all data concerning tables of contents, -%D references, two||pass optimizations, sorted lists etc. This file is loaded as -%D many times as needed. During such a pass we skip the commands thate are of no use -%D at that moment. Because we don't want to come into trouble with undefined -%D auxiliary commands, we call the macros in a way similar to \type {\getvalue}. The -%D next macro take care of such executions and when not defined, gobbles the -%D unwanted arguments. -%D -%D \starttyping -%D \executeifdefined{name}\gobbleoneargument -%D \stoptyping -%D -%D We can of course gobble more arguments using the appropriate gobbling command. - -\def\executeifdefined#1% #2 / never change this one again - {\ifcsname#1\endcsname - % \csname#1\expandafter\expandafter\expandafter\endcsname\expandafter\gobbleoneargument - \expandafter\expandafter\expandafter\lastnamedcs\expandafter\gobbleoneargument - \else - \expandafter\firstofoneargument - \fi} - -%D This one also has the advantage that it is fully expandable and that it can be -%D used after an assignment. - -%D \macros -%D {doifsomespaceelse} -%D -%D The next command checks a string on the presence of a space and executed a -%D command accordingly. -%D -%D \starttyping -%D \doifsomespaceelse {tekst} {then ...} {else ...} -%D \stoptyping -%D -%D We use this command in \CONTEXT\ for determing if an argument must be broken into -%D words when made interactive. Watch the use of \type {\noexpand}. - -%D Is this one still needed? - -\def\syst_helpers_if_some_space_else#1 #2#3^^^^0004{\if\noexpand#2@} - -\def\doifelsesomespace#1% % #2#3% - {\syst_helpers_if_some_space_else#1 @ @^^^^0004% #3\else#2\fi} - \expandafter\secondoftwoarguments - \else - \expandafter\firstoftwoarguments - \fi} - -\let\doifsomespaceelse\doifelsesomespace - -%D \macros -%D {processseparatedlist} -%D -%D Maybe a bit late, but here is a more general version of the \type -%D {\processcommalist} command. This time we don't handle nesting but accept -%D arbitrary seperators. -%D -%D \starttyping -%D \processseparatedlist[list][separator]\command -%D \stoptyping -%D -%D One can think of things like: -%D -%D \starttyping -%D \processseparatedlist[alfa+beta+gamma][+]\message -%D \stoptyping -%D -%D We want to handle all situations, like: -%D -%D \startbuffer -%D \processseparatedlist[{aap noot}] [ ]{\def\xxx} \convertcommand\xxx\to\ascii {\tttf\ascii} -%D \processseparatedlist[{aap} {noot}][ ]{\def\xxx} \convertcommand\xxx\to\ascii {\tttf\ascii} -%D \processseparatedlist[aap {noot}] [ ]{\def\xxx} \convertcommand\xxx\to\ascii {\tttf\ascii} -%D \processseparatedlist[aap noot] [ ]{\def\xxx} \convertcommand\xxx\to\ascii {\tttf\ascii} -%D \stopbuffer -%D -%D \typebuffer \getbuffer -%D -%D Therefore we smuggle a \type {\relax} in front of the argument, which we remove -%D afterwards. - -\let\syst_helpers_process_separated_list_step\relax - -\def\syst_helpers_process_separated_list#1]#2[#3]#4% - {\def\syst_helpers_process_separated_list_step##1##2#3% - {\def\m_syst_string_one{##2}% suggested by VZ - \if]##1% - \let\syst_helpers_process_separated_list_step\relax - \orelse\ifx\blankspace\m_syst_string_one - #4{##1}% - \orelse\if]##2% - \let\syst_helpers_process_separated_list_step\relax - \else - #4{##1##2}% - \fi - \syst_helpers_process_separated_list_step}% - \expandafter\syst_helpers_process_separated_list_step\gobbleoneargument#1#3]#3} - -\unexpanded\def\processseparatedlist[% - {\syst_helpers_process_separated_list\relax} - -%D \macros -%D {processlist} -%D -%D An even more general list processing macro is the following one: -%D -%D \starttyping -%D \processlist{beginsym}{endsym}{separator}\docommand list -%D \stoptyping -%D -%D This one supports arbitrary open and close symbols as well as user defined -%D separators. -%D -%D \starttyping -%D \processlist(){=>}\docommand(a=>b=>c=>d) -%D \stoptyping - -\let\syst_helpers_process_any_list \relax -\let\syst_helpers_process_any_list_indeed\relax -\let\syst_helpers_process_any_list_step \relax - -\unexpanded\def\processlist#1#2#3#4% no blank skipping ! - {\def\syst_helpers_process_any_list_indeed##1#2% - {\def\syst_helpers_process_any_list_step####1####2#3% - {\ifx#2####1% - \let\syst_helpers_process_any_list_step\relax - \orelse\ifx#2####2% - \let\syst_helpers_process_any_list_step\relax - \else - #4{####1####2}% - \fi - \syst_helpers_process_any_list_step}% - \expandafter\syst_helpers_process_any_list_step\gobbleoneargument##1#3#2#3}% - \def\syst_helpers_process_any_list#1% - {\syst_helpers_process_any_list_indeed\relax}% - \syst_helpers_process_any_list} - -%D \macros -%D {processassignlist} -%D -%D Is possible to combine an assignment list with one containing keywords. -%D Assignments are treated accordingly, keywords are treated by \type {\command}. -%D -%D \starttyping -%D \processassignlist[...=...,...=...,...]\commando -%D \stoptyping -%D -%D This command can be integrated in \type {\getparameters}, but we decided best not -%D to do so. - -\unexpanded\def\processassignlist#1[#2]#3% - {\def\syst_helpers_process_assign_list_assign[##1=##2=##3]% - {\doif{##3}\relax{#3{##1}}}% - \def\syst_helpers_process_assign_list_step##1% - {\syst_helpers_process_assign_list_assign[##1==\relax]}% - \processcommalist[#2]\syst_helpers_process_assign_list_step} - -%D \macros -%D {untextargument -%D untexcommand} -%D -%D When manipulating data(bases) and for instance generating index entries, the next -%D three macros can be of help: -%D -%D \starttyping -%D \untextargument{...}\to\name -%D \untexcommand {...}\to\name -%D \stoptyping -%D -%D They remove braces and backslashes and give us something to sort. - -\let\m_syst_helpers_untexed\empty - -\unexpanded\def\untexsomething - {\begingroup - \catcode\leftbraceasciicode \ignorecatcode - \catcode\rightbraceasciicode\ignorecatcode - \escapechar\minusone - \syst_helpers_untex_something} - -\def\syst_helpers_untex_something#1#2\to#3% - {\doglobal#1#2\to\m_syst_helpers_untexed - \endgroup - \let#3\m_syst_helpers_untexed} - -\unexpanded\def\untexargument{\untexsomething\convertargument} -\unexpanded\def\untexcommand {\untexsomething\convertcommand} - -%D \macros -%D {ScaledPointsToBigPoints,ScaledPointsToWholeBigPoints} -%D -%D One characteristic of \POSTSCRIPT\ and \PDF\ is that both used big points (\TEX's -%D bp). The next macros convert points and scaled points into big points. The magic -%D factor $72/72.27$ can be found in most \TEX\ related books. -%D -%D \starttyping -%D \ScaledPointsToBigPoints {number} \target -%D \ScaledPointsToWholeBigPoints {number} \target -%D \stoptyping - -\let\tobigpoints \clf_tobigpoints -\let\towholebigpoints\clf_towholebigpoints - -\unexpanded\def\PointsToBigPoints #1#2{\edef#2{\tobigpoints #1}} % can be avoided -\unexpanded\def\PointsToWholeBigPoints #1#2{\edef#2{\towholebigpoints#1}} % can be avoided -\unexpanded\def\ScaledPointsToBigPoints #1#2{\edef#2{\tobigpoints #1\scaledpoint}} % obsolete -\unexpanded\def\ScaledPointsToWholeBigPoints#1#2{\edef#2{\towholebigpoints#1\scaledpoint}} % obsolete - -%D \macros -%D {PointsToReal} -%D -%D Points can be stripped from their suffix by using \type {\withoutpt}. The next -%D macro enveloppes this macro. -%D -%D \starttyping -%D \PointsToReal {dimension} \target -%D \stoptyping - -\unexpanded\def\PointsToReal#1#2% - {\edef#2{\withoutpt\the\dimexpr#1}} - -%D \macros -%D {dontleavehmode} -%D -%D Sometimes when we enter a paragraph with some command, the first token gets the -%D whole first line. We can prevent this by saying: -%D -%D \starttyping -%D \dontleavehmode -%D \stoptyping -%D -%D This command is used in for instance the language module \type {lang-ini}. The -%D first version was: -%D -%D \starttyping -%D \def\dontleavehmode{\ifhmode\else\ifmmode\else$ $\fi\fi} -%D \stoptyping -%D -%D Next, Taco came with a better alternative (using mathsurround): -%D -%D \starttyping -%D \def\dontleavehmode -%D {\ifhmode\else \ifmmode\else -%D {\mathsurround\zeropoint\everymath\emptytoks$ $}% -%D \fi \fi} -%D \stoptyping -%D -%D And finaly we got the following alternative, one that avoids interfering grouping -%D at the cost of a box. -%D -%D \starttyping -%D \newbox\b_syst_helpers_dlh -%D -%D \unexpanded\def\dontleavehmode -%D {\ifhmode\else \ifmmode\else -%D \setbox\b_syst_helpers_dlh\hbox{\mathsurround\zeropoint\everymath\emptytoks$ $}\unhbox\b_syst_helpers_dlh -%D \fi \fi} -%D \stoptyping -%D -%D But, as we run a recent version of \TEX, we can use the new primitive: - -\ifdefined\normalquitvmode \let\dontleavehmode\normalquitvmode \fi - -%D \macros -%D {utfupper, utflower, uppercasestring, lowercasestring} -%D -%D The names tell what they do: -%D -%D \starttyping -%D \uppercasestring somestring\to\somestring -%D \lowercasestring somestring\to\somestring -%D \stoptyping -%D -%D The first argument may be a \type{\macro}. -%D -%D These macros are sort of obsolete as we never use uppercase this way. But -%D nevertheless we provide them: - -\def\utfupper#1{\clf_upper{#1}} % expandable -\def\utflower#1{\clf_lower{#1}} % expandable - -\unexpanded\def\uppercasestring#1\to#2{\dodoglobal\edef#2{\clf_upper{#1}}} -\unexpanded\def\lowercasestring#1\to#2{\dodoglobal\edef#2{\clf_lower{#1}}} - -%D \macros -%D {handletokens} -%D -%D With the next macro we enter a critical area of macro expansion. What we want is -%D a macro that looks like: -%D -%D \starttyping -%D \handletokens some tokens\with \somemacro -%D \stoptyping -%D -%D A bonus example: -%D -%D \starttyping -%D \hbox{\handletokens tekst en meer tekst\with\ruledhbox} -%D -%D \def\weetikveel#1{\if#1\blankspace\space\else\ruledhbox{#1}\fi} -%D -%D \hbox{\handletokens tekst en meer tekst\with\weetikveel} -%D \stoptyping - -%D \macros -%D {counttoken,counttokens} -%D -%D For the few occasions that we want to know the number of specific tokens in a -%D string, we can use: -%D -%D \starttyping -%D \counttoken token\in string\to \somecount -%D \counttokens string\to \somecount -%D \stoptyping -%D -%D This macro, that for instance is used in \type {cont-tab}, takes a real counter. -%D The macro can be preceded by \type {\doglobal}. - -\def\syst_helpers_count_token#1% obeys {} - {\def\m_syst_string_three{#1}% - \ifx\m_syst_string_two\m_syst_string_three \else - \ifx\m_syst_string_one\m_syst_string_three - \advance\privatescratchcounter\plusone - \fi - \expandafter\syst_helpers_count_token - \fi} - -\unexpanded\def\counttoken#1\in#2\to#3% - {\privatescratchcounter\zerocount - \def\m_syst_string_one{#1}% - \def\m_syst_string_two{\end}% - \syst_helpers_count_token#2\end - \dodoglobal#3\privatescratchcounter} - -\unexpanded\def\counttokens#1\to#2% - {\privatescratchcounter\zerocount - \def\syst_helpers_count_token##1{\advance\privatescratchcounter\plusone}% - \handletokens#1\with\syst_helpers_count_token - \dodoglobal#2\privatescratchcounter} - -%D \macros -%D {splitofftokens} -%D -%D Running this one not always gives the expected results. Consider for instance the -%D macro for which I originally wrote this token handler. - -\unexpanded\def\splitofftokens#1\from#2\to#3% slow but hardly used - {\ifnum#1>\zerocount - \privatescratchcounter#1\relax - \def\syst_helpers_split_off_tokens##1% - {\ifnum\privatescratchcounter>\zerocount - \advance\privatescratchcounter \minusone - \edef#3{#3##1}% - \fi}% - % \let#3\empty % #3 can be #2, so: - \expandafter\let\expandafter#3\expandafter\empty - \expandafter\handletokens#2\with\syst_helpers_split_off_tokens - \else - \edef#3{#2}% - \fi} - -%D This macro can be called like: -%D -%D \startbuffer[example] -%D \splitofftokens10\from01234567 890123456789\to\test [\test] -%D \stopbuffer -%D -%D up there. The reason for this is not that logical but follows from \TEX's -%D However, the characters that we expect to find in \type {\test} just don't show -%D sometimes mysterious way of expanding. Look at this: -%D -%D \startbuffer[next] -%D \def\next{a} \edef\test{\next} [\test] -%D \let\next=b \edef\test{\test\next} [\test] -%D \let\next=c \edef\test{\next} [\test] -%D \let\next=d \edef\test{\test\next} [\test] -%D \let\next=e \expandafter\edef\expandafter\test\expandafter{\test\next} [\test] -%D \stopbuffer -%D -%D \typebuffer[next] -%D -%D Careful reading shows that inside an \type {\edef} macro's that are \type {\let} -%D are not expanded! -%D -%D \unprotect\getbuffer[next]\protect -%D -%D That's why we finally end up with a macro that looks ahead by using an -%D assignment, this time by using \type {\futurelet}, and grabbing an argument as -%D well. That way we can handle the sentinal, a blank space and grouped tokens. - -\unexpanded\def\syst_helpers_handle_tokens % \nexthandledtoken is part of interface - {\futurelet\nexthandledtoken\syst_helpers_handle_tokens_indeed} - -\def\handletokens#1\with#2% - {\gdef\syst_helpers_handle_tokens_command{#2}% permits more complex #2's - \syst_helpers_handle_tokens#1\end} - -\def\syst_helpers_handle_tokens_indeed - {\ifx\nexthandledtoken\blankspace - \expandafter\syst_helpers_handle_tokens_indeed_one - \orelse\ifx\nexthandledtoken\end - \expandafter\gobbletwoarguments % also gobble the \end - \else - \expandafter\syst_helpers_handle_tokens_indeed_two - \fi *} - -\def\syst_helpers_handle_tokens_indeed_one * % - {\syst_helpers_handle_tokens_command{ }\syst_helpers_handle_tokens} - -\def\syst_helpers_handle_tokens_indeed_two *#1% - {\syst_helpers_handle_tokens_command{#1}\syst_helpers_handle_tokens} - -%D This macro is tested on: -%D -%D \def\xxx#1{[#1]} -%D -%D \startlines -%D \handletokens abc\with\xxx -%D \handletokens a b c\with\xxx -%D \handletokens a b c\with\xxx -%D \handletokens a{bc}d\with\xxx -%D \handletokens a\space bc \with\xxx -%D \stoplines -%D -%D And our previous example shows up as: -%D -%D \getbuffer[example] - -%D \macros -%D {iftrialtypesetting, ifvisible} -%D -%D The next boolean is at first sight a strange one. Sometimes one does a trial -%D typesetting run, for instance to determine dimensions. Some mechanisms, like -%D object inclusion, can fail on such trials. Temporary setting the next boolean to -%D true, helps a lot. The second boolena can be used to inhibit processing -%D completely. - -\newif\ifvisible \visibletrue - -\newtoks\everysettrialtypesetting -\newtoks\everyresettrialtypesetting - -\unexpanded\def\settrialtypesetting {\the\everysettrialtypesetting } % obeys grouping so -\unexpanded\def\resettrialtypesetting{\the\everyresettrialtypesetting} % this one is seldom needed - -\let\iftrialtypesetting\iffalse % so we have no \trialtypesettingtrue|false in mkiv ! - -\appendtoks \let\iftrialtypesetting\iftrue \to \everysettrialtypesetting -\appendtoks \let\iftrialtypesetting\iffalse \to \everyresettrialtypesetting - -%D \macros -%D {twodigitrounding} -%D -%D When using \type {\special}s or \type {\pdfliteral}s, it sometimes makes sense to -%D limit the precission. The next macro rounds a real number to two digits. It takes -%D one argument and only works in \ETEX. - -\def\integerrounding #1{\clf_rounded\zerocount\numexpr#1\relax} -\def\onedigitrounding #1{\clf_rounded\plusone \numexpr#1\relax} -\def\twodigitrounding #1{\clf_rounded\plustwo \numexpr#1\relax} -\def\threedigitrounding#1{\clf_rounded\plusthree\numexpr#1\relax} - -%D \macros -%D {processcontent} -%D -%D This macro is first used in the tabulation macros. -%D -%D \starttyping -%D \unexpanded\def\starthans% -%D {\processcontent{stophans}\test{\message{\test}\wait}} -%D \stoptyping - -\unexpanded\def\processcontent#1% - {\begingroup\expandafter\syst_helpers_process_content\csname#1\endcsname} - -\unexpanded\def\syst_helpers_process_content#1#2#3% - {\unexpanded\def\syst_helpers_process_content##1#1% - {\endgroup\def#2{##1}#3}% - \syst_helpers_process_content} - -%D \macros -%D {dogobblesingleempty, dogobbledoubleempty} -%D -%D These two macros savely grab and dispose two arguments. - -\def\dogobblesingleempty{\dosingleempty\syst_helpers_gobble_single_empty} -\def\dogobbledoubleempty{\dodoubleempty\syst_helpers_gobble_double_empty} - -\def\syst_helpers_gobble_single_empty [#1]{} -\def\syst_helpers_gobble_double_empty[#1][#2]{} - -\let\gobblesingleempty\dogobblesingleempty % also used -\let\gobbledoubleempty\dogobbledoubleempty % also used - -%D \macros -%D {setdimensionwithunit, freezedimensionwithunit} -%D -%D The next assignments are all valid: -%D -%D \starttyping -%D \setdimensionwithunit\scratchdimen{10} {cm} -%D \setdimensionwithunit\scratchdimen{10cm}{cm} -%D \setdimensionwithunit\scratchdimen{10cm}{} -%D \freezedimensionwithunit\SomeWidth{\textwidth} -%D \freezedimensionwithunit\SomeDepth{\dp\strutbox} -%D \stoptyping -%D -%D As an alternative for the next macro we can use a global assignment inside a box. -%D The \type {\empty}'s permits gobbling while preventing spurious \type {\relax}'s. - -\unexpanded\def\setdimensionwithunit#1#2#3% number unit dimension / nice trick - {\afterassignment\gobblefourarguments#1=#2#3pt\relax\empty\empty\empty\empty} - -\unexpanded\def\freezedimensionwithunit#1#2% - {\setdimensionwithunit\privatescratchdimen#1{#2}\edef#1{\the\privatescratchdimen}} - -%D \macros -%D {doifsometokselse, doifsometoks} -%D -%D Not that fast I guess, but here's a way to test for token registers being empty. - -\unexpanded\def\doifelsesometoks#1% - {\iftok#1\emptytoks - \expandafter\secondoftwoarguments - \else - \expandafter\firstoftwoarguments - \fi} - -\unexpanded\def\doifsometoks#1% - {\iftok#1\emptytoks - \expandafter\gobbleoneargument - \else - \expandafter\firstofoneargument - \fi} - -\unexpanded\def\doifemptytoks#1% - {\iftok#1\emptytoks - \expandafter\firstofoneargument - \else - \expandafter\gobbleoneargument - \fi} - -\let\doifsometokselse\doifelsesometoks - -%D \macros -%D {startstrictinspectnextcharacter} -%D -%D This one is for the bibliography module (still?): - -\let\syst_helpers_strict_inspect_next_character[ - -\def\syst_helpers_strict_inspect_next_character% no user macro ! - {\ifx\nexttoken[% - \expandafter\m_syst_action_yes - \else - \expandafter\m_syst_action_nop - \fi} - -\unexpanded\def\strictdoifelsenextoptional#1#2% - {\def\m_syst_action_yes{#1}% - \def\m_syst_action_nop{#2}% - \futurelet\nexttoken\syst_helpers_strict_inspect_next_character} - -\let\strictdoifnextoptionalelse\strictdoifelsenextoptional - -%D \macros -%D {gobblespacetokens} -%D -%D This macro needs a speed-up! - -%\def\gobblespacetokens -% {\doifnextcharelse\empty\donothing\donothing} % no {}\do\do ! - -\def\gobblespacetokens - {\afterassignment\nexttoken\let\nexttoken=} - -%D \macros -%D {verbatimargument} -%D -%D As the name says, this macro converts its argument to a (rather safe) string. - -\let\verbatimstring\detokenize - -%D These are needed in ordinal number conversions: - -\def\lastdigit#1% - {\expandafter\thelastdigit\number#1\relax} - -\def\thelastdigit#1#2% - {\ifx#2\relax#1\else\expandafter\thelastdigit\expandafter#2\fi} - -\def\lasttwodigits#1% - {\expandafter\thelasttwodigits\expandafter0\number#1\relax} - -\def\thelasttwodigits#1#2#3% 0 dig ... \relax - {\ifx#3\relax#1#2\else\expandafter\thelasttwodigits\expandafter#2\expandafter#3\fi} - -%D \macros -%D {serializecommalist} -%D -%D Concatenate commalists: - -\let\syst_helpers_serialize_comma_list_step\relax - -\def\syst_helpers_serialize_comma_list_step#1% - {\edef\serializedcommalist{\serializedcommalist#1}} - -\unexpanded\def\serializecommalist[#1]% - {\let\serializedcommalist\empty - \processcommacommand[#1]\syst_helpers_serialize_comma_list_step} - -%D \macros -%D {purenumber} -%D -%D Sometimes we need control over when \TEX\ stops reading a number, especially in -%D full expandable macros where using \type {\relax} would lead to disasters. -%D -%D \starttyping -%D \ifodd\purenumber{...}\space ... \else ... \fi -%D \stoptyping -%D -%D Here we use a space as number delimiter in combination with a space- and -%D relax-less \type {\purenumber}. This macro works ok with \type {\the}, \type -%D {\number} as well as \ETEX's \type {\numexpr}. - -\def\purenumber#1{\expandafter\firstofoneargument\expandafter{\number#1}} - -%D \macros -%D {filterfromvalue} -%D -%D \starttyping -%D \setvalue{xx}{{A}{B}{C}} -%D -%D \filterfromvalue{xx}{3}{3} -%D \filterfromvalue{xx}{3}{2} -%D \filterfromvalue{xx}{3}{1} -%D \stoptyping -%D -%D An alternative is to store 'max' in the list, say: -%D -%D \starttyping -%D \setvalue{xx}{3{A}{B}{C}} -%D -%D \filterfromvalues{3}{xx}{3} -%D \filterfromvalues{3}{xx}{2} -%D \filterfromvalues{3}{xx}{1} -%D \stoptyping -%D -%D I'll implement this when I'm in \quotation {writing dirty macros mood}. - -\def\dofilterfromstr#1#2% max n % no need to be fast - {\expandafter \expandafter \expandafter \csstring - \ifcase#1\or \ifcase#2\or - \firstofoneargument \else - \gobbleoneargument \fi - \or \ifcase#2\or - \firstoftwoarguments \or - \secondoftwoarguments \else - \gobbletwoarguments \fi - \or \ifcase#2\or - \firstofthreearguments \or - \secondofthreearguments \or - \thirdofthreearguments \else - \gobblethreearguments \fi - \or \ifcase#2\or - \firstoffourarguments \or - \secondoffourarguments \or - \thirdoffourarguments \or - \fourthoffourarguments \else - \gobblefourarguments \fi - \or \ifcase#2\or - \firstoffivearguments \or - \secondoffivearguments \or - \thirdoffivearguments \or - \fourthoffivearguments \or - \fifthoffivearguments \else - \gobblefivearguments \fi - \fi} - -\def\filterfromvalue#1#2#3% value max n - {\expandafter\doubleexpandafter\csname % we use the fact that an - \expandafter\ifx\csname#1\endcsname\relax % undefined cs has become \relax - \csstring\gobbleoneargument % which we then gobble here - \else - \dofilterfromstr{#2}{#3}% - \fi - \endcsname\csname#1\endcsname} - -\def\filterfromnext#1#2% max n {..}{..}{..}{..} - {\csname\dofilterfromstr{#1}{#2}\endcsname} - -%D \macros -%D {definemeasure} -%D -%D \starttyping -%D \definemeasure[mywidth][\dimexpr(\textwidth-1cm)] -%D -%D ... \measure{mywidth} ... -%D \stoptyping - -\installsystemnamespace{measure} - -\unexpanded\def\definemeasure - {\dodoubleargument\syst_helpers_define_measure} - -\def\syst_helpers_define_measure[#1][#2]% - {\expandafter\def\csname\??measure#1\endcsname{#2}} - -\unexpanded\def\freezemeasure - {\dodoubleargument\syst_helpers_freeze_measure} - -\def\syst_helpers_freeze_measure[#1][#2]% - {\expandafter\edef\csname\??measure#1\endcsname{\the\dimexpr#2}} - -\unexpanded\def\setmeasure #1#2{\expandafter\def \csname\??measure#1\endcsname{#2}} % quick way -\unexpanded\def\setgmeasure#1#2{\expandafter\gdef\csname\??measure#1\endcsname{#2}} % quick way -\unexpanded\def\setemeasure#1#2{\expandafter\edef\csname\??measure#1\endcsname{\the\dimexpr#2}} % quick way -\unexpanded\def\setxmeasure#1#2{\expandafter\xdef\csname\??measure#1\endcsname{\the\dimexpr#2}} % quick way - -\def\measure - {\the\measured} - -\def\measured#1% - %{\dimexpr\ifcsname\??measure#1\endcsname\csname\??measure#1\endcsname\else\zeropoint\fi\relax} - {\dimexpr\ifcsname\??measure#1\endcsname\lastnamedcs\else\zeropoint\fi\relax} - -% #2 could be omitted, but we want to support spaces -% -% \setmeasure {x} {1cm} -% \setmeasure {xx} {1cm} -% \setmeasure {xxx}{1cm} - -%D \macros -%D {definequantity} -%D -%D These do the same but for numbers. - -\installsystemnamespace{quantity} - -\unexpanded\def\definequantity - {\dodoubleargument\syst_helpers_define_quantity} - -\def\syst_helpers_define_quantity[#1][#2]% - {\expandafter\def\csname\??quantity#1\endcsname{#2}} - -\unexpanded\def\freezequantity - {\dodoubleargument\syst_helpers_freeze_quantity} - -\def\syst_helpers_freeze_quantity[#1][#2]% - {\expandafter\edef\csname\??quantity#1\endcsname{\the\numexpr#2}} - -\unexpanded\def\setquantity #1#2{\expandafter\def \csname\??quantity#1\endcsname{#2}} % quick way -\unexpanded\def\setgquantity#1#2{\expandafter\gdef\csname\??quantity#1\endcsname{#2}} % quick way -\unexpanded\def\setequantity#1#2{\expandafter\edef\csname\??quantity#1\endcsname{\the\numexpr#2}} % quick way -\unexpanded\def\setxquantity#1#2{\expandafter\xdef\csname\??quantity#1\endcsname{\the\numexpr#2}} % quick way - -\def\quantity - {\the\quantitied} - -\def\quantitied#1% - {\numexpr\ifcsname\??quantity#1\endcsname\lastnamedcs\else\zeropoint\fi\relax} - -\def\directquantity#1% - {\the\numexpr#1\relax} - -% let\quantified\quantitied - -%D \macros -%D {dividedsize} -%D -%D This one can be used inside a measure (used in m4all): -%D -%D \starttyping -%D \definemeasure[columnwidth][\dividedsize\textwidth{1em}{3}] -%D \stoptyping - -\def\dividedsize#1#2#3% size gap n - {\dimexpr - \ifnum\dimexpr#1\relax>\plusone - (\dimexpr#1\relax-\numexpr#3-\plusone\relax\dimexpr#2\relax)/#3\else#1% - \fi - \relax} - -%D \macros -%D {doifdimensionelse} -%D -%D This is a dirty one: we simply append a unit and discard it when needed. - -\def\doifelsedimension#1% - {\ifchkdim#1\or - \expandafter\firstoftwoarguments - \else - \expandafter\secondoftwoarguments - \fi} - -\let\doifdimensionelse\doifelsedimension - -%D Ok, here's another one, slower but seldom used. This one scans the text. -%D -%D \starttabulate[|Tc|Tc|] -%D \NC pt \NC \doifdimenstringelse {pt}{yes}{no} \NC \NR -%D \NC 12pt \NC \doifdimenstringelse {-12pt}{yes}{no} \NC \NR -%D \NC 1pt \NC \doifdimenstringelse {1pt}{yes}{no} \NC \NR -%D \NC 12pt \NC \doifdimenstringelse {12pt}{yes}{no} \NC \NR -%D \NC 12.0pt \NC \doifdimenstringelse {12.0pt}{yes}{no} \NC \NR -%D \NC -.12pt \NC \doifdimenstringelse {-.12pt}{yes}{no} \NC \NR -%D \NC .12pt \NC \doifdimenstringelse {.12pt}{yes}{no} \NC \NR -%D \NC -12pt \NC \doifdimenstringelse {-12pt}{yes}{no} \NC \NR -%D \NC -12.0pt \NC \doifdimenstringelse{-12.0pt}{yes}{no} \NC \NR -%D \NC big \NC \doifdimenstringelse {big}{yes}{no} \NC \NR -%D \NC 10 \NC \doifdimenstringelse {10}{yes}{no} \NC \NR -%D \NC 1 \NC \doifdimenstringelse {1}{yes}{no} \NC \NR -%D \stoptabulate - -\let\doifelsedimenstring\doifelsedimension -\let\doifdimenstringelse\doifelsedimenstring - -%D \macros -%D {comparedimension,comparedimensioneps} -%D -%D This is a dirty one: we simply append a unit and discard it when needed. - -\newdimen \roundingeps \roundingeps=10sp -\newconstant\compresult - -\def\comparedimension#1#2% - {\compresult - \ifdim#1<#2% - \zerocount - \orelse\ifdim#1<#2% - \plusone - \else - \plustwo - \fi} - -\def\comparedimensioneps#1#2% todo: use eps feature - {\compresult - \ifdim\dimexpr#1-#2\relax<\roudingeps - \zerocount - \orelse\ifdim\dimexpr#2-#1\relax<\roudingeps - \zerocount - \orelse\ifdim#1<#2% - \plusone - \else - \plustwo - \fi} - -% pretty ugly but fast - -% \copycsname xxx\endcsname\csname ..\endcsname - -\unexpanded\def\copycsname{\expandafter\expandafter\expandafter\let\expandafter\expandafter\csname} - -% \letcscsname \crap \csname ..\endcsname -% \letcsnamecs \csname ..\endcsname\crap -% \letcsnamecsname\csname ..\endcsname\csname ..\endcsname - -\unexpanded\def\letcscsname {\expandafter\let\expandafter} -\unexpanded\def\letcsnamecs {\expandafter\let} -\unexpanded\def\letcsnamecsname{\expandafter\expandafter\expandafter\let\expandafter\expandafter} - -% another one, add an item to a commalist - -\unexpanded\def\addvalue#1#2% cs item - {\ifcsname#1\endcsname\else\expandafter\let\csname#1\endcsname\empty\fi - \normalexpanded{\noexpand\addtocommalist{#2}\expandafter\noexpand\csname#1\endcsname}} - -\def\unspaced#1% - {\syst_helpers_unspaced#1\end} - -\def\syst_helpers_unspaced#1% - {\ifx#1\end - \expandafter\gobbleoneargument - \orelse\ifx#1\blankspace - % go on - \else - #1% - \fi - \syst_helpers_unspaced} - -\unexpanded\def\unspaceargument#1\to#2% - {\privatescratchcounter\catcode\spaceasciicode - \catcode\spaceasciicode\ignorecatcode - \scantextokens{\edef#2{#1}}% - \catcode\spaceasciicode\privatescratchcounter} - -\unexpanded\def\unspaceafter#1#2% - {\unspaceargument#2\to\ascii - \expandafter#1\expandafter{\ascii}} - -% sometimes handy: - -\unexpanded\def\doifelsehasspace#1% - {\edef\m_syst_string_one{#1}% - \normalexpanded{\syst_helpers_if_has_space_else#1\space}\empty\relax} - -\let\doifhasspaceelse\doifelsehasspace - -\unexpanded\def\syst_helpers_if_has_space_else#1 #2#3\relax % \space\empty\relax - {\ifx\m_syst_string_one\space - \expandafter\firstoftwoarguments - \orelse\ifx#2\empty - \expandafter\secondoftwoarguments - \else - \expandafter\firstoftwoarguments - \fi} - -% this will replace loadfile once and alike !!! todo - -\installsystemnamespace{flag} - -\unexpanded\def\setflag #1{\expandafter\dodoglobal\expandafter\let\csname\??flag#1\endcsname\zerocount} -\unexpanded\def\resetflag#1{\expandafter\dodoglobal\expandafter\let\csname\??flag#1\endcsname\plusone} - -\def\flag#1{\csname\??flag#1\endcsname} - -\def\doifelseflagged#1% - {\expandafter\ifx\csname\??flag#1\endcsname\relax - \expandafter\secondoftwoarguments - \orelse\ifcase\csname\??flag#1\endcsname - \expandafter\firstoftwoarguments - \else - \expandafter\secondoftwoarguments - \fi} - -\let\doifflaggedelse\doifelseflagged - -\def\doifnotflagged#1% - {\expandafter\ifx\csname\??flag#1\endcsname\relax - \expandafter\firstofoneargument - \orelse\ifcase\csname\??flag#1\endcsname - \expandafter\gobbleoneargument - \else - \expandafter\firstofoneargument - \fi} - -\unexpanded\def\inheritparameter[#1]#2[#3]#4[#5]% tag tokey fromkey - {\expandafter\def\csname#1#3\expandafter\endcsname\expandafter{\csname#1#5\endcsname}} - -\def\syst_helpers_if_non_zero_positive_else#1#2\end % #3#4% - {\ifx#1\relax - \ifcase\privatescratchcounter - \endgroup - \doubleexpandafter\secondoftwoarguments - \else - \endgroup - \doubleexpandafter\firstoftwoarguments - \fi - \else - \endgroup - \expandafter\secondoftwoarguments - \fi} - -% used ? - -\def\doifelsenonzeropositive#1% - {\begingroup\afterassignment\syst_helpers_if_non_zero_positive_else\privatescratchcounter=0#1\relax\empty\end} - -\let\doifnonzeropositiveelse\doifelsenonzeropositive - -% here ? - -\unexpanded\def\dosetrawvalue #1#2#3{\expandafter \def\csname#1#2\endcsname{#3}} -\unexpanded\def\dosetrawevalue#1#2#3{\expandafter\edef\csname#1#2\endcsname{#3}} -\unexpanded\def\dosetrawgvalue#1#2#3{\expandafter\gdef\csname#1#2\endcsname{#3}} -\unexpanded\def\dosetrawxvalue#1#2#3{\expandafter\xdef\csname#1#2\endcsname{#3}} - -\unexpanded\def\getrawparameters {\dogetparameters\dosetrawvalue } -\unexpanded\def\getraweparameters {\dogetparameters\dosetrawevalue} -\unexpanded\def\getrawgparameters {\dogetparameters\dosetrawgvalue} -\unexpanded\def\getrawxparameters {\dogetparameters\dosetrawxvalue} - -\unexpanded\def\globalgetrawparameters{\dogetparameters\dosetrawgvalue} % obsolete - -%D Sort of obsolete: - -\newcount\c_syst_helpers_mod - -\unexpanded\def\dosetmodulo#1#2#3% - {\c_syst_helpers_mod#1\divide\c_syst_helpers_mod#2\multiply\c_syst_helpers_mod#2% - #3#1\advance#3-\c_syst_helpers_mod} - -\unexpanded\def\dosetdivision#1#2#3% - {#3#1\divide#3 #2\relax} - -\unexpanded\def\DoMod#1by#2to#3{\dosetmodulo {#1}{#2}{#3}} -\unexpanded\def\DoDiv#1by#2to#3{\dosetdivision{#1}{#2}{#3}} - -\def\syst_helpers_unprotected#1\par - {#1\protect} - -\unexpanded\def\unprotected - {\unprotect - \syst_helpers_unprotected} - -\let\resettimer \clf_resettimer -\let\elapsedtime \clf_elapsedtime -\let\elapsedseconds \elapsedtime - -\newcount\c_syst_helpers_test_feature_n -\newcount\c_syst_helpers_test_feature_m - -\def\currentfeaturetest{\number\c_syst_helpers_test_feature_n} - -\unexpanded\def\testfeature#1#2% - {\c_syst_helpers_test_feature_m#1\relax - \def\syst_helpers_test_feature_yes - {\advance\c_syst_helpers_test_feature_n\plusone - \ifnum\c_syst_helpers_test_feature_n>\c_syst_helpers_test_feature_m\else - #2\expandafter\syst_helpers_test_feature_yes - \fi}% - \def\syst_helpers_test_feature_nop - {\advance\c_syst_helpers_test_feature_n\plusone - \ifnum\c_syst_helpers_test_feature_n>\c_syst_helpers_test_feature_m\else - \expandafter\syst_helpers_test_feature_nop - \fi}% - \retestfeature} - -\unexpanded\def\retestfeature % timer support is new per 10/5/2005 - {\bgroup - \ifcase\interactionmode\let\wait\relax\fi - \clf_resettimer - \c_syst_helpers_test_feature_n\zerocount - \syst_helpers_test_feature_nop - \clf_benchmarktimer - \writestatus\m!system{starting feature test (n=\number\c_syst_helpers_test_feature_m)}\wait - \c_syst_helpers_test_feature_n\zerocount - \syst_helpers_test_feature_yes - \writestatus\m!system{\number\c_syst_helpers_test_feature_m\space feature tests done (\elapsedseconds s)}% - \wait - \egroup} - -\unexpanded\def\showtimer#1% - {\writestatus{runtime}{\elapsedseconds\space s / #1}} - -\unexpanded\def\testfeatureonce#1#2% - {\begingroup - \let\wait\relax - \testfeature{#1}{#2}% - \endgroup} - -%D \macros -%D {freezedimenmacro} -%D -%D This macro is use as: -%D -%D \starttyping -%D \freezedimenmacro\leftmargindistance -%D \stoptyping - -\unexpanded\def\freezedimenmacro#1% - {\edef#1{\the\dimexpr#1}} - -%D The next macro negates a macro (dimension or number, or actually, whatever. It's -%D a typical example of \type {\if} usage: -%D -%D \starttyping -%D \if-\whatever \else-\whatever\fi => else => -whatever -%D \if--\whatever\else-\whatever\fi => then => whatever -%D \stoptyping - -\def\negated#1{\if-#1\else-#1\fi} % does only work in macros or text - -\def\gobbleassigndimen#1\\{} - -\def\assigndimen#1#2% - {\afterassignment\gobbleassigndimen#1=#2\zeropoint\\} - -\unexpanded\def\appended#1#2#3{\expandafter#1\expandafter#2\expandafter{#2#3}} -\unexpanded\def\appendvalue #1{\expandafter\appended\expandafter \def\csname#1\endcsname} -\unexpanded\def\appendgvalue#1{\expandafter\appended\expandafter\gdef\csname#1\endcsname} - -\unexpanded\def\prepended#1#2#3% - {\t_syst_helpers_scratch{#3}% - \expandafter\expandafter\expandafter#1\expandafter\expandafter\expandafter#2\expandafter\expandafter\expandafter - {\expandafter\the\expandafter\t_syst_helpers_scratch#2}} - -\unexpanded\def\prependvalue #1{\expandafter\prepended\expandafter \def\csname#1\endcsname} -\unexpanded\def\prependgvalue#1{\expandafter\prepended\expandafter\gdef\csname#1\endcsname} - -%D \macros -%D {dowithrange} -%D -%D This one is for Mojca Miklavec, who made me aware of the fact that \type -%D {page-imp.tex} was not the best place to hide it. -%D -%D \startbuffer -%D \def\DoSomething#1{ [item #1] } -%D -%D \processranges[1,4:5]\DoSomething \par -%D \dowithrange {1,4:5}\DoSomething \par -%D \stopbuffer -%D -%D \typebuffer \blank \getbuffer \blank - -\def\syst_helpers_with_range#1% - {\splitstring#1\at:\to\m_syst_helpers_range_from\and\m_syst_helpers_range_to - \ifx\m_syst_helpers_range_to\empty\let\m_syst_helpers_range_to\m_syst_helpers_range_from\fi - \dostepwiserecurse\m_syst_helpers_range_from\m_syst_helpers_range_to\plusone{\m_helpers_range_action{##1}}}% - -\unexpanded\def\processranges[#1]#2% #1= n:m,p,q:r - {\def\m_helpers_range_action{#2}% - \processcommacommand[#1]\syst_helpers_with_range} - -\unexpanded\def\dowithrange#1#2% - {\def\m_helpers_range_action{#2}% - \processcommacommand[#1]\syst_helpers_with_range} - -% \def\DoSomething#1{ [item #1] } -% \dowithrange[1,4:5]\DoSomething - -%D \macros -%D {ignoreimplicitspaces} -%D -%D \startbuffer -%D \def\whatever[#1]{\expanded{\definedfont[#1 at 12pt]}\ignorespaces} -%D {a\whatever[Serif]b a\whatever[Serif] b a\whatever[Serif]\space b} -%D \def\whatever[#1]{\expanded{\definedfont[#1 at 12pt]}\ignoreimplicitspaces} -%D {a\whatever[Serif]b a\whatever[Serif] b a\whatever[Serif]\space b} -%D \stopbuffer -%D -%D \typebuffer \getbuffer - -\unexpanded\def\ignoreimplicitspaces - {\doifelsenextchar\relax\relax\relax} - -%D \macros -%D {processwords} -%D -%D Not that sophisticated but sometimes users (like in metafun). - -\def\syst_helpers_process_word#1 #2\_e_o_w_ - {\doifsomething{#1}{\processword{#1} \syst_helpers_process_word#2 \_e_o_w_}} - -\def\processwords#1% - {\syst_helpers_process_word#1 \_e_o_w_}% no \unskip - -\let\processword\relax - -%D \macros -%D {startnointerference} -%D -%D \starttyping -%D \startnointerference -%D all kind of code -%D \stopnointerference -%D \stoptyping - -\newbox\b_syst_helpers_no_interference - -\unexpanded\def\startnointerference % not even grouped ! - {\setbox\b_syst_helpers_no_interference\vbox - \bgroup} - -\unexpanded\def\stopnointerference - {\egroup - \setbox\b_syst_helpers_no_interference\emptybox} - -%D A variant for \type {\executeifdefined}: - -\def\expandcheckedcsname#1#2% #2 is often a \xxxparameter so let's expand it once - {\normalexpanded{\noexpand\syst_helpers_expand_checked_csname{#1}{#2}}} - -\def\syst_helpers_expand_checked_csname#1#2#3% - {\csname#1\ifcsname#1#2\endcsname#2\else#3\fi\endcsname} - -%D Signal. Some fonts have a char0 rendering so we need to make sure that it is not -%D set in the font! (This will be overloaded) - -\unexpanded\def\signalcharacter{\char\zerocount} % \zwj - -%D A few secial variants of commands defined here. Some more will be moved here (e.g. -%D from table modules. - -\def\dodirectdoubleempty#1#2% used in math (lookahead issues) - {\ifx#2[% - \expandafter\syst_helpers_direct_double_empty_one_yes - \else - \expandafter\syst_helpers_direct_double_empty_one_nop - \fi#1#2} - -\def\syst_helpers_direct_double_empty_one_yes#1[#2]#3% - {\ifx#3[\else\expandafter\syst_helpers_direct_double_empty_two_nop\fi#1[#2]#3} - -\def\syst_helpers_direct_double_empty_one_nop#1{#1[][]} -\def\syst_helpers_direct_double_empty_two_nop#1[#2]{#1[#2][]} - -%D Used in math definitions (in an \type {\edef}): - -%D \startbuffer -%D [\docheckedpair{}] -%D [\docheckedpair{a}] -%D [\docheckedpair{a,b}] -%D [\docheckedpair{a,b,c}] -%D \stopbuffer -%D -%D \typebuffer \startlines \getbuffer \stoplines - -\def\docheckedpair#1% - {\syst_helpers_checked_pair#1,,\_o_e_p_} - -\def\syst_helpers_checked_pair#1,#2,#3\_o_e_p_ - {#1,#2} - -%D Here are some nasty helpers. They can be used to fill often expanded token -%D lists efficiently (see tabulate for an example). - -\def\constantnumber#1% - {\ifcase#1\zerocount - \or \plusone - \or \plustwo - \or \plusthree - \or \plusfour - \or \plusfive - \or \plussix - \or \plusseven - \or \pluseight - \or \plusnine - \or \plusten - \else \number#1\relax\fi} - -\def\constantnumberargument#1% - {\ifcase#1\zerocount - \or \plusone - \or \plustwo - \or \plusthree - \or \plusfour - \or \plusfive - \or \plussix - \or \plusseven - \or \pluseight - \or \plusnine - \or \plusten - \else {\number#1}\fi} - -\def\constantdimen#1% - {\ifdim#1=\zeropoint - \zeropoint - \else - \the#1\relax - \fi} - -\def\constantdimenargument#1% - {\ifdim#1=\zeropoint - \zeropoint - \else - {\the#1}% - \fi} - -\def\constantemptyargument#1% - {\ifx#1\empty - \noexpand\empty - \else - {#1}% - \fi} - -%D \macros -%D {getsubstring} -%D \startbuffer -%D -%D \getsubstring{4}{}{Who Wants This} -%D \getsubstring{4}{9}{Who Wants This} -%D \getsubstring{9}{-2}{Who Wants This} -%D \getsubstring{1}{5}{Who Wants This} -%D \stopbuffer -%D -%D \typebuffer -%D -%D \startlines -%D \getbuffer -%D \stoplines - -% expandable: - -\def\getsubstring#1#2#3{\clf_getsubstring{#3}{#1}{#2}} - -%D Other dimensions than pt (used in mb-mp) - -\def\converteddimen#1#2{\clf_converteddimen\dimexpr#1\relax{#2}} - -%D Maybe (looks ugly): -%D -%D \starttyping -%D \doifcase {foo} -%D {bar} {BAR} -%D {foo} {FOO} -%D {default} {DEFAULT} -%D -%D \doifcase {foo} -%D {bar} {BAR} -%D {foo} {\doifcase {bar} -%D {bar} {BAR} -%D {foo} {FOO} -%D {default} {DEFAULT} -%D } -%D {default} {DEFAULT} -%D \stoptyping - -% \doifcase {\btxfoundname{author}} -% {author} {\btxflush{author}} -% {editor} {\texdefinition{btx:apa:editor-or-editors}} -% {title} {\texdefinition{btx:apa:title-subtitle-type}} -% {default} {\btxflush{author}} - -% \unexpanded\def\doifcase#1% -% {\edef\m_case_asked{#1}% -% \syst_aux_case} -% -% \def\syst_aux_case#1% -% {\edef\m_case_temp{#1}% -% \ifx\m_case_temp\m_case_asked -% \expandafter\syst_aux_case_yes -% \orelse\ifx\m_case_temp\s!default -% \expandafter\firstofoneargument -% \else -% \expandafter\syst_aux_case_nop -% \fi} -% -% \def\syst_aux_skip#1#2% -% {\edef\m_case_temp{#1}% -% \ifx\m_case_temp\s!default -% \expandafter\syst_aux_done -% \else -% \expandafter\syst_aux_skip -% \fi} -% -% \def\syst_aux_case_yes#1% -% {\def\syst_aux_done{#1}% -% \syst_aux_skip} -% -% \def\syst_aux_case_nop#1% -% {\syst_aux_case} - -%D \macros -%D {ntimes} -%D -%D some repetition: -%D -%D \startbuffer -%D \ntimes{*}{20} -%D \stopbuffer -%D -%D \typebuffer \blank gives: \getbuffer \blank -%D -%D This is not real fast but quite okay: - -%def\ntimes#1#2{\ifnum#2>\zerocount#1\ntimes{#1}{\numexpr#2-\plusone\relax}\fi} % 1.72 -\def\ntimes#1#2{\clf_ntimes{#1}\numexpr#2\relax} % 0.33 - -%D Experiment (sometimes looks nicer in code): - -\unexpanded\def\sameargumentscondition#1#2% - {\edef\m_syst_string_one{#1}% - \edef\m_syst_string_two{#2}% - \ifx\m_syst_string_one\m_syst_string_two} - -\unexpanded\def\emptyargumentcondition#1% - {\edef\m_syst_string_one{#1}% - \ifx\m_syst_string_one\empty} - -\protect \endinput |