%% HeVeA support for checklistings.
%%
%% Limitations / caveats
%%
%% * checklistings.hva requires all the intermediate generated by latex and
%%   checklistings.sh (*.<ext>, *.tex, *.msg, *.err).
%%
%% * The options 'codestyle', 'msgstyle', 'errstyle', 'codelst', 'msglst',
%%   and 'errlst' cannot be set as in LaTeX, e.g.,
%%	\checklistings{codelst={language=caml}}
%%   Since HeVeA eliminates the grouping braces and passes 'language' to
%%   the handler for 'codelst' (rather than 'language=caml').
%%
%%   One workaround is to \usepackage{hevea} and use \ifhevea to select
%%   the most appropriate of the two forms.
%%
%% * fancyvrb and the package options codestyle, msgstyle, and errstyle are
%%   not supported.
%%   Alternative 1: use the codelst, msglst, and errlst options.
%%   Alternative 2: use css for formatting code, messages, and errors.
%%
%% * Non-empty labels in the arguments of \chklistingmsg and
%%   \chklistingerr are not supported.
%%
\ProvidesPackage{checklistings}
\RequirePackage{keyval}
\RequirePackage{listings}

\newcounter{chklisting}
\setcounter{chklisting}{-1}

\newif\ifCHKL@fileexists
\newif\ifCHKL@showcode\CHKL@showcodetrue
\newif\ifCHKL@shouldfail\CHKL@shouldfailfalse
\newif\ifCHKL@withresult\CHKL@withresultfalse
\newif\ifCHKL@showerrors\CHKL@showerrorstrue
\newif\ifCHKL@loadhtml\CHKL@loadhtmlfalse
\def\CHKL@pkg@skipopts{}

% % % Declare Options % % %

\DeclareOption{withresult}{\CHKL@withresulttrue}
\DeclareOption{withoutresult}{\CHKL@withresultfalse}
\DeclareOption{skipone}{\def\CHKL@pkg@skipopts{firstline=2}}
\DeclareOption{skiptwo}{\def\CHKL@pkg@skipopts{firstline=3}}
\DeclareOption{showproblems}{\CHKL@showproblemstrue}
\DeclareOption{hideproblems}{\CHKL@showproblemsfalse}

\def\CHKL@codestyle{}
\def\CHKL@msgstyle{}
\def\CHKL@errstyle{}
\define@key{CHKL@pkgkeys}{codestyle}[]{\def\CHKL@codestyle{#1}}
\define@key{CHKL@pkgkeys}{msgstyle}[]{\def\CHKL@msgstyle{#1}}
\define@key{CHKL@pkgkeys}{errstyle}[]{\def\CHKL@errstyle{#1}}

\def\CHKL@codelst{}
\def\CHKL@msglst{}
\def\CHKL@errlst{}
\define@key{CHKL@pkgkeys}{codelst}[]{\def\CHKL@codelst{#1}}
\define@key{CHKL@pkgkeys}{msglst}[]{\def\CHKL@msglst{#1}}
\define@key{CHKL@pkgkeys}{errlst}[]{\def\CHKL@errlst{#1}}

\def\CHKL@subdir{.}
\def\CHKL@prefix{chklisting}
\def\CHKL@prompt{\#}
\def\CHKL@ext{.ml}
\define@key{CHKL@pkgkeys}{prompt}[]{\def\CHKL@prompt{#1}}
\define@key{CHKL@pkgkeys}{subdir}[]{\def\CHKL@subdir{#1}}
\define@key{CHKL@pkgkeys}{prefix}[]{\def\CHKL@prefix{#1}}
\define@key{CHKL@pkgkeys}{ext}[]{\def\CHKL@ext{#1}}
\define@key{CHKL@pkgkeys}{html}[]{\CHKL@loadhtmltrue}

% Unused options
\define@key{CHKL@pkgkeys}{compiler}[]{}
\define@key{CHKL@pkgkeys}{compilerflags}[]{}
\define@key{CHKL@pkgkeys}{lastflags}[]{}
\define@key{CHKL@pkgkeys}{includecmd}[]{}

% % % Process Options % % %

% Work around the lack of \DeclareOption* in package.hva
\renewcommand{\@process@option}[1]%
        {\def\pkg@opt{{\@nostyle\@callprim{\@eatspaces}{#1,}}}%
         \ifu\csname\@pkg@opt@name{\pkg@opt}\endcsname
	 \setkeys{CHKL@pkgkeys}{#1}
	 \else
         \csname\@pkg@opt@name{\pkg@opt}\endcsname\fi}%

\ProcessOptions*
\newcommand{\checklistings}[1]{\ExecuteOptions{#1}}

% % % Macros used in files generated by checklistings.sh % % %

\newif\ifchklisting
\newcommand{\setchklistingcmd}[1]{%
    \global\def\chklistingcmd{\emph{\CHKL@prompt{#1}}}}

\newenvironment{ChkListingMsg}{\verblatex}{\endverblatex}
\newenvironment{ChkListingErr}{\verblatex}{\endverblatex}

\newcommand{\chklistingfile}{\CHKL@prefix\CHKL@ext}

% % % Checklistings user macros % % %

\define@key{CHKL@envkeys}{continue}[]{}
\define@key{CHKL@envkeys}{include}[]{}
\define@key{CHKL@envkeys}{label}[]{}
\define@key{CHKL@envkeys}{showproblems}[]{\CHKL@showproblemstrue}
\define@key{CHKL@envkeys}{hideproblems}[]{\CHKL@showproblemsfalse}
\define@key{CHKL@envkeys}{skipnone}[]{\def\CHKL@pkg@skipopts{firstline=1}}
\define@key{CHKL@envkeys}{skipone}[]{\def\CHKL@pkg@skipopts{firstline=2}}
\define@key{CHKL@envkeys}{skiptwo}[]{\def\CHKL@pkg@skipopts{firstline=3}}
\define@key{CHKL@envkeys}{hide}[]{\CHKL@showcodefalse}
\define@key{CHKL@envkeys}{withresult}[]{\CHKL@withresulttrue}
\define@key{CHKL@envkeys}{withoutresult}[]{\CHKL@withresultfalse}
\define@key{CHKL@envkeys}{fail}[]{\CHKL@shouldfailtrue}

% Work around the lack of \edef and \expandafter
\def\CHKL@lstset#1{\lstset{#1}}
\def\elstset#1{\@callprim{\CHKL@lstset}{\{#1\}}}

\newcommand{\chklistingmsg}{\bgroup%
  \setenvclass{lstlisting}{lstlisting chklistingmsg}%
  \elstset{\CHKL@msgstyle}%
  \elstset{\CHKL@msglst}%
  \lstinputlisting{\CHKL@subdir/\CHKL@prefix\CHKL@num.msg}%
  \egroup}%

\newcommand{\chklistingerr}{\bgroup%
  \setenvclass{lstlisting}{lstlisting chklistingerr}%
  \elstset{\CHKL@errstyle}%
  \elstset{\CHKL@errlst}%
  \lstinputlisting{\CHKL@subdir/\CHKL@prefix\CHKL@num.err}%
  \egroup}%

\newenvironment{chklisting}[1][]
  {%
    \setenvclass{lstlisting}{lstlisting chklisting}%
    \stepcounter{chklisting}%
    \def\@currentlabel{\thechklisting}%
    \@setkeys{CHKL@envkeys}{#1}%
    \global\def\CHKL@num{%
	\ifthenelse{\value{chklisting}<1000}{0}{}%
        \ifthenelse{\value{chklisting}<100}{0}{}%
        \ifthenelse{\value{chklisting}<10}{0}{}%
        \arabic{chklisting}}%
    \global\def\CHKL@file{\CHKL@subdir/\CHKL@prefix\CHKL@num}%
    \global\let\chklistingcmd\relax%
    \ifCHKL@showcode%
      \bgroup%
      \ifCHKL@loadhtml%
        \@open{div}{class="chklisting"}%
        \rawinput{\CHKL@file{}.html}%
        \@close{div}%
      \else%
        \elstset{\CHKL@pkg@skipopts}%
        \elstset{\CHKL@codestyle}%
        \elstset{\CHKL@codelst}%
        \lstinputlisting{\CHKL@file\CHKL@ext}%
      \fi%
      \egroup%
      \input{\CHKL@file.tex}%
      \ifCHKL@shouldfail%
	\ifchklisting%
	  \ifCHKL@showproblems%
	    \begin{divstyle}{checklistingserror}%
	    Unexpected success: \chklistingmsg{}
	    \end{divstyle}%
	  \fi%
	\else%
	  \ifCHKL@withresult{\chklistingerr{}}\fi%
	\fi%
      \else
	\ifchklisting%
	  \ifCHKL@withresult{\chklistingmsg{}}\fi%
	\else%
	  \ifCHKL@showproblems%
	    \begin{divstyle}{checklistingserror}%
	    Unexpected failure: \chklistingerr{}
	    \end{divstyle}%
	  \fi%
	\fi%
      \fi
    \fi%
    \verblatex%
  }
  {\endverblatex}%
\endinput
