% openclose.tex  
%%%%%%%%%%%%%%%%%%%%%%
% Petr Olsak 2014

% see
% http://tex.stackexchange.com/questions/196071/macro-to-close-all-open-environments-groups-and-argument-delimiters

% This macro defines \Open ...\Close pair which reads the text between them
% and repairs it to balanced text. The appropriated braces could be added at
% the begin (open braces) or at the end (close braces) of the text.
% After \Open ...\Close preprocessing is done the repaired text is 
% normally processed.

% Examples:

% \Open abc\Close       ... does nothing ->  abc
% \Open a}b}c\Close     ... adds braces  ->  {{a}b}c
% \Open a{b{c\Close     ... adds braces  ->  a{b{c}}
% \Open a}b}c{d{e\Close ... adds braces  ->  {{a}b}c{d{e}}

% The \Open...\Close pairs would be nested. The processing of repairing
% braces is done from inner pairs to outer, like normal parentheses.

% The \autobracelist macro is empty by default and it can include the list
% of control sequences which have special feature between \Open ...\Close:
% It such control sequence is followed by open brace then it behaves normally
% else the open brace is added after it.

% Examples:

% \def\autobrcelist{\x\y}
% \Open \x \y \z aha \x \Close   ->  \x{\y{\z aha \x{}}}
% \Open \x{\y} aha\Close         ->  \x{\y{} aha}

\newcount\openLnum
\newtoks\currtext
\def\Open{\begingroup\let\bgroup=\relax \let\egroup=\relax 
   \expandafter\checkbracesJ\autobracelist\end 
   \let\ifIamInGroup=\iffalse \currtext={}\checkbracesA
}
\def\checkbracesA{\futurelet\tmp\checkbracesB}
\def\checkbracesB{%
   \let\next=\checkbracesN
   \ifx\tmp\spacetoken \let\next=\checkbracesC \let\nexxt=\checkbracesA \addtocurrtext{ }\fi
   \ifx\tmp\bgroupOri  \let\next=\checkbracesC \let\nexxt=\checkbracesD \fi
   \ifx\tmp\egroupOri  \let\next=\checkbracesC \let\nexxt=\checkbracesE \fi
   \ifx\tmp\autobraced \let\next=\checkbracesH \fi
   \ifx\tmp\Close \let\next=\checkbracesC \let\nexxt=\checkbracesF \fi
   \ifx\tmp\Open  \global\advance\openLnum by1 \let\next=\relax \fi
   \next
}
\def\checkbracesC{\afterassignment\nexxt \let\next= }
\long\def\checkbracesN#1{\addtocurrtext#1\checkbracesA}
\def\checkbracesD{\begingroup \let\ifIamInGroup=\iftrue \currtext={}\checkbracesA}
\def\checkbracesE{\ifIamInGroup \addtocurrtextclosebrace
   \else \currtext\expandafter{\expandafter{\the\currtext}}%
   \fi \checkbracesA
}
\def\checkbracesF{%
   \ifIamInGroup \addtocurrtextclosebrace \expandafter\checkbracesF
   \else \expandafter\checkbracesG \fi
}
\def\checkbracesG{%
   \ifnum\openLnum>0 \global\advance\openLnum by-1 
       \def\next{\expandafter\endgroup \expandafter 
          \currtext \expandafter\expandafter\expandafter
             {\expandafter\the\expandafter\currtext \the\currtext}\checkbracesA}%
   \else \def\next{\expandafter\endgroup \the\currtext}%
   \fi \next
}
\def\checkbracesH#1{\addtocurrtext#1\futurelet\tmp\checkbracesI}
\def\checkbracesI{\ifx\tmp\bgroupOri \expandafter\checkbracesB
                  \else \expandafter\checkbracesD \fi
}
\def\checkbracesJ#1{\ifx#1\end \else \let#1=\autobraced \expandafter\checkbracesJ \fi}

\def\addtocurrtextclosebrace{\expandafter\endgroup
   \expandafter\currtext\expandafter\expandafter\expandafter
      {\expandafter\the\expandafter\currtext\expandafter{\the\currtext}}%
}
\long\def\addtocurrtext#1{\currtext\expandafter{\the\currtext#1}}
\let\bgroupOri=\bgroup
\let\egroupOri=\egroup
\def\tmp/{\let\spacetoken= }\tmp/ %
\def\Close{^\Close^}
\def\autobraced{^\autobraced^}
\def\autobracelist{}

\endiput
