% $Id: logreq.sty,v 1.0 2010/08/04 16:12:57 lehman stable $

% Copyright (c) 2010 Philipp Lehman.
%
% Permission is granted to copy, distribute and/or modify this
% software under the terms of the LaTeX Project Public License
% (LPPL), version 1.3.
%
% The LPPL maintenance status of this software is 'maintained'.
%
% This software is provided 'as is', without warranty of any kind,
% either expressed or implied, including, but not limited to, the
% implied warranties of merchantability and fitness for a
% particular purpose.

\def\lrq@rcsid$#1: #2 #3 #4 #5${#4 v#3}

\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{logreq}
[\lrq@rcsid $Id: logreq.sty,v 1.0 2010/08/04 16:12:57 lehman stable $
 xml request logger]
\RequirePackage{etoolbox}
\RequirePackage{keyval}

\let\lrq@tempa\@empty
\def\do#1{%
  \edef\lrq@tempa{\lrq@tempa
    \catcode\number`#1=\the\catcode`#1\relax}%
  \@makeother#1}
\do\<\do\>\do\?\do\!\do\/\do\=\do\"
\let\do\noexpand
\AtEndOfPackage{\lrq@tempa\undef\lrq@tempa}

\def\lrq@version$#1: #2 ${#2}
\edef\lrq@version{\lrq@version$Revision: 1.0 $}

\newcount\lrq@indent
\def\lrq@nl{^^J}
\def\lrq@tab{\lrq@tab@i\lrq@indent}
\def\lrq@tab@i#1{%
  \ifnumgreater{#1}\z@
    {\space\space
     \expandafter\lrq@tab@i
     \expandafter{\the\numexpr#1-\@ne}}
    {}}
\let\lrq@hook@data\@empty
\def\lrq@hook@init{%
  \lrq@indent\@ne
  \let\comment\lrq@xml@comment}

\def\lrq@xml@sig{<!-- logreq request file -->}
\edef\lrq@xml@ver{<!-- logreq version \lrq@version\space / dtd version \noexpand\LogreqDTDVersion\space -->}

\def\lrq@xml@comment#1{%
  \xappto\lrq@hook@data{\lrq@tab<!-- #1 -->\lrq@nl}}

\def\lrq@xml@container#1#2#3{%
  \begingroup
  \lrq@parseattributes{#1}{#2}%
  \xappto\lrq@hook@data{\lrq@tab<#1\lrq@attribs>\lrq@nl}%
  \advance\lrq@indent\@ne#3\advance\lrq@indent\m@ne
  \xappto\lrq@hook@data{\lrq@tab</#1>\lrq@nl}%
  \endgroup}

\def\lrq@xml@element#1#2#3{%
  \begingroup
  \lrq@parseattributes{#1}{#2}%
  \xappto\lrq@hook@data{\lrq@tab<#1\lrq@attribs>#3</#1>\lrq@nl}%
  \endgroup}

\def\lrq@xml@setup{%
  \begingroup
  \lrq@indent\@ne
  \let\do\lrq@dtd@doelement
  \dolistloop\lrq@lst@elm
  \xdef\lrq@hook@data{%
    <?xml version="1.0" standalone="yes"?>\lrq@nl
    \lrq@xml@sig\lrq@nl
    \lrq@xml@ver\lrq@nl
    <!-- Do not edit this file! -->\lrq@nl
    <!DOCTYPE requests [\lrq@nl\lrq@hook@dtd]>\lrq@nl
    <requests version="\LogreqDTDVersion">\lrq@nl\lrq@hook@data</requests>}%
  \endgroup
}

\def\lrq@dtd@doelement#1{%
  \ifcsdef{lrq@lst@att@#1}%
    {\xappto\lrq@hook@dtd{\lrq@tab<!ATTLIST #1\lrq@nl}%
     \begingroup
     \lrq@indent\tw@
     \let\do\lrq@dtd@doattribute
     \dolistcsloop{lrq@lst@att@#1}%
     \endgroup
     \xappto\lrq@hook@dtd{\lrq@tab>\lrq@nl}}
    {}}

\def\lrq@dtd@doattribute#1{%
  \xappto\lrq@hook@dtd{\lrq@tab#1\lrq@nl}}

\def\lrq@writeout{%
  \PackageInfo{logreq}{%
    Writing requests to '\@reqoutput'\@gobble}%
  \begingroup
  \openin\@mainaux\@reqoutput\relax
  \ifeof\@mainaux
    \lrq@writeout@ii
  \else
    \endlinechar\m@ne
    \readline\@mainaux to \lrq@tempa
    \ifeof\@mainaux
      \lrq@writeout@ii
    \else
      \readline\@mainaux to \lrq@tempa
      \edef\lrq@xml@sig{\detokenize\expandafter{\lrq@xml@sig}}%
      \ifx\lrq@xml@sig\lrq@tempa
	\readline\@mainaux to \lrq@tempa
	\edef\lrq@xml@ver{\noexpand\detokenize{\lrq@xml@ver}}%
        \edef\lrq@xml@ver{\lrq@xml@ver}%
	\ifx\lrq@xml@ver\lrq@tempa
	\else
	  \PackageWarning{logreq}{%
	    File '\@reqoutput' created\MessageBreak
	    by different version of logreq.\MessageBreak
	    Overwriting file}%
	\fi
	\lrq@writeout@ii
      \else
	\lrq@writeout@i
	\PackageError{logreq}
	  {File '\@reqoutput' not created by logreq}
	  {This file was apparently not created by logreq.\MessageBreak
	   I'm aborting now}%
      \fi
    \fi
  \fi}

\def\lrq@writeout@i{%
  \closein\@mainaux
  \endgroup}

\def\lrq@writeout@ii{%
  \lrq@writeout@i
  \lrq@xml@setup
  \immediate\openout\@mainaux\@reqoutput\relax
  \immediate\write\@mainaux{\lrq@hook@data}%
  \immediate\closeout\@mainaux}

\AtEndDocument{\AfterEndDocument{\lrq@writeout}}

\protected\def\lrq@container{\lrq@parser\lrq@xml@container}
\protected\def\lrq@element{\lrq@parser\lrq@xml@element}

\def\lrq@parser#1#2{%
  \@ifnextchar[%]
    {\lrq@parser@i{#1}{#2}}
    {\lrq@parser@i{#1}{#2}[]}}

\def\lrq@parser@i#1#2[#3]#4{%
  #1{#2}{#3}{#4}}

% {<element>}{<dtd spec>}

\newrobustcmd*{\DeclareLogreqContainer}{\lrq@defparser\lrq@container}
\@onlypreamble\DeclareLogreqContainer

\newrobustcmd*{\DeclareLogreqElement}{\lrq@defparser\lrq@element}
\@onlypreamble\DeclareLogreqElement

\def\lrq@defparser#1{%
  \begingroup\@makeother\#%
  \lrq@defparser@i{#1}}

\def\lrq@defparser@i#1#2#3{%
  \endgroup
  \eappto\lrq@hook@init{%
    \def\expandafter\noexpand\csname#2\endcsname{%
      \noexpand#1{#2}}}%
  \listadd\lrq@lst@elm{#2}%
  \begingroup
  \lrq@indent\@ne
  \xappto\lrq@hook@dtd{\lrq@tab<!ELEMENT #2 \detokenize{#3}>\lrq@nl}%
  \endgroup}

% {<element>}[<default>]{<attribute>}{<dtd spec>}

\newrobustcmd*{\DeclareLogreqAttribute}[1]{%
  \@ifnextchar[%]
    {\lrq@defattibute{#1}}
    {\lrq@defattibute{#1}[]}}
\@onlypreamble\DeclareLogreqAttribute

\def\lrq@defattibute#1[#2]#3{%
  \ifblank{#2}
    {\define@key{lrq@att@#1}{#3}}
    {\define@key{lrq@att@#1}{#3}[#2]}%
      {\eappto\lrq@attribs{ #3="##1"}}%
  \begingroup\@makeother\#%
  \lrq@defattibute@i{#1}{#3}}

\def\lrq@defattibute@i#1#2#3{%
  \endgroup
  \listcseadd{lrq@lst@att@#1}{#2 #3}}

\def\lrq@parseattributes#1#2{%
  \let\lrq@attribs\@empty
  \setkeys{lrq@att@#1}{#2}}

% {<macro>}{<attributes>}{<request>}

\protected\def\lrq@request#1#2#3{%
  \begingroup
  \setbox\@tempboxa=\hbox{%
    \let\if@safe@actives\iftrue
    \let\protect\string
    \lrq@hook@init
    #1[#2]{#3}}%
  \endgroup}

% package interface

% {<package>}{<active>}{<request>}

\newrobustcmd*{\ltxrequest}[3]{%
  \lrq@request\internal{package={#1},priority=9,active={#2}}{\generic{latex}#3}}

% [package=<package>,priority=<priority>,active=<0|1>]{<request>}

\newrobustcmd*{\logrequest}[2][]{%
  \lrq@request\external{#1}{#2}}

% initialization

\newcommand*{\@reqoutput}{\jobname.run.xml}
\newcommand*{\LogreqDTDVersion}{}
\input{logreq.def}

\endinput