%D \module
%D   [       file=core-var,
%D        version=1998.02.21,
%D          title=\CONTEXT\ Core Macros,
%D       subtitle=Variables,
%D         author=Hans Hagen,
%D           date=\currentdate,
%D      copyright={PRAGMA / Hans Hagen \& Ton Otten}]
%C
%C This module is part of the \CONTEXT\ macro||package and is
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.

\writestatus{loading}{Context Core Macros / Variables}

\unprotect

%D Modes:
%D
%D \starttyping
%D \enablemode[screen,paper,bound]
%D
%D \doifmodeelse {paper}        {this} {that}
%D \doifmode     {paper,screen} {this}
%D \doifnotmode  {paper,bound}  {that}
%D
%D \startmode [list]
%D \stopmode
%D
%D \startnotmode [list]
%D \stopnotmode
%D \stoptyping
%D
%D system modes have a * as prefix
%D
%D Sometimes, we want to prevent a mode for being set. Think
%D of situations where a style enables a mode, but an outer
%D level style does not want that. Preventing can be
%D considered a permanent disabling on forehand.

% \def\systemmodeprefix{*}
%
% \let\currentmode   \empty
% \let\preventedmodes\empty
%
% \def\preventmode[#1]%
%   {\expanded{\addtocommalist{#1}\noexpand\preventedmodes}}
%
% \def\enablemode[#1]%
%   {\expanded
%      {\doifnotinset{#1}{\preventedmodes}
%         {\noexpand\addtocommalist{#1}\noexpand\currentmode}}}
%
% \def\disablemode[#1]%
%   {\expanded{\removefromcommalist{#1}\noexpand\currentmode}}
%
% \def\doifmodeelse{\unprotect\dodoifmodeelse}
% \def\doifmode    {\unprotect\dodoifmode    }
% \def\doifnotmode {\unprotect\dodoifnotmode }
% \def\startmode   {\unprotect\dostartmode   }
% \def\startnotmode{\unprotect\dostartnotmode}
%
% \long\def\dodoifmodeelse#1%
%   {\protect\expanded{\doifcommonelse{#1}{\currentmode}}}
%
% \long\def\dodoifmode#1%
%   {\protect\expanded{\doifcommon    {#1}{\currentmode}}}
%
% \long\def\dodoifnotmode#1%
%   {\protect\expanded{\doifnotcommon {#1}{\currentmode}}}
%
% \let\stopmode   \relax
% \let\stopnotmode\relax
%
% \long\def\dostartmode[#1]%
%   {\protect
%    \expanded{\doifnotcommon{#1}{\currentmode}}{\gobbleuntil\stopmode}}
%
% \long\def\dostartnotmode[#1]%
%   {\protect
%    \expanded{\doifcommon   {#1}{\currentmode}}{\gobbleuntil\stopnotmode}}
%
% \def\doifallmodeselse{\unprotect\dodoifallmodeselse}
% \def\doifallmodes    {\unprotect\dodoifallmodes}
% \def\doifnotallmodes {\unprotect\dodoifnotallmodes}
% \def\startallmodes   {\unprotect\dostartallmodes}
% \def\startnotallmodes{\unprotect\dostartnotallmodes}
%
% \long\def\dodoifallmodeselse#1%
%   {\protect\expanded{\doifallcommonelse{#1}{\currentmode}}}
%
% \long\def\dodoifallmodes#1%
%   {\protect\expanded{\doifallcommon    {#1}{\currentmode}}}
%
% \long\def\dodoifnotallmodes#1%
%   {\protect\expanded{\doifnotallcommon {#1}{\currentmode}}}
%
% \let\stopallmodes   \relax
% \let\stopnotallmodes\relax
%
% \long\def\dostartallmodes[#1]%
%   {\protect
%    \expanded{\doifnotallcommon{#1}{\currentmode}}{\gobbleuntil\stopallmodes}}
%
% \long\def\dostartnotallmodes[#1]%
%   {\protect
%    \expanded{\doifallcommon   {#1}{\currentmode}}{\gobbleuntil\stopnotallmodes}}

% faster

\def\@mode@{@md@}

\def\systemmodeprefix{*}

\def\disabledmode    {0}
\def\enabledmode     {1}
\def\preventedmode   {2}

% fast internal ones

\def\setmode  #1{\@EA\let\csname\@mode@#1\endcsname\enabledmode }
\def\resetmode#1{\@EA\let\csname\@mode@#1\endcsname\disabledmode}

\def\setsystemmode  #1{\@EA\let\csname\@mode@\systemmodeprefix#1\endcsname\enabledmode }
\def\resetsystemmode#1{\@EA\let\csname\@mode@\systemmodeprefix#1\endcsname\disabledmode}

% user ones

\def\preventmode{\unprotect\dopreventmode}
\def\enablemode {\unprotect\doenablemode }
\def\disablemode{\unprotect\dodisablemode}

% \def\dopreventmode[#1]{\protect\rawprocesscommalist[#1]\dodopreventmode}
% \def\doenablemode [#1]{\protect\rawprocesscommalist[#1]\dodoenablemode }
% \def\dodisablemode[#1]{\protect\rawprocesscommalist[#1]\dododisablemode}
%
% better:

\def\dopreventmode[#1]{\protect\cleanuplabel{#1}\rawprocesscommalist[\cleanlabel]\dodopreventmode}
\def\doenablemode [#1]{\protect\cleanuplabel{#1}\rawprocesscommalist[\cleanlabel]\dodoenablemode }
\def\dodisablemode[#1]{\protect\cleanuplabel{#1}\rawprocesscommalist[\cleanlabel]\dododisablemode}

\def\dodopreventmode#1%
  {\@EA\let\csname\@mode@#1\endcsname\preventedmode}

\def\dodoenablemode#1% mode can be relax
  {\ifcase0\csname\@mode@#1\endcsname\relax
     \@EA\let\csname\@mode@#1\endcsname\enabledmode
   \fi}

\def\dododisablemode#1%
  {\ifcase0\csname\@mode@#1\endcsname\or
     \@EA\let\csname\@mode@#1\endcsname\disabledmode
   \fi}

% handy for mp

\def\booleanmodevalue#1% can be \relax
  {\expandafter\ifx\csname\@mode@#1\endcsname\relax
     fals%
   \else\ifnum0\csname\@mode@#1\endcsname=0
     fals%
   \else
     tru%
   \fi\fi e}

% check macros

\newif\ifcheckedmode

\def\dodocheckformode#1%
  {\ifcase0\csname\@mode@#1\endcsname\or\checkedmodetrue\fi}

\def\docheckformode#1#2#3% will be sped up with a quit
  {\cleanuplabel{#3}%
   \protect\checkedmodefalse\rawprocesscommacommand[\cleanlabel]\dodocheckformode
   \ifcheckedmode\@EA#1\else\@EA#2\fi}

\def\dodocheckforallmodes#1%
  {\ifcase0\csname\@mode@#1\endcsname\relax\checkedmodefalse\or\or\checkedmodefalse\fi}

\def\docheckforallmodes#1#2#3% will be sped up with a quit
  {\cleanuplabel{#3}%
   \protect\checkedmodetrue\rawprocesscommacommand[\cleanlabel]\dodocheckforallmodes
   \ifcheckedmode\@EA#1\else\@EA#2\fi}

% simple ones

\def\doifmodeelse{\unprotect\dodoifmodeelse}
\def\doifmode    {\unprotect\dodoifmode}
\def\doifnotmode {\unprotect\dodoifnotmode}
\def\startmode   {\unprotect\dostartmode}
\def\startnotmode{\unprotect\dostartnotmode}

\def\dodoifmodeelse
  {\docheckformode\firstoftwoarguments\secondoftwoarguments}

\def\dodoifmode
  {\docheckformode\firstofoneargument\gobbleoneargument}

\def\dodoifnotmode
  {\docheckformode\gobbleoneargument\firstofoneargument}

\long\def\dostartmode[#1]%
  {\docheckformode\donothing\dostopmode{#1}}

\long\def\dostartnotmode[#1]%
  {\docheckformode\dostopnotmode\donothing{#1}}

\let\stopmode   \donothing
\let\stopnotmode\donothing

\long\def\dostopmode   #1\stopmode   {}
\long\def\dostopnotmode#1\stopnotmode{}

\def\doifallmodeselse{\unprotect\dodoifallmodeselse}
\def\doifallmodes    {\unprotect\dodoifallmodes}
\def\doifnotallmodes {\unprotect\dodoifnotallmodes}
\def\startallmodes   {\unprotect\dostartallmodes}
\def\startnotallmodes{\unprotect\dostartnotallmodes}

\def\dodoifallmodeselse
  {\docheckforallmodes\firstoftwoarguments\secondoftwoarguments}

\def\dodoifallmodes
  {\docheckforallmodes\firstofoneargument\gobbleoneargument}

\def\dodoifnotallmodes
  {\docheckforallmodes\gobbleoneargument\firstofoneargument}

\long\def\dostartallmodes[#1]%
  {\docheckforallmodes\donothing\dostopallmodes{#1}}

\long\def\dostartnotallmodes[#1]%
  {\docheckforallmodes\dostopallmodes\donothing{#1}}

\let\stopallmodes   \donothing
\let\stopnotallmodes\donothing

\long\def\dostopallmodes   #1\stopallmodes   {}
\long\def\dostopnotallmodes#1\stopnotallmodes{}

%D \macros
%D   {every...}
%D
%D A few every's.

\newevery \everyshipout            \relax
\newevery \everybeforeshipout      \relax
\newevery \everyaftershipout       \relax
\newevery \everyfirstshipout       \relax
\newevery \everylastshipout        \relax
\newevery \everybye                \relax
\newevery \everygoodbye            \relax
\newevery \everystarttext          \relax
\newevery \everystoptext           \relax
\newevery \everyforgetall          \relax
\newevery \everybeforepagebody     \relax
\newevery \everyafterpagebody      \relax
\newevery \everybeforeutilityread  \relax
\newevery \everyafterutilityread   \relax

\let      \everypagebody           \everybeforepagebody % backward compatible

%newevery \everybeforeutilitywrite \relax

\newevery \everycleanupfeatures    \relax
\newevery \everyinsidefloat        \relax
\newevery \everyheadstart          \relax
\newevery \everyendoftextbody      \relax
\newevery \everybeginofpar         \relax
\newevery \everyendofpar           \relax
\newevery \everylistentry          \relax
\newevery \everymarking            \relax
\newevery \everysavesortkeys       \relax

\newevery \everyfont               \relax
\newevery \everybodyfont           \EveryBodyFont
\newevery \everyfontswitch         \EveryFontSwitch
\newevery \everydefinedfont        \relax

\def\cleanupfeatures{\the\everycleanupfeatures}
\def\forgetall      {\the\everyforgetall}

%D For shared \type {\everymath} and \type {\everydisplay}:

\newevery \everymathematics        \relax

\prependtoks \the\everymathematics \to \everymath
\prependtoks \the\everymathematics \to \everydisplay

% \newevery \everyparflush           \relax % collected nodes

%D Experimental (used in xml <p> .. </p>

\def\bpar{\the\everybeginofpar\ignorespaces} % may interfere with \everypar
\def\epar{\ifhmode\removeunwantedspaces\the\everyendofpar\fi} % test prevents problems with \bpar\epar

%D More generic (used to be pushcolor etc)

\newtoks\everypushproperties
\newtoks\everypopproperties
\newtoks\everypopsplitproperties

\newtoks\everystarttextproperties
\newtoks\everystoptextproperties

\def\pushproperties     {\the\everypushproperties}
\def\popproperties      {\the\everypopproperties}
\def\popsplitproperties {\the\everypopsplitproperties}

\def\starttextproperties{\the\everystarttextproperties}
\def\stoptextproperties {\the\everystoptextproperties}

%D This is pretty important (esp since we now ignore shipouts).
%D Actually we should nil all writes, marks, specials.

\appendtoks \globallet\popproperties     \relax \to \everylastshipout
\appendtoks \globallet\popsplitproperties\relax \to \everylastshipout

%D \macros
%D   {defineinputmode,setinputmode}
%D
%D New. Some work needs to be done.

\def\defineinputmode[#1]{\@EA\newtoks\csname every#1inputmode\endcsname}
%def\setinputmode   [#1]{\the        \csname every#1inputmode\endcsname}
\def\setinputmode   [#1]{\the\executeifdefined{every#1inputmode}\emptytoks}

\defineinputmode [TEX]
\defineinputmode [XML]

\setinputmode    [TEX]

%D \macros
%D   {trialtypesetting}
%D
%D We disable trial typesetting in the output routine,
%D just to be sure.

% defined in syst-ext

\prependtoks \trialtypesettingfalse \to \everybeforepagebody

%D \macros
%D   {ifinpagebody,ifinsidecolumns,ifdoublesided,ifsinglesided}

\newif \ifinpagebody
\newif \ifinsidecolumns
\newif \ifdoublesided   \doublesidedfalse
\newif \ifsinglesided   \singlesidedtrue
\newif \ifinsidefloat
\newif \ifdoingblocks
\newif \ifgridsnapping

%D \macros
%D   {ifprocessingXML}
%D
%D We need this one even if no \XML\ is supported.

\newif\ifprocessingXML

%D \macros
%D   {ifproductionrun}
%D
%D This boolean can be used to bypass certain
%D initializations.

\newif\ifproductionrun \appendtoks \productionruntrue \to \everydump

\appendtoks \ifcase\protectionlevel\else\reportunprotection\fi \to \everydump

%D \macros
%D   {everyboxedcontent, ifboxedcontent,
%D    startboxedcontent, stopboxedcontent}
%D
%D This one is relatively new and will be used as a more
%D robust test for inner situations.

\newif    \ifboxedcontent
\newevery \everyboxedcontent \relax

\appendtoks \boxedcontenttrue \to \everyboxedcontent

\def\startboxedcontent{\bgroup\the\everyboxedcontent}
\let\stopboxedcontent  \egroup

%D \macros
%D   {fastmode}
%D
%D The command \type {\fastmode} disables some time consuming
%D typesetting.

\newevery \everyfastmode \relax

\newif\iffastmode

\def\fastmode
  {\fastmodetrue
   \the\everyfastmode}

\def\silentmode % ook hier \everysilentmode net als \fastmode
  {\showmessagesfalse
   \showwarningsfalse
   \let\writestatus\gobbletwoarguments}

%D \macros
%D   {pdfoutput}
%D
%D There are some fundamental differences between producing
%D \DVI\ and \PDF\ output, especially when we use \PDFTEX, like
%D object reuse, one pass graphic inclusion and the lack of a
%D postprocessing stage. Because we must make sure that
%D \CONTEXT\ knows what it's up to, we always default to \DVI\
%D mode, even when users explicitly ask for \PDF\ output in the
%D \PDFTEX\ configuration file.

\ifx\pdfoutput\undefined \else

  \prependtoks \pdfoutput=0 \to \everyjob

\fi

%D \macros
%D   {setvariables,getvariable,getvariabledefault}
%D
%D \starttyping
%D \setvariables[xx][title=]
%D \setvariables[xx][title=test test]
%D \setvariables[xx][title=test $x=1$ test]   % fatal error reported
%D \setvariables[xx][title=test {$x=1$} test]
%D \setvariables[xx][title]                   % fatal error reported
%D \setvariables[xx][titletitel=e]
%D \stoptyping

\def\??vars{@@vars}

\def\setvariables {\dotripleargument\dosetvariables[\getrawparameters ]}
\def\setevariables{\dotripleargument\dosetvariables[\getraweparameters]}
\def\setgvariables{\dotripleargument\dosetvariables[\getrawgparameters]}
\def\setxvariables{\dotripleargument\dosetvariables[\getrawxparameters]}

\def\globalsetvariables % obsolete
  {\dotripleargument\dosetvariables[\globalgetrawparameters]}

\long\def\dosetvariables[#1][#2][#3]%
  {\errorisfataltrue
   \def\currentvariableclass{#2}%
   \getvariable{#2}\s!reset
   #1[\??vars:#2:][#3]%
   \getvariable{#2}\s!set
   \errorisfatalfalse}

\long\def\setvariable #1#2#3{\long\setvalue {\??vars:#1:#2}{#3}}
\long\def\setevariable#1#2#3{\long\setevalue{\??vars:#1:#2}{#3}}
\long\def\setgvariable#1#2#3{\long\setgvalue{\??vars:#1:#2}{#3}}
\long\def\setxvariable#1#2#3{\long\setxvalue{\??vars:#1:#2}{#3}}

\beginTEX

\def\getvariable#1#2% to be sped up
  {\csname
     \ifundefined{\??vars:#1:#2}\s!empty\else\??vars:#1:#2\fi
   \endcsname}

\endTEX

\beginETEX \ifcsname

\def\getvariable#1#2% to be sped up
  {\csname
     \ifcsname\??vars:#1:#2\endcsname\??vars:#1:#2\else\s!empty\fi
   \endcsname}

\endETEX

\def\showvariable#1#2%
  {\showvalue{\ifundefined{\??vars:#1:#2}\s!empty\else\??vars:#1:#2\fi}}

\let\currentvariableclass\empty

%D \macros
%D   {doifelsevariable,doifvariable,doifnotvariable}
%D
%D A few trivial macros:

\def\doifelsevariable#1#2%
  {\ifundefined{\??vars:#1:#2}%
     \expandafter\secondoftwoarguments
   \else
     \expandafter\firstoftwoarguments
   \fi}

\def\doifvariable#1#2%
  {\ifundefined{\??vars:#1:#2}%
     \expandafter\gobbleoneargument
   \else
     \expandafter\firstofoneargument
   \fi}

\def\doifnotvariable#1#2%
  {\ifundefined{\??vars:#1:#2}%
     \expandafter\firstofoneargument
   \else
     \expandafter\gobbleoneargument
   \fi}

\def\getvariabledefault#1#2% #3%
  {\executeifdefined{\??vars:#1:#2}}% {#3}

%D \macros
%D   {defineselector,setupselector}
%D
%D \starttyping
%D \defineselector[caption][max=2,n=2]
%D
%D \start
%D     \setupselector[caption][n=1]
%D     \placelist[figure][criterium=all]
%D \stop
%D
%D \starttext
%D     \placefigure
%D       {\select{caption}{zapf}{\input zapf \relax}}
%D       {}
%D \stoptext
%D \stoptyping

\def\defineselector{\dodoubleargument\dodefineselector}
\def\setupselector {\dodoubleargument\dosetupselector}

\def\dodefineselector[#1][#2]{\getparameters[\??sx#1][\c!max=2,\c!n=1,#2]}
\def\dosetupselector [#1][#2]{\getparameters[\??sx#1][#2]}

\unexpanded\def\select#1%
  {\filterfromnext
     {\executeifdefined{\??sx#1\c!max}1}
     {\executeifdefined{\??sx#1\c!n  }1}}

%D \macros
%D   {checkvariables}
%D
%D I'll probably forget that this on exists.

\def\checkvariables
  {\dodoubleargument\docheckvariables}

\def\docheckvariables
  {\dogetparameters\docheckrawvalue}

\def\docheckrawvalue#1#2#3%
  {\doifundefined   {\??vars:#1:#2}{\setvalue{\??vars:#1:#2}{#3}}
  {\doifvaluenothing{\??vars:#1:#2}{\setvalue{\??vars:#1:#2}{#3}}}}

%D We store some original meanings, maybe in \type
%D {math-ini}.

\let\normalat             \at
\let\normalin             \in
\let\normalfrom           \from
\let\normalover           \over
\let\normalabout          \about

\let\normalabove          \above
\let\normalatop           \atop

\let\normaloverwithdelims \overwithdelims
\let\normalabovewithdelims\abovewithdelims
\let\normalatopwithdelims \atopwithdelims

%D Add-ons:

\let\startlayoutcomponent\gobbletwoarguments
\let\stoplayoutcomponent \relax

%D Label cleanup:

\bgroup % some day this will go away / we could use detokenize as well

% actually we should handle all discretionaries here

\catcode`:=\@@active

\gdef\cleanuplabel#1%
  {\begingroup
   \let:\lettercolon
   \xdef\cleanlabel{#1}%
   \endgroup}

\gdef\cleanupprefixedlabel#1#2%
  {\begingroup
   \let:\lettercolon
   \xdef\cleanprefix{#1}%
   \xdef\cleanlabel {#2}%
   \endgroup}

\gdef\protectlabels
  {\let:\lettercolon}

\global\def\blabelgroup {\begingroup \let:\lettercolon}
\global\let\elabelgroup  \endgroup

\gdef\labelcsname
  {\begingroup\let:\lettercolon
   \expandafter\endgroup\csname}

\gdef\labelvalue#1%
  {\labelcsname#1\endcsname}

\egroup

%D TO BE TESTED FIRST (needs changes in usage too)

% \def\cleanuplabel#1%
%   {\edef\cleanlabel{\detokenize{#1}}}
%
% \def\cleanupprefixedlabel#1#2%
%   {\edef\cleanprefix{\detokenize{#1}}%
%    \edef\cleanlabel {\detokenize{#2}}}
%
% \def\labelvalue#1%
%   {\csname\detokenize{#1}\endcsname}
%
% \let\protectlabels\donothing
%
% \def\blabelgroup {\begingroup} % why no \let ?
% \let\elabelgroup  \endgroup

%D Concepts:

\chardef\conceptmode\zerocount

\def\doifconcepttracing
  {\ifnum\conceptmode>\plustwo
     \expandafter\firstofoneargument
   \else
     \expandafter\gobbleoneargument
   \fi}

\protect \endinput
