%
% verbfwr.sty -- LaTeX package that writes verbatim to a file
% by pts@fazekas.hu at Sat Sep 27 23:40:12 CEST 2003
%
% Code partially ripped from sverb.sty
% Dat: space tokens at EOL are ignored by TeX's eyes
%
% Dat: changed \@tempa to \VerbFwrLines, so we have:
%      ! File ended while scanning use of \VerbFwrLines.
% !! use latex.ltx \begin{filecontents}
%
% Dat: callbacks are: (see below)
%   \verbfwr@actemitlineone
%   \verbfwr@actemitline
%   \verbfwr@actemitdone
%

\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{verbfwr}[2003/09/25 v0.02 Verbatim file write]

\newif\ifverbfwr@matched
\def\verbfwr@matcher#1#2#3{%
  \expandafter\def\csname\string#1$after\endcsname##1#2\relax{%
    \def\verbfwr@@terminator{#2}% `\end{foo}' with \string
    \def\verbfwr@@after{##1}}%
  \expandafter\def\csname\string#1$match\endcsname##1#2##2##3\end{%
    \ifx##2\relax\verbfwr@matchedfalse
    \else\verbfwr@matchedtrue\csname\string#1$after\endcsname##2##3\fi
    #3{##1}%
  }%
  \expandafter\def\expandafter#1\expandafter##\expandafter1\expandafter{%
    \csname\string#1$match\endcsname##1#2\relax\end%
  }%
}
\begingroup
\catcode\string`\%=12
\gdef\verbfwr@percent#1#2\relax
    {\ifx\check@percent\@@undefined
                     \ifx#1\relax\def\VerbFwrLines{}\else
                         \def\VerbFwrLines{#1#2}\fi\else
                     \ifx#1\relax\def\VerbFwrLines{}\else
                         \ifx#1%\def\VerbFwrLines{#2}\else
                             \def\VerbFwrLines{#1#2}\fi\fi\fi}
\endgroup
\begingroup
\lccode\string`\~32
\lowercase{\endgroup
  \def\verbfwr@isspaces#1{%
    \ifx#1\relax \def\@tempb{\@tempswafalse}%
    \else\ifx#1~\let\@tempb\verbfwr@isspaces%
    \else\def\@tempb##1\relax{}%
    \fi\fi%
    \@tempb%
  }
  \def\verbfwr@safespc{\catcode32 13 \def~{ }}
}
\def\verbfwr@default@acts{%
%** Callback called before each line. Should call
%** `\let\verbfwr@actemitlineone\@empty' to prevent subsequent callbacks.
\gdef\verbfwr@actemitlineone{%
  %\hrule
  \let\verbfwr@actemitlineone\@empty
}%
%** Callback called after the last line (even if \verbfwr@actemitlineone
%** isn't \@empty). This can detect the presence of lines by checking
%** \ifx\verbfwr@actemitlineone\@empty .
\let\verbfwr@actemitdone\@empty
%** Called fore each line, with macro \VerbFwrLines containing the line itself
%** @param #1 \cs process-line-proc
\def\verbfwr@actemitline##1{%
  \begingroup
  \expandafter##1\expandafter{\VerbFwrLines}%
  \endgroup
}%
}
\verbfwr@default@acts
%** Dat: discards spaces at EOL (but not at BOL if BOL!=EOL)
%** @param #1 end-text
%** @param #2 \cs process-line-proc
%** @param #3 \cs end-proc
\def\verbfwr@read#1#2#3{%
  \begingroup%
  \verbfwr@matcher\verbfwr@match{#1}\verbfwr@read@ii%
  \@tempswafalse
  \catcode13 13 \catcode32 13
  \lccode\string`\~13\lowercase{%
    \def\verbfwr@read@i##1~{\verbfwr@match{##1}}%
  }%
  \def\verbfwr@read@ii##1{%
    % Dat: The TeXbook, page 46 says that characters with code 32 are removed
    %      from the end of the lines. This is independent of \catcode32
    %%\def\VerbFwrLines{##1}\show\VerbFwrLines
    \verbfwr@percent##1\relax\relax%
    \ifverbfwr@matched\@tempswafalse\fi%
    % vvv Dat: ignore the very first line (with \begin{VerbWrite}), entirely
    %     made of spaces -- will never occur, because
    %     trailing spaces have already been trimmed
    \if@tempswa\else\@tempswatrue\expandafter\verbfwr@isspaces\VerbFwrLines\relax\fi%
    \if@tempswa
      \verbfwr@actemitlineone
      \verbfwr@actemitline{#2}%
    \fi%
    \@tempswatrue
    \ifverbfwr@matched
      \ifx\verbfwr@@after\@empty\else
        \PackageWarning{verbfwr}{Text right from \verbfwr@@terminator\space was ignored}%
      \fi
      %\def\reserved@a{##1}%
      \def\VerbFwrLines{%\ifx\verbfwr@actemitlineone\@empty\verbfwr@actemitdone\fi
        \verbfwr@actemitdone \endgroup#3}%
    \else\let\VerbFwrLines\verbfwr@read@i\fi%
    \VerbFwrLines
  }%
  \verbfwr@read@i
}
\begingroup
\lccode\string`\<=\string`\{ \lccode\string`\>=\string`\} \lccode\string`\|=\string`\\
\lowercase{\endgroup
  %** @example \verbfwr@readenv\verbfwr@read
  \def\verbfwr@readenv#1{%
    \expandafter\expandafter\expandafter%
    #1\expandafter\verbfwr@readenv@i\@currenvir\hfuzz}
  \def\verbfwr@readenv@i#1\hfuzz{{|end<#1>}{\end{#1}}}
  %** @param #1 stop line
  %** @param #2 code to call at stop
  \def\verbfwr@readenv@ii#1\hfuzz#2{{|end<#1>}{#2}}
}
%** @param #1<-\end{VerbWrite} (with full catcode 12)
%** @param #2<-\end {VerbWrite} (with various catcodes for \, e, { and }
\def\verbfwr@write#1#2{%
  \begingroup%
  \@savsf1000 \@savsk\z@skip% in case \verbfwr@actemitlineone initiates horizontal mode
  \@bsphack% Dat: too early to say \@bsphack here, because
  \let\do\@makeother\dospecials% \catcode`\\=12 etc. (see latex.ltx for \dospecials)
  \@tempcnta127
  \loop\ifnum\@tempcnta<256 \catcode\@tempcnta12 \advance\@tempcnta\@ne\repeat
  \catcode9=12 % tab: \t, will be emitted as ^^I to the file (force this!)
  % Dat: eempost.sty has to be updated (?! not sure)
  %\catcode\string`\^13 % allow ^^e1 hex...
  \verbfwr@safespc% each space counts when reading (similar to \obeyspaces)
  \verbfwr@read{#1}\verbfwr@actwriteline{\@esphack\endgroup#2}%
}
%** \let\verbfwr@actwriteline\verbfwr@writeline
\def\verbfwr@writeline#1{%
  %%\showthe\catcode92 \toks0{#1} \showthe\toks0
  \immediate\write\verbfwr@writecs{#1}%
}
\newwrite\verbfwr@writefile
%** Usage: \begin{VerbWrite}{filename.ext}...\end{VerbWrite}. File will end with \n. The
%** line contents after \end{verbwrite} are ignored.
\def\VerbWrite#1{%
  \immediate\openout\verbfwr@writefile#1\relax%
  \let\verbfwr@writecs\verbfwr@writefile
  \let\verbfwr@actwriteline\verbfwr@writeline
  \verbfwr@readenv\verbfwr@write
  % \foo\bar % would write also this!
}
\def\endVerbWrite{\immediate\closeout\verbfwr@writefile}
%\expandafter\def\csname verbwrite*\endcsname#1#2{%
%  \immediate\openout\verbfwr@writefile#2\relax%
%  \let\verbfwr@writecs\verbfwr@writefile
%  \verbfwr@write{#1}{\immediate\closeout\verbfwr@writefile\end{verbwrite*}}%
%}

\begingroup\catcode\string`\^^M=3 % math shift. Weird enough.
% ^^^ Dat: Each line following the prev. catcode def. must end with `%'
%     otherwise we get `! Missing $ inserted' for
%     \begin{PSource}[srcstyle=leftleft]
%     a&b
%     \end{PSource}
\gdef\verbfwr@noter@endtest#1#2#3#4#5#6^^M{%%
  \edef\reserved@a{\string#1}%%
  \def\reserved@b{#1#2#3#4{#5}}%%
}%%
\gdef\verbfwr@noter@eachline#1^^M{%%
  \expandafter\verbfwr@noter@endtest\string#1[][][]^^M% set \reserved@a and \reserved@b
  %%\show\reserved@b%
  \if\string^^M\reserved@a%%
    % If we are here then our line, #1 begins with ^^M (with a \catcode
    % different from 3, which we've set above). This means that somebody
    % (our caller) has inserted a ^^M before we've been able to change
    % \catcodes. The typical example is \@ifnextchar, looking for a `[', but
    % finding only ^^M. That ^^M would have whatever catcode. Another typical
    % example is \verbfwr@noter@read0, whose ^^M we should ignore immediately
    %   Our strategy is to ignore that extra ^^M.
    \expandafter\expandafter\expandafter\verbfwr@noter@endtest%%
    \expandafter\string\@gobble#1[][][]^^M%%
    % ^^^ this sets \reserved@b, so we can properly end the environment here
    \let\reserved@a\@gobble%%
  \else%%
    \let\reserved@a\@empty%%
  \fi%%
  \ifx\reserved@b\verbfwr@@noter@end%%
    %\ifx\verbfwr@actemitlineone\@empty\verbfwr@actemitdone\fi%
    \verbfwr@actemitdone%% BUGFIX: added `%' to this line at Fri Nov 12 00:03:26 CET 2004
    \endgroup%% &agroup;
    \expandafter\end\expandafter{\@currenvir}%%
  \else%%
    \verbfwr@actemitlineone%%
    \expandafter\def\expandafter\VerbFwrLines\expandafter{\reserved@a#1}%%
    \verbfwr@actemitline{}%%
    \expandafter\verbfwr@noter@eachline%%
  \fi%%
}%%
\endgroup% \catcode

%** by pts@fazekas.hu at Sun Dec  7 20:41:22 CET 2003
%** Similar to \verbfwr@readenv\verbfwr@write (which doesn't write anything
%** to a file if all \verbfwr@actemit.. callbacks are redefined), but always
%** stops reading at end of \@currenvir (and doesn't gobble the rest of the
%** line) provided that it is at BOL (/^\s*/). Calls the usual callbacks
%** \verbfwr@actemitlineone, \verbfwr@actemitlineone and
%** \verbfwr@actemitline. Works with normal \catcodes, only the \catcode of
%** ^^M is changed.
%** @param #1 0|1. Insert an empty line if \begin{...} is followed by ^^M?
%** Dat: discards spaces at BOL and EOL
%** Dat: doesn't discard empty lines
%** Dat: accepts \end{...} marker only at BOL (/^\s*/)
\def\verbfwr@noter@read#1{%
  \begingroup% &agroup;
  \edef\verbfwr@@noter@end{\string\end{\@currenvir}}%
  \if1\noexpand#1%
    \expandafter\verbfwr@noter@ignore@start% remember ^^M just after \begin{foo}
  \else
    \obeylines% \catcode\string`^^M=13
    \expandafter\expandafter\expandafter\verbfwr@noter@ignore@start
    \expandafter\noexpand% trick to ignore ^^M after \begin{foo}
  \fi
}
\def\verbfwr@noter@ignore@start{%
  \catcode\string`\^^M=3
  \verbfwr@noter@eachline%
}

%** \begin{WFile}{filename}contents^^J\end{WFile}
\def\WFile#1{%
  \immediate\openout\verbfwr@writefile#1\relax
  \let\verbfwr@writecs\verbfwr@writefile
  \let\verbfwr@actwriteline\verbfwr@writeline
  \verbfwr@default@acts
  \verbfwr@readenv\verbfwr@write}% finish this \cs here
\def\endWFile{\immediate\closeout\verbfwr@writefile}

%** Writes directly to the aux file
\def\WAux{%
  \let\verbfwr@writecs\@auxout
  \let\verbfwr@actwriteline\verbfwr@writeline
  \verbfwr@default@acts
  \verbfwr@readenv\verbfwr@write}% finish this \cs here
\def\endWAux{}%

\endinput%% End of verbfwr.sty