% \iffalse meta-comment % Line endings: UNIX % Tab size: 4 % % Copyright 2004 Jonathan Sauer % % This work may be distributed and/or modified under the % conditions of the LaTeX Project Public License, either version 1.3 % of this license or (at your option) any later version. % The latest version of this license is in % % http://www.latex-project.org/lppl.txt % % and version 1.3 or later is part of all distributions of LaTeX % version 2003/12/01 or later. % % This work has the LPPL maintenance status "maintained". % % The Current Maintainer of this work is Jonathan Sauer % (). % % This work consists of the files collect.dtx and collect.ins % and the derived file collect.sty. % % \fi % % \iffalse % %<*driver> \documentclass{ltxdoc} \usepackage{collect} \EnableCrossrefs \CodelineIndex \RecordChanges % Modification of verbatim for tabs in listings \makeatletter {\catcode`\ =\active% \catcode`\^^I=\active% \gdef\@vobeyspaces{% \catcode`\ \active\let \@xobeysp% \catcode`\^^I\active\def^^I{~~}% }}% \makeatother \begin{document} \DocInput{\jobname.dtx} \end{document} % % %\NeedsTeXFormat{LaTeX2e} %\ProvidesPackage{collect} % [2004/09/12 v0.9 collect the contents of an environment] % % \fi % % \CheckSum{256} % \CharacterTable % {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z % Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z % Digits \0\1\2\3\4\5\6\7\8\9 % Exclamation \! Double quote \" Hash (number) \# % Dollar \$ Percent \% Ampersand \& % Acute accent \' Left paren \( Right paren \) % Asterisk \* Plus \+ Comma \, % Minus \- Point \. Solidus \/ % Colon \: Semicolon \; Less than \< % Equals \= Greater than \> Question mark \? % Commercial at \@ Left bracket \[ Backslash \\ % Right bracket \] Circumflex \^ Underscore \_ % Grave accent \` Left brace \{ Vertical bar \| % Right brace \} Tilde \~} % % % \DoNotIndex{\@currenvir,\@ehc,\@ifundefined,\@input} % \DoNotIndex{\@tempa,\@tempb,\bgroup,\catcode,\closeout,\csname} % \DoNotIndex{\def,\edef,\egroup,\else,\end,\endcsname,\expandafter} % \DoNotIndex{\fi,\futurelet,\gdef,\global,\ifx,\immediate,\jobname,\let,\long} % \DoNotIndex{\meaning,\newcommand,\newenvironment,\newif,\newwrite} % \DoNotIndex{\openout,\PackageError,\par,\strip@prefix,\the,\toks@} % \DoNotIndex{\write} % % \GetFileInfo{\jobname.sty} % % \title{The \textsf{collect} package\thanks{This document % corresponds to \textsf{\filename}~\fileversion, dated \filedate.}} % % \author{Jonathan Sauer \\ \texttt{jonathan.sauer@gmx.de}} % % \date{\filedate} % % \maketitle % % \begin{abstract} % This file describes the \textsf{collect} package that % makes it possible to collect text for later use. % % \end{abstract} % % \tableofcontents % % \section{Introduction} % % Suppose you are writing the specification of a programming language. % Then you will surely insert definitions of the grammar (i.e. using % the \textsf{syntax} package). Most likely you will insert the % grammar for i.e. loops, conditions et cetera in the appropriate % chapter, but for easy implementation of a parser, you will want to % include the complete grammar as an appendix, so that one does not % have to collect the complete grammar from the bits in each chapter. % % Of course you could do this by hand using the copy-and-paste % facility of your text editor. But this is cumbersome and errorprone % if you modify the grammar afterwards, i.e. for a second version. % % This package provides the |collect| environment that typesets % its contents and collects it for later use as well. % % In other situations you will want to save the contents of an % environment in a macro. Then the |collectinmacro| environment % should do the trick. % % % % \section{Usage} % % \paragraph{General note} If an environment exists in a normal and a % starred form (i.e. |collect| and |collect*|), then the former does % not typeset the environment contents, while the latter typesets it. % Note, too, that the normal and the starred version of an environment % often have a different number of parameters. % % \paragraph{Stripping of spaces} All environments strip any leading % space before the start of the text and any trailing space after the % end of the text. Trailing |\par|s (i.e. resulting from a blank line % at the end of the environment) are \emph{not} removed. % % % % % \subsection{\texttt{collect}} % % You can define several \emph{collections}. Each collection can be % used independently to collect text across the document. You define a % collection using |\definecollection|, use it in the |collect| and % |collect*| environment and typeset it using |\includecollection|. % % \paragraph{Note} The name of the collection is used as the suffix of % the file that stores the collection (the complete name is % \meta{jobname}|.|\meta{name)}. So you should not name a collection % |tex|, |log|, |dvi|, |pdf| and so on. % % \paragraph{Note} You can only include a collection after completely % collecting it. If you include it and continue to collect afterwards, % the collection will be cleared after its inclusion. % % This can be used to recycle a collection: Use it in the first part % of your document to collect text, typeset this text using % |\includecollection| and then reuse the collection in the second % part of your document to collect new text which will finally be % typeset using |\includecollection| a second time. % % % \DescribeMacro{\definecollection} Usage: |\definecollection| % \marg{name}. % % Defines a collection of the name \meta{name}. % % % \DescribeEnv{collect*} Usage: |\begin{collect*}| % \marg{name} \marg{before} \marg{after} \marg{beforecol} % \marg{aftercol} \ldots\ |\end{collect*}|. % % Collects the text inside the environment in the collection % \meta{name}. Then typesets the text. \meta{name} must have been % defined using |\definecollection|. % % \meta{before} and \meta{after} are tokens inserted before and after % the environment contents in the collection as well as the typeset % text. % % \meta{beforecol} and \meta{aftercol} are tokens inserted before and % after the environment contents only in the collection. This can be % used to insert a section heading (\meta{beforecol}) and a backref to % the section where the text has been collected (\meta{aftercol}). % % \paragraph{Note} The |collect*| environment uses a temporary file % \meta{jobname}|.tmp| to temporarily store the environment contents % and include it afterwards.\footnote{This way, catcode changes inside % the environment are honored.} % % % \DescribeEnv{collect} Usage: |\begin{collect}| \marg{name} % \marg{beforecol} \marg{aftercol} \ldots\ |\end{collect}|. % % Collects the text inside the environment in the collection % \meta{name}. \emph{Does not} typeset the text (therefore, the two % parameters \meta{before} and \meta{after} are missing); except for % that, this environment is identical to |collect*|. % % % \DescribeMacro{\includecollection} Usage: |\includecollection| % \marg{name}. Includes the collection \meta{name}. Afterwards, the % collection is reset. % % You can include the collection \emph{before} it is actually % collected in the same way you can include a table of contents at the % beginning of your document. Simply say |\includecollection| and then % use the |collect*| or |collect| environment to collect text. Then % run \LaTeX\ on your file \emph{twice}. (the first time to collect % the text, the second time to put it in the document using % |\includecollection|) % % % % \subsection{Other environments} % % \DescribeEnv{collectinmacro} Usage: |\begin{collectinmacro}| % \marg{macro} \marg{before} \marg{after} \ldots\ % |\end{collectinmacro}|. % % Collects the contents of an environment inside a macro \meta{macro} % without typesetting it. If \meta{macro} has been defined prior to % using this environment, its previous meaning is lost. The new % definition is global. % % \meta{before} and \meta{after} are tokens inserted before and after % the environment contents in the macro. % % \paragraph{Important note} This environment differs slightly from % |collect| and |collect*|: Some macros, i.e. |\verb|, do not work % correctly when \meta{macro} is used later on.\footnote{As the % catcodes have already been set when collecting the contents and % cannot be changed afterwards, at least not without e\TeX.} % % % % % \section{Examples} % % \subsection{\texttt{collect}} % % \begin{verbatim} % \begin{collect*}{tst}{Before\par}{\par After}{Before file\par}{\par After file} % This is a test % \end{collect*} % \end{verbatim} % % \noindent This results in the following text typeset directly: % % \begin{verbatim} % Before % This is a test % After % \end{verbatim} % % \noindent And following text is typeset when the collection |tst| is % included using |\includecollection{tst}|: % % \begin{verbatim} % Before file % Before % This is a test % After % After file % \end{verbatim} % % % % % \subsection{Other environments} % % \begin{verbatim} % \begin{collectinmacro}{\collectedtext}{Before\par}{\par After} % This is a test % \end{collectinmacro} % \end{verbatim} % % \noindent This results in no text typeset directly and the following % text stored in the macro |\collectedtext|: % % \begin{verbatim} % Before\par This is a test\par After % \end{verbatim} % % % % % \section{Creating your own environment} % % You can create your own environment based on any of the environments % in this package, i.e. to create a |grammarpart| environment to % typeset part of a grammar. % % You can for example say: % % \begin{verbatim} % \definecollection{gra} % % \newenvironment{grammarpart}[1]{% % \@nameuse{collect*}{gra}{% % \emph{Start of grammar `#1'}\par% % }{% % \par\emph{End of grammar}\par% % }{% % \subsection{#1}% % }{% % \par See some section in the text. % }% % }{% % \@nameuse{endcollect*}% % } % \end{verbatim} % % \noindent This will create a |grammarpart| environment with one % parameter, the part of the grammar defined. (i.e. `Identifiers') At % the start of the environment the text `\emph{Start of grammar % \meta{part}}' will be typeset, followed by the grammar (the contents % of the environment), and finally a line `\emph{End of grammar}' will % be added. % % When including the collected grammar parts using % |\includecollection| each grammar part will be prefixed by a % subsection heading bearing the grammar part as its title and % suffixed by `See some section in the text.' (this could be extended % to include a backref using |\ref|\meta{label}) % % \paragraph{Note} If you use any of the environments inside a custom % environment to afterwards collect text with this custom environment % (as in the example of the |grammarpart| environment above), you % \emph{must not} begin and end it using |\begin| and |\end|, or the % environment contents will not be collected correctly. You must use % |\@nameuse{|\meta{environment}|}| and % |\@nameuse{end|\meta{environment}|}| as in the example above, or, if % the environment is not starred, |\|\meta{environment} and % |\end|\meta{environment}. % % \paragraph{Note} You still can use the environments of this package % inside other environments (i.e. a |itemize| environment) without any % problems. % % % % % \section{Notes} % % \begin{itemize} % \item If you use any of the environments inside your own % environment, note that the end of the environment is % executed, but not included in the collected text! (that's % why the the environments |collect*| and |collectinmacro| % have two parameters for including text before and after % the environment, \meta{before} and \meta{after}). % % \end{itemize} % % % % % \StopEventually{} % % \section{Implementation} % % \subsection{Main environments and macros} % % \subsubsection{\texttt{collect}} % % \begin{macro}{\definecollection} % % Usage: |\definecollection| \marg{name} % % Defines a collection \meta{name}. % % This macro allocates a |\newwrite| |CE@@|\meta{name}|@out| and % defines a |\newif| |CE@@|\meta{name}|open|. % % \begin{macrocode} \newcommand{\definecollection}[1]{% \@ifundefined{CE@@#1@out}{% \expandafter\newwrite\csname CE@@#1@out\endcsname% \expandafter\newif\csname ifCE@@#1@open\endcsname% \csname CE@@#1@openfalse\endcsname% }{% \PackageError{collect}{Collection `#1' has already % been defined}{\@ehc}% }% } % \end{macrocode} % \end{macro} % % % \begin{environment}{collect*} % % Usage: |\begin{collect*}| \marg{name} \marg{before} % \marg{after} \marg{beforecol} \marg{aftercol} \ldots\ % |\end{collect*}|. % % \begin{macrocode} \newenvironment{collect*}[5]{% \global\toks@{}% \def\CE@file{#1}% \def\CE@preenv{#2}% \def\CE@postenv{#3}% \def\CE@prefileenv{#4}% \def\CE@postfileenv{#5}% \CE@get@env@body@start% }{% % \end{macrocode} % % What are we doing? We make sure the collection is open, then we save % \meta{beforecol}, \meta{before}, the collected environment contents, % \meta{after} and \meta{aftercol} in the collection file. % % \begin{macrocode} \CE@ensure@opened{\CE@file}% \edef\@tempa{\csname CE@@\CE@file @out\endcsname}% \immediate\write\@tempa{\CE@meaning\CE@prefileenv}% \immediate\write\@tempa{\CE@meaning\CE@preenv}% \immediate\write\@tempa{\the\toks@}% \immediate\write\@tempa{\CE@meaning\CE@postenv}% \immediate\write\@tempa{\CE@meaning\CE@postfileenv}% % \end{macrocode} % % Now we repeat the same thing, but with the temporary file and % writing only \meta{before}, the collected environment contents and % \meta{after}. Then we include the temporary file. % % Why so complicated, as we have the contents of the environment in % |\toks@|? Because the catcodes might not be correct, i.e. if |\verb| % is used inside the environment. So we have to read the environment % contents again, which without e\TeX\ is only possible using a % temporary file. % % \begin{macrocode} \immediate\openout\CE@tmp@out=\jobname.tmp% \immediate\write\CE@tmp@out{\CE@meaning\CE@preenv}% \immediate\write\CE@tmp@out{\the\toks@}% \immediate\write\CE@tmp@out{\CE@meaning\CE@postenv}% \immediate\closeout\CE@tmp@out% \@input{\jobname.tmp}% \par% } % \end{macrocode} % \end{environment} % % % \begin{environment}{collect} % % Usage: |\begin{collect}| \marg{name} \marg{beforecol} % \marg{aftercol} \ldots\ |\end{collect}|. % % \begin{macrocode} \newenvironment{collect}[3]{% \global\toks@{}% \def\CE@file{#1}% \def\CE@prefileenv{#2}% \def\CE@postfileenv{#3}% \CE@get@env@body@start% }{% % \end{macrocode} % % As this environment, contrary to |collect*|, does not typeset its % contents, we only write to the collection file: % % \begin{macrocode} \CE@ensure@opened{\CE@file}% \edef\@tempa{\csname CE@@\CE@file @out\endcsname}% \immediate\write\@tempa{\CE@meaning\CE@prefileenv}% \immediate\write\@tempa{\the\toks@}% \immediate\write\@tempa{\CE@meaning\CE@postfileenv}% } % \end{macrocode} % \end{environment} % % % \begin{macro}{\includecollection} % % Usage: |\includecollection| \marg{name}. % % Includes the collection \meta{name} which must have been defined % previously using |\definecollection|. Afterwards, the collection is % cleared. % % \begin{macrocode} \newcommand{\includecollection}[1]{% \CE@ensure@closed{#1}% \@input{\jobname.#1}% } % \end{macrocode} % \end{macro} % % % % \subsubsection{Other environments} % % \begin{environment}{collectinmacro} % % Usage: |\begin{collectinmacro}| \marg{macro} \marg{before} % \marg{after} \ldots\ |\end{collectinmacro}|. % % Collects the contents of an environment inside a macro. % % \begin{macrocode} \newenvironment{collectinmacro}[3]{% \def\CE@destmacro{#1}% \def\CE@postenv{#3}% % \end{macrocode} % % We initialize the result with \meta{before}: % % \begin{macrocode} \toks@{#2}% \CE@get@env@body@start% }{% % \end{macrocode} % % We add \meta{after}: % % \begin{macrocode} \toks@\expandafter\expandafter\expandafter{% \expandafter\the\expandafter\toks@\CE@postenv}% % \end{macrocode} % % Finally we globally define \meta{macro} to contain the collected % contents: % % \begin{macrocode} \expandafter\expandafter\expandafter% \gdef\expandafter\CE@destmacro\expandafter{\the\toks@}% \toks@{}% } % \end{macrocode} % \end{environment} % % % % % \subsection{Internal environments and macros} % % We allocate a new |\newwrite| for the processing of a temporary % file: % % \begin{macrocode} \newwrite\CE@tmp@out % \end{macrocode} % % % \begin{macro}{\CE@get@env@body@start} % % Starts the collecting of the contents of an environment. (the % environment starts immediately after the macro) % % \begin{macrocode} \def\CE@get@env@body@start{% \let\@tempa\CE@get@env@body% % \end{macrocode} % % We may have to gobble leading spaces, therefore we check the first % character in the environment: % % \begin{macrocode} \futurelet\@tempb\CE@get@env@body@start@% } % \end{macrocode} % \end{macro} % % % \begin{macro}{\CE@get@env@body@start@} % % Support macro for |\CE@get@env@body@start|. Checks if the next token % is a space, then calls |\CE@get@env@body@start@@|. Otherwise, the % collecting of the environment contents is started. % % \begin{macrocode} \def\CE@get@env@body@start@{% % \end{macrocode} % % |\@sptoken| contains a single space and is defined in % \textsf{ltdefns.dtx}: % % \begin{macrocode} \ifx\@tempb\@sptoken% \expandafter\CE@get@env@body@start@@% \else% \expandafter\CE@get@env@body% \fi% } % \end{macrocode} % \end{macro} % % % \begin{macro}{\CE@get@env@body@start@@} % % Support macro for |\CE@get@env@body@start@|. Gobbles up any space % following the macro, then start the collecting of the environment % contents using |\CE@get@env@body|. % % \begin{macrocode} \def\CE@get@env@body@start@@{% \afterassignment\CE@get@env@body% \let\@tempb= % } % \end{macrocode} % \end{macro} % % % \begin{macro}{\CE@get@env@body} % % Usage: |\CE@get@env@body| \marg{body} |\end| \marg{envname}. % % To ensure proper initialization, this macro should not be called % directly; instead |\CE@get@env@body@start| should be called. % % First we change the catcode of |Q| to 3 (math switch) in order to % have a really unique character for parameter matching later % on.\footnote{Taken from `Around the bend 15'} We do this in a group % in order to easily restore the catcode later on and make all macro % definitions global: % % \begin{macrocode} \bgroup \catcode`\Q=3 % \end{macrocode} % % Now we begin the macro: % % \begin{macrocode} \long\gdef\CE@get@env@body#1\end#2{% % \end{macrocode} % % Right at the beginning of the macro, we are at an |\end| (and |#1| % contains the contents prior to it). We check if it ends the current % environment (|#2| contains the name of the environment ended): % % \begin{macrocode} \def\@tempb{#2}% \ifx\@tempb\@currenvir% % \end{macrocode} % % \paragraph{Yes, it ends the current environment.} We add the % contents to |\toks@| and are done. But we do not add the contents % directly as there may be a trailing space left (multiple spaces have % been collapsed into one space by \TeX). So we call % |\CE@get@env@body@| using delimited parameters (note that |Q| has % catcode 3, therefore a normal |Q| is not matched). % % What exactly is going on here? Suppose we have the text % % \begin{verbatim} % Hello World_ % \end{verbatim} % % % \noindent (the |_| denotes the trailing space). Then % |\CE@get@env@body@| is called like this: % % \begin{verbatim} % \CE@get@env@body@Hello World Q Q % \end{verbatim} % % % \noindent |\CE@get@env@body@| matches the parameters like this: |#1| % is `Hello World'; leaving |_Q| (added by the call from % |\CE@get@env@body|) in the input. |\CE@get@env@body@| then calls % |\CE@get@env@body@@| using |#1| and |Q|, resulting in the call: % % \begin{verbatim} % \CE@get@env@body@@Hello WorldQ Q % \end{verbatim} % % % \noindent |\CE@get@env@body@@| matches its parameter like this: |#1| % is `Hello World' again, and |#2| is the second |Q|. % % But what happened to the space between the two |Q|s? As |#2| is not % a delimited parameter, \TeX\ skips spaces after matching the first % |Q| until it reaches the second |Q|, thus gobbling up the space % inbetween.\footnote{c.f. \TeX book chapter 20.} % % \addvspace{\baselineskip}\noindent Now suppose we have the text % \begin{verbatim} % Hello World % \end{verbatim} % % % \noindent without any trailing space. Then |\CE@get@env@body@| is % called like this: % % \begin{verbatim} % \CE@get@env@body@Hello WorldQ Q % \end{verbatim} % % % \noindent |\CE@get@env@body@| matches its parameters like this: |#1| % is `Hello WorldQ'. |\CE@get@env@body@| then calls % |\CE@get@env@body@@| using |#1| and |Q|, resulting in the call: % % \begin{verbatim} % \CE@get@env@body@@Hello WorldQQ % \end{verbatim} % % % \noindent |\CE@get@env@body@@| matches its parameter like this: |#1| % is `Hello World' without the trailing `Q', and |#2| is the second % |Q|. The only difference to the situation described above is the % missing space between the two |Q|s. % % Remember that the `Q' is always `Q' with catcode 3, thus no `Q' in % the environment contents is matched. % % \begin{macrocode} \CE@get@env@body@#1Q Q% \def\@tempa{\end{#2}}% \else % \end{macrocode} % % \paragraph{No, it ends another environment.} We add the contents as % well as the |\end|\meta{environment} to |\toks@|. Then we continue % collecting: % % \begin{macrocode} \toks@\expandafter{\the\toks@#1\end{#2}}% \fi% \@tempa% } % \end{macrocode} % \end{macro} % % % \begin{macro}{\CE@get@env@body@} % % Support macro for |\CE@get@env@body|. See |\CE@get@env@body| for % explanations. % % \begin{macrocode} \long\gdef\CE@get@env@body@#1 Q{% \CE@get@env@body@@#1Q% } % \end{macrocode} % \end{macro} % % \begin{macro}{\CE@get@env@body@@} % % Support macro for |\CE@get@env@body@|. See |\CE@get@env@body| for % explanations. % % \begin{macrocode} \long\gdef\CE@get@env@body@@#1Q#2{% \toks@\expandafter{\the\toks@#1}% } % \end{macrocode} % \end{macro} % % Finally we end the group, thus restoring the catcode of |Q|: % % \begin{macrocode} \egroup % \end{macrocode} % % % \begin{macro}{\CE@meaning} % % Usage: |\CE@meaning| \marg{macro}. % % Expands to the meaning of \meta{macro}. % % \begin{macrocode} \long\def\CE@meaning#1{% \expandafter\strip@prefix\meaning#1% } % \end{macrocode} % \end{macro} % % % \begin{macro}{\CE@ensure@opened} % % Usage: |\CE@ensure@opened| \marg{name}. % % Ensures that the file for collection \meta{name} is opened. % % \begin{macrocode} \def\CE@ensure@opened#1{% \@ifundefined{ifCE@@#1@open}{% \PackageError{collect}{Collection `#1' has not been defined}{\@ehc}% }{% \csname ifCE@@#1@open\endcsname\else% \expandafter\immediate\expandafter\openout% \csname CE@@#1@out\endcsname=\jobname.#1% \expandafter\global\csname CE@@#1@opentrue\endcsname% \fi% }% } % \end{macrocode} % \end{macro} % % % \begin{macro}{\CE@ensure@closed} % % Usage: |\CE@ensure@closed| \marg{name}. % % Ensures that the file for collection \meta{name} is closed. % % \begin{macrocode} \def\CE@ensure@closed#1{% \@ifundefined{ifCE@@#1@open}{% \PackageError{collect}{Collection `#1' has not been defined}{\@ehc}% }{% \csname ifCE@@#1@open\endcsname% \expandafter\immediate\expandafter\closeout% \csname CE@@#1@out\endcsname% \expandafter\global\csname CE@@#1@openfalse\endcsname% \fi% }% } % \end{macrocode} % \end{macro} % % % \Finale % \PrintChanges % \PrintIndex \endinput