%D \module
%D   [       file=core-sys, % moved from main-001
%D        version=1997.03.31,
%D          title=\CONTEXT\ Core Macros,
%D       subtitle=System,
%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.

% we need to mkiv-ize this file !

\writestatus{loading}{ConTeXt Core Macros / System}

\registerctxluafile{core-sys}{autosuffix}

\unprotect

%D Version checking:

\permanent\protected\def\newcontextversion#1%
  {\ifcstok{#1}\contextversion
     \enforced\let\newcontextversion\gobbleoneargument
   \else
     \writeline
     \writestatus{Fatal    Error}{Your format does not match the base files!}%
     \writeline
     \writestatus{Format Version}{\contextversion\space\contextmark}%
     \writestatus{Files  Version}{#1}%
     \batchmode
     \normalend
   \fi}

%D End of lines to the output. \TEX\ will map this onto the platform specific
%D line ending. I hate this mess.


% \operatingsystem % defined at lua end

%D The jobname is what gets loaded by the cont-yes stub file. This name also
%D determines the name of tuc etc files.

% \jobfilefullname  % defined at lua end
% \jobfilename      % defined at lua end
% \jobfilesuffix    % defined at lua end

%D However, that one can itself load another file.

% \inputfilebarename    % defined at lua end
% \inputfilerealsuffix  % defined at lua end
% \inputfilesuffix      % defined at lua end
% \inputfilename        % defined at lua end

%D The output name is only used for some checking.

% \outputfilename % defined at lua end

\installcorenamespace{system}

\installdirectcommandhandler \??system {system}

\appendtoks
%   \edef\outputfilename  {\directsystemparameter\c!file      }%
%   \edef\inputfilename   {\directsystemparameter\c!inputfile }%
\to \everysetupsystem

\appendtoks
    \ifcase\directsystemparameter\c!n\relax
        %                        % 0 : unknown
    \or
        \setsystemmode\v!first   % 1 : first run
    \or
        %                        % 2 : successive run
    \or
        \setsystemmode\v!first   % 3 : first and only run
    \or
        \setsystemmode\v!last    % 4 : (extra) last run
    \fi
\to \everysetupsystem

\newconditional\prerollrun % when true it means that we have a forced number of runs

% Some mechanisms (see x-res-01) use either \jobfilename or
% \jobfilename.somesuffix, in which case we need to use the full name if given or a
% default (like \jobfilename.xml); this comes down to replacing the default tex
% suffix.

\permanent\def\jobfullname{\jobfilename.\jobfilesuffix}

\permanent\protected\def\setjobfullname#1% #1 = default if not given
  {\ifempty\jobfilename
     \lettonothing\jobfullname
   \orelse\ifcstok\jobfilesuffix\c!tex
     \edef\jobfullname{\jobfilename.#1}%
   \fi}

%D There are a couple of system states avaiable:
%D
%D \starttabulate [|T|T|]
%D     \NC \type{\jobname}           \NC \jobname           \NC \NR
%D     \NC \type{\jobfilename}       \NC \jobfilename       \NC \NR
%D     \NC \type{\jobfilesuffix}     \NC \jobfilesuffix     \NC \NR
%D     \NC \type{\inputfilename}     \NC \inputfilename     \NC \NR
%D     \NC \type{\inputfilebarename} \NC \inputfilebarename \NC \NR
%D     \NC \type{\inputfilesuffix}   \NC \inputfilesuffix   \NC \NR
%D     \NC \type{\outputfilename}    \NC \outputfilename    \NC \NR
%D     \NC \type{\operatingsystem}   \NC \operatingsystem   \NC \NR
%D \stoptabulate

% \appendtoks
%     \edef\outputresolution{\directsystemparameter\c!resolution}%
% \to \everysetupsystem

%D The system modes set by the setup command can be used in situations like:
%D
%D \starttyping
%D \startmode[*first]
%D   \executesystemcommand{cleanupxml text.xml clean-text.xml}
%D \stopmode
%D
%D \starttext
%D   \typefile{clean-text.xml}
%D \stoptext
%D \stoptyping

\permanent\protected\def\setuprandomize[#1]%
  {\ifempty{#1}\else
     \begingroup
     % tex's time is in minutes
     \scratchcounter\normaltime
     \processaction
       [#1]
       [  \v!small=>\divideby\scratchcounter 15, %  900,
         \v!medium=>\divideby\scratchcounter 30, % 1800,
            \v!big=>\divideby\scratchcounter 60, % 3600,
         \v!normal=>\scratchcounter\newrandomseed,
        \s!default=>\scratchcounter\newrandomseed,
        \s!unknown=>\scratchcounter#1]%
     \setrandomseed\scratchcounter
    %\writestatus\m!system{randomseed: \the\scratchcounter}%
     \endgroup
   \fi}

\setupsystem
  [\c!directory=,
   \c!n=0, % 0:unknown 1: one run 2: first 3: successive 4: final run
 % \c!resolution=600,% in dpi, no unit in mkiv, not used in lmtx
 % \c!random=, % obsolete here
 % \c!file=\jobname,
 % \c!inputfile=\outputfilename,
   \c!type=unix, % windows is normally less sensitive to handle
   \c!bodyfont=\normalizedlocalbodyfontsize] % of iets anders

%D Remark: windows programs normally handle \type {cr|lf|crlf} but unix is more
%D picky, so we default to the \type {cr}. I never understood why \type {crlf} was
%D not used in all systems, since it makes most sense. But anyway, in \MKIV\ we
%D avoid most of the complications anyway as we deal with much at the \LUA\ end.

\lettonothing\m_syst_start_stop

\permanent\tolerant\protected\def\start[#1]%
  {\bgroup
   \ifparameters
     \lettonothing\m_syst_start_stop
     \expandafter\syst_start_nop
   \else
     \cdef\m_syst_start_stop{#1}%
     \expandafter\syst_start_yes
   \fi}

\let\syst_stop_indeed\donothing

\def\syst_start_yes
 {\ifempty\m_syst_start_stop
    \let\syst_stop_indeed\donothing
  \orelse\ifcsname\e!start\m_syst_start_stop\endcsname
    \expandafter\let\expandafter\syst_stop_indeed\csname\e!stop\m_syst_start_stop\endcsname
    \csname\e!start\m_syst_start_stop\expandafter\expandafter\expandafter\endcsname
  \else
    \let\syst_stop_indeed\donothing
  \fi}

\def\syst_start_nop
  {\let\syst_stop_indeed\donothing}

\permanent\protected\def\stop
  {\syst_stop_indeed
   \egroup}

% \c!before \c!after \c!inbetween \c!commands \c!style \c!color

\installcorenamespace{startstop}

\installcommandhandler \??startstop {startstop} \??startstop

\appendtoks
    \ifcstok{\startstopparameter\c!arguments}\v!yes
        \protected\frozen\instance\edefcsname\e!start\currentstartstop\endcsname{\syst_startstop_start_yes {\currentstartstop}}%
        \protected\frozen\instance\edefcsname\e!stop \currentstartstop\endcsname{\syst_startstop_stop_yes  }%
        \protected\frozen\instance\edefcsname        \currentstartstop\endcsname{\syst_startstop_indeed_yes{\currentstartstop}}%
    \else
        \protected\frozen\instance\edefcsname\e!start\currentstartstop\endcsname{\syst_startstop_start_nop {\currentstartstop}}%
        \protected\frozen\instance\edefcsname\e!stop \currentstartstop\endcsname{\syst_startstop_stop_nop  {\currentstartstop}}%
        \protected\frozen\instance\edefcsname        \currentstartstop\endcsname{\syst_startstop_indeed_nop{\currentstartstop}}%
    \fi
\to \everydefinestartstop

\ifdefined\dotagconstruct \else \aliased\let\dotagconstruct\relax \fi

\protected\def\syst_startstop_start_indeed
  {% we will keep this for a while:
   \startstopparameter\c!commands\relax % obsolete
   % this is the new method:
   \usesetupsparameter\startstopparameter\relax % only in the display version
   \dostarttagged\t!construct\currentstartstop
   \uselanguageparameter\startstopparameter
  %\usestartstoplanguage\c!language
   \usestartstopstyleandcolor\c!style\c!color
   \dotagconstruct}

% Here before and after are grouped!

\tolerant\protected\def\syst_startstop_start_yes#1#*[#S#2]%
  {\begingroup
   \cdef\currentstartstop{#1}%
   \ifparameter#2\or\setupcurrentstartstop[#2]\fi
   \startstopparameter\c!before\relax
   \syst_startstop_start_indeed}

\tolerant\protected\def\syst_startstop_indeed_yes#1#*[#S#2]%
  {\groupedcommand
     {\cdef\currentstartstop{#1}%
      \ifparameter#2\or\setupcurrentstartstop[#2]\fi
      \startstopparameter\c!commands\relax % better: setups so that will show op soon
      \dostarttagged\t!construct\currentstartstop
      \uselanguageparameter\startstopparameter
     %\usestartstoplanguage\c!language
      \usestartstopstyleandcolor\c!style\c!color
      \dostarttaggednodetail\t!constructleft
      \startstopparameter\c!left\relax
      \dostoptagged
      \dostarttaggednodetail\t!constructcontent}%
     {\dostoptagged
      \cdef\currentstartstop{#1}% safeguard, not really needed
      \dostarttaggednodetail\t!constructright
      \startstopparameter\c!right\relax
      \dostoptagged
      \dostoptagged
      \startstopparameter\c!inbetween\relax}}

\protected\def\syst_startstop_stop_yes
  {\dostoptagged
   \startstopparameter\c!after\relax
   \endgroup}

% Here before and after are not grouped!

\protected\def\syst_startstop_start_nop#1%
  {\namedstartstopparameter{#1}\c!before\relax
   \bgroup
   \cdef\currentstartstop{#1}%
   \syst_startstop_start_indeed}

\protected\def\syst_startstop_stop_nop#1%
  {\dostoptagged
   \egroup
   \namedstartstopparameter{#1}\c!after\relax}

\protected\def\syst_startstop_indeed_nop#1%
  {\syst_startstop_indeed_yes{#1}[]}

% \definestartstop[tracing][\c!style=\tt]

% \protected\def\ignorestartstop[#1]%
%   {\protected\defcsname\e!start#1\expandafter\endcsname\expandafter
%      {\expandafter\ignoreupto\csname\e!stop#1\endcsname}}
%
% \ignorestartstop[bagger]

%D When looking at an application of \type {\beginsimplegroup} I wondered
%D about this one but it doesn't make much sense. One hould define highlights that
%D have style and color, but on the other hand, we might want to combine a font
%D style and some other treatment. The overhead of commalists (where we can use
%D \type {\aftergrouped} for collecting stop tags) is neglectable but it makes no sense.
%D Maybe we need a \type {command} or better (as commands can take arguments) a
%D \type {setups} key, but no one ever asked so \unknown.

% \processnextcommalist\typo_highlights_step ...
%
% list  : 10K single: 0.111 / 0.132 with command / 0.134 with setups
% single: 10K single: 0.075 / 0.098 with command / 0.099 with setups

\installcorenamespace{highlight}

\installcommandhandler \??highlight {highlight} \??highlight % we could do with less

\setuphighlight
  [\c!define=\v!yes]
%  \c!command=,
%  \c!setups=]

\appendtoks
    \ifcstok{\highlightparameter\c!define}\v!yes
        \protected\frozen\instance\edefcsname\currenthighlight\endcsname
           {\typo_highlights_indeed{\currenthighlight}}%
    \fi
\to \everydefinehighlight

\ifdefined\dotaghighlight \else \aliased\let\dotaghighlight\relax \fi

\permanent\protected\def\typo_highlights_indeed#1% inline style/color switch
  {\dontleavehmode\groupedcommand % otherwise wrong par number in tags
     {\cdef\currenthighlight{#1}%
      \dostarttagged\t!highlight\currenthighlight
      \uselanguageparameter\highlightparameter
     %\usehighlightlanguage\c!language
      \usehighlightstyleandcolor\c!style\c!color
    % \highlightparameter\c!command % better after tagged then
      \dotaghighlight}
     {\dostoptagged}}

\permanent\protected\def\highlight[#1]%
  {\typo_highlights_indeed{#1}}

\permanent\protected\def\starthighlight[#1]%
  {\begingroup
   \cdef\currenthighlight{#1}%
   \dostarttagged\t!highlight\currenthighlight
   \uselanguageparameter\highlightparameter
  %\usehighlightlanguage\c!language
   \usehighlightstyleandcolor\c!style\c!color
 % \highlightparameter\c!command
   \dotaghighlight}

\permanent\protected\def\stophighlight
  {\dostoptagged
   \endgroup}

\aliased\let\directhighlight\typo_highlights_indeed

%D Defining commands (rather old):

\permanent\protected\def\defineexpandable
  {\integerdef\c_syst_parameter_catcode\catcode\hashasciicode
   \catcode\hashasciicode\parametercatcode%
   \doifelsenextoptional
     {\syst_basics_define_yes\def}%
     {\syst_basics_define_nop\def}}

\permanent\protected\def\define
  {\integerdef\c_syst_parameter_catcode\catcode\hashasciicode
   \catcode\hashasciicode\parametercatcode%
   \doifelsenextoptional
     {\syst_basics_define_yes{\protected\def}}%
     {\syst_basics_define_nop{\protected\def}}}

\protected\def\syst_basics_define_yes#1[#2]#3#4%
  {\ifdefined#3%
     \showmessage\m!system4{\string#3}%
   \fi
   \ifcase0#2\relax
     #1#3{#4}\or
     #1#3##1{#4}\or
     #1#3##1##2{#4}\or
     #1#3##1##2##3{#4}\or
     #1#3##1##2##3##4{#4}\or
     #1#3##1##2##3##4##5{#4}\or
     #1#3##1##2##3##4##5##6{#4}\or
     #1#3##1##2##3##4##5##6##7{#4}\or
     #1#3##1##2##3##4##5##6##7##8{#4}\or
     #1#3##1##2##3##4##5##6##7##8##9{#4}\else
     #1#3##1##2##3##4##5##6##7##8##9##A{#4}\else
     #1#3##1##2##3##4##5##6##7##8##9##A##B{#4}\else
     #1#3##1##2##3##4##5##6##7##8##9##A##B##C{#4}\else
     #1#3##1##2##3##4##5##6##7##8##9##A##B##C##D{#4}\else
     #1#3##1##2##3##4##5##6##7##8##9##A##B##C##D##E{#4}\else
     #1#3{#4}\fi
   \catcode\hashasciicode\c_syst_parameter_catcode}

\protected\def\syst_basics_define_nop#1#2#3%
  {\ifdefined#2%
     \showmessage\m!system4{\string#2}%
   \fi
   #1#2{#3}%
   \catcode\hashasciicode\c_syst_parameter_catcode}

\aliased\let\redefine\define

% new but maybe not needed:
%
% \checked\def \whatever#alpha#beta{#alpha + #beta}
% \checked\edef\whatever#alpha#beta{#alpha + #beta}

\mutable\let\gobbleddefinition\relax % only for diagnostics

\permanent\protected\def\unique#1#2%
  {\ifdefined#2%
     \showmessage\m!system4{\string#2}%
     \expandafter#1\expandafter\gobbleddefinition
   \else
     \expandafter#1%
   \fi#2}

\permanent\protected\def\checked#1#2%
  {\ifdefined#2%
     \showmessage\m!system4{\string#2}%
   \fi
   #1#2}

% \startluacode
%     local formatters = string.formatters
%     local contextsprint, ctxcatcodes, prtcatcodes = context.sprint, tex.ctxcatcodes, tex.prtcatcodes
%     local match, gmatch, rep = string.match, string.gmatch, string.rep
%     local empty = {
%         "single",
%         "double",
%         "triple",
%         "quadruple",
%         "quintuple",
%     }
%     local check = {
%         "first",
%         "second",
%         "third",
%         "fourth",
%         "fifth",
%     }
%     function commands.define(str)
%         -- we could store the defaults in lua and call lua instead but why bother
%         local arg, cmd = match(str,"(.*)\\(.-)$")
%         local a = { }
%         for s in gmatch(arg,"%[(.-)%]") do
%             a[#a+1] = s
%         end
%         local n = tonumber(a[#a])
%         if n then
%             a[#a] = nil
%         else
%             n = 0
%         end
%         contextsprint(ctxcatcodes,formatters["\\protected\\def\\%s"](cmd))
%         if #a > 0 then
%             contextsprint(prtcatcodes,formatters["{\\do%sempty\\user_defined_%s}"](empty[#a],cmd))
%             contextsprint(prtcatcodes,formatters["\\def\\user_defined_%s"](cmd))
%             for i=1,#a do
%                 contextsprint(ctxcatcodes,formatters["[#%s]"](i))
%             end
%             contextsprint(ctxcatcodes,"{")
%             for i=#a,1,-1 do
%                 contextsprint(ctxcatcodes,formatters["\\if%sargument"](check[i]))
%                 contextsprint(prtcatcodes,formatters["\\def\\next{\\user_defined_indeed_%s"](cmd))
%                 for j=1,#a-i do
%                     contextsprint(ctxcatcodes,formatters["[%s]"](a[j]))
%                 end
%                 for j=1,i do
%                     contextsprint(ctxcatcodes,formatters["[#%s]"](j))
%                 end
%                 contextsprint(ctxcatcodes,"}")
%                 if i == 1 then
%                     contextsprint(ctxcatcodes,rep("\\fi",#a))
%                 else
%                     contextsprint(ctxcatcodes,"\\else")
%                 end
%             end
%             contextsprint(ctxcatcodes,"\\next}")
%             contextsprint(prtcatcodes,formatters["\\def\\user_defined_indeed_%s"](cmd))
%             for i=1,#a do
%                 contextsprint(ctxcatcodes,formatters["[#%s]"](i))
%             end
%         end
%         for i=1,n do
%             contextsprint(ctxcatcodes,formatters["#%s"](#a+i))
%         end
%     end
% \stopluacode
%
% \protected\def\define#1#{\ctxcommand{define([[\detokenize{#1}]])}}
%
% \starttext
%     \define[2]\whatevera{#1+#2}
%     \whatevera{A}{B}
%     \define[me][too][2]\whateverb{#1+#2+#3+#4}
%     \whateverb[A]{B}{C}
%     \whateverb[A][B]{C}{D}
%     \define[alpha][beta][gamma][delta]\whateverc{#1+#2+#3+#4}
%     \whateverc[P][Q]
% \stoptext

%D This is a checked variant of \type {\getvalue}.

\permanent\protected\def\macroname#1% brrr
  {\begincsname#1\endcsname}

% \definedasluacommand\systemlog

\permanent\protected\def\systemlogfirst
  {\ifcase\directsystemparameter\c!n\relax
     \expandafter\systemlog
   \or
     \expandafter\systemlog
   \else
     \expandafter\gobblethreearguments
   \fi}

\permanent\protected\def\systemloglast
  {\ifcase\directsystemparameter\c!n\relax
     \expandafter\systemlog
   \or
     \expandafter\gobblethreearguments
   \or
     \expandafter\gobblethreearguments
   \or
     \expandafter\gobblethreearguments
   \or
     \expandafter\systemlog
   \fi}

\protect \endinput
