%D \module
%D   [       file=core-buf, % blocks are moved to core-blk
%D        version=2000.01.05,
%D          title=\CONTEXT\ Core Macros,
%D       subtitle=Buffers,
%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 / Buffers}

\unprotect

\let\mkresetbuffer      \donothing
\let\mksetbuffer        \gobbleoneargument
\let\mkstartbuffer      \gobblefivearguments
\let\mkdobuffer         \gobbleoneargument
\let\mkstartmemorybuffer\startbuffer
\let\mkstartfilebuffer  \startbuffer
\let\mkgetbuffer        \donothing
\let\mktypebuffer       \donothing

\chardef\buffernestmode\plusone % 0: not nested, 1: startbuffer nested, 2: all buffers nested

\newif\ifsegmentatebuffer
\newif\ifemptybufferline

\def\currentbuffer{\jobname}

\def\setcurrentbuffer#1%
  {\doifelsenothing{#1}{\edef\currentbuffer{\jobname}}{\edef\currentbuffer{#1}}}

\def\resetbuffer
  {\dosingleempty\doresetbuffer}

\def\doresetbuffer[#1]%
  {\begingroup
   \setcurrentbuffer{#1}%
   \mkresetbuffer
   \endgroup}

\def\dostartbuffer
  {\bgroup
   \obeylines % nodig, anders gaat 't fout als direct \starttable (bv)
   \doquadrupleempty\dodostartbuffer}

\def\dodostartbuffer[#1][#2][#3][#4]% upward compatible
  {\iffourthargument
     \def\next{\dododostartbuffer{#1}{#2}{#3}{#4}}%
   \else
     \def\next{\dododostartbuffer  {}{#1}{#2}{#3}}%
   \fi
   \next}

\def\dododostartbuffer#1#2#3#4%
  {%\showmessage\m!systems{15}{#2}%
   \doifelsevalue{\??bu#1\c!paragraph}\v!yes
     {\segmentatebuffertrue} % todo in mkiv
     {\doifnumberelse{\getvalue{\??bu#1\c!paragraph}}\segmentatebuffertrue\segmentatebufferfalse}%
   \doifvalue{\??bu#1\c!local}\v!yes
     {\chardef\buffernestmode\plustwo}% permit nesting
   \setcurrentbuffer{#2}%
   \mkstartbuffer{#1}{#2}{#3}{#4}{\egroup}}

\letvalue{\e!start\v!buffer}\dostartbuffer

\let\endbuffer\undefined % to please the dep parser

\def\setbuffer
  {\dosingleempty\dosetbuffer}

\def\dosetbuffer[#1]#2\endbuffer % seldom used so we just pass #2
  {\begingroup
   \setcurrentbuffer{#1}%
   \mksetbuffer{#2}%
   \endgroup}

\def\setupbuffer
  {\dodoubleempty\dosetupbuffer}

\def\dosetupbuffer[#1][#2]%
  {\ifsecondargument
     \getparameters[\??bu#1][#2]%
   \else
     \getparameters[\??bu][#1]%
   \fi}

\def\dodefinebuffer[#1][#2]%
  {\iffirstargument % else problems
     \doglobal\increment\nofdefinedbuffers
     \letvalue{\??bu#1\c!number   }\nofdefinedbuffers
     \letvalue{\??bu#1\c!paragraph}\v!no
     \setevalue{\e!start#1}{\noexpand\dostartbuffer       [#1][def-\nofdefinedbuffers][\e!start#1][\e!stop#1]}%
     \setevalue{\e!get  #1}{\noexpand\dodoprocessTEXbuffer[#1][def-\nofdefinedbuffers]}%
     \setevalue{\e!type #1}{\noexpand\dotypebuffer        [#1][def-\nofdefinedbuffers]}%
     \getparameters[\??bu#1][#2]%
   \fi}

\def\definebuffer
  {\dodoubleempty\dodefinebuffer}

\def\getbuffer
  {\dodoubleempty\dogetbuffer}

\def\dogetbuffer[#1][#2]%
  {\ifsecondargument
     \dodogetbuffer[#1][#2]%
   \else
     \dodogetbuffer[][#1]%
   \fi}

\def\dodogetbuffer[#1][#2]%
  {\getvalue{\??bu#1\c!before}%
   \dobuffer{16}{#2}\mkgetbuffer
   \getvalue{\??bu#1\c!after}}

\def\typebuffer
  {\dodoubleempty\dotypebuffer}

\def\dotypebuffer[#1][#2]%
  {\iffirstargument
     \dobuffer{17}{#1}\mktypebuffer
   \else
     \dobuffer{17}{#2}\mktypebuffer
   \fi}

\def\dobuffer#1#2#3%
  {\doifelsenothing{#2}
     {\dodobuffer#3\jobname}
     {\processcommalist[#2]{\dodobuffer#3}}}

\def\dodobuffer#1#2% command name
  {\pushmacro\currentbuffer
   \edef\currentbuffer{\ifcsname\??bu#2\c!number\endcsname def-\csname\??bu#2\c!number\endcsname\else#2\fi}%
   \mkdobuffer#1%
   \popmacro\currentbuffer}

\def\processTEXbuffer{\getbuffer} % handy

% seldom used, only in a few projects that demanded more speed

\def\usememorybuffers{\let\startbuffer\mkstartmemorybuffer}
\def\usefilebuffers  {\let\startbuffer\mkstartfilebuffer}

% this features is soldom used (complex examns where we need to fetch
% special parts of a text
%
% this is not yet supported in mkiv (relatively easy to do but there
% we don't have the par tags but need to grab 'm

\def\skippedbufferparagraphs{0}

\let\startbufferparagraph\relax
\let\stopbufferparagraph \par   % \relax

\newcount\currentbufferparagraph

\def\getbufferparagraphs
  {\dodoubleempty\dogetbufferparagraphs}

\def\dosetbufferoffset#1%
  {\doifnumberelse{\getvalue{\??bu#1\c!paragraph}}
     {\currentbufferparagraph-\getvalue{\??bu#1\c!paragraph}}
     {\currentbufferparagraph \zerocount}%
   \relax}

\def\dogetbufferparagraphs[#1][#2]%
  {\iffirstargument
     \ifsecondargument
       \dosetbufferoffset{#1}%
       \doifelse{#2}\v!all
         {\def\startbufferparagraph{\normalbufferparagraph{#1}}}
         {\def\startbufferparagraph{\filterbufferparagraph{#1}{#2}}}%
       \def\stopbufferparagraph{\dostopbufferparagraph{#1}}%
       \def\next{\getparagraphedbuffer[#1]}%
     \else
       \dosetbufferoffset\empty
       \def\startbufferparagraph{\filterbufferparagraph{}{#1}}%
       \def\stopbufferparagraph{\dostopbufferparagraph{}}%
       \def\next{\getparagraphedbuffer[]}%
     \fi
   \else
     \dosetbufferoffset\empty
     \def\startbufferparagraph{\normalbufferparagraph{}}%
     \def\stopbufferparagraph{\dostopbufferparagraph{}}%
     \def\next{\getparagraphedbuffer[]}%
   \fi
   \next}

\def\getparagraphedbuffer[#1]%
  {\dobuffer{16}{#1}\mkgetbuffer}

\def\dostopbufferparagraph#1%
  {\getvalue{\??bu#1\c!after}\par}

\def\dostartbufferparagraph#1%
  {\par\getvalue{\??bu#1\c!before}}

\def\normalbufferparagraph
  {\advance\currentbufferparagraph \plusone
   \ifnum\currentbufferparagraph>\zerocount
     \expandafter\dostartbufferparagraph
   \else
     \expandafter\gobbleoneargument
   \fi}

\def\filterbufferparagraph#1#2%
  {\advance\currentbufferparagraph \plusone
   \ifcase\currentbufferparagraph
     \@EA\gobblebufferparagraph
   \else
     \doifinsetelse{\the\currentbufferparagraph}{#2}
       {\@EA\dostartbufferparagraph}
       {\@EA\fakebufferparagraph}%
   \fi
   {#1}}

\long\def\gobblebufferparagraph#1#2\stopbufferparagraph
  {}

\def\fakebufferparagraph#1%
  {\bgroup
   \def\stopbufferparagraph{\dostopbufferparagraph{#1}\egroup\egroup}%
   \setbox\scratchbox\vbox\bgroup\dostartbufferparagraph{#1}}

% only mkiv

\beginLUATEX
    \def\savebuffer{\dosingleempty\dosavebuffer}
    \def\dosavebuffer[#1]{\ctxlua{buffers.save("#1")}}
\endLUATEX

% plugins

\loadmarkfile{core-buf}

% definitions

\definebuffer[\v!hiding] \setupbuffer[\v!hiding][\c!local=\v!yes]

\setupbuffer
  [\c!paragraph=\v!no,
   \c!before=,
   \c!after=]

\protect \endinput
