%D \module
%D   [       file=core-uti,
%D        version=1997.03.31,
%D          title=\CONTEXT\ Core Macros,
%D       subtitle=Utility File Handling,
%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 / Utility File Handling}

\unprotect 

% Utility-file
%
% De onderstaande macro's ondersteunen het gebruik van de
% zogeheten utility-file. Alle extern onder te brengen
% informatie wordt opgeslagen in de file \jobname.tui, tenzij
% er selectief pagina's worden gezet. In dat geval wordt de
% file \jobname.tmp gebruikt. Informatie wordt ingelezen uit
% de file \jobname.tuo, welke door TeXUtil wordt aangemaakt.

% Bepaalde commando's worden als string weggeschreven. Deze
% zijn aan het eind van deze file gedefinieerd.

% Om een opbouw van spaties te voorkomen (???) moet ^^M een
% andere betekenis krijgen:
%
% \catcode`\^^M=14 (comment)
%
% read file
%
% \catcode`\^^M=5  (end of line)

\newwrite\uti
\newif\ifutilitydone

\def\@@utilityerrormessage%
  {\showmessage{\m!systems}{8}{}%
   \global\let\@@utilityerrormessage=\relax}

\def\thisisutilityversion#1%
  {\doifnot{\utilityversion}{#1}%
     {\@@utilityerrormessage
      \resetutilities
      \endinput}}

\def\writeutility%
  {\write\uti}

\def\immediatewriteutility%
  {\immediate\write\uti}

\def\writeutilitycommand#1%
  {\writeutility{c \string#1}}

\def\immediatewriteutilitycommand#1%
  {\immediatewriteutility{c \string#1}}

\def\openutilities%
  {\immediate\openout\uti=\jobname.\f!inputextension
   \immediatewriteutilitycommand{\thisisutilityversion{\utilityversion}}}

\def\closeutilities%
  {\savenofsubpages
   \savenofpages
   \immediate\closeout\uti
   \reportutilityproblems}

\def\abortutilitygeneration%
  {\immediatewriteutilitycommand{\utilitygenerationaborted}%
   \immediatewriteutility{q {quit}}}

\def\utilitygenerationaborted%
  {\showmessage{\m!systems}{21}{}%
   \global\let\utilitygenerationaborted=\endinput
   \gdef\reportutilityproblems{\showmessage{\m!systems}{22}{}}%
   \endinput}

\def\savecurrentvalue#1#2%
  {\immediatewriteutilitycommand{\initializevariable\string#1{#2}}}

\let\initializevariable\gdef

\def\disableinitializevariables%
  {\global\let\initializevariable\gobbletwoarguments}

\let\reportutilityproblems=\relax

\let\utilityresetlist=\empty

%\def\addutilityreset#1%
%  {\addtocommalist{\s!reset#1}\utilityresetlist}
%
%\def\resetutilities%
%  {\processcommacommand[\utilityresetlist]\getvalue}

\def\addutilityreset#1%
  {\addtocommalist{#1}\utilityresetlist}

\def\doresetutility#1%
  {\getvalue{\s!reset#1}}

\def\resetutilities%
  {\processcommacommand[\utilityresetlist]\doresetutility}

% #1=type
% #2=file
% #3=melding

% #4=voor
% #5=na

% Er wordt gegroepeerd. Als binnen een lijst (bijvoorbeeld) de
% \leftskip is aangepast, maar nog geen \par is gegeven, dan
% geldt buiten de groep de oude \leftskip. Aan #5 kan dan
% ook \par worden meegegeven om de paragraaf af te sluiten.

\newif\ifdoinpututilities
\newif\ifunprotectutilities   % voor't geval er \v!xxxxxx's zijn

\def\utilitycheckmessage%
  {\showmessage{\m!systems}{12}{}%
   \global\let\utilitycheckmessage=\relax}

\def\saveutilityline#1 #2\txen% tricky maar ok, want achter \command
  {\if     #1c% commands      % in \ascii staat een spatie; #1 kan
     \write\scratchwrite{#2}% % \par in stringvorm zijn (eof)!
   \else\if#1s% synoniems
     \utilitycheckmessage
   \else\if#1r% registers
     \utilitycheckmessage
   \fi\fi\fi}

% no longer needed, since texutil is now multi platform
%
% \def\checkutilityfile%
%   {\doiflocfileelse{\jobname.\f!outputextension}
%      {}
%      {\doiflocfileelse{\jobname.\f!inputextension}
%         {\bgroup
%          \showmessage{\m!systems}{11}{}%
%          \openout\scratchwrite=\jobname.\f!outputextension
%          \openlocin\scratchread{\jobname.\f!inputextension}%
%          \def\doprocessline%
%            {\ifeof\scratchread
%               \def\doprocessline{\closein\scratchread}%
%             \else
%               \read\scratchread to \ascii
%               \convertcommand\ascii\to\ascii
%               \expandafter\saveutilityline\ascii\txen
%             \fi
%             \doprocessline}%
%          \doprocessline
%          \closeout\scratchwrite
%          \egroup}
%         {}}}

\def\checkutilityfile%
  {}

\long\def\doutilities#1#2#3#4#5% % introduceren in utility file
  {\restorecatcodes
   \resetutilities
   \def\docommando##1%                 % zo kunnen meerdere dingen
     {\getvalue{\s!set##1}}%           % in een pass worden gedaan,
   \processcommacommand[#1]\docommando % zie bijvoorbeeld lijsten
   \begingroup
   \footnotesenabledfalse
   \doinpututilitiestrue
   \global\utilitydonefalse
   \catcode`\%=\@@comment\relax
   \pushendofline % geeft problemen zodra andere file wordt ingelezen
   \ifunprotectutilities % nog nodig ?
     \unprotect
   \fi
   \ifnum\catcode`\@=\@@active \else
     \catcode`\@=\@@letter % permits expanded commands with \@'s
   \fi
   \ifnum\catcode`\!=\@@active \else
     \catcode`\!=\@@letter % permits multilingual constants
   \fi
   #4\readjobfile{#2.\f!outputextension}{}{}#5%
   \relax
   \ifunprotectutilities
     \protect
   \fi
   \popendofline
   \ifutilitydone\else
     \doifnot{#3}{}
       {\showmessage{\m!systems}{9}{{#3}}%
        \ifvoorlopig
          \blanko
          \type{[\currentmessagetext]}%
          \blanko
        \fi}%
   \fi
   \disableinitializevariables
   \endgroup}

% Saving the sort vector: 

\def\savesortkeys%
  {\setbox\scratchbox=\hbox
     \bgroup
       \def\flushsortkey##1##2##3##4%
         {\convertargument{##1}{##2}{##3}{##4}\to\ascii
          \immediatewriteutility{k {\currentlanguage}{\currentencoding}\ascii}}%
       \let\definesortkey\flushsortkey
       \flushsortkeys
     \egroup
   \global\let\savesortkeys\relax}

\prependtoks \savesortkeys \to \everystarttext 

% Commando's ten behoeve van two-pass lists. In principe
% kan alles in een keer worden ingelezen. Omdat de macro's
% groeien is de kans groot dat het (main) geheugen door
% (de)allocatie volloopt. Vandaar dat we het toch maar niet
% doen.
%
% \definetwopasslist{\s!xxx}
%
% \gettwopassdata{\s!xxx}
% \getfrompassdata{\s!xxx}{n}       n=index (getal)
% \findtwopassdata{\s!xxx}{tag}     bijvoorbeeld {label:}
% \iftwopassdatafound
% \twopassdata
%
% \twopassentry{\s!xxx}{nr}{data}   nr alleen voor testdoeleinden
%
% also: 
%
% \definerawpasslist{\s!xxx}       
% \moverawpasslist\s!xxx\to\somemacro 

\let\alltwopasslists\empty % with    0,0 -> stepwise commalist
\let\allrawpasslists\empty % without 0,0 -> raw commalist 

\newif\iftwopassdatafound

\def\twopassentry#1%
  {\executeifdefined{@@#1\s!pass}\gobbletwoarguments}

\def\appendtwopasselement#1#2#3%
  {%\debuggerinfo{\m!systems}{twopass data #1 - #2 = #3}%
   \@EA\ifx\csname#1:\s!list\endcsname\empty
     \setxvalue{#1:\s!list}{#3}%
   \else
     \setxvalue{#1:\s!list}{\getvalue{#1:\s!list},#3}%
   \fi}

\def\dodefinetwopasslist#1%
  {\doifundefined{#1:\s!list}
     {%\debuggerinfo{\m!systems}{defining twopass class #1}%
      \doglobal\addutilityreset{#1\s!pass}%
      \setgvalue{\s!set#1\s!pass}%
        {\global\letvalue{\s!set#1\s!pass}\gobbletwoarguments
         \setgvalue{@@#1\s!pass}{\appendtwopasselement{#1}}}%
      \setgvalue{\s!reset#1\s!pass}%
        {\global\letvalue{@@#1\s!pass}\gobbletwoarguments}%
      \getvalue{\s!reset#1\s!pass}}}

\def\definetwopasslist#1%
  {\expanded{\dodefinetwopasslist{#1}}%
   \doglobal\addtocommalist{#1}\alltwopasslists}

\def\definerawpasslist#1%
  {\expanded{\dodefinetwopasslist{#1}}%
   \doglobal\addtocommalist{#1}\allrawpasslists}

\def\doloadtwopassdata#1%
  {\doifundefined{#1:\s!list}
     {\global\letvalue{#1:\s!list}\empty
      \doutilities{#1\s!pass}{\jobname}{}{}{}%
      \ifx\twopassdata\empty\else
        \appendtwopasselement{#1}{0}\twopassdata
      \fi}}

\def\loadtwopassdata%
  {\ifx\alltwopasslists\empty\else
     \def\twopassdata{0,0}% end condition 
     \processcommacommand[\alltwopasslists]\doloadtwopassdata
     \global\let\alltwopassdata\empty
   \fi
   \ifx\allrawpasslists\empty\else
     \let\twopassdata\empty
     \processcommacommand[\allrawpasslists]\doloadtwopassdata
     \global\let\allrawpassdata\empty
   \fi}

\def\moverawpasslist#1#2% erases the old one, like the others do
  {\loadtwopassdata
   \@EA\let\@EA#2\csname#1:\s!list\endcsname
   \@EA\let\csname#1:\s!list\endcsname\empty}

\let\twopassdata=\empty

\def\dogettwopassdata[#1,#2]#3%
  {\doifelse{#1}{0} % \ifcase truukje gaat fout
     {\twopassdatafoundfalse
      \let\twopassdata\empty}
     {\twopassdatafoundtrue
      \setxvalue{#3:\s!list}{#2}%
      \edef\twopassdata{#1}}}

\def\gettwopassdata#1%
  {\loadtwopassdata
   \edef\!!stringa{\getvalue{#1:\s!list}}%
  %\debuggerinfo{\m!systems}{twopass get #1 - \!!stringa}%
   \expandafter\dogettwopassdata\expandafter[\!!stringa]{#1}}

\def\findtwopassdata%
  {\loadtwopassdata
   \ExpandBothAfter\dofindtwopassdata}

\def\dofindtwopassdata#1#2%
  {\edef\!!stringa{,\getvalue{#1:\s!list}}%
  %\debuggerinfo{\m!systems}{twopass find #2 - \!!stringa}%
   \def\dodofindtwopassdata[##1,##2#2##3,##4]%
     {\edef\twopassdata{##3}%
      \ifx\twopassdata\empty
        \twopassdatafoundfalse
      \else
        \twopassdatafoundtrue
      \fi}%
   \@EA\dodofindtwopassdata\@EA[\!!stringa,#2,#2,]}

\def\getfirsttwopassdata#1%
  {\loadtwopassdata
   \edef\!!stringa{\getvalue{#1:\s!list}}%
   \expandafter\dogetfirsttwopassdata\expandafter[\!!stringa]{#1}}

\def\dogetfirsttwopassdata[#1,#2]#3%
  {\doifelse{#1}{0}
     {\twopassdatafoundfalse
      \let\twopassdata\empty}
     {\twopassdatafoundtrue
      \edef\twopassdata{#1}}}

\def\getlasttwopassdata#1%
  {\loadtwopassdata
   \edef\twopassdata{0}\twopassdatafoundfalse
   \newcounter\noftwopassitems
   \def\docommando##1%
     {\doifnot{##1}{0}
        {\increment\noftwopassitems
         \edef\twopassdata{##1}\twopassdatafoundtrue}}%
   \processcommacommand[\getvalue{#1:\s!list}]\docommando}

\def\getfromtwopassdata#1#2%
  {\loadtwopassdata
   \getfromcommacommand[\getvalue{#1:\s!list}][#2]%
   \doifelsenothing{\commalistelement}
     {\twopassdatafoundfalse
      \let\twopassdata\empty}
     {\twopassdatafoundtrue
      \let\twopassdata\commalistelement}}

% Default-instellingen (verborgen)

\prependtoks \resetutilities \to \everyjob 

\protect \endinput 
