From 876cb4219f46ce0c2c326a9c5bb78de833b52904 Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Thu, 2 Apr 2009 18:38:05 +0000 Subject: new latex package codedoc (1apr09) git-svn-id: svn://tug.org/texlive/trunk@12603 c570f23f-e606-0410-a88d-b1316a301751 --- .../doc/latex/codedoc/CodeDoc-manual.pdf | Bin 0 -> 595537 bytes .../doc/latex/codedoc/CodeDoc-manual.tex | 4870 ++++++++++++++++++++ Master/texmf-dist/doc/latex/codedoc/README | 31 + 3 files changed, 4901 insertions(+) create mode 100644 Master/texmf-dist/doc/latex/codedoc/CodeDoc-manual.pdf create mode 100644 Master/texmf-dist/doc/latex/codedoc/CodeDoc-manual.tex create mode 100644 Master/texmf-dist/doc/latex/codedoc/README (limited to 'Master/texmf-dist/doc/latex/codedoc') diff --git a/Master/texmf-dist/doc/latex/codedoc/CodeDoc-manual.pdf b/Master/texmf-dist/doc/latex/codedoc/CodeDoc-manual.pdf new file mode 100644 index 00000000000..3f78a83663c Binary files /dev/null and b/Master/texmf-dist/doc/latex/codedoc/CodeDoc-manual.pdf differ diff --git a/Master/texmf-dist/doc/latex/codedoc/CodeDoc-manual.tex b/Master/texmf-dist/doc/latex/codedoc/CodeDoc-manual.tex new file mode 100644 index 00000000000..e0d76d10c7f --- /dev/null +++ b/Master/texmf-dist/doc/latex/codedoc/CodeDoc-manual.tex @@ -0,0 +1,4870 @@ +\ifnum\month<10 \edef\month{0\the\month}\else \edef\month{\the\month}\fi +\ifnum\day<10 \edef\day{0\the\day}\else \edef\day{\the\day}\fi + +\documentclass[article(a4paper), +index,% Comment this out if you don't want an index +%obeystop,% Uncomment this if you don't want to print the implementation +%produce,% Uncomment this to produce 'codedoc.cls' +]{codedoc} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Definitions for the example environments + +\def\bluecolor{blue!75!white} +\def\redcolor{red!75!white} +\def\yellowcolor{yellow!75!white} + +\newcount\colorcount + +\def\tryblue{% + \ifnum\colorcount=\inputlineno% + \let\incolor\bluecolor% + \def\commentcolor{white}% + \ifodd\inputlineno% + \let\outcolor\redcolor% + \let\filcolor\yellowcolor% + \else% + \let\outcolor\yellowcolor% + \let\filcolor\redcolor% + \fi% + \else% + \advance\colorcount by1\relax% + \expandafter\tryred% + \fi} + +\def\tryred{% + \ifnum\colorcount=\inputlineno% + \let\incolor\redcolor% + \def\commentcolor{white}% + \ifodd\inputlineno% + \let\outcolor\yellowcolor% + \let\filcolor\bluecolor% + \else% + \let\outcolor\bluecolor% + \let\filcolor\yellowcolor% + \fi% + \else% + \advance\colorcount by1\relax% + \expandafter\tryyellow% + \fi} + +\def\tryyellow{% + \ifnum\colorcount=\inputlineno% + \let\incolor\yellowcolor% + \def\commentcolor{gray}% + \ifodd\inputlineno% + \let\outcolor\bluecolor% + \let\filcolor\redcolor% + \else% + \let\outcolor\redcolor% + \let\filcolor\bluecolor% + \fi% + \else% + \advance\colorcount by1\relax% + \expandafter\tryblue% + \fi} + +\newdimen\csize +\csize15cm + +\newskip\exskip +\exskip=2em plus 1em minus 1em\relax + +\newif\iftrycolor +\trycolortrue + +\NewExample[]{ex0}{\ttfamily#}{#}{% + \vskip\exskip% + \iftrycolor% + \tryblue% + \else% + \global\trycolortrue% + \fi% + \fboxsep6pt% + \fboxrule4pt% + \noindent\hfil\fcolorbox{black}{\incolor}{% + \parbox{\csize}{\CodeInput}}% + \global\csize15cm\relax% + \vskip\exskip\relax} + +\NewExample{ex1}{\ttfamily#}{}{} + +\newdimen\exdimen +\def\getnumber#1#2#3#4!{% + \ifnum\inputlineno<1000 % + \exdimen#3#2pt\def\movefil{\hskip-.#2\wd\filbox}\relax% + \else% + \exdimen#4#3pt\def\movefil{\hskip-.#3\wd\filbox}\relax% + \fi} + +\newbox\inbox +\newbox\outbox +\newbox\filbox +\newdimen\outdimen +\outdimen30pt + + +\NewExample[visibleEOL]{sidebyside}{\ttfamily#}{#}{% + \expandafter\getnumber\the\inputlineno! + \iftrycolor% + \tryblue% + \else% + \global\trycolortrue% + \fi% + \vskip\exskip% + \noindent + \fboxsep6pt% + \fboxrule4pt% + \setbox\inbox=\hbox{\fcolorbox{black}{\incolor}{% + \vbox{% + \hsize.47\hsize% + \CodeInput}}}% +% + \setbox\outbox=\hbox{\fcolorbox{black}{\outcolor}{% + \vtop{% + \hsize.3\hsize% + \parindent0pt% + \vskip1em\CodeOutput\vskip1em}}}% +% + \setbox\filbox=\hbox{\fcolorbox{black}{\filcolor}{% + \hbox to.15\ht\inbox{% + \color{\filcolor}\vrule height.15\ht\inbox depth0pt width0pt\hss}}}% +% + \hfil\unhcopy\inbox% + \movefil% + \ifdim\exdimen>.5\ht\inbox\relax\raise.4\ht\inbox\copy\filbox\else\raise.2\ht\inbox\copy\filbox\fi% + \hskip-\fboxrule\raise\exdimen\box\outbox% + \vskip\exskip\relax} + +\def\InvisibleSpace{\catcode`\ =10\relax} +\def\cdcomment#1{\textcolor{\commentcolor}{\emph{#1}}} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Definitions to print macro names + +\def\macrotopskip{\goodbreak\vskip1em plus .2em minus .2em} + +\def\maccolor{red!70!black} + +\def\OneMac#1{\macrotopskip\noindent\textcolor{\maccolor}{\llap{\textbullet\ }\ttfamily#1}\par\nobreak\noindent\ignorespaces} +\def\TwoMac#1{\noindent\textcolor{\maccolor}{\llap{\textbullet\ }\ttfamily#1}\par\nobreak} +\let\PrintMacro\OneMac + +\IgnorePrefix{cd@} +\def\PrintPrefix{\textcolor{gray}} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Opening the file + +\Header +{%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +This is the CodeDoc class, produced by itself +with the `produce' option on, from `\jobname.tex'. + +Date: \FileDate +Version: \FileVersion +Author: Paul Isambert + +The documentation can be found in `\jobname.pdf' +(you can produce it with `\jobname.tex' without the +`produce' option). + +This file is published under the LaTeX Project Public License: + +Do whatever you want to that software, +but if you modify it, change its name to avoid confusion, +and if you copy part of the code please mention where it comes from. + +Comments, suggestions, bugs and, of course, NOTES: +zappathustra@free.fr + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%} + +\ProduceFile{codedoc.cls}[codedoc][v.0.1][\the\year/\month/\day] +\AddBlankLine\AddBlankLine\AddBlankLine + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% The ladybug + +\def\makecox(#1,#2,#3,#4)#5{% + \vbox to0pt{\vskip-#3% + \hbox to0pt{\hskip#2% + \rotatebox[origin=c]{#1}{\coccinelle}\raise#5\hbox{\vbox{\everypar{}\vskip-5pt\tiny\sffamily\noindent#4}}\hss}\vss}} + +\def\coxx[#1](#2,#3,#4,#5){\makecox(#2,#3,#4,#5){#1}\index{Zmakecox(240,0pt,8pt,What am I\\doing here?){0pt}\hskip1.8cm|hyperpage}} + +\def\cox#1{% + \ifx#1[% + \def\next{\coxx[}% + \else% + \def\next{\coxx[0pt](}% + \fi\next} + +\def\coccinelle{% + \bgroup% + \setbox0=\hbox{\Huge\textbullet\llap{\raise-.4pt\hbox{\textbullet}}} + \color{black}% + \setbox1=\hbox{\textbullet} + \leavevmode\raise8.5pt\hbox to0pt{\hskip.5\wd0\hskip-.47\wd1\textbullet\hss}% + \Huge\color{red}% + \unhcopy0% + \hskip-\wd0% + \color{black}% + \raise3pt\rlap{\color{red!80!black}\hskip.47\wd0\vrule height7.5pt depth1.5pt}% + \raise3pt\rlap{\hskip.5pt.}% + \raise6pt\rlap{\hskip1.5pt.}% + \raise2.5pt\rlap{\hskip5pt.}% + \raise7.5pt\rlap{\hskip5.8pt.} + \egroup}% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\usepackage[T1]{fontenc} +\usepackage[textwidth=16cm,textheight=24cm]{geometry} +\usepackage{xcolor} +\usepackage{graphicx} +\usepackage{silence}% This avoids tens of `Marginpar on page X moved' +\WarningFilter{latex}{Marginpar on page}% messages. Nothing vital, however. +\let\next\relax +\expandafter\ifx\csname pdfoutput\endcsname\relax + \ClassWarningNoLine{CodeDoc}{% + Because of numerous color manipulations,\MessageBreak + This documentation looks better in PDF.\MessageBreak + Give it a try} +\else% + \ifnum\pdfoutput=1 % + \def\next{\usepackage[pdfborder=0 0 0]{hyperref}} + \else + \ClassWarningNoLine{CodeDoc}{% + Because of numerous color manipulations,\MessageBreak + This documentation looks better in PDF.\MessageBreak + Give it a try} + \fi +\fi\next + + + +\ShortVerb" +\VerbCommand§¤£ +\VerbBreak¨ + +\def\CD{\textsf{CodeDoc}} +\def\eTeX{$\varepsilon$-\TeX} +\let\Part\part +\def\part{\clearpage\Part} + +\title{The \textsf{CodeDoc} class\\\FileVersion\\\FileDate} +\author{Paul Isambert\\\texttt{zappathustra@free.fr}} +\date{} + + + + + + + + +\begin{document} + +\maketitle + +\vfil +{\fboxrule4pt % +\hfil\fcolorbox{black}{blue}{\hbox to4cm{% + \Huge\scshape\raise.2cm\hbox{C}\hfil\raise.2cm\hbox{o}\hfil\raise.2cm\hbox{d}\hfil\textcolor{blue}{e}\hfil\vbox to1cm{\vfil}}}% +\kern-1.5cm\raise.3cm\hbox{\fcolorbox{black}{yellow}{\hbox to.5cm{% + \Huge\raise.6cm\hbox{\&}\hfil\vbox to1.8cm{\vfil}}}}% +\kern-.3cm\raise1.7cm\hbox{\fcolorbox{black}{red}{\hbox to2cm{% + \Huge\scshape D\hfil o\hfil c\hfil\vbox to2cm{\vfil}}}}% +\cox(240,-3.2cm,3.1cm,\hskip-5pt???)} + +\vfil +\noindent\CD\ is a class designed to produce \LaTeX\ files +such as packages and classes along with their documentations. It does not +depart from \LaTeX's ordinary syntax, unlike e.g. \textsf{DocStrip}, +allows any existing class to be loaded with its options and +offers various fully customizable verbatim environments that +allows authors to typeset the code and documentation of +their files as they want. To create the documentation, +we compile the document as usual; to create the external file(s), +we simply put "produce" in the class options and compile as before. + +Despite my earliest expectations, \CD\ is not better than +\textsf{DocStrip}. It is simply different. If you want +a well-delimited approach to literate programming, use +\textsf{DocStrip}. On the other hand, \CD\ is more natural, +in the sense that it is ordinary \LaTeX\ all the way down. +Note that you can `mimick' \textsf{DocStrip}, either by +putting any character at the beginning of each line of +your code and setting the "\Gobble" parameter to 1 (this +would be `inverted \textsf{DocStrip}'), or by setting +the comment character to be of category 9 (`ignored') +and beginning each line of the documentation with this character. +In this latter case, only commands that are considered by +\CD\ when producing a file should not be commented out... +but I'm going too fast here, and you should learn the basics +first... + +\vskip1em +\noindent \CD\ is still in its infancy, as indicated by +its version number. Although it has passed the test of producing +this documentation, countless bugs will probably be reported, +and meaningful suggestions will be made. Be patient, and +send them to me. \emph{Any reported bug and meaningful +suggestion will be rewarded by a musical note, played by +a virtual instrument, and sent in the mp3 format.} Isn't +it amazing? I know it is. I will have to hire musically +educated secretaries to face the consequences of such +a reckless proposition. But it is worth it. Once a stable +version is reached, I might even write a symphony.\footnote{% +`Meaningful suggestion' and `stable version' are fuzzy terms, +you complain. Of course they are. Give me a chance!} + +Some of the ideas of this class are not mine; some were +inspired by others; some are mine but were independantly +implemented in other places; may all these people be +thanked, as well as all the verbatim wizards around the world. +And, oh, yeah, some ideas are mine, too. +\thispagestyle{empty} +\pagebreak + +\strut\vfil +\tableofcontents +\vfil +\thispagestyle{empty} +\pagebreak + +\part{User's manual} + +\section{Code \& Documentation} + +The source of this documentation looks roughly like this: +\csize10cm +\begin{ex0} +\documentclass[article(a4paper), +%produce, +]{codedoc} + +§cdcomment¤Preamble of the document£ + +\begin{document} +\section{Code \& Documentation} +The source of this document... + +\ProduceFile{codedoc.cls}[codedoc][v.0.1][2009/03/13] +\begin{code} + §cdcomment¤Material here will be written to codedoc.cls£ + §cdcomment¤and typeset verbatim in the documentation.£ +\end{code} + +\ShortCode/ +/ + §cdcomment¤This too...£ +/ + +\begin{invisible} + §cdcomment¤This material will be written to codedoc.cls£ + §cdcomment¤but not typeset in the documentation.£ +\end{invisible} + +\end{document} +\end{ex0} + +Everything between "\begin{code}" and "\end{code}" is written +verbatim to the dvi file. It is also the case for everything +between two "\ShortCode" symbol, in this example `"/"'. Finally, +if the comment sign at the beginning of the second line were +removed, thus enabling the "produce" option, then this code +would be written to "codedoc.cls" and no documentation would +be produced. This is \CD's basic mechanism. Let's +review it more precisely. In what follows, I will say `normal +mode' if the "produce" option is not turned on, that is when +we're typesetting the documentation, and `produce mode' otherwise, +that is when \texttt{produce} is present among the class options and +\CD\ is used to create an external file. + +The first two sections of this manual explain how \CD\ works +and provide many examples. +The third section lists all commands in alphabetical order, +and explains what they do in each mode in a more systematic +fashion. + + + + +\subsection{Writing code} + +\DescribeMacro{\ProduceFile\marg{File}\oarg{File name}\oarg{File version}\oarg{File date}} +\noindent In normal mode, this macro provides four commands: +"\FileSource" stores \meta{File}, and the next three arguments +are stored in "\FileName", "\FileVersion" and "\FileDate" +respectively. Those are optional, as indicated by their syntax. + +In produce mode, \CD\ opens \meta{File} and writes to it everything +in a "code" environment. "\FileName", "\FileVersion" and "\FileDate" +are also provided and may be used in "\Header" (see below) or in the +file itself with "\CodeEscape" (see page \pageref{CodeEscape}). Thus, you can avoid +mismatches between your documentation and the "\ProvidesPackage" declaration, +for instance. + +\DescribeMacro{\CloseFile\marg{File}} +\noindent In produce mode, when the "autoclose" option is on, "\ProduceFile" +closes the file that was currently under production, if any. But you +might want to keep a file open, in case you're writing to several files +at the same time. That's why \CD's basic behavior is to keep all files +open. Thus + +\csize5cm +\begin{ex0} +\ProduceFile{myfile} +\begin{code} +\def\foo{% +\end{code} + +\ProduceFile{myotherfile} +\begin{code} +\relax +\end{code} + +\ProduceFile{myfile} +\begin{code} + FOO} +\end{code} +\end{ex0} + +\begin{ex1} +\def\foo{% + FOO}\end{ex1} + +\noindent will write \fbox{\parbox{2cm}\CodeInput} to "myfile" and +"\relax" to "myotherfile". This might not be very good practice, +but who knows? that might be useful when building a complicated package. + +But \TeX\ cannot keep open as many files as one wants. Actually, \CD\ +will start complaining when more than 16 files are simultaneously in +production. "\CloseFile" is used to close those whose production is +over and allocate their streams to new files.\cox(240,4pt,12pt,Do files flow?) + +\DescribeEnvironment{code} +This is the basic environment that writes its content to an external +file in produce mode or displays it verbatim in the documentation in +normal mode. There is nothing much to say. Each line is numbered, +as one generally wants the implementation of a code to be. One important +thing is that everything on the line after "\begin{code}" will be gobbled. +"\end{code}" can appear wherever you want. + +\DescribeMacro{\CodeFont\marg{Font specifications}} +The font of the "code" environment may be changed with "\CodeFont" +(by default, it's "\ttfamily"). Since everything is in a group, +you can use `spreading commands'. + +\DescribeMacro{\LineNumber\{code\}\marg{Font specifications}\marg{Width}\oarg{Number}} +This sets the style of the line number, the width of the box it is put in (by default, +it's "0pt", so numbers are in the left margin), and the starting value. The first argument +is "code" and not \meta{code}, because "\LineNumber" is a macro that applies to +all "example" environments (see the next section), and its first argument is the name +of the environment to modify. By default, "code" is not an "example" environment (although +it might be redefined as such) but this command is nonetheless available. + +\trycolorfalse +\let\incolor\redcolor \let\outcolor\yellowcolor \let\filcolor\bluecolor +\begin{sidebyside} +\CodeFont{\color{red}\itshape} +\LineNumber{code}{\ttfamily\footnotesize¨\color{green}}{2cm}[25] +\begin{code} This will be gobbled +\def\foo{% + FOO} +\end{code} +\end{sidebyside} + +\noindent Note that "\LineNumber" inherits the specification of "\CodeFont" that it +doesn't override, in this example the italic shape. The "\color" command does \emph{not} +belong to \CD, but to the \textsf{xcolor} package. If you want to do really interesting +things with "code", it is better to redefine it as an "example" (see next section). + +As usual with "verbatim" environments, there exists a starred version of "code" +that shows spaces. + +\DescribeEnvironment{invisible} +In normal mode, everything in a "invisible" environment is skipped. In produce mode, +however, the material is written to the file in production. This is useful to +write code you don't want to comment in the documentation, like specifications +at the beginning of the file or repetitive macro definitions. As you might imagine, +there is no starred variant. + +\DescribeMacro{\Header\marg{Text}} +In produce mode, unless the "noheader" option is on, \CD\ writes the following at the +beginning of every file: + +\begin{ex1} +% This is §meta¤\FileName£, produced by the CodeDoc class +% with the `produce' option on. +% +% To create the documentation, compile §meta¤jobname.tex£ +% without the `produce' option. +% +% SOURCE: §meta¤File (\input in File...)£ +% DATE: §meta¤\FileDate£ +% VERSION: §meta¤\FileVersion£ +\end{ex1} +\CodeInput + +\noindent where "\FileName", "\FileDate" and "\FileVersion" are set by "\ProduceFile". +The `"\input in file"' part is optional and recursive, depending on files "\input" in +your document. With "\Header", you can change this and print \meta{Text} instead. +In \meta{Text}, ends of line are obeyed, and a comment sign followed by a space +will start every line. Comment signs are normal sign. +"\Header" should appear before "\ProduceFile". + +\DescribeMacro{\AddBlankLine} +In produce mode, \CD\ writes a blank line to the file under production. Useful +to delimit macros. + +\DescribeMacro{\TabSize\marg{Number}} +This is the number of spaces by which a tabulation will be represented in verbatim +context. Default is~2. In produce mode, however, tabs are written as tabs, so this +parameter has no effect. + +\DescribeMacro{\Gobble\marg{Number}} +The number of characters that will be gobbled at the beginning of each line. This +works both in normal mode and in produce mode. This might be useful to indent code +lines to make them more visible. When gobbling, a tab is considered as a single +character and not as \emph{n} characters, \emph{n} being the value of "\TabSize". + +A totally blank line is written as a totally blank line in both modes, i.e. \CD\ +does not fill its need for gobbled characters on the next line. The "\end{code}" +line doesn't need to be indented, although it can be. If there are more characters +than the value of "\Gobble" before "\end{code}", then a new line is created. + +\LineNumber{code}{\ttfamily\footnotesize}{1em}[1] +\CodeFont{\ttfamily} +\begin{sidebyside*} +\TabSize{3} +\Gobble{2} +§bgroup§InvisibleSpace§cdcomment¤My own value for \TabSize is 2, +hence the 2-space tab here, +but in the right panel it's 3£§egroup +\begin{code*} +12\foo \foo + +12\foo \foo +\end{code*} +\end{sidebyside*} + +\DescribeMacro{\BoxTolerance\marg{Dimension}} +Verbatim lines often go into the right margin. This is the threshold above +which \TeX\ reports an overfull box. Default is 0pt. + + + + +\subsection{Macros to describe macros} + +Most of the commands in this section are similar to those in \textsf{DocStrip}. +\CD\ has an indexing mechanism that simply uses \textsf{MakeIndex}; if the "index" option +is on, the "makeidx" package is loaded and "\makeindex" is executed. This also +means that "\printindex" is available. \CD\ does not require a special style file +for \textsf{MakeIndex}. Thus, users can compile a documentation made with \CD\ +with \textsf{MakeIndex}'s default specifications. + +\let\PrintMacro\TwoMac + +\macrotopskip +\DescribeMacro{\DescribeMacro\marg{Macro}} +\DescribeMacro{\DefineMacro\marg{Macro}} +\noindent These commands print their argument according to "\PrintMacro" (see below). +The first token is "\stri§-ng"'ed,% +\footnote{Verbatim text does not break by itself. I've used \texttt{\bslash VerbCommand} +here (see below) to include a discretionary.} +so it can be a control sequence. They also create +an index entry with the first token, and here lies their difference: they print the +page number differently to distinguish whether a macro is described or defined (in the +implementation). By default "described" macros have normal page numbers while +"defined" macros have theirs in italics. This is not conventional, I agree, but +it can be changed.\footnote{Since \CD\ doesn't index macros when \emph{used} in the +code, I've found this choice more readable.} + +\macrotopskip +\DescribeMacro{\DescribeEnvironment\marg{Environment}}\nobreak +\DescribeMacro{\DefineEnvironment\marg{Environment}}\nobreak +\noindent This is similar to the "macro" version above, except that the entry is followed +by `(environment)' in the index. + +\macrotopskip +\DescribeMacro{\DescribeIndexFont\marg{Font specifications}} +\DescribeMacro{\DefineIndexFont\marg{Font specifications}} +\noindent This sets how the page numbers are printed for "described" and "defined" macros +(and environments) respectively.\cox[6pt](110,6cm,40pt,Don't you find these\\names confusing?) +\marg{Font specifications} should be commands like "\ttfamily" and not argument-taking +commands like "\texttt". You know that if you use \textsf{MakeIndex}. + +\let\PrintMacro\OneMac +\DescribeMacro{\PrintMacro\marg{Macro or environment}} +This is the command that typeset the ("\string"'ed) macro. It takes one argument. +It is shown here not to use it as is but to redefine it. Its default definition is: + +\csize8cm +\begin{ex0} +\def\PrintMacro#1{% + \noindent% + \marginpar{\raggedleft\strut\ttfamily#1}% + \ignorespaces} +\end{ex0} + +\noindent That is, it puts the macro in the margin. (Obviously, it was redefined in this documentation.) +To achieve the same effect as with \textsf{DocStrip}, the following command is needed. + +\DescribeMacro\DocStripMarginpar +This reverses marginpar and sets the right value for "\marginparpush" and "\marginparwidth". +They weren't included by default because you have the right to do what you want +with your margins. + +\DescribeMacro{\IgnorePrefix\marg{Macro prefix}} +Many package and class authors prefix their internal commands with a string +of letters to avoid clashes with other packages. For instance, if one writes +a package "mypack", one may name all internal commands "\mp@foo", "\mp@boo", +"\mp@moo", etc. Unfortunately, when indexed, they will all end up in the `M' +letter, whereas one might want to have them sorted without the prefix, +with "\mp@foo" indexed as if it was "\foo", etc. This is what "\IgnorePrefix" +does; when sorting entries produced by "\DescribeMacro" and "\DefineMacro", +\meta{Macro prefix} is ignored, although it is printed of course as part +of the name. In our example, one would say "\IgnorePrefix{mp@}". +This command has two restrictions: first, \meta{Macro prefix} should be +no more than 8 characters long; second, any macro described with +"\DescribeMacro" or "\DefineMacro" should have as many characters as +"\IgnorePrefix", 3 in our example. A simple way to circumvent the latter +shortcoming is to temporarily define \meta{Macro prefix} as an empty string: + +\csize9cm +\begin{ex0} +\IgnorePrefix{mp@} +\DefineMacro\mp@foo §cdcomment¤Will be indexed as \foo£ + +\DefineMacro\fo §cdcomment¤This will cause an error message£ + +\IgnorePrefix{} +\DefineMacro\fo §cdcomment¤This is perfectly ok£ +\IgnorePrefix{mp@} +\end{ex0} + +\noindent You can have several "\IgnorePrefix" specifications, they +are effective for the macros that follow them. For instance, some +macros in \CD\ are prefixed with "cd@@", and when I define them +in this documentation I specify "\IgnorePrefix{cd@@}" and then +immediately "\IgnorePrefix{cd@}", which is the normal prefix. + +\DescribeMacro{\PrintPrefix\marg{Macro prefix}} +Like "\PrintMacro", this command is not shown here to be used but +to be redefined. It is put just before \meta{Macro prefix} when +printing the index, so that you can typeset it differently. For +instance, most \CD's internal macros are prefixed with "cd@". +I have specified "\IgnorePrefix{cd@}" for this documentation +and defined "\PrintPrefix" as "\def\PrintPrefix{\textcolor{gray}}" +so that all prefixes are printed in gray (thanks to the \textsf{xcolor} +package). For instance, "\cd@BadChar" is printed "\"{\color{gray}"cd@"}"BadChar" +in the index (which you can verify if the "obeystop" option is commented out, +thus including the implementation in the documentation). +Obviously, "\def\PrintPrefix#1{\textcolor{gray}{#1}}" would have +been equally efficient. Just note that since "\PrintPrefix" is +"\let" to "\relax" by default, you have to use "\newcommand" +and not "\renewcommand" when defining it for the first time, +in case you prefer \LaTeX's command definitions. + +\let\PrintMacro\TwoMac +\macrotopskip +\DescribeMacro{\meta\marg{Argument}} +\DescribeMacro{\marg\marg{Argument}} +\DescribeMacro{\oarg\marg{Argument}} +\DescribeMacro{\parg\marg{Argument}} +\noindent These are well-known. In case you've forgotten: + +\noindent"\meta{Argument}" $\Rightarrow$ \meta{Argument}\par +\noindent"\marg{Mandatory argument}" $\Rightarrow$ \marg{Mandatory argument}\par +\noindent"\oarg{Optional argument}" $\Rightarrow$ \oarg{Optional argument}\par +\noindent"\parg{Picture argument}" $\Rightarrow$ \parg{Picture argument} + +\let\PrintMacro\OneMac +\DescribeMacro\bslash +Everybody needs a backslash. This one is meant to print +equally well in usual contexts and in PDF bookmarks created +by \textsf{hyperref}, if any. So it can be used in titles +without restriction. + +\DescribeMacro{\StopHere\marg{Code}} +If the "obeystop" command is on, \CD\ will execute \meta{Code} and then "\end{document}", +otherwise nothing happens. +If the "index" option is also on, "\printindex" will be automatically executed after \meta{Code}. +This is useful to let the user print a version of the documentation with some part(s) +left out, typically the implementation. + + +\subsection{Choosing the class} +\CD\ by itself defines nothing that one wants a class to define. It lets the +user call the desired class. To do so, just add the name of the class in the +options of the "\documentclass" declaration. If you want the class to load +options itself, put them after the name of the class, between parenthesis, +and separated by semi-colons. Thus, "\documentclass[memoir]{codedoc}" loads +the \textsf{memoir} class without options while "\documentclass[memoir(a4paper;oneside)]{codedoc}" +loads it with the "a4paper" and "oneside" options.% +\footnote{This means that if you specify an unknown option for +\CD, it will try to load an (probably) unknown class, and you +will get the corresponding error message.} + +By default, \CD\ loads the \textsf{article} class without options. + + + + + + + +\subsection{Dangerous strings}\label{dangerous} +In produce mode, \CD\ becomes a string tester and nothing else.\cox(160,-5cm,30pt,\hskip-10pt Daaaaaaangerouuuuuus...) +Hence, there are strings you don't want it to see because you don't want it to execute +them. For instance, you don't want "\end{document}" to be executed +unless at the end of the document. So when you say "\verb+\end{document}+", +you want \CD\ to identify that "\end{document}" is not for real. +Fortunately, \CD\ does so. To some extent. + +More precisely, \CD\ identifies its own verbatim commands (described in the +next section), \LaTeX's "\verb" and "verbatim" environment, as well as +verbatim environments created with the "fancyvrb" package and the `short +verb' characters defined with "\DefineShortVerb" from the same package. +Thus, you can safely use "fancyvrb" and its companion "fvrb-ex". + +However, "\begin"'s and "\end"'s are not the only strings that must be +used carefully. The most important things you want \CD\ to ignore +in case they shouldn't be executed are its own macros. For instance, you +don't want "\ProduceFile" to be executed when there's no reason to do so. +But, unless you're documenting \CD\ itself, what might be the situation +where "\ProduceFile" is executed wrongly? Simply if you use it in a statement with +"\let", "\def", "\newcommand", etc. In produce mode, \CD\ does not recognizes +these commands and for instance in "\let\ProduceFile\mycommand", "\let" will +be skipped and "\ProduceFile" executed. Hence the following. + +\DescribeMacro{\DangerousEnvironment\marg{List of environments}} +Whenever you want \CD\ to skip an environment in produce mode, for instance +because it's a verbatim environment designed by yourself, you can add +its name to "\DangerousEnvironment". If you add more than one name, +use commas as separators. + +\let\PrintMacro\TwoMac +\macrotopskip +\DescribeMacro{\StartIgnore} +\DescribeMacro{\StopIgnore} +\noindent In produce mode, when \CD\ encouters "\StartIgnore", everything +is skipped until "\StopIgnore" is found. This is useful to hide parts of +your document that are irrelevant to the file you're building in produce +mode (which is probably contained in the `implementation' section). You should +be careful to define your "example" environments and other verbatim devices +outside the skipped material, if you want \CD\ to identify them properly +when it stops ignoring things. + +\csize12cm +\begin{ex0} +\DangerousEnvironment{myenv,myotherenv} +\begin{myenv} +\end{document} §cdcomment¤This will be skipped by §CD£ +\end{myenv} + +\StartIgnore +\let\ProduceFile\myproduce §cdcomment¤This too, but that will be taken into£ + §cdcomment¤account in normal mode£ +\StopIgnore +\end{ex0} + +However, you should be aware of the following points: + +\noindent\llap{\textbullet\ }\emph{Any command that has some effect in produce mode should +appear verbatim in your document}. + +\noindent Conversely, + +\noindent\llap{\textbullet\ }\emph{Commands that have some effect +in produce mode cannot be redefined for that mode}. + +\noindent And when I say `cannot', I mean `you can try, it won't work'. This leads +to the final principle: + +\noindent\llap{\textbullet\ }\emph{You can redefine a command to have the desired effect in normal mode +as long as you respect its arguments, so that it can work properly in produce +mode. And this should be done between} "\StartIgnore" \emph{and} "\StopIgnore"\emph{, of course.} + +For instance, you can say: + +\csize8.8cm +\begin{ex0} +\StartIgnore +\renewcommand\CloseFile[1]{End of #1\clearpage} +\StopIgnore +\end{ex0} + +\noindent and when you say "\CloseFile{myfile}", `"End of myfile"' will be printed to +the documentation, and a new page will be created, while in produce mode \CD\ will +do its usual job. On the other hand, although "\let\cf\CloseFile" is meaningful in +normal mode, in produce mode it won't take effect, i.e. \CD\ won't close anything. +Finally, the previous example would have been catastrophic without "\StartIgnore" +and "\StopIgnore", because in produce mode, \CD\ would have tried to execute "\CloseFile". + +"\StartIgnore" and "\StopIgnore" are also useful to make \CD\ go faster and avoid errors, +if you use it with "\input". For instance, the following file would be perfect, provided +everything that should be written to an external file is contained in "implementation.tex" + +\csize13cm +\begin{ex0} +\documentclass{codedoc} +§cdcomment¤Write your verbatim definitions here, so that §CD§ can see them£ +\begin{document} + +\StartIgnore +\input{documentation} +\StopIgnore +\input{implementation} + +\end{document} + +\end{ex0} + +\noindent This example leads us to the final restriction: + +\noindent\llap{\textbullet\ }\emph{You should use} "\input" \emph{in the \LaTeX's way, i.e.} +"\input{myfile}"\emph{, and not in \TeX's original way, i.e.} "\input myfile"\emph{, +if the file in question is to be read in produce mode.} In the example above, +"documentation" can be "\input" as you want, but "implementation" should be +"\input" as shown. + +To know what commands have some effect in produce mode, see the summary of commands. + + + +\section{Verbatim Madness} +\subsection{Example environments} +\let\PrintMacro\TwoMac +\DescribeEnvironment{example} +\DescribeMacro\CodeInput +\DescribeMacro\CodeOutput +\noindent At first sight, the "example" environment is totally useless. Indeed, the following +code does nothing: + +\csize3cm +\begin{ex0} +\begin{example} +\TeX +\end{example} +\end{ex0} + +\noindent However, it provides two commands "\CodeInput" and "\CodeOuput". The former +prints the code verbatim (and in typewriter font), and the latter executes it. So in the end it's very useful +to document your package or class, because it avoids typing the code twice (and therefore +errors are avoided). + +\begin{sidebyside} +\begin{example} +\TeX +\end{example} +\CodeInput\noindent yields \CodeOutput. +\end{sidebyside} + +The "example" environment is just one instance of a family of environments that you can +create by yourself with the following commands. + +\macrotopskip +\DescribeMacro{\NewExample\oarg{Options}\marg{Name}\marg{Code input}\marg{Code output}\marg{Immediate execution}} +\DescribeMacro{\RenewExample\oarg{Options}\marg{Name}\marg{Code input}\marg{Code output}\marg{Immediate execution}} +\noindent These two macros (whose difference is similar to the one between "\newcommand" and "\renewcommand") +create an environment \meta{Name} that will provide two commands, "\CodeInput" and "\CodeOutput", +whose effect is defined by \meta{Code input} and \meta{Code output}. Moreover, \meta{Name} +will execute \meta{Immediate execution}. + +\meta{Code input} and \meta{Code output} have a peculiar syntax. The code to be processed +is represented by~"#". For instance, the "example" environment is defined as: + +\begin{ex0} +\NewExample{example} §cdcomment¤This is §meta¤Name££ + {\ttfamily#} §cdcomment¤\CodeInput yields but the code in typewriter font£ + {#} §cdcomment¤\CodeOutput simply executes the code£ + {} §cdcomment¤Nothing is done when §emph¤example£ is called£ +\end{ex0} + +You can do whatever you want. The code, represented by "#", may be the argument +of a macro. For instance:\cox(220,0pt,6pt,`Hello, world', what a \emph{clich\'e}!) + +\eTeXOff +\begin{sidebyside} +\NewExample{myex} + {\ttfamily\underline{#}} + {} + {\CodeInput} +\begin{myex} +Hello, world! +\end{myex} +\end{sidebyside} +\eTeXOn + +\noindent What does "myex" do? It sets the verbatim code in typewriter font +and underlines it (which is admittedly not the most interesting thing you can do). +\meta{Code output} is empty, so "\CodeOutput" will yields nothing. Finally, +\meta{Immediate execution} calls "\CodeInput", so there's no need to call it +after the environment. + +The following points apply: + +\noindent\llap{\textbullet\ }All environments thus defined have a starred variant +that shows spaces as characters. + +\noindent\llap{\textbullet\ }"\CodeInput", "\CodeOuput" and \meta{Immediate execution} are +groups, so you can put any command in them, they won't spread. For instance, in +"myex" above, there's no need to add a group to restrict the application +of "\ttfamily". + +\noindent\llap{\textbullet\ }"\CodeOuput" \emph{really} executes your code. Any error +will appear as such. + +\noindent\llap{\textbullet\ }Since "\CodeOuput" is a group, the definition you make +won't work for the rest of your document, unless you make them global. For instance: + +\csize5cm +\begin{ex0} +\NewExample{myex}{}{#}{} + +\begin{myex} +\def\foo{FOO!} +\end{myex} + +\CodeOutput +\foo +\end{ex0} + +\noindent will yield an error message, because "\foo" was only locally defined in +"\CodeOuput". + +\noindent\llap{\textbullet\ }Everything on the same line after the "\begin" statement +of an environment will be gobbled. + +\noindent\llap{\textbullet\ }By default, \CD\ does not add any space or "\par" before +"\CodeInput", "\CodeOuput" and \meta{Immediate execution}. A "\par" is added after +"\CodeInput" if and only if the "\end" statement appears on its own +line. Here's an illustration: + +\begin{sidebyside} +\NewExample{myex}{\ttfamily#}{#}{} +\parindent0pt + +\begin{myex} +\TeX +\end{myex} ++\CodeInput+ yields +\CodeOutput+ + +\vskip1em +\begin{myex} +\TeX\end{myex} ++\CodeInput+ yields +\CodeOutput+ +\end{sidebyside} + +\noindent\llap{\textbullet\ }The "code" environment can be freely redefined as an +example environment. + +\noindent\llap{\textbullet\ }All example environments obey "\TabSize" and "\Gobble" +as defined in the previous section, as well as "\LineNumber" if they are numbered +(see below). See the description of "\eTeXOff" and "\eTeXOn" below for a comment +on "\Gobble". + +\meta{Options} may be one or several of the following (separated by commas): + +\noindent\textcolor{\maccolor}{\texttt{numbered}}\par +\noindent Each line of "\CodeInput" is numbered. The count starts back to 1 at +each occurrence of the environment. + +\noindent\textcolor{\maccolor}{\texttt{continuous}}\par +\noindent Each line of "\CodeInput" is numbered. The count starts where the +last occurrence of the same environment left. As an (utterly boring) example:\nobreak + +\trycolorfalse\let\incolor\yellowcolor \let\outcolor\bluecolor \let\filcolor\redcolor +\begin{sidebyside} +\NewExample[numbered]{myex1}{\ttfamily#}¨ {}{\CodeInput} +\LineNumber{myex1}{\itshape}{1em} +\NewExample[continuous]{myex2}{\ttfamily¨ \color{red}#}{}{\CodeInput} +\LineNumber{myex2}{\itshape}{2em} +\begin{myex2} +First line +Second line +\end{myex2} +\begin{myex1} +First line +Second line +\end{myex1} +\begin{myex2} +Third line +Fourth line +\end{myex2} +\end{sidebyside} + +\noindent\textcolor{\maccolor}{\texttt{visibleEOL}}\label{visibleEOL}\par\nobreak +\noindent This is more complicated and requires some knowledge of how \CD\ +builds examples. + +Although you might not know it, your \TeX\ distribution is very probably running +on \eTeX. That's the reason why \CD\ can process some code verbatim +and executes it at the same time, as in the example environments, without the need +for an external file. This is completely impossible with the original implementation of \TeX. +If, for some reason, you don't have \eTeX, or you're not running on it, +then \CD\ will use an external file. + +However, \eTeX's `virtual external file' mechanism is not perfect, and +\CD\ has to cope with it. What happens is that when you use "\CodeOutput", \CD\ +hacks your code a little in order to simulate a real \TeX\ code; namely, before +anything is processed, \CD\ removes ends of lines and commented parts of lines. +For instance, if you say: + +\csize2cm +\begin{ex0} +\def\foo{% + FOO!} +\foo +\end{ex0} + +\noindent what \CD\ really processes with "\CodeInput" is \verb*"\def\foo{FOO!} \foo". +Most of the time, that's exactly what you want. But it might happen that you're +toying around with ends of lines or comment characters, and in that case everything +will go wrong, as in: + +\csize4cm +\begin{ex0} +\catcode`\%=12 +I'm writing a % sign. +\end{ex0} + +\noindent This\cox(290,-1.8cm,.5cm,\hskip-1.2cm*\emph{SIGH}*) will \emph{not} produce `I'm writing a \% sign', because \CD\ will remove +everything from the comment sign to the end of the line, so that what "\CodeOuput" +will try to execute is: + +\csize2.5cm +\begin{ex0} +\catcode`\ +I'm writing a +\end{ex0} + +\noindent and of course the aborted "\catcode" declaration will yield an error message. +To avoid this problem, the "visibleEOL" option makes \CD\ keeps everything. But now +there's another issue: comments and end of line characters are processed at the same +time as other macros and aren't interpreted independantly as in normal \TeX. +For instance, the following code, if the "visibleEOL" option is on for the environment +in question, will apply "\emph" to the end of line character and not to "A". + +\csize1.5cm +\begin{ex0} +\emph +A +\end{ex0} + +\noindent So you should be sure that comments and line ends occur where they won't hinder anything. +If you find this utterly complicated, then you can use an external file whenever you're +hacking ends of line, thanks to the following two macros. + +\macrotopskip +\DescribeMacro{\eTeXOff} +\DescribeMacro{\eTeXOn} +\noindent The former makes \CD\ process all examples environments with an external file +(whose extension is~".exp"). +The latter makes everything back to normal. If "\eTeXOff" applies, the "visibleEOL" option +is of course irrelevant. Note that these two macros apply to examples that follow them +and not to example definitions. For instance, "\eTeXOff" and then "\NewExample{myex}{#}{}{}" +will not lead \CD\ to use an external file whenever "myex" is called, but simply as long +as no "\eTeXOn" appears. To put simply, these two macros have no effect on "\NewExample". + +If "\Gobble" is positive, examples with \eTeX\ and examples without behave differently. +The latter gobble characters before writing to the external file. Thus, "\CodeOutput" +will execute line with the first characters gobbled. With \eTeX, however, nothing +is gobbled in "\CodeOutput". This means that first characters, if meant to be +gobbled, will be executed. Most of the time, such characters are spaces, +and the difference won't be noticed. If, for some reason, you use other +characters instead, and if you want to call "\CodeOutput" nonetheless, then +a switch to an external file may be a good idea. + + + + + +\subsection{\texttt{\bslash ShortVerb} and friends} + +\CD\ provides a number of facilities to act on verbatim contexts. They +declare one or more character(s) to have a special effect under certain +circumstances. + +\macrotopskip +\DescribeMacro{\ShortVerb\marg{Character}} +\DescribeMacro\UndoShortVerb +\noindent This is well-known. \meta{Character} is turned into a shorthand +for "\verb". You can define only one such character, and that's why "\UndoShortVerb" +doesn't take an argument (like all "\Undo..." below). In \CD\ verbatim contexts, this character returns +to its normal value. + +\UndoShortVerb +\begin{sidebyside} +\ShortVerb{*} +The command *\TeX* gives \TeX. + +\begin{example} +And the star appeared:* +\end{example}\CodeInput +\end{sidebyside} +\ShortVerb" + +\DescribeMacro{\ShortCode\oarg{Example name}\marg{Character}} +\DescribeMacro\UndoShortCode +\noindent This turns \meta{Character} into an equivalent of "\begin{code}" +and "\end{code}". In normal mode, the verbatim material will be printed +according to \meta{Example name}'s specifications. If this optional +argument is not present, then "\ShortCode" will follow "code"'s style. +Most importantly, in produce mode everything between two \meta{Characters} +will be written to the file under production. + +\begin{sidebyside} +\RenewExample[continuous]{code}¨{\itshape\ttfamily#}{}{\CodeInput} +\LineNumber{code}{\small\rmfamily}{1em} +\ShortCode+ §cdcomment¤Oh yeah, braces are never£ + §cdcomment¤needed...£ + +\begin{code} +Here it's +normal+ +\end{code} + ++ +Here it writes code... ++ +\end{sidebyside} + +"\ShortVerb" and "\ShortCode" have one caveat. If you "\Undo..." +them and the next character (disregarding spaces, comments and +ends of lines) is a short verb or a short code respectively, +in produce mode it will fire as if it was still active. A pair +of braces after the "\Undo..." statement prevents this. + +\macrotopskip +\DescribeMacro{\VerbBreak\marg{Character}} +\DescribeMacro\UndoVerbBreak +\noindent Every once in a while, breaking a verbatim line may be +useful. In verbatim contexts, \meta{Character} breaks the line, +creates an unnumbered new one and indents it to the indentation of +the original line. When "\CodeOutput" is processed, the "\VerbBreak" +character is ignored. However, you should not break in the middle of +a control sequence (admittingly a strange idea), or it won't form. +It is also ignored, of course, when writing to a file in produce mode. + +\UndoVerbBreak +\begin{sidebyside} +\VerbBreak{\=} §cdcomment¤An escape character is ok£ +\begin{example*} +\TeX + \emph=\TeX +\end{example*}\CodeInput + +And the result is: \CodeOutput +\end{sidebyside} +\VerbBreak¨ + +\DescribeMacro{\VerbCommand\marg{Escape}\marg{Left brace}\marg{Right brace}} +\DescribeMacro\UndoVerbCommand +\noindent In verbatim contexts, those three characters will serve to form control sequences. +In "\CodeOuput" and produce mode, they are ignored. More specifically, \meta{Escape} +gobbles all letters following it (forming a putative command name) while everything +vanishes that appears between \meta{Left brace} and \meta{Right brace}. This is +not a very sound device, and above all you should add a \meta{Left brace}-\meta{Right brace} +pair after a command called with \meta{Escape}, if it precedes a command to be executed +in "\CodeOutput". That is, suppose "\VerbCommand{!}{(}{)}", then "!foo\foo" is a very +bad idea in your code, \cox[6pt](70,3cm,0pt,Mind my word,\\don't use it)while "!foo()\foo" is ok. +All the comments in the examples here are done with "\VerbCommand". + +Since numbered examples environment define the current label to be the number +of the current line, an interesting application is to use "\label" to refer to it. + + + + +\UndoVerbCommand +\begin{sidebyside} +\VerbCommand!() + +(Everything is normal here!) +\RenewExample[numbered]{example}¨{\ttfamily#}{#}{} +\LineNumber{example}{}{1cm} + +\begin{example} +\TeX !underline(\Tex!TeX) +%Second line !label(myline) +\end{example} + +\CodeInput + +gives \CodeOutput and the label is ¨on line \ref{myline}. +\end{sidebyside} +\VerbCommand§¤£ + + +\DescribeMacro{\CodeEscape\marg{Character}}\label{CodeEscape} +\DescribeMacro\UndoCodeEscape +In normal mode, this command does absolutely nothing. However, in produce +mode, \meta{Character} becomes an escape character to form control sequences +that will be expanded when writing to the file under production. It's useful +mainly to put the values defined by "\ProduceFile" somewhere in your file. For +instance, the following code + +\trycolorfalse\let\incolor\redcolor +\csize15cm +\begin{ex0} +\CodeEscape! +\ProduceFile{mypack.sty}[mypack][v.2.1][2009/02/24] + +\begin{code} +\ProvidesPackage{!FileName}[!FileDate!space !FileVersion!space My super package.] +\end{code} +\end{ex0} + +\noindent\cox(210,14cm,3.5cm,invisible...) will write "\ProvidesPackage{mypack}[2009/02/24 v.2.1 My super package.]" +to "mypack.sty". + + +\subsection{Using \textsf{fancyvrb}} +\CD\ is minimally compatible with \textsf{fancyvrb}, in the sense that +verbatim characters defined and undefined with "\DefineShortVerb" +and "\UndefineShortVerb" are recognized in produce mode (hopefully). Besides, verbatim environments +defined with "\DefineVerbatimEnvironment" are automatically added to the list +of dangerous environments. The environments offered by \textsf{fancyvrb} and +the \textsf{fvrb-ex} companion package already belong to that list. + +You can even redefine the "code" environment with \textsf{fancyvrb} facilities.\footnote{% +It will indeed add \texttt{code} to the list of dangerous environment, which is already +the case when \texttt{code} is redefined with \texttt{$\backslash$RenewExample}. But \CD\ evaluates +whether an environment is \texttt{code} before checking the list of dangerous environments.} +However: + +\noindent\llap{\textbullet\ }"\ShortCode" will stick to the last style defined +for "code" (if it is set to follow this environment). + +\noindent\llap{\textbullet\ }Since everything is gobbled after "\begin{code}" +in produce mode, you can freely put your \textsf{keyval} pairs here, as usual +with \textsf{fancyvrb}. However, \emph{you should not input these pairs on +the following line(s)}, although it's ok with \textsf{fancyvrb}. The following +code will lead "xleftmargin=1cm]" to be written on the file under production. + + +\csize5cm +\begin{ex0} +\begin{code}[frame=single, +xleftmargin=1cm] +\def\foo{FOO} +\end{code} +\end{ex0} + +\noindent\llap{\textbullet\ }The "gobble" and "commandchars" parameters will +be obeyed in normal mode (since \textsf{fancyvrb} is in charge), but \emph{not +in produce mode, unless you also specify the} "\Gobble" \emph{and} +"\VerbCommand" \emph{parameters (see above) accordingly}. + + + +\section{Summary of commands} + +In this section I explain the behavior of all \CD\ constructions in normal and +produce mode respectively. Commands which have some effect in produce mode are +subject to the restrictions given in section~\ref{dangerous}. + +\newcommand\NM{\textbf{Normal Mode: }} +\newcommand\PM{\par\noindent\bgroup\def\par{\egroup\endgraf}\itshape\textbf{Produce Mode: }} +\newcommand\NMX{\textbf{Normal Mode: }Does nothing.\par} +\newcommand\PMX{\par\noindent\textit{\textbf{Produce Mode: }Does nothing.}\par} +\let\PrintMacro\OneMac\let\macrotopskip\relax +\small + +\subsection{Class options} + +\PrintMacro{autoclose} +\NMX +\PM The current file is closed when a new one is opened with "\ProduceFile". + +\PrintMacro{index} +\NM Loads \textsf{makeidx} and calls "\makeindex". "\StopHere" automatically +launches "\printindex". +\PMX + +\PrintMacro{noheader} +\NMX +\PM No header is written to the file when it is opened. + +\PrintMacro{obeystop} +\NM The document stops at "\StopHere"\marg{Code} and executes +\meta{Code}. If the "index" option is on, "\printindex" is +executed after \meta{Code}. +\PMX + +\PrintMacro{tracing0, tracing1, tracing2} +\NMX +\PM \CD\ normally writes a report to the log file. If "tracing0" +is on, there's no report; if "tracing1" is on (which is default), +\CD\ reports only about opening files and writing code. With +"tracing2", it also reports about characters defined as +"\ShortVerb" or "\CodeEscape", environments added to the +list of dangerous environments, etc. + +\subsection{Environments} + + +\DescribeEnvironment{code} +\NM The content is displayed verbatim according to the style +defined for "code". +\PM The content is written to the file in production. + +\DescribeEnvironment{example} +\NM A minimal example environment that provides "\CodeInput" +(in typewriter font) and "\CodeInput". +\PM The content is skipped. + +\DescribeEnvironment{invisible} +\NM The content is skipped. +\PM The content is written to the file in production. + +\subsection{Commands} + +\DescribeMacro\AddBlankLine +\NMX +\PM Adds a blank line to the file in production. + +\DescribeMacro\bslash +\NM Prints \bslash. Designed to adapt to \textsf{hyperref}'s bookmarks. +\PMX + +\DescribeMacro{\BoxTolerance\marg{Dimension}} +\NM Excess size tolerated before a verbatim line is +reported as an overfull box. +\PMX + +\DescribeMacro{\CloseFile\marg{File}} +\NM "\FileName" and others are not available anymore. +\PM Closes \meta{File}. No file is considered in +production until the next "\ProduceFile", even if +there are open files. Useless in "autoclose" mode. + +\DescribeMacro{\CodeEscape\marg{Character}} +\NMX +\PM \meta{Character} turns into an escape character in +"code" contexts. + +\DescribeMacro{\CodeFont\marg{Font specifications}} +\NM The style of the "code" environment if it has not +been redefined with "\RenewExample". Default is +"\ttfamily". +\PMX + +\DescribeMacro\CodeInput +\NM Displays the code of the last example environment +verbatim, according to the style defined for that +environment. +\PMX + +\DescribeMacro\CodeOutput +\NM Executes the code of the last example environment, +according to the style defined for that environment. +\PMX + +\DescribeMacro{\DangerousEnvironment\marg{List of environments}} +\NMX +\PM The environments in the list are skipped during processing. + +\DescribeMacro{\DefineEnvironment\marg{Environment}} +\NM Prints \meta{Environment} according to "\PrintMacro" and adds +it to the index with `(environment)' and a line number typeset +according to "\DefineIndexFont". +\PM Gobbles the first characters of \meta{Environment}, just in case. + +\DescribeMacro{\DefineIndexFont\marg{Font specifications}} +\NM Style of the page number in the index for "\DefineMacro" +and "\DefineEnvironment" entries. +\PMX + +\DescribeMacro{\DefineMacro\marg{Macro}} +\NM Prints \meta{Macro} according to "\PrintMacro" and adds +it to the index with a line number typeset according to "\DefineIndexFont". +\PM Gobbles the first characters of \meta{Macro}, just in case. + +\DescribeMacro{\DescribeEnvironment\marg{Environment}} +\NM Prints \meta{Environment} according to "\PrintMacro" and adds +it to the index with `(environment)' and a line number typeset +according to "\DescribeIndexFont". +\PM Gobbles the first characters of \meta{Environment}, just in case. + +\DescribeMacro{\DescribeIndexFont\marg{Font specifications}} +\NM Style of the page number in the index for "\DescribeMacro" +and "\DescribeEnvironment" entries. +\PMX + +\DescribeMacro{\DescribeMacro\marg{Macro}} +\NM Prints \meta{Macro} according to "\PrintMacro" and adds +it to the index with a line number typeset according to "\DescribeIndexFont". +\PM Gobbles the first characters of \meta{Macro}, just in case. + +\DescribeMacro\DocStripMarginpar +\NM Sets the adequate values for the proper printing of macros +with "\DescribeMacro" and "\DefineMacro" (and variants for environments), +so that they appear "\marginpar"'ed as with \textsf{DocStrip}. +More precisely, it executes "\reversmarginpar", and sets "\marginparpush" +to "0pt" and "\marginparwidth" to "8pc". +\PMX + +\DescribeMacro\eTeXOff +\NM All subsequent example environments are processed with an +external file, whose extension is~".exp". +\PMX + +\DescribeMacro\eTeXOn +\NM All subsequent example environments are processed without an +external file. This is default. (Requires \eTeX, of course.) +\PMX + +\DescribeMacro{\Gobble\marg{Number}} +\NM The number of characters that will be gobbled at the beginning +of each example and code environments. In case of a blank line, nothing +is gobbled, but a blank line is added. Tab characters count as one character. +\PM Same as in normal mode, but when writing to the file in production. + +\DescribeMacro{\Header\marg{Text}} +\NMX +\PM Text to be written at the beginning of a file when it is opened +with "\ProduceFile". Comment characters will be automatically added +at the beginning of each line. Ends of lines are obeyed. If the "noheader" +option is on, nothing is written. + +\DescribeMacro{\IgnorePrefix\marg{Macro prefix}} +\NM Ignores \meta{Macro prefix} when sorting index entries generated +by "\DescribeMacro" and "\DefineMacro". \meta{Macro prefix} will be +typeset according to "\PrintPrefix" in the index. +\PMX + +\DescribeMacro{\LineNumber\marg{Name}\marg{Font specifications}\marg{Width}\oarg{Number}} +\NM The line number of \meta{Name} will be typeset according to +\meta{Font specifications} in a box that will spread from the left\cox(270,-4.5cm,12pt,What???) +margin into the main text width by a length of \meta{Width} (0pt by default). +The next \meta{Name} will start at \meta{Number} if specified. +\PMX + +\DescribeMacro{\marg\marg{Argument}} +\NM "\marg{Argument}" prints \marg{Argument} (mandatory argument). +\PMX + +\DescribeMacro{\meta\marg{Argument}} +\NM "\meta{Argument}" prints \meta{Argument}. +\PMX + +\DescribeMacro{\NewExample\oarg{Options}\marg{Name}\marg{Code input}\marg{Code output}\marg{Immediate execution}} +\NM Creates \meta{Name} as an example environment to provide +"\CodeInput" as \meta{Code input} (where the code to be typeset +is represented by "#") and "\CodeOutput" as \meta{Code output} +(where the code to be executed is represented by "#"). When +encountered, \meta{Name} executes \meta{Immediate execution}. +\meta{Code input}, \meta{Code output} and \meta{Immediate execution} +can be empty.\\ +Options are:\\ +\texttt{numbered:} Each line of \meta{Name} is numbered.\\ +\texttt{continuous:} Each line of \meta{Name} is numbered and numbering +continues from one \meta{Name} to the other.\\ +\texttt{visibleEOL:} If \meta{Name} is processed with \eTeX, +This prevents ends of lines and commented parts of lines from being removed +before anything is executed in "\CodeInput". See page \pageref{visibleEOL} +for a discussion. +\PM Adds \meta{Name} to the list of dangerous environments and gobbles +the remaining arguments. + +\DescribeMacro{\oarg\marg{Argument}} +\NM "\oarg{Argument}" prints \oarg{Argument} (optional argument). +\PMX + +\DescribeMacro{\parg\marg{Argument}} +\NM "\parg{Argument}" prints \parg{Argument} (picture argument). +\PMX + +\DescribeMacro{\PrintMacro\marg{Macro or environment}} +\NM Typesets the argument to "\DescribeMacro", "\DefineMacro", +"\DescribeEnvironment" and "\Defi§-neEnvironment". Should be freely +redefined by users. By default, it prints its argument as with +\textsf{DocStrip}, provided "\DocStripMarginpar" has been executed +beforehand. +\PMX + +\DescribeMacro{\PrintPrefix\marg{Macro prefix}} +\NM Typesets \meta{Macro prefix}, as defined by "\IgnorePrefix", +in the index. +Should be redefined by the user. By default, it does nothing. +\PMX + +\DescribeMacro{\ProduceFile\marg{File}\oarg{File name}\oarg{File version}\oarg{File date}} +\NM Provides \meta{File} as "\FileSource", \meta{File name} as "\FileName", +\meta{File version} as "\FileVersion" and \meta{File date} as "\FileDate". +\PM Opens \meta{File} and writes the header (unless "noheader" is on), +unless \meta{File} is already open and "autoclose" is not specified, in +which case \CD\ will simply puts \meta{File} back in production. Subsequent code +will be written to this file. Closes the current file if "autoclose" is on. +Provides \meta{File name} as "\FileName", +\meta{File version} as "\FileVersion" and \meta{File date} as "\FileDate", +to be used with "\CodeEscape". + +\DescribeMacro{\RenewExample\oarg{Options}\marg{Name}\marg{Code input}\marg{Code output}\marg{Immediate execution}} +\NM Same as "\NewExample" to redefine \meta{Name}. +\PM Adds \meta{Name} to the list of dangerous environments and gobbles +the remaining arguments. + +\DescribeMacro{\ShortCode\marg{Character}} +\NM Turns \meta{Character} into a shorthand for "\begin{document}" +and "\end{document}". +\PM Like in normal mode: everything between two \meta{Characters} +will be written to the file in production. + +\DescribeMacro{\ShortVerb\marg{Character}} +\NM Turns \meta{Character} into a shorthand for "\verb". +\PM Subsequently gobbles everything between two \meta{Characters}. + +\DescribeMacro\StartIgnore +\NMX +\PM Stops executing anything until "\StopIgnore". + +\DescribeMacro{\StopHere\marg{Code}} +\NM If the "obeystop" option is on, executes +\meta{Code} followed by "\printindex" if "index" is on, and +ends the document. +\PMX + +\DescribeMacro\StopIgnore +\NMX +\PM Marks the end of "\StartIgnore". + +\DescribeMacro{\TabSize\marg{Number}} +\NM Sets the number of spaces to represent a tab character +in verbatim contexts. +\PMX + +\DescribeMacro\UndoCodeEscape +\NMX +\PM Sets the "\CodeEscape" character to a normal character. + +\DescribeMacro\UndoShortCode +\NM Sets the "\ShortCode" character to a normal character. +\PM Sets the "\ShortCode" character to a normal character. + +\DescribeMacro\UndoShortVerb +\NM Sets the "\ShortVerb" character to a normal character. +\PM Sets the "\ShortVerb" character to a normal character. + +\DescribeMacro\UndoVerbBreak +\NM Sets the "\VerbBreak" character to a normal character. +\PM Sets the "\VerbBreak" character to a normal character. + +\DescribeMacro\UndoVerbCommand +\NM Sets the "\VerbCommand" characters to normal characters. +\PM Sets the "\VerbCommand" character to normal characters. + +\DescribeMacro{\VerbBreak\marg{Character}} +\NM Turns \meta{Character} into a line breaker in verbatim +contexts; more precisely, the line will break where \meta{Character} +appears and will be indented with the same amount of space as the +original one. \meta{Character} is ignored in "\CodeOutput". +\PM Ignores \meta{Character} when writing to the file in production. + +\DescribeMacro{\VerbCommand\marg{Escape}\marg{Left brace}\marg{Right brace}} +\NM Turns \meta{Escape} into an escape character in verbatim contexts, +and \meta{Left brace} and \meta{Right brace} into characters of category +1 and 2 respectively. In "\CodeOutput", \meta{Escape} gobbles all subsequent +letters and everything between \meta{Left brace} and \meta{Right brace} +is gobbled too. +\PM Does the same as normal mode for "\CodeOutput". Letters following +\meta{Escape} are gobbled, as is everything between \meta{Left brace} +and \meta{Right brace}. + +\normalsize +\StopHere{% +\def\section*#1{\part{#1} +\itshape +This index was generated by the \emph{\texttt{\bslash DescribeMacro}}-like +commands. It only reports where macros are described (page numbers in +normal font) and defined (page numbers in italics). +In the current version, \CD\ does not index macros when used in the code. + +Entries are sorted ignoring the \emph{\texttt{cd@}} and \emph{\texttt{cd@@}} prefixes.\vskip1em}% +\catcode`\Z=0\relax% +\let\partname\relax% +\let\thepart\relax} + +\part{Implementation} +\newskip\codeskip +\newskip\printskip +\codeskip=2cm +\newskip\boxskip +\boxskip=2cm +\RenewExample[continuous]{code}% + {\let\noindent\relax\color{\maccolor}\ttfamily\small#}{}% + {\par\leftskip\codeskip\vskip.5em\CodeInput\vskip.5em\goodbreak} +\LineNumber{code}{\footnotesize\rmfamily}{0pt}[1] +\DocStripMarginpar +\def\PrintMacro#1{% + \noindent% + \marginpar{% + \raggedleft\strut\ttfamily\small\hbox to\boxskip{% + \printskip\codeskip% + \advance\printskip1.6cm% + \hbox to\printskip{\hfil#1}\hss}}\ignorespaces} +\everypar{\hangindent\codeskip\hangafter0\relax} +\ShortCode/ +\BoxTolerance{10cm} +\let\Section\section +\let\Subsection\subsection +\let\Subsubsection\subsubsection +\def\section#1{\Section{#1}\everypar{\hangindent\codeskip\hangafter0\relax}\noindent\ignorespaces} +\def\subsection#1{\Subsection{#1}\everypar{\hangindent\codeskip\hangafter0\relax}\noindent\ignorespaces} +\def\subsubsection#1{\Subsubsection{#1}\everypar{\hangindent\codeskip\hangafter0\relax}\noindent\ignorespaces} + +\noindent The usual things (";" is my "\CodeEscape" character). Turning "^^?" into +an active character is less usual but useful to delimit ends of code material. +\CodeEscape; + + + +/ +\NeedsTeXFormat{LaTeX2e} +\ProvidesClass{;FileName}[;FileDate ;FileVersion Code and documentation in one file.] +\makeatletter +\catcode`\^^?=13 +/\AddBlankLine +\UndoCodeEscape + + +\section{Options and basic definitions} +\DefineMacro\cd@GetClass +Options are mostly conditional switching. "\cd@tracingmode" will +be used in an "\ifcase" statement. "\cd@GetClass" will be analyzed +to retrieve the class and its options. + + +/ +\newif\ifcd@produce +\newif\ifcd@autoclose +\newif\ifcd@obeystop +\newif\ifcd@makeindex +\newif\ifcd@noheader +\newcount\cd@tracingmode +\cd@tracingmode1 +\def\cd@GetClass{article()} + +\DeclareOption{autoclose}{\cd@autoclosetrue} +\DeclareOption{produce}{\cd@producetrue} +\DeclareOption{index}{\cd@makeindextrue} +\DeclareOption{obeystop}{\cd@obeystoptrue} +\DeclareOption{noheader}{\cd@noheadertrue} +\DeclareOption{tracing0}{\cd@tracingmode0} +\DeclareOption{tracing1}{\cd@tracingmode1} +\DeclareOption{tracing2}{\cd@tracingmode2} +\DeclareOption*{\edef\cd@GetClass{\CurrentOption()}} +\ProcessOptions\relax +/\AddBlankLine + + + +\DefineMacro\cd@end +\DefineMacro\cd@LoadClass +\DefineMacro\cd@GetOptions +We define "\cd@LoadClass" as a recursive retrieval of options, +then passed to the class with "\PassOptionsToClass", which we load. +This is done only if we're not in produce mode, in which case no +class is loaded. +/ +\def\cd@end{cd@end} +\ifcd@produce +\else +\def\cd@LoadClass#1(#2){% + \def\cd@Class{#1} + \expandafter\cd@GetOptions#2;cd@end;% + \LoadClass{#1}% + \@ifnextchar({\expandafter\@gobble\@gobble}{}} +\def\cd@GetOptions#1;{% + \def\cd@TempArg{#1} + \ifx\cd@TempArg\cd@end% + \let\cd@next\relax + \else% + \PassOptionsToClass{#1}{\cd@Class}% + \let\cd@next\cd@GetOptions% + \fi\cd@next} +\expandafter\cd@LoadClass\cd@GetClass +/\AddBlankLine + +\DefineMacro\StopHere +Still in normal mode, we load \textsf{makeidx} if required +and define "\StopHere" accordingly. +/ +\ifcd@makeindex + \RequirePackage{makeidx} + \makeindex +\else + \let\printindex\relax +\fi +\ifcd@obeystop + \ifcd@makeindex + \long\def\StopHere#1{#1\relax\par\printindex\end{document}} + \else + \long\def\StopHere#1{#1\relax\par\end{document}} + \fi +\else + \long\def\StopHere#1{} +\fi +\fi +/\AddBlankLine + +\section{Normal mode} +Although the following code is used in normal mode only, +I did not feel like embedding hundreds of lines under a "\ifcd@produce" +conditional. Pure superstition, perhaps. + +Here's the switch for \eTeX\ and some shorthands. +/ +\newif\ifcd@eTeX +\@ifundefined{eTeXversion}{\cd@eTeXfalse}{\cd@eTeXtrue} + +\def\cd@Warning{\ClassWarningNoLine{codedoc}} +\def\cd@Error#1{\ClassError{codedoc}{#1}{}} +/\AddBlankLine + +\subsection{Describing macros} + +\DefineMacro\DocStripMarginpar +\DefineMacro\PrintMacro +Most of the following macros are imitated from \textsf{DocStrip}, +in a simpler but less careful manner. The first two are straightforward. +/ +\def\DocStripMarginpar{\reversemarginpar\marginparpush0pt\relax\marginparwidth8pc\relax} +\def\PrintMacro#1{\noindent\marginpar{\raggedleft\strut\ttfamily#1}\ignorespaces} +/\AddBlankLine + +\DefineMacro\DescribeIndexFont +\DefineMacro\DescribeMacro +\DefineMacro\cd@DescribeMacro +\DefineMacro\DescribeEnvironment +\DefineMacro\cd@DescribeEnvironment + +\DefineMacro\DefineIndexFont +\DefineMacro\DefineMacro +\DefineMacro\cd@DefineMacro +\DefineMacro\DefineEnvironment +\DefineMacro\cd@DefineEnvironment +\vskip-24pt\noindent"\DescribeMacro" and its companions first turn "@" into a letter, +so that a control sequence containing it is recognized as such, +sets "\cd@Index", used in the "\ifcase" statement below (a simple +conditional could do the job, since there are only two values, +but there might be more someday if one wants to distinguish +other index entries, like `used' macros), and pass their +arguments to "\PrintMacro" with the first token "\string"'ed +(even in the case of an environment, because someone might +describe its environment with a "\begin{myenv}" command). +In case of a macro, the argument is also passed to "\cd@MakeEntry" +to index it. + +The \textsf{hyperref} package does not work properly with indexes +if a style is specified with "|" in the entry. Since we use such +styles, and since we want to use \textsf{hyperref}, we circumvent +the problem with "\hyperpage" added to the style. By default, it +does nothing, but if the user loads \textsf{hyperref}, it will +have the adequate meaning. +/ +\newcount\cd@Index +\def\hyperpage#1{#1} + +\def\DescribeIndexFont#1{\gdef\cdatDescribeFont##1{{#1\hyperpage{##1}}}} +\DescribeIndexFont{} +\def\DescribeMacro{\makeatletter\cd@DescribeMacro} +\def\cd@DescribeMacro#1{% + \makeatother% + \cd@Index=0 % + \cd@MakeEntry#1\cd@EndOfEntry% + \PrintMacro{\string#1}} +\def\DescribeEnvironment{\makeatletter\cd@DescribeEnvironment} +\def\cd@DescribeEnvironment#1{% + \makeatother% + \index{#1@\texttt{#1} (environment)|cdatDescribeFont}% + \PrintMacro{\string#1}} + +\def\DefineIndexFont#1{\gdef\cdatDefineFont##1{{#1\hyperpage{##1}}}} +\DefineIndexFont{\itshape} +\def\DefineMacro{\makeatletter\cd@DefineMacro} +\def\cd@DefineMacro#1{% + \makeatother% + \cd@Index1 % + \cd@MakeEntry#1\cd@EndOfEntry% + \PrintMacro{\string#1}} +\def\DefineEnvironment{\makeatletter\cd@DefineEnvironment} +\def\DefineEnvironment#1{% + \makeatother% + \index{#1@\texttt{#1} (environment)|cdatDefineFont}% + \PrintMacro{\string#1}} +/\AddBlankLine + +\DefineMacro\cd@MakeEntry +This takes two arguments but considers only the first one, +so that "\DescribeMacro{\foo\marg{Argument}}" will +ignore "\marg{Argument}". We pass that argument to "\cd@AnalyzeEntry" +with the escape character removed (for a proper indexing), +call "\cd@AnalyzePrefix" on the result and finally "\cd@@MakeEntry" +/ +\def\cd@MakeEntry#1#2\cd@EndOfEntry{% + \def\cd@TempEntry{}% + \begingroup\escapechar\m@ne\expandafter\cd@AnalyzeEntry\string#1\cd@end\endgroup% + \expandafter\cd@AnalyzePrefix\cd@TempEntry\cd@end% + \expandafter\cd@@MakeEntry\cd@TempEntry\cd@EndOfEntry}/ + +\DefineMacro\cd@AnalyzeEntry +\DefineMacro\AtChar +The aim of this macro is to process "@". Indeed, "@" +is \textsf{MakeIndex}'s operator to signal that an entry +should be indexed under another name (as done here). But +"@" is also a very popular letter in \TeX's world when it +comes to macros. \textsf{DocStrip}'s solution is to create +a special style file for \textsf{MakeIndex}, so that the +function of "@" is taken over by another character. But +then, when a user compiles a \textsf{DocStrip} document, +this style file must be indicated to \textsf{MakeIndex}, +which many people might not do. So I prefer to leave +\textsf{MakeIndex} alone and process the entry beforehand, +replacing "@" by a character denotation. That's the job +of "\cd@AnalyzeEntry", which scans the macro name token +by token and replace "@" by "\AtChar". +/ +\chardef\AtChar=`\@ +\def\cd@AnalyzeEntry#1{% + \let\cd@next\cd@AnalyzeEntry% + \ifx#1\cd@end% + \let\cd@next\relax% + \else\if#1@% + \expandafter\gdef\expandafter\cd@TempEntry\expandafter{\cd@TempEntry\AtChar}% + \else% + \expandafter\gdef\expandafter\cd@TempEntry\expandafter{\cd@TempEntry#1}% + \fi\fi\cd@next} +/\AddBlankLine + +\DefineMacro\IgnorePrefix +Here comes the mechanism to remove prefixes when sorting entries. +"\IgnorePrefix" simply resets% +\cox[1pt](0,-3.7cm,8pt,\hskip-.4cm\raise3pt\hbox{{\normalsize\ttfamily\bslash}\hskip.5cmI am a macro}) +some values and call "\cd@IgnorePrefix" on its argument along with a terminator. +/ +\newcount\cd@PrefixCount +\def\IgnorePrefix#1{\cd@PrefixCount\z@\def\Prefix{}\cd@IgnorePrefix#1\cd@end} +/ + +\DefineMacro\cd@IgnorePrefix +\DefineMacro\cd@MakePrefix +This analyzes the prefix just like "\cd@AnalyzeEntry" above and +replaces all occurrences of "@" by "\AtChar". Since the name +of the macro is "\string"'ed when subjected to "\DefineMacro" +and others, we also "\string" all letters of the prefix, which have then +category code 12. +/ +\def\cd@IgnorePrefix#1{% + \let\cd@next\cd@IgnorePrefix% + \ifx#1\cd@end% + \def\cd@next{\expandafter\cd@ScanPrefix\Prefix\cd@end}% + \else\if#1@% + \expandafter\def\expandafter\Prefix\expandafter{\Prefix\AtChar}% + \else% + \edef\cd@PrefixLetter{\string#1}% + \expandafter\cd@MakePrefix\cd@PrefixLetter% + \fi\fi\cd@next} +\def\cd@MakePrefix#1{% + \expandafter\def\expandafter\Prefix\expandafter{\Prefix#1}}% +/ + +\DefineMacro\cd@ScanPrefix +\DefineMacro\cd@DefPrefix +\DefineMacro\cd@AnalyzePrefix +Then we just scan the prefix to compute the number of +characters it is made of. "\cd@Analy§-zePrefix" is defined +accordingly to take the right number of characters out of +a macro name (fed in "\cd@MakeEntry" above) and +lump them into "\cd@TempPrefix", and define the rest of the +entry as the remaining characters up to the terminator. +/ +\def\cd@ScanPrefix#1{% + \ifx#1\cd@end% + \let\cd@next\cd@DefPrefix% + \else% + \advance\cd@PrefixCount\@ne% + \let\cd@next\cd@ScanPrefix% + \fi\cd@next} +\def\cd@DefPrefix{% + \ifcase\cd@PrefixCount% + \def\cd@AnalyzePrefix##1\cd@end{}% + \or\def\cd@AnalyzePrefix##1##2\cd@end{% + \def\cd@TempPrefix{##1}\def\cd@RestOfEntry{##2}\cd@ComparePrefix}% + \or\def\cd@AnalyzePrefix##1##2##3\cd@end{% + \def\cd@TempPrefix{##1##2}\def\cd@RestOfEntry{##3}\cd@ComparePrefix}% + \or\def\cd@AnalyzePrefix##1##2##3##4\cd@end{% + \def\cd@TempPrefix{##1##2##3}\def\cd@RestOfEntry{##4}\cd@ComparePrefix}% + \or\def\cd@AnalyzePrefix##1##2##3##4##5\cd@end{% + \def\cd@TempPrefix{##1##2##3##4}\def\cd@RestOfEntry{##5}\cd@ComparePrefix}% + \or\def\cd@AnalyzePrefix##1##2##3##4##5##6\cd@end{% + \def\cd@TempPrefix{##1##2##3##4##5}\def\cd@RestOfEntry{##6}\cd@ComparePrefix}% + \or\def\cd@AnalyzePrefix##1##2##3##4##5##6##7\cd@end{% + \def\cd@TempPrefix{##1##2##3##4##5##6}\def\cd@RestOfEntry{##7}\cd@ComparePrefix}% + \or\def\cd@AnalyzePrefix##1##2##3##4##5##6##7##8\cd@end{% + \def\cd@TempPrefix{##1##2##3##4##5##6##7}\def\cd@RestOfEntry{##8}\cd@ComparePrefix}% + \or\def\cd@AnalyzePrefix##1##2##3##4##5##6##7##8##9\cd@end{% + \def\cd@TempPrefix{##1##2##3##4##5##6##7##8}\def\cd@RestOfEntry{##9}\cd@ComparePrefix}% + \fi\ignorespaces} +/ + +\DefineMacro\cd@ComparePrefix +Comparing prefixes is simply a matter of string testing. +In case they match, the entry is redefined as the "\cd@RestOfEntry", +so that macros will be indexed with the prefix removed. +/ +\newif\ifcd@Prefix +\def\cd@ComparePrefix{% + \ifx\cd@TempPrefix\Prefix% + \expandafter\def\expandafter\cd@TempEntry\expandafter{\cd@RestOfEntry}% + \cd@Prefixtrue% + \else% + \cd@Prefixfalse% + \fi} +/ + +\IgnorePrefix{cd@@} +\DefineMacro\cd@@MakeEntry +\IgnorePrefix{cd@} +\DefineMacro\PrintPrefix +Finally, "\cd@@MakeEntry" indexes the macro under its +name with a prefixed escapechar (since it was removed +above) and "\Prefix" in case it was found to match. We also +set some default values. +/ +\def\cd@@MakeEntry#1\cd@EndOfEntry{% + \ifcd@Prefix% + \ifcase\cd@Index% + \index{#1@\texttt{\char\escapechar\PrintPrefix\Prefix#1}|cdatDescribeFont}% + \or% + \index{#1@\texttt{\char\escapechar\PrintPrefix\Prefix#1}|cdatDefineFont}% + \fi% + \else% + \ifcase\cd@Index% + \index{#1@\texttt{\char\escapechar#1}|cdatDescribeFont}% + \or% + \index{#1@\texttt{\char\escapechar#1}|cdatDefineFont}% + \fi% + \fi} + +\IgnorePrefix{}% +\let\PrintPrefix\relax +/\AddBlankLine + +\DefineMacro\meta +\DefineMacro\marg +\DefineMacro\oarg +\DefineMacro\parg +These again are imitated from the \textsf{DocStrip} bundle, +with less care. +/ +\def\meta#1{{\ensuremath\langle\emph{#1}\ensuremath\rangle}} +\def\marg#1{\texttt{\{}\meta{#1}\texttt{\}}} +\def\oarg#1{\texttt{[}\meta{#1}\texttt{]}} +\def\parg#1{\texttt{(}\meta{#1}\texttt{)}} +/ + +\DefineMacro\cd@bslash +\DefineMacro\bslash +We define our backslash to adapt to \textsf{hyperref}. +To this end, we use "\texorpdfstring", an \textsf{hyperref} +command that expands to its first argument in normal contexts +and to its second one in bookmarks. + +The only problem is that \textsf{hyperref} defines +"\textorpdfstring" with "\newcommand" instead of "\def". +So we obviously can't define it here, and we wait for the +beginning of the document. +/ +\def\cd@bslash{\char`\\} +\def\bslash{\texorpdfstring{\cd@bslash}{\string\\}} +\AtBeginDocument{\@ifundefined{texorpdfstring}{\def\texorpdfstring#1#2{#1}}{}} +/ + +\subsection{\texttt{\bslash ShortVerb} and associates} + +\DefineMacro\cd@CharErr +\DefineMacro\cd@BadChar +Before entering the intricate realm of verbatim text, here are some +simpler definitions. First, we delimit what characters we consider to +be acceptable in "\ShortVerb" and other. The choice might seem rather +conservative, but things are less dangerous this way. + +/ +\def\cd@CharErr#1#2{% + \bgroup + \escapechar\m@ne + \cd@Error{You can't use \string#1 for \string\\#2} + \egroup} + +\newif\ifcd@BadChar + +\def\cd@BadChar#1#2{% + \cd@BadChartrue + \ifcase\catcode`#1 % \ + \cd@CharErr{\\}{#2}% + \or% { + \cd@CharErr{\{}{#2}% + \or% } + \cd@CharErr{\}}{#2}% + \or% $ + \cd@BadCharfalse% + \or% & + \cd@BadCharfalse% + \or% ^^M + \or% # + \cd@BadCharfalse% + \or% ^ + \cd@BadCharfalse% + \or% _ + \cd@BadCharfalse% + \or% Ignored + \or% Spaces + \cd@CharErr{spaces}{#2}% + \or% Letters + \cd@CharErr{letters}{#2. \MessageBreak That's really bad}% + \or% Other + \cd@BadCharfalse% + \or% Active + \cd@CharErr{#1}{#2 - it's already active}% + \or% % + \cd@CharErr{#1}{#2}% + \fi} +/\AddBlankLine + +\DefineMacro\cd@UndoErr +\DefineMacro\cd@DefErr +We also define two templates for error messages in case +the user wants to "\Undo..." something that was never done +or define a new character while one is already in use. + +/ +\def\cd@UndoErr#1{% + \bgroup% + \escapechar\m@ne% + \cd@Error{% + There is no \string\\\string#1\space defined.\MessageBreak% + \string\\Undo\string#1\space on line \the\inputlineno\space is useless}% + \egroup} +\def\cd@DefErr#1#2{% + \bgroup% + \escapechar\m@ne% + \expandafter\xdef\csname cd@#2Error\endcsname{% + \noexpand\cd@Error{% + You've already defined \string#1 as a \string\\#2\noexpand\MessageBreak% + on l. \the\inputlineno. You can't have two.\noexpand\MessageBreak% + Say \string\\Undo#2\space and then \string\\#2\space to change}}% + \egroup} +/\AddBlankLine + +\DefineMacro\ShortVerb +Before defining any character, we run some tests: is it a bad character, +and is there another character already in use? In the latter case, "\ifcd@ShortVerb" +should be switched to "true". +/ +\newif\ifcd@ShortVerb + +\def\ShortVerb#1{% + \cd@BadChar{#1}{ShortVerb}% + \ifcd@BadChar% + \else\ifcd@ShortVerb + \cd@ShortVerbError +/ + +\noindent If none of the above applies, we switch the conditional to +true define "\cd@ShortVerbError" with "\cd@DefErr". We also store +the character's original catcode to restore if undone. +/ + \else + \cd@ShortVerbtrue + \cd@DefErr{#1}{ShortVerb} + \chardef\cd@ShortVerbCat\catcode`#1% +/ + +\noindent Then we use the "~" with lowercase trick to define +the character. +/ + \bgroup% + \lccode`\~=`#1% + \lowercase{% +/ + +\noindent A "\ShortVerb" character makes the adequate modifications +to display text verbatim. "\cd@Verbatim" is \CD's container of +all such modifications (mostly catcode changing). "\catcode`#1=13" +is necessary because the character might be one of the specials +whose catcode is changed in "\cd@Verbatim", e.g. "&". We also +launch "\cd@ShortVerb" which works like "\verb". + +"\leavevmode" is needed in case the "\ShortVerb" character +starts a paragraph, as in the one you're reading. +/ + \gdef~{\leavevmode\bgroup\ttfamily\cd@Verbatim\catcode`#1\active\cd@ShortVerb}% + \gdef\cd@ShortVerb##1~{##1\egroup}% +/ + +\noindent Finally we (re)define "\UndoShortVerb" to restore the original catcode +and switch the appropriate conditional. Last but not least, we make the +character active. +/ + \gdef\UndoShortVerb{% + \ifcd@ShortVerb% + \cd@ShortVerbfalse% + \catcode`~\cd@ShortVerbCat% + \else% + \cd@UndoErr{\ShortVerb}% + \fi}}% + \egroup% + \catcode`#1=13 + \fi\fi}% +/ + +\DefineMacro\UndoShortVerb +This is the default definition for this command, when no +"\ShortVerb" has been defined. +/ +\def\UndoShortVerb{\cd@UndoErr{\ShortVerb}} +/\AddBlankLine + +\DefineMacro\ShortCode +"\ShortCode" works with the same pattern as "\ShortVerb" +with important variations. First, we check whether there's +an optional argument. +/ +\newif\ifcd@ShortCode +\newif\ifcd@ShortCodeChar + +\def\ShortCode{% + \@ifnextchar[ + {\cd@MakeShortCode} + {\cd@MakeShortCode[code]}} +/ + +\DefineMacro\cd@MakeShortCode +Then we define the real macro. We store the name of +the environment and run the same tests as above. +/ +\bgroup +\catcode`\^^M13% +\gdef\cd@MakeShortCode[#1]#2{% + \def\cd@TempEnv{#1}% + \cd@BadChar{#2}{ShortCode}% + \ifcd@BadChar% + \else\ifcd@ShortCodeChar% + \cd@ShortCodeError% +/ + +\noindent Then we check whether the environment exists, +thanks to "\"\meta{Environment}"@cd@EOL" which is defined +for \meta{Environment} when created with "\NewExample". +/ + \else% + \expandafter\ifx\csname #1@cd@EOL\endcsname\relax% + \cd@Error{% + `#1' is not an example environment.\MessageBreak% + `code' is selected instead}% + \def\cd@TempEnv{code}% + \fi% +/ + +\noindent This is the same as above: we state that a character +has been defined as a "\ShortCode". +/ + \cd@ShortCodeChartrue% + \cd@DefErr{#2}{ShortCode}% + \chardef\cd@ShortCodeCat=\catcode`#2% +/ + +\DefineMacro\cd@ShortCode +\DefineMacro\cd@ShortEnd +\DefineMacro\cd@ActivateShortCode +\noindent Then we define the character to launch the appropriate +environment, but with "\ifcd@Short§-Code" turned to true. What will +happen depends on the status of the environment. If it is the +default "code" environement, it will call "\cd@ShortCode" as +defined here, which is equivalent to "\code" itself (see below). +On the other hand, if the environment is an "example" environement, +the special example macro will be called and delimit its argument +with "\cd@ShortEnd", which is the "\ShortCode" character itself. +"\cd@ActivateShortCode" is needed to reactivate the character +in case it was one of the specials, as we did for "\ShortVerb". +/ + \bgroup% + \lccode`\~=`#2% + \lowercase{% + \gdef~{\cd@ShortCodetrue\csname\cd@TempEnv\endcsname}% + \gdef\cd@ShortEnd{~}% + \gdef\cd@ShortCode##1^^M##2~{\cd@StartGobble##2^^?\egroup}% + \gdef\cd@ActivateShortCode{\catcode`#2=13\relax}% +/ + +\DefineMacro\UndoShortCode +The rest is equivalent to "\ShortVerb" above. +/ + \gdef\UndoShortCode{% + \ifcd@ShortCodeChar% + \catcode`~=\cd@ShortCodeCat\relax% + \let\cd@ActivateShortCode\relax% + \cd@ShortCodeCharfalse% + \else% + \cd@UndoErr{\ShortCode}% + \fi}}% + \egroup% + \catcode`#2=13 % + \fi\fi}% +\egroup +\def\UndoShortCode{\cd@UndoErr{\ShortCode}} +/\AddBlankLine + +\DefineMacro\VerbBreak +"\VerbBreak" starts as above. +/ +\newif\ifcd@VerbBreak +\newtoks\cd@@Everypar + +\def\VerbBreak#1{% + \cd@BadChar{#1}{VerbBreak}% + \ifcd@BadChar% + \else\ifcd@VerbBreak% + \cd@VerbBreakError% + \else\cd@VerbBreaktrue + \cd@DefErr{#1}{VerbBreak}% + \bgroup% + \lccode`\~`#1 % + \lowercase{% +/ + +\DefineMacro\cd@ActivateVerbBreak +However, "\VerbBreak" characters become active +only in verbatim contexts. We create "\cd@ActivateVerbBreak" +to that end. When active the character stores the current +value of "\everypar" and then empties it (because the broken +line should start with nothing). +/ + \gdef\cd@ActivateVerbBreak{% + \catcode`#1\active% + \gdef~{% + \cd@@Everypar\everypar% + \everypar{}% +/ + +\noindent Then we set a scratch dimension to "\cd@FirstSpaces" +times the width of a space in the current font. "\cd@FirstSpaces" +is incremented by spaces and tabs at the beginning of each lines. +In case the current environment is numbered, we increase our +scratch dimension by the width of the box containing the number, +stored in "\"\meta{Environment}"@cd@boxwidth". +/ + \dimen0=\cd@FirstSpaces\fontdimen2\font\relax% + \expandafter\ifx\csname\cd@ExampleName @cd@boxwidth\endcsname\relax% + \else% + \advance\dimen0 \csname\cd@ExampleName @cd@boxwidth\endcsname\relax% + \fi% +/ + +\noindent Finally, we create a paragraph, turn to horizontal mode, restore +"\everypar" in its initial value and create a space of the desired +width, namely the same as the space at the beginning of the original broken line. +/ + \endgraf\leavevmode\everypar\cd@@Everypar\hbox to\dimen0{\hss}}}}% + \egroup% +/ + +\DefineMacro\cd@IgnoreVerbBreak +The character should be ignored in "\CodeOutput", and this +is what we do here. The "\Undo..." variant simply sets these +commands to "\relax". +/ + \def\cd@IgnoreVerbBreak{\catcode`#1=9\relax}% + \fi\fi} +\def\UndoVerbBreak{% + \ifcd@VerbBreak% + \let\cd@ActivateVerbBreak\relax + \let\cd@IgnoreVerbBreak\relax + \cd@VerbBreakfalse + \else + \cd@UndoErr{\VerbBreak} + \fi} +\let\cd@ActivateVerbBreak\relax +/ + +\DefineMacro\VerbCommand +\DefineMacro\cd@ActivateVerbCommand +\DefineMacro\cd@IgnoreVerbCommand +\DefineMacro\UndoVerbCommand +"\VerbCommand" is similar once again. We define +"\cd@ActivateVerbCommand" to change the catcodes of the characters +to 0, 1 and 2 in verbatim contexts and "\cd@IgnoreVerbCommand" +to turn the second character into a command that gobbles +its argument, delimited by the third character. This is +straightforward, but the first character is more complicated: +it has to gobble letters and only letters. +/ +\newif\ifcd@VerbCommand + +\def\VerbCommand#1#2#3{% + \cd@BadChar{#1}{VerbCommand}% + \cd@BadChar{#2}{VerbCommand}% + \cd@BadChar{#3}{VerbCommand}% + \ifcd@BadChar% + \else\ifcd@VerbCommand% + \cd@VerbCommandError + \else% + \cd@DefErr{#1, \string#2 and \string#3}{VerbCommand} + \cd@VerbCommandtrue% + \def\cd@ActivateVerbCommand{\catcode`#1=0 \catcode`#2=1 \catcode`#3=2\relax}% + \def\cd@IgnoreVerbCommand{% + \catcode`#1=13 % + \lccode`\~=`#1 % + \lowercase{\def~{\cd@GobbleLetters}}% + \catcode`#2=13 % + \lccode`\~=`#2 % + \lowercase{\def~####1#3{}}}% + \fi\fi} +\def\UndoVerbCommand{% + \ifcd@VerbCommand% + \let\cd@ActivateVerbCommand\relax% + \let\cd@IgnoreVerbCommand\relax% + \cd@VerbCommandfalse% + \else% + \cd@UndoErr{\VerbCommand}% + \fi}% +\let\cd@IgnoreVerbCommand\relax +\let\cd@ActivateVerbCommand\relax +/ + +\DefineMacro\cd@GobbleLetters +Gobbling letters is not a very delicate process. We +take the next token, check whether it is of category +11, and eat it away if it is the case. That's the reason +why "\VerbCommand" is not very sound. If the next token +happens to be a macro (as might be the case since in +"\CodeOutput", since the escape character is turned back to 0), +trying to evaluate its catcode is not a good idea. +/ +\def\cd@GobbleLetters#1{\ifnum\catcode`#1=11 \expandafter\cd@GobbleLetters\else\expandafter#1\fi} +/ + +\DefineMacro\CodeEscape +\DefineMacro\UndoCodeEscape +Finally, "\CodeEscape" doesn't do much in normal mode. +We simply check characters. +/ +\newif\ifcd@CodeEscape% + +\def\CodeEscape#1{% + \cd@BadChar{#1}{CodeEscape}% + \ifcd@BadChar% + \else\ifcd@CodeEscape% + \cd@CodeEscapeError% + \else% + \cd@CodeEscapetrue% + \cd@DefErr{#1}{CodeEscape}% + \fi\fi} +\def\UndoCodeEscape{% + \ifcd@CodeEscape% + \cd@CodeEscapefalse% + \else% + \cd@UndoErr{\CodeEscape}% + \fi}% +/\AddBlankLine + +\subsection{Verbatim definitions} + +\DefineMacro\cd@SpaceChar +Here comes the time to do some verbatim. We start +with space. "\ifcd@Star" is the conditional switched +to true if we're in a starred verbatim environment. +We define the visible space character to be space +of category 12 in typewriter font, as usual.\cox[12pt](110,0pt,0pt,Forget me not) +/ +\newif\ifcd@Star +\newif\ifcd@NewLine +\newcount\cd@FirstSpaces + +\bgroup +\catcode`\ 12% +\gdef\cd@SpaceChar{\texttt{ }}% +/\AddBlankLine + +\DefineMacro\cd@MakeSpace +\DefineMacro\cd@ObeySpaces +\noindent Since we want spaces at the beginning of +a line to count how many they are, so that "\VerbBreak" +can properly break the line, we don't equate the +space character with "\@xobeysp" (\LaTeX's verbatim +space) or "\cd@SpaceChar" directly; instead, "\cd@ObeySpaces" +will print the space, being called by real spaces in +"\cd@VerbTab" and "\cd@VerbSpace". ("^^I" denotes a +tab character). + +/ +\catcode`\^^I=13\relax% +\catcode`\ =13\relax% +\gdef\cd@MakeSpace{% +\ifcd@Star% +\let\cd@ObeySpaces\cd@SpaceChar% +\else% +\let\cd@ObeySpaces\@xobeysp% +\fi% +\catcode`\ =13\relax% +\catcode`\^^I=13\relax% +\let =\cd@VerbSpace% +\let^^I=\cd@VerbTab}% +/ + +\DefineMacro\cd@VerbSpace +\DefineMacro\cd@VerbTab +In verbatim contexts, a space takes the next +character as an argument; in case "\ifcd@NewLine" is true, +which it is at the beginning of every line (thanks to +an "\everypar"), it increments "\cd@FirstSpaces", +which is used by "\VerbBreak". A tab character does +the same except that the "\cd@FirstSpaces" is increased +by the value of "\TabSize" (stored in "\cd@TabSize"). +In case the next character is not a space or a tab, "\ifcd@NewLine" +is set to false. + +Spaces leaves a "\cd@ObeySpaces" while tabs create an +empty box of width "\TabSize" times the width of a space +in the current font. +/ +\gdef\cd@VerbSpace#1{% +\cd@ObeySpaces% +\ifcd@NewLine\advance\cd@FirstSpaces1\relax\fi% +\ifx#1^^I\else\ifx#1 \else\cd@NewLinefalse\fi\fi#1}% +\gdef\cd@VerbTab#1{% +\leavevmode\hbox% +to\cd@TabSize\fontdimen2\font{\hss}% +\ifcd@NewLine\advance\cd@FirstSpaces\cd@TabSize\fi% +\ifx#1^^I\else\ifx#1 \else\cd@NewLinefalse\fi\fi#1} +\egroup +/\AddBlankLine + +\DefineMacro\cd@Verbatim +Here comes the verbatimizer. First, we cancel the +parindent and sets "\hfuzz" to "\cd@Box§-Tolerance", +which stores the argument of "\BoxTolerance". +/ +\def\cd@Verbatim{% + \parindent\z@% + \hfuzz=\cd@BoxTolerance% +/ + +\noindent Then, if a "\ShortVerb" was defined, we +undo it, so that it appears as any other character +in this context. If this verbatim was called by the +"\ShortVerb" character itself, remember that it restores +itself to 13. +/ + \ifcd@ShortVerb% + \UndoShortVerb% + \fi% +/ + +\noindent If we're not in a verbatim context called +by "\ShortCode", we undo it, for the same reason. +/ + \ifcd@ShortCode% + \else% + \ifcd@ShortCodeChar% + \UndoShortCode% + \fi% + \fi% +/ + +\noindent We change the usual catcodes and reactivate +the "\ShortCode" character, just in case it was changed +by "\dospecials" or "\@noligs". We activate the verb break +and the verb command, and the rest is straightforward. +/ + \let\do\@makeother\dospecials\@noligs% + \ifcd@ShortCode% + \cd@ActivateShortCode% + \fi% + \cd@ActivateVerbBreak% + \cd@ActivateVerbCommand% + \frenchspacing% + \catcode`\^^M=13\relax% + \cd@MakeSpace}% +/\AddBlankLine + +\DefineMacro\BoxTolerance +\DefineMacro\TabSize +\DefineMacro\Gobble +These are pretty straigthforward too. I defined a macro instead +of a simple dimension or number, because it seems to +me that something like "\TabSize{25}" is much more +common in the \LaTeX\ world than "\TabSize25". Besides, +a "\relax" is automatically added, which avoids errors. +/ +\newdimen\cd@BoxTolerance +\def\BoxTolerance#1{\cd@BoxTolerance=#1\relax} +\def\TabSize#1{\chardef\cd@TabSize=#1\relax} +\TabSize2 +\def\Gobble#1{\chardef\cd@GobbleNum=#1\relax} +\Gobble0 +/\AddBlankLine + +\subsection{The default \texttt{code} environment} + +\DefineMacro\CodeFont +The basic "code" environment is quite simple. First, +we define "\CodeFont", which simply stores its argument +in "\cd@CodeFont", to be released later. The following +macros are explained more properly in the definition +of "\NewExample" below. +/ +\def\CodeFont#1{\def\cd@CodeFont{#1}} +\CodeFont{\ttfamily} +\newcount\code@cd@LineNumber +\def\code@cd@boxwidth{0pt} +\def\code@cd@BoxStyle{\rmfamily\footnotesize} +\gdef\code@cd@LineNumberBox{% + \global\advance\code@cd@LineNumber1\relax% + \def\@currentlabel{\code@cd@LineNumber}% + \hbox to\code@cd@boxwidth{% + \hss% + \code@cd@BoxStyle\relax% + \the\code@cd@LineNumber\enspace}}% +\let\code@cd@EOL\iffalse% +/ + +\DefineMacro\code +We create a paragraph and stores the name of the environment +(used in "\VerbBreak" to check the width of the line number +box). +/ +\def\code{% + \endgraf% + \bgroup% + \def\cd@ExampleName{code}% +/ + +\noindent We launch the verbatim definitions and the complicated +"\cd@ObeyLines" (see below) that makes ends of lines work properly +(gobbling characters if needed). +/ + \cd@Verbatim% + \cd@ObeyLines% +/ + +\noindent Every new paragraph, i.e. every line in that +context, typeset the line number and switches some values +exlplained above. We also set the font. +/ + \everypar{% + \code@cd@LineNumberBox + \cd@NewLinetrue% + \cd@FirstSpaces0\relax}% + \cd@CodeFont% +/ + +\noindent Finally, we call the proper macro, depending +on whether "\code" was called by "\begin{code}", "\begin{code*}" +or the "\ShortCode" character. +/ + \ifcd@ShortCode% + \global\cd@ShortCodefalse% + \let\cd@next\cd@ShortCode% + \else\ifcd@Star% + \global\cd@Starfalse% + \let\cd@next\cd@StarCode% + \else% + \let\cd@next\cd@Code% + \fi\fi\cd@next} +/ + +\DefineMacro\invisible +\noindent The starred variant of "\code" switches to true +the conditional used just above. Let's also define the +"invisible" environment, which takes an argument delimited +by "\end{invisible}" and thus needs to turn some catcodes. +/ +\expandafter\def\csname code*\endcsname{\cd@Startrue\code} +\def\invisible{% + \bgroup% + \catcode`\\=12 \catcode`\{=12 \catcode`\}=12 \catcode`\^^M=13 % + \cd@Invisible} +/ + +The "^^?" character is used to delimit the end of the verbatim +material (this is important because all ends of line scan ahead, +see below). Since it is compared in an "\ifx" conditional, I +define it to do nothing but with a distinct definition. +/ +\gdef^^?{\cd@UnlikelyCommand} +\gdef\cd@UnlikelyCommand{} +/\AddBlankLine + +\DefineMacro\cd@Code +\DefineMacro\cd@StarCode +\DefineMacro\cd@Invisible +"\begin{code}" expects "\end{code}" while "\begin{code*}" +expects "\end{code*}". That's the reason why we distinguish +"\cd@Code" and "\cd@StarCode". Apart from that, they do the +same: they typeset their argument (the first one is the end +of the line) and close the environment. "\cd@StartGobble" is, +obviously, the character gobbler for the first line. +"\cd@Invisible" also matches its end but prints nothing. +/ +\begingroup +\catcode`|=0 +\catcode`<=1 +\catcode`>=2 +\catcode`{=12 +\catcode`}=12 +\catcode`\^^M=13 % +\catcode`\\=12 % +|gdef|cd@Code#1^^M#2\end{code}<|cd@StartGobble#2^^?|egroup|end>% +|gdef|cd@StarCode#1^^M#2\end{code*}<|cd@StartGobble#2^^?|egroup|end>% +|gdef|cd@Invisible#1^^M#2\end{invisible}<|egroup|end|ignorespaces>% +|endgroup +/ + +Here comes a fastidious part. Because we want to gobble +characters at the beginning of each line (according to +"\Gobble"), ends of lines do not simply create a new +paragraph, they also give a look at the next line and +gobble the adequate number of characters. Unfortunately, +their definition changes slightly according to the +context (default "code" and examples with or without +\eTeX). Let's set the stage. +/ +\newcount\cd@GobbleCount% +\begingroup +\catcode`\^^M13\relax% +/ + +\DefineMacro\cd@StartGobble +This is the gobbler called at the beginning of the +material enclosed in a default "code" environment. +If we meet "^^?", i.e. if the environment is empty, +we do nothing. +/ +\gdef\cd@StartGobble#1{% + \ifx#1^^?% + \cd@GobbleCount=0 % + \let\cd@next\relax% +/ + +\noindent Else, if we have reached the +value set by "\Gobble" (stored in "\cd@GobbleNum"), +we replace the token we were considering in the stream. +/ + \else\ifnum\cd@GobbleCount=\cd@GobbleNum% + \cd@GobbleCount=0 % + \def\cd@next{#1}% +/ + +\noindent If we meet an end of line character, that is, +if the environment begins with a blank line, +we put it back too (it will create a paragraph, +among other things). +/ + \else\ifx#1^^M% + \cd@GobbleCount=0 % + \def\cd@next{^^M}% +/ + +Finally, if none of the above apply, we keep +gobbling. +/ + \else% + \advance\cd@GobbleCount1 % + \let\cd@next\cd@StartGobble% + \fi\fi\fi\cd@next}% +/ + +\DefineMacro\cd@ObeyLines +In the "code" environment, ends of lines +act exactly like "\cd@StartGobble" except +that they create a paragraph in the first +three cases. +/ +\gdef\cd@ObeyLines{% + \def^^M##1{% + \ifx##1^^?% + \cd@GobbleCount=0 % + \def\cd@next{\leavevmode\endgraf}% + \else\ifnum\cd@GobbleCount=\cd@GobbleNum% + \cd@GobbleCount=0 % + \def\cd@next{\leavevmode\endgraf##1}% + \else\ifx##1^^M% + \cd@GobbleCount=0 % + \def\cd@next{\leavevmode\endgraf^^M}% + \else% + \advance\cd@GobbleCount1 % + \let\cd@next^^M% + \fi\fi\fi\cd@next}}% +\endgroup +/\AddBlankLine + + +\subsection{Example environments} +Examples are quite different from the default "code" +environment, since they provide both the input and +the output of a code. Besides, if available, they +make use of \eTeX. + +\DefineMacro\eTeXOn +\DefineMacro\eTeXOff +Here's the command to switch from \eTeX\ to external file. + +/ +\def\eTeXOn{% + \@ifundefined{eTeXversion}% + {\cd@Error{% + You're not running on eTeX.\MessageBreak% + Command \string\eTeXOn\space ignored}}% + {\cd@eTeXtrue}} +\def\eTeXOff{\cd@eTeXfalse} +/ + +\DefineMacro\NewExample +\DefineMacro\cd@NewExample +\DefineMacro\RenewExample +\DefineMacro\cd@RenewExample +\DefineMacro\cd@GobbleThree +"\NewExample" and "\RenewExample" work similarly +but in an inverted way. Both test for options and launch +"\cd@@NewExample" on the options and example name if nothing +is wrong. Beforehand, they turn "#" into an active character, +which will be "\let" later to the code material with additional +macros. +/ +\def\NewExample{% + \@ifnextchar[% + {\cd@NewExample}% + {\cd@NewExample[]}} +\def\cd@NewExample[#1]#2{% + \expandafter\ifx\csname #2\endcsname\relax + \def\cd@next{\catcode`\#=13 \cd@@NewExample{#1}{#2}}% + \else% + \let\cd@next\relax% + \cd@Error{% + Style `#2' already defined or the name\MessageBreak% + is already in use.\MessageBreak% + Use \protect\RenewExample\space if you want to redefine it}% + \let\cd@next\cd@GobbleThree% + \fi\cd@next} + +\def\RenewExample{% + \@ifnextchar[% + {\cd@RenewExample}% + {\cd@RenewExample[]}} +\def\cd@RenewExample[#1]#2{% + \expandafter\ifx\csname #2\endcsname\relax + \let\cd@next\relax% + \cd@Error{% + Style `#2' is undefined.\MessageBreak% + Use \protect\NewExample\space to redefine it}% + \let\cd@next\cd@GobbleThree% + \else\expandafter\ifx\csname #2\endcsname\code% + \def\CodeFont{% + \cd@Error{% + You have redefined the `code' environment.\MessageBreak% + \string\CodeFont\space is no longer operative}} + \fi% + \def\cd@next{\catcode`\#=13 \cd@@NewExample{#1}{#2}}% + \fi\cd@next} + +\def\cd@GobbleThree#1#2#3{} +/\AddBlankLine + +\IgnorePrefix{cd@@}\DefineMacro\cd@@NewExample\IgnorePrefix{cd@} +Here is the working mechanism behind both "\NewExample" and "\RenewExample". +Since "#" will have a special function, we do some catcode changing. +The definition is "\long", of course. +/ +\begingroup +\catcode`\"=6 % +\catcode`\#=13 % +\long\gdef\cd@@NewExample"1"2"3"4"5{% +/ + +\noindent We define some default values: "\"\meta{Example}"@cd@EOL" +is a switch used when the example is processed with \eTeX, indicating +whether ends of lines are visible or not. By default, they aren't, but +options may change it. "\"\meta{Example}"@cd@LineNumberBox" is the +command used in examples to typeset the line number. By default, it +is set to "\relax" because examples have no line number. + +\DefineMacro\cd@ExampleName +We store the name of the example to be retrieved when the +environment is processed, but actually it is stored here for +the options. Finally, we analyze options with a terminator. +/ + \expandafter\gdef\csname"2@cd@EOL\endcsname{\iffalse}% + \expandafter\let\csname"2@cd@LineNumberBox\endcsname\relax% + \def\cd@ExampleName{"2}% + \cd@ExampleOptions"1,cd@end,% +/ + +\DefineMacro\CodeInput +\DefineMacro\CodeOutput +\DefineMacro\cd@MakeExample +Now we define "\"\meta{Example}, which will be called +by "\begin"\marg{Example}, as usual in \LaTeX. Each time, it +redefines "\CodeInput" and "\CodeOutput". Both store the name +of the example, "\let" "#" to "\cd@Input" and "\cd@Output" respectively, +whose definitions depends on the way the example is processed +(\eTeX\ or not), and finally execute the definition given +by the user. "\cd@MakeExample" simply executes the last +argument; it will be called at the end of the environment. Note +the extra pairs of braces in all cases. +/ + \expandafter\def\csname"2\endcsname{% + \gdef\CodeInput{{% + \def\cd@ExampleName{"2}% + \let#\cd@Input% + "3}}% + \gdef\CodeOutput{% + \def\cd@ExampleName{"2}% + \let#\cd@Output{"4}}% + \gdef\cd@MakeExample{{"5}}% +/ + +\noindent Finally, we launch the example maker with the +name of the environment (to match its proper end). +/ + \cd@Example{"2}}% +/ + +\noindent We also define the starred version of "\"\meta{Example}, +whose only difference is to switch the star conditional. Finally, +we restore the category code of "#" and close. +/ + \expandafter\def\csname"2*\endcsname{% + \global\cd@Startrue% + \gdef\CodeInput{{% + \def\cd@ExampleName{"2}% + \cd@Startrue% + \let#\cd@Input% + "3}}% + \gdef\CodeOutput{% + \def\cd@ExampleName{"2}% + \let#\cd@Output{"4}}% + \gdef\cd@MakeExample{{"5}}% + \cd@Example{"2*}}% + \catcode`\#=6\relax}% +\endgroup +/\AddBlankLine + +\DefineMacro\cd@numbered +\DefineMacro\cd@continuous +\DefineMacro\cd@visibleEOL +\DefineMacro\cd@empty +Now we process options. First we define some keywords. +/ +\def\cd@numbered{numbered} +\def\cd@continuous{continuous} +\def\cd@visibleEOL{visibleEOL} +\def\cd@empty{} +/ + +\DefineMacro\cd@ExampleOptions +This is the option processor. It is recursive and stops +when it meets the terminator. It simply stores the name +of the option and acts accordingly. +/ +\def\cd@ExampleOptions#1,{% + \def\cd@TempOption{#1}% + \let\cd@next\cd@ExampleOptions% + \ifx\cd@TempOption\cd@end% + \let\cd@next\relax% +/ + +\noindent If the option is "numbered", we create a new +count register, set the width of the box containing the +number to 0pt by default, and define the style of this +number to be "\relax" by default too. They will be modified +by "\LineNumber". +/ + \else\ifx\cd@TempOption\cd@numbered% + \global\expandafter\newcount\csname\cd@ExampleName @cd@LineNumber\endcsname% + \expandafter\gdef\csname\cd@ExampleName @cd@boxwidth\endcsname{0pt}% + \expandafter\let\csname\cd@ExampleName @cd@BoxStyle\endcsname\relax% +/ + +\noindent We then define the macro executed by the environment for +the line number; it increments the count, stores its value as the +current label for "\label" and "\ref", create a box of the +desired width, flushes everything to the right, executes the style +and typeset the value of the counter. +/ + \expandafter\gdef\csname\cd@ExampleName @cd@LineNumberBox\endcsname{% + \expandafter\advance\csname\cd@ExampleName @cd@LineNumber\endcsname1\relax% + \def\@currentlabel{\expandafter\the\csname\cd@ExampleName @cd@LineNumber\endcsname}% + \hbox to\csname\cd@ExampleName @cd@boxwidth\endcsname{% + \hss% + \csname\cd@ExampleName @cd@BoxStyle\endcsname\relax% + \expandafter\the\csname\cd@ExampleName @cd@LineNumber\endcsname\enspace}}% +/ + +\noindent If the option is "continuous", we do the same thing, +except that the count register is created if and only if it +does not already exists (so that a modified "continuous" example +environment will continue where it stopped; the user may +use "\LineNumber" to start back from 0), and the "\advance" +of the count is "\global", so that the last value is always +retained from one environment to the other. +/ + \else\ifx\cd@TempOption\cd@continuous% + \expandafter\ifx\csname\cd@ExampleName @cd@LineNumber\endcsname\relax% + \global\expandafter\newcount\csname\cd@ExampleName @cd@LineNumber\endcsname% + \fi% + \expandafter\gdef\csname\cd@ExampleName @cd@boxwidth\endcsname{0pt}% + \expandafter\let\csname\cd@ExampleName @cd@BoxStyle\endcsname\relax% + \expandafter\gdef\csname\cd@ExampleName @cd@LineNumberBox\endcsname{% + \global\expandafter\advance\csname\cd@ExampleName @cd@LineNumber\endcsname1\relax% + \def\@currentlabel{\expandafter\the\csname\cd@ExampleName @cd@LineNumber\endcsname}% + \hbox to\csname\cd@ExampleName @cd@boxwidth\endcsname{% + \hss% + \csname\cd@ExampleName @cd@BoxStyle\endcsname\relax% + \expandafter\the\csname\cd@ExampleName @cd@LineNumber\endcsname\enspace}}% +/ + +\noindent The "visibleEOL" option simply sets the relevant conditional to "true". +/ + \else\ifx\cd@TempOption\cd@visibleEOL% + \expandafter\gdef\csname\cd@ExampleName @cd@EOL\endcsname{\csname iftrue\endcsname}% + \else\ifx\cd@TempOption\cd@empty% + \else% + \cd@Error{`#1' is not a valid option}% + \fi\fi\fi\fi\fi\cd@next}% +/\AddBlankLine + +\DefineMacro\LineNumber +\DefineMacro\cd@SetLineNumber +"\LineNumber" is straightforward. After some testing, it sets +the macro created above to the values specified. If a +a square bracket follows, it executes "\cd@SetLineNumber". +/ +\def\LineNumber#1#2#3{% + \expandafter\ifx\csname#1@cd@EOL\endcsname\relax% + \cd@Error{`#1' is not an example environment'}% + \else\expandafter\ifx\csname #1@cd@LineNumber\endcsname\relax% + \cd@Warning{% + `#1' is not `numbered' nor `continuous'.\MessageBreak% + \string\LineNumber\space on line \the\inputlineno\space is useless}{}% + \else% + \expandafter\gdef\csname #1@cd@BoxStyle\endcsname{#2}% + \expandafter\gdef\csname #1@cd@boxwidth\endcsname{#3}% + \fi\fi% + \@ifnextchar[{\cd@SetLineNumber#1}\relax} +\def\cd@SetLineNumber#1[#2]{% + \expandafter\ifx\csname#1@cd@LineNumber\endcsname\relax% + \else% + \csname#1@cd@LineNumber\endcsname=#2\relax% + \expandafter\advance\csname#1@cd@LineNumber\endcsname\m@ne% + \fi} +/\AddBlankLine + +\DefineEnvironment{example} +The default "example" environment is thus easily created. +/ +\NewExample{example}{\ttfamily#}{#}{} +/ + +\DefineMacro\CodeInput +\DefineMacro\CodeOutput +If no example has been created, these two macros yields +error messages. +/ +\def\CodeInput{% + \cd@Error{% + No example environment has been created.\MessageBreak% + \string\CodeInput\space is void}} +\def\CodeOutput{% + \cd@Error{% + No example environment has been created.\MessageBreak% + \string\CodeOutput\space is void}} +/\AddBlankLine + +\noindent And here comes the core example environment. First, +some catcode changing. +/ +\begingroup +\catcode`|=0 % +\catcode`<=1 % +\catcode`>=2 % +\catcode`{=12 % +\catcode`}=12 % +\catcode`\\=12 % +/ + +\DefineMacro\cd@Example +This prepares the conditions for the processing +of the material. Let's start with the usual stuff: +/ +|gdef|cd@Example#1<% + |bgroup% + |let|do|@makeother% + |dospecials% +/ + +\noindent Now, if the environment was called by a "\ShortCode" +character, there is no environment to close ("\cd@EndEnv" +executes "\end"\marg{Environment}). We call "\cd@MakeExampleEnd", +defined below, on the character, and we reactivate this character +just in case it was one of the special. +/ + |ifcd@ShortCode% + |global|let|cd@EndEnv|relax + |expandafter|cd@MakeExampleEnd|expandafter<|cd@ShortEnd>% + |global|cd@ShortCodefalse% + |cd@ActivateShortCode% +/ + +\noindent If the environment was called by a regular +"\begin"\meta{Environment} statement, we define the proper +end (the argument comes from "\"\meta{Example}, see the definition +in "\cd@@NewExample" above). If there exists a "\ShortCode" +character, we undefine it. +/ + |else% + |gdef|cd@EndEnv<|end<#1>>% + |cd@MakeExampleEnd<\end{#1}>% + |ifcd@ShortCodeChar% + |UndoShortCode% + |fi% + |fi% +/ + +\noindent If there's a short verb, we turn it off, +we set tabs to 12 so they are written to the file +as any other character, we activate ends of lines +and in case \eTeX\ is to process the example, we +also activate comment characters (\eTeX's scanning +mechanism is peculiar and commented parts of the +code wouldn't be taken into account otherwise). +/ + |ifcd@ShortVerb% + |UndoShortVerb% + |fi% + |catcode`|^^I=12 % + |catcode`|^^M=13 % + |ifcd@eTeX% + |catcode`|%=13 % + |fi% + |cd@ExampleEnd>% +|endgroup +/ + +\DefineMacro\cd@MakeExampleEnd +\DefineMacro\cd@ExampleEnd +"\cd@MakeExampleEnd" defines "\cd@ExampleEnd" so that +the environment meets its proper end. It also launches +the real processing, depending on the use of \eTeX\ or not. + +The argument has been passed in "\cd@Example" above, and +is either "\end"\marg{Environment} (with the proper catcodes) +or the "\ShortCode" character. + +In case we're using \eTeX, we close some groups and environments, +empty "\everypar" and assign the input. We switch the star +conditional after that, because it is needed when the input +is assigned and "\cd@Verbatim" is called. + +/ +\begingroup +\catcode`\^^M=13 % +% +\gdef\cd@MakeExampleEnd#1{% + \ifcd@eTeX% + \gdef\cd@ExampleEnd##1^^M##2#1{% + \egroup% + \cd@EndEnv% + \bgroup% + \everypar{}% + \cd@AssigneTeXInput{##2}% + \global\cd@Starfalse}% +/ + +\noindent If we're not using \eTeX, we do some testing beforehand. +We just want to inform the user that we're opening an external file. +If it already exists, we keep silent. +/ + \else% + \def\cd@ExampleEnd##1^^M##2#1{% + \expandafter\ifx\csname cd@TestRead\endcsname\relax% + \newread\cd@TestRead% + \fi% + \openin\cd@TestRead=\jobname.exp % + \ifeof\cd@TestRead\relax% + \cd@Warning{% + You're not running on eTeX or you've said \string\eTeXOff.\MessageBreak% + I create the file \jobname.exp to produce\MessageBreak% + the example environment on line \the\inputlineno.\MessageBreak% + You can delete it whenever you want, but\MessageBreak% + keeping it prevents this message from reappearing.}% + \fi% + \closein\cd@TestRead % +/ + +\DefineMacro\cd@expFile +If it does not already exists, we create +the output stream "\cd@expFile", which opens +an external scratch file for example processing. +/ + \expandafter\ifx\csname cd@expFile\endcsname\relax% + \newwrite\cd@expFile% + \fi% + \immediate\openout\cd@expFile=\jobname.exp % +/ + +\noindent We "\let" ends of lines to a macro +equivalent to the one described above for the default "code" +environment, except that each line is written to the +external file. We launch it on the material suffixed +with a complicated tail to match all cases. +/ + \let^^M\cd@noeTeXEOL% + ^^M##2^^?^^M^^?%§label¤eol£ +/ + +\noindent Finally, we close everything and assign input +once again. +/ + \egroup% + \cd@EndEnv% + \immediate\closeout\cd@expFile% + \bgroup% + \everypar{}% + \cd@AssignInput% + \egroup\global\cd@Starfalse}% + \fi}% +\endgroup +/ + + +\subsubsection{Examples without \eTeX} + +\DefineMacro\cd@noeTeXEOL +Here's how ends of lines are processed when writing +the code material to an external file. If we find +"^^?", which marks the end of the material, we stop. +/ +\begingroup +\catcode`\^^M\active% +\gdef\cd@noeTeXEOL#1{% + \ifx#1^^?% + \cd@GobbleCount=0 % + \let^^M\relax% + \let\cd@next\relax% +/ + +\noindent If we find an end of line, that means there's +a blank line, and we write it to the "jobname.exp". +/ + \else\ifx#1^^M% + \cd@GobbleCount=0 % + \def\cd@next{\immediate\write\cd@expFile{}\cd@noeTeXEOL}% +/ + +\noindent If we have gobbled enough characters, we +write the line to the external file. Otherwise, we repeat. +/ + \else\ifnum\cd@GobbleCount=\cd@GobbleNum% + \cd@GobbleCount=0 % + \def\cd@next{\cd@LineWrite#1}% + \else% + \advance\cd@GobbleCount1 % + \let\cd@next\cd@noeTeXEOL% + \fi\fi\fi\cd@next}% +/ + +\DefineMacro\cd@LineWrite +The line written is delimited by its end. This explains +the "^^?^^M^^?" suffix at the end of the material on line~\ref{eol}. +In case "\end"\marg{Example} occurs on its own line, we need +a terminator, hence the first "^^?". If it occurs at the end +of the last line, as in "... end of code\end{code}", we need +"^^M" so that the argument of "\cd@LineWrite" is properly +delimited. The first "^^?" is then written to the file, but it +expands to nothing. Since "\cd@LineWrite" calls "\cd@noeTeXEOL", +we need another delimitator, hence the second "^^?". +/ +\gdef\cd@LineWrite#1^^M{\immediate\write\cd@expFile{#1}\cd@noeTeXEOL}% +/ + +\DefineMacro\cd@AssignInput +Now we define the macro that will be used in "\CodeInput" (where +"#" is "\let" to "\cd@Input") and "\CodeOutput" (where it is "\let" +to "\cd@Output"). + +\DefineMacro\cd@Input +The input is quite similar to the default "code" environment. +We define ends of lines as usual in verbatim contexts and we +read from the scratch file. +/ +\newtoks\cd@Everypar +% +\gdef\cd@AssignInput{% + \gdef\cd@Input{% + \bgroup% + \cd@Everypar\everypar% + \everypar{% + \leavevmode\csname\cd@ExampleName @cd@LineNumberBox\endcsname\relax% + \cd@NewLinetrue\cd@FirstSpaces0\relax\the\cd@Everypar\relax}% + \cd@Verbatim% + \def^^M{\leavevmode\endgraf}% + \input{\jobname.exp}% + \egroup}% +/ + +\DefineMacro\cd@Output +The output also reads from the file and simply ignores +verb breaks and commands. +/ + \gdef\cd@Output{% + \bgroup% + \cd@IgnoreVerbBreak% + \cd@IgnoreVerbCommand% + \input{\jobname.exp}% + \egroup}% +/ + +\noindent Finally, we execute the last argument to "\NewExample", +i.e. what was dubbed here \meta{Immediate execution}. +/ + \cd@MakeExample}% +/ + +\begin{invisible} +% +\end{invisible} + +\subsubsection{Examples with \eTeX} +\DefineMacro\cd@AssigneTeXInput +Examples with \eTeX\ are much more complicated. We use +the "\scantokens" command, whose function is to read +its argument as if catcodes were not fixed. For instance,\\ +"\def\scan#1{{\catcode`\\=12\scantokens{#1}}}"\\ +"\scan\foo"\\ +yields "\foo", although the backslash was an escape character +when read. The problem is that "\scantokens" interprets ends +of lines and comments characters with their current values. +Ends of lines yields a "\par" token as usual; the problem +is that this token is scanned anew, and if you have turned +the backslash to a category 12 character, it will appear as +such. Moreover, commented parts of a line are ignored. For instance,\\ +"\scan{"\\ +"a% mycomment"\\ +""\\ +"b}"\\ +yields "a\par b". So "\scantokens" as it stands is not appropriate +for verbatim material.\cox(240,3pt,20pt,Progress...) + +The solution is to turned ends of lines and comments to other +catcodes beforehand. Thus the previous example yields "a% mycomment^^M^^Mb^^M". +(The final end of line is added by "\scantokens".) Now we need +some hacking to produce the desired result. + +\DefineMacro\cd@Input +The input begins with the usual verbatim preparation. +/ +\long\gdef\cd@AssigneTeXInput#1{% + \gdef\cd@Input{% + \bgroup% + \cd@Everypar\everypar% + \everypar{% + \leavevmode\csname\cd@ExampleName @cd@LineNumberBox\endcsname\relax% + \cd@NewLinetrue\cd@FirstSpaces0\relax\the\cd@Everypar\relax}% + \cd@Verbatim% +/ + +\noindent We define ends of lines as yet another gobbling +mechanism. We use "^^?" once again to delimit material, +and define it to make ends of lines ignored in case it +is read, so that the additional "^^M" at the end of +"\scantokens" will be ineffective. +/ + \catcode`\^^M=13 % + \let^^M\cd@eTeXStartGobble% + \catcode`\^^?13 % + \def^^?{\catcode`\^^M=9\relax}% + \scantokens{^^M#1^^?}% + \egroup}% +/ + +\DefineMacro\cd@Output +Output is still worse. Even comments are active. +/ + \gdef\cd@Output{% + \bgroup% + \cd@IgnoreVerbBreak% + \catcode`\^^?13 % + \catcode`\%=13 % + \catcode`\^^M=13 % +/ + +\noindent The next step depends on the user's choice about +ends of lines. If they are visible, we process the material +as is, with special definitions of "%" and "^^M" to mimick +\TeX's normal behavior. +/ + \csname\cd@ExampleName @cd@EOL\endcsname% + \cd@VisibleComment% + \let^^M\cd@eTeXOutVisibleEOL% + \def^^?{\let^^M\relax}% + \cd@IgnoreVerbCommand% + \scantokens{#1^^?}% +/ + +\noindent If ends of lines are not visible, we execute the +material beforehand with only "%", "^^M" and "^^?" effective, +to remove unwanted code. Macros are not executed because +the backslash is still of category 12. Once ends of lines +are thus processed, we scan everything anew, ignoring the +last "^^M" and "^^@", which has a special function (see below). +/ + \else% + \cd@ActiveComment% + \let^^M\cd@eTeXOutEOL% + \def^^?{\catcode`\^^M9\relax}% + \xdef\cd@exinput{#1^^?}% + \cd@IgnoreVerbCommand% + \catcode`\^^M=9 % + \catcode`\^^@=9 % + \expandafter\scantokens\expandafter{\cd@exinput}% + \fi% + \egroup}% + \cd@MakeExample\egroup}% +/ +\begin{invisible} +% +\end{invisible} + +\DefineMacro\cd@eTeXStartGobble +\DefineMacro\cd@eTeXEOL +Once again, macros to gobble the right number of +characters at the beginning of each line. These are +for the input. It is not +possible to put "\cd@eTeXStartGobble" directly at +the beginning of "\scantokens", because the backslash +would not be understood as an escape character. Thus we +have to "\let" "^^M" to it, and once it has done its +job, make it change the meaning of "^^M" to "\cd@eTeXEOL". +(That's also the reason why we couldn't reuse the +gobble macro of the default "code" environment, although +they are quite similar.) +/ +\gdef\cd@eTeXStartGobble#1{% + \ifx#1^^?% + \cd@GobbleCount=0 % + \let\cd@next\relax% + \else\ifnum\cd@GobbleCount=\cd@GobbleNum% + \cd@GobbleCount=0 % + \let^^M\cd@eTeXEOL% + \def\cd@next{#1}% + \else\ifx#1^^M% + \cd@GobbleCount=0 % + \let^^M\cd@eTeXEOL% + \let\cd@next^^M% + \else% + \advance\cd@GobbleCount1 % + \let\cd@next\cd@eTeXStartGobble% + \fi\fi\fi\cd@next}% +% +\gdef\cd@eTeXEOL#1{% + \ifx#1^^?% + \cd@GobbleCount=0 % + \def\cd@next{\let^^M\relax\leavevmode\endgraf}% + \else\ifx#1^^M% + \cd@GobbleCount=0 % + \def\cd@next{\leavevmode\endgraf^^M}% + \else\ifnum\cd@GobbleCount=\cd@GobbleNum% + \cd@GobbleCount=0 % + \def\cd@next{\leavevmode\endgraf#1}% + \else% + \advance\cd@GobbleCount1 % + \let\cd@next^^M% + \fi\fi\fi\cd@next}% +/ +\begin{invisible} +% +\end{invisible} + + +\DefineMacro\cd@eTeXOutVisibleEOL +And now, the output. If ends of lines are visible, we set +them to create a "\par" if the next +character is another end of line (i.e. if +we find a blank line) or to put it back into +the stream otherwise, with a space before. +/ +\gdef\cd@eTeXOutVisibleEOL#1{% + \ifx#1^^?% + \let^^M\relax% + \let\cd@next\relax% + \else\ifx#1^^M% + \par% + \let\cd@next^^M% + \else% + \def\cd@next{ #1}% + \fi\fi\cd@next}% +/ + +\DefineMacro\cd@eTeXOutEOL +If ends of lines are not visible, i.e. if +they are processed before anything else, we do +something similar, except that we add a dummy +character, which will be ignored when the material +is scanned, but will nonetheless prevent the +formation of macro names across lines. Tail recursion +is forbidden, since this will be used in a "\edef", +so we "\expandafter" instead. +/ +\catcode`\^^@=12\relax% +\gdef\cd@eTeXOutEOL#1{% + \ifx#1^^?% + \else\ifx#1^^M% + \par% + \expandafter^^M% + \else% + ^^@ \expandafter\expandafter\expandafter#1% + \fi\fi}% +/ + +\noindent Now we deal with comments. First we do +some catcode changing. (We need a comment character +since we're currently in a group where ends of lines +are active). +\begin{code} +\catcode`\/=14\relax% +\catcode`\%=13\relax/ +\catcode`\ =12\relax/ +\catcode`\^^I=12\relax/ +\end{code} + +\DefineMacro\cd@VisibleComment +\DefineMacro\cd@EatBOL +If ends of lines are visible we define comments to +eat everything until the end of the line and then +launch a macro whose sole purpose is to remove +spaces at the beginning of the next line. +\begin{code} +\gdef\cd@VisibleComment{/ +\def%##1^^M{\cd@EatBOL}/ +\def\cd@EatBOL##1{/ +\let\cd@next\cd@EatBOL/ +\ifx##1 / +\else\ifx##1^^I/ +\else\ifx##1^^M/ +\let\cd@next\par/ +\else/ +\def\cd@next{##1}/ +\fi\fi\fi\cd@next}}/ +\end{code} + +\DefineMacro\cd@ActiveComment +\DefineMacro\cd@EatBOL +If ends of line are not visible, we do the same +in the "\expandafter" way. +\begin{code} +\gdef\cd@ActiveComment{/ +\def%##1^^M{\cd@EatBOL}/ +\def\cd@EatBOL##1{/ +\ifx##1 / +\expandafter\cd@EatBOL/ +\else\ifx##1^^I/ +\expandafter\expandafter\expandafter\cd@EatBOL/ +\else\ifx##1^^M/ +\par/ +\else/ +\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter##1/ +\fi\fi\fi}}/ +\endgroup +\end{code} + + +\subsection{File management} +Here are some simple macro for the reader's relief. + +\DefineMacro\CloseFile +Closing a file in normal mode simply makes all file identification macros +unavailable. + +/ +\def\CloseFile#1{% + \def\FileSource{% + \cd@Error{% + No file in production. \string\FileSource\space is empty}}% + \def\FileName{% + \cd@Error{% + No file in production. \string\FileName\space is empty}}% + \def\FileVersion{% + \cd@Error{% + No file in production. \string\FileVersion\space is empty}}% + \def\FileDate{% + \cd@Error{% + No file in production. \string\FileDate\space is empty}}} +/ + +\DefineMacro\@cd@LineCount +That's why, in normal mode, we close a file right now. We nonetheless +create a dummy file name for the sake of "\ProduceFile" below. +/ +\ifcd@produce% + \def\FileName{} + \def\FileVersion{} + \def\FileDate{} +\else + \CloseFile{} + \def\FileSource{} + \newcount\@cd@LineCount% +\fi +/ + +\DefineMacro\ProduceFile +In normal mode, the main job of "\ProduceFile" is to reset some line number +counts. In "autoclose" mode, there's only one counter, since files +are closed when a new one is opened. +/ +\def\ProduceFile#1{% + \ifcd@autoclose% + \code@cd@LineNumber0\relax% +/ + +\noindent If "autoclose" is off, we allocate a count for each file, +so lines are numbered according to the file they belong to. We +store the last value for the file we're going to close (stored +in "\FileSource"), and set the line number of the code to the number +for the file we're going to (re)open. That's why we needed a dummy +"\FileSource" above, when "\ProduceFile" is executed for the first time. +/ + \else% + \expandafter\csname\FileSource @cd@LineCount\endcsname=\code@cd@LineNumber% + \expandafter\ifx\csname #1@cd@LineCount\endcsname\relax% + \expandafter\newcount\csname #1@cd@LineCount\endcsname% + \code@cd@LineNumber0\relax% + \else% + \expandafter\code@cd@LineNumber\csname #1@cd@LineCount\endcsname% + \fi% + \fi% +/ + +\DefineMacro\FileSource +We reset "\FileName" and others, because their definition +is optional. "\FileSource" is mandatory and is the actual +argument of "\ProduceFile". We launch the appropriate macro +if a left bracket follows. +/ + \def\FileName{% + \cd@Error{% + No \string\FileName\space has been given to \FileSource}}% + \def\FileVersion{% + \cd@Error{% + No \string\FileVersion\space has been given to \FileSource}}% + \def\FileDate{% + \cd@Error{% + No \string\FileDate\space has been given to \FileSource}}% + \edef\FileSource{#1}% + \@ifnextchar[% + {\cd@GetFileName}% + \relax} +/ + +\DefineMacro\cd@GetFileName +\DefineMacro\FileName +\DefineMacro\cd@GetFileVersion +\DefineMacro\FileVersion +\DefineMacro\cd@GetFileDate +\DefineMacro\FileDate +These are straightforward and don't need any comment. +\cox[6pt](30,0pt,0pt,What if \emph{I} want\\\strut\kern2pt comment?) +/ +\def\cd@GetFileName[#1]{% + \edef\FileName{#1}% + \@ifnextchar[\cd@GetFileVersion\relax} +\def\cd@GetFileVersion[#1]{% + \edef\FileVersion{#1}% + \@ifnextchar[\cd@GetFileDate\relax} +\def\cd@GetFileDate[#1]{% + \edef\FileDate{#1}} +/\AddBlankLine + +\DefineMacro\Header +\DefineMacro\cd@HeaderGobble +\DefineMacro\AddBlankLine +\DefineMacro\StartIgnore +\DefineMacro\StopIgnore +\DefineMacro\DangerousEnvironment +Finally, we define those macros that have no effect +in normal mode to have, well, no effect. Since comment +signs are `other' characters in produce mode, we change +their catcode here too, so that the user may close the +argument to "\Header" after a comment sign. +/ +\def\Header{\bgroup\catcode`\%=12 \cd@HeaderGobble} +\long\def\cd@HeaderGobble#1{\egroup} +\let\AddBlankLine\relax +\let\StartIgnore\relax +\let\StopIgnore\relax +\def\DangerousEnvironment#1{} +/\AddBlankLine + +\begin{invisible} +% +% Definitions for the produce mode +% +\end{invisible} + + + +\section{Produce mode} +We now turn to produce mode, where "codedoc" becomes "CodeDoc" +and strange things happen.\cox[10pt](120,0pt,20pt,\hskip-4pt Woooo, scary...) + +\subsection{Messages} +\DefineMacro\cd@Tracing +\DefineMacro\cd@TChar +\DefineMacro\cd@TUChar +\DefineMacro\cd@TCode +\CD\ may be quite talkative. According to the "tracing" +option, we define some messages. +/ +\ifcase\cd@tracingmode + \def\cd@Tracing#1{} + \def\cd@TChar#1#2{} + \def\cd@TUChar#1{} + \let\cd@TCode\relax +\or + \def\cd@Tracing#1{} + \def\cd@TChar#1#2{} + \def\cd@TUChar#1{} + \def\cd@TCode{\immediate\write17{% + *** Code written from line \the\cd@ProduceLine\space to ¨\the\inputlineno\space to \cd@CurrentFile. ***}} +\or + \def\cd@Tracing#1{\immediate\write17{On line \the\cd@ProduceLine: #1.}} + \def\cd@TChar#1#2{ + \bgroup + \escapechar\m@ne\cd@Tracing{`\string#1' defined as \string\\#2} + \egroup} + \def\cd@TUChar#1{ + \bgroup + \escapechar\m@ne\cd@Tracing{\string\\#1 undone} + \egroup} + \def\cd@TCode{\immediate\write17{% + *** Code written from line \the\cd@ProduceLine\space to ¨\the\inputlineno\space to \cd@CurrentFile. ***}} +\fi +/ + +\DefineMacro\cd@Error +\DefineMacro\cd@CDWarning +\DefineMacro\cd@NoFileWarning +We also define errors and warnings; there's no need to +follow \LaTeX's ordinary syntax here. +/ +\def\cd@CDError#1{% + \immediate\write17{% + ^^J! CodeDoc Error:^^J#1^^Jl.\the\cd@ProduceLine^^J }} +\def\cd@CDWarning#1{% + \immediate\write17{% + ^^J? CodeDoc Warning: ^^J#1^^Jl.\the\cd@ProduceLine^^J }} +\def\cd@NoFileWarning{\cd@CDWarning{No file in production. This code will be lost.}} +/\AddBlankLine + + + +\subsection{Testing strings} +In produce mode, \CD\ is a string tester; more precisely +it imitates \TeX's normal mechanism: the escape character +is turned into an active character that gathers letters +following it and executes the name they form (in a modified +fashion, however, to execute only relevant macros). + +\DefineMacro\@documentclasshook +First, we redefine what happens at the end of the +class to alter the behavior of special characters. +However, we maintain comments and turn "\" into an +active character. +/ +\ifcd@produce +\def\@documentclasshook{ + \let\do\@makeother + \dospecials + \catcode`\^^I=12\relax + \catcode`\%=14\relax + \catcode`\\\active +/ + +\noindent By default, "\normalsize" is an error message, +so we redefine it. We start the report. +/ + \let\normalsize\relax + \ifnum\cd@tracingmode>0 + \immediate\write17{^^J*** CODEDOC REPORT ***^^J} + \fi +/ + +\noindent We don't load any font, so there's no need +to bother with overfull boxes nor outputs. However, +by pure superstition, I prefer some care.\cox[6pt](120,0pt,0pt,\hskip-5pt Does he know\\what he's doing?) +/ + \hfuzz=100cm% + \output={\deadcycles0\setbox0\box255} + \everypar{} +/ + +\noindent Most of the following are already 0. However, +"\tracingcommands2" would explode the log file, so we +take some care once again. +/ + \tracingcommands\z@\tracingmacros\z@\tracingoutput\z@\tracingparagraphs\z@ + \tracingpages\z@\tracinglostchars\z@\tracingrestores\z@\tracingstats\z@} +\fi +/\AddBlankLine + +\DefineMacro\cd@LeftBrace +\DefineMacro\cd@RightBrace +\DefineMacro\cd@LeftBracket +\DefineMacro\cd@Space +\DefineMacro\cd@Tab +\DefineMacro\cd@EndOfLine +\DefineMacro\cd@Comment +Some characters are special, to say the least. +We need to be able to recognize them. +\begin{code} +\begingroup +\catcode`\{=12 % +\catcode`\}=12 % +\catcode`\<=1 % +\catcode`\>=2 % +\gdef\cd@LeftBrace<{> +\gdef\cd@RightBrace<}> +\gdef\cd@LeftBracket<[> +\catcode`\ =12\relax +\catcode`\^^I=12\relax +\gdef\cd@Space< > +\gdef\cd@Tab<^^I> +\catcode`\^^M=12\relax% +\gdef\cd@EndOfLine<^^M>% +\catcode`\/=14\relax/ +\catcode`\%=12\relax/ +\gdef\cd@Comment<%>/ +\endgroup +\end{code}\AddBlankLine + +\DefineMacro\cd@Escape +Here comes the definition of the escape character +as itself... The backslash can't be allowed to have +catcode 0, otherwise control sequences would form and +fire. We don't want that, obviously. On the other hand, +some control sequences should be executed, so they must +be form beforehand. Here's how "\" works. First, it +stores the current line number for messages. +/ +\newcount\cd@ProduceLine + +\begingroup +\catcode`|=0 % +\catcode`\\=13 % +|gdef|cd@Escape{\}% +|gdef\#1{% + |cd@ProduceLine|inputlineno% +/ + +\noindent Then it turns ends of lines +and comments to other characters, because +we don't want to pass them unnoticed. +If the next character is of category code +11, we start forming a control sequence. +Otherwise, we gobble it and stop. + +/ + |bgroup + |catcode`|^^M=12 % + |catcode`|%=12 % + |gdef|cd@MacroName{}% + |ifnum|catcode`#1=11 % + |def|cd@next{|cd@Gather#1}% + |else + |def|cd@next{|egroup|relax} + |fi + |cd@next} +/ + +\DefineMacro\cd@Gather +\DefineMacro\cd@MacroName +\DefineMacro\cd@NextChar +Forming macro names is quite simple: +if the next character is a letter, we +add it to the temporary name. Otherwise, +we store it in "\cd@NextChar" and start +doing what \TeX\ does when it has formed +a control sequence. +/ +|long|gdef|cd@Gather#1{% + |ifnum|catcode`#1=11 % + |xdef|cd@MacroName{|cd@MacroName#1}% + |let|cd@next|cd@Gather% + |else% + |gdef|cd@NextChar{#1}% + |let|cd@next|cd@GobbleSpace% + |fi|cd@next} +|endgroup +/\AddBlankLine + +\DefineMacro\cd@GobbleSpace +That is, we skip spaces and ends of lines, +so that the \emph{real} next character will +be put next to the formed control sequence, +in case it is an argument. + +In case the next argument is none of the above, +we call "\cd@Evaluate", which will expand the +macro, on the next character. +/ +\long\def\cd@GobbleSpace{% + \let\cd@next\cd@TakeNextChar + \ifx\cd@NextChar\cd@Space + \else\ifx\cd@NextChar\cd@Tab + \else\ifx\cd@NextChar\cd@EndOfLine + \else\ifx\cd@NextChar\cd@Comment + \let\cd@next\cd@GobbleEndOfLine + \else + \egroup + \def\cd@next{\expandafter\cd@Evaluate\cd@NextChar} + \fi\fi\fi\fi\cd@next} +/ + +\DefineMacro\cd@TakeNextChar +\DefineMacro\cd@GobbleEndOfLine +These do what they say. +/ +\long\def\cd@TakeNextChar#1{\gdef\cd@NextChar{#1}\cd@GobbleSpace} +\begingroup +\catcode`\^^M=12% +\gdef\cd@GobbleEndOfLine#1^^M#2{% + \gdef\cd@NextChar{#2}% + \cd@GobbleSpace}% +\endgroup +/ + +\DefineMacro\cd@Evaluate +Finally, we take the name thus formed, and +execute "\"\meta{Name}"@Produce". As you might +imagine, the only macros containing the "@Produce" +suffix are defined by \CD. So, most of the time, +this execution will be no more than a "\relax". +Which is exactly what we want. + +/ +\def\cd@Evaluate{\csname\cd@MacroName @Produce\endcsname} +/ + +\codeskip=3cm +\boxskip=2cm +\subsection{Macros executed in produce mode} +To understand what follows, simply remember that +"\"\meta{Macro}"@Produce" is executed when \CD\ +encounters "\"\meta{Macro}. So, for instance, +"\ShortVerb@Produce" is "\ShortVerb" in produce mode. + +Macro names will become quite long, so we add some +left margin.\cox[6pt](80,0pt,0pt,You could have done\\that before...) + +\DefineMacro\cd@Gobble +First, some gobbler. + +/ +\def\cd@Gobble#1{} +/ + +\DefineMacro\cd@PrepareChar +Macros like "\ShortVerb" can take four kinds of argument. +If you want "+" to be a "\ShortVerb", you can say "\ShortVerb+", +"\ShortVerb\+", "\ShortVerb{+}" and "\Short§-Verb{\+}". Since +\CD\ has already considered the next character when executing +"\ShortVerb@Produce", its catcode can't be changed, and a left +brace is of category 12 and a backslash of category 13. So we have +to gobble the next character if it is one of them. + +\leavevmode"\cd@PrepareChar" takes a macro as an argument and replaces +it in the stream with the next character gobbled or not. +The backslash is turned into an escape character to handle +the "\ShortVerb{\+}" case, where the left brace is gobbled; +the backslash hasn't been read yet, so we can use it. +/ +\def\cd@PrepareChar#1{% + \catcode`\\=0 % + \def\cd@next{\expandafter#1\cd@Gobble} + \ifx\cd@NextChar\cd@LeftBrace% + \else\ifx\cd@NextChar\cd@Escape% + \else% + \def\cd@next{#1} + \fi\fi}% +/\AddBlankLine + +\DefineMacro\ShortVerb@Produce +\DefineMacro\DefineShortVerb@Produce +\DefineMacro\cd@VerbList +Thus, "\ShortVerb@Produce" calls "\cd@PrepareChar" with +"\cd@MakeShortVerb@Produce", which will do the real job +to the character. We define \textsf{fancyvrb}'s "\DefineShortVerb" +to do the same thing. "\cd@VerbList" contains all such characters, +since "\DefineShortVerb" can define several of them. It will +be used in writing environments to neutralize them. +/ +\def\ShortVerb@Produce{\cd@PrepareChar\cd@MakeShortVerb@Produce\cd@next} +\let\DefineShortVerb@Produce\ShortVerb@Produce +\def\cd@VerbList{} +/ + +\DefineMacro\cd@MakeShortVerb@Produce +Now we inform the user that the character was "\ShortVerb"'ed. +/ +\def\cd@MakeShortVerb@Produce#1{% + \cd@TChar{#1}{ShortVerb} +/ + +\noindent We add it to "\cd@VerbList". +/ + \expandafter\def\expandafter\cd@VerbList\expandafter{\cd@VerbList#1,} +/ + +\DefineMacro\cd@ShortVerb@Produce +\DefineMacro\UndoShortVerb@Produce +And we simply define the character to gobble everything +until its next occurrence. We also define the "\Undo..." variant. +/ + \lccode`\~=`#1 % + \lowercase{% + \def~{\bgroup\let\do\@makeother\dospecials\catcode`#1\active\cd@ShortVerb@Produce}% + \def\cd@ShortVerb@Produce##1~{\egroup}}% + \def\UndoShortVerb@Produce{\cd@TUChar{ShortVerb}\catcode`#1=12\relax}% + \catcode`#1=13 % + \catcode`\\=13\relax} +\let\UndoShortVerb@Produce\relax +/ + +\DefineMacro\UndefineShortVerb@Produce +\DefineMacro\cd@UndefineShortVerb@Produce +We define a variant for \textsf{fancyvrb}, because it +takes an argument.\vskip5pt +/ +\def\UndefineShortVerb@Produce{\cd@PrepareChar\cd@UndefineShortVerb@Produce\cd@next}% +\def\cd@UndefineShortVerb@Produce#1{ + \cd@TUChar{ShortVerb (from fancyvrb)} + \catcode`#1=12 \catcode`\\=13\relax} +/\AddBlankLine + +\DefineMacro\VerbBreak@Produce +\DefineMacro\cd@MakeVerbBreak@Produce +\DefineMacro\cd@IgnoreVerbBreak +\DefineMacro\UndoVerbBreak@Produce +In produce mode, the "\VerbBreak" character is simply ignored.\vskip5pt +/ +\def\VerbBreak@Produce{\cd@PrepareChar\cd@MakeVerbBreak@Produce\cd@next} +\def\cd@MakeVerbBreak@Produce#1{ + \cd@TChar{#1}{VerbBreak} + \def\cd@IgnoreVerbBreak{\catcode`#1=9\relax} + \def\UndoVerbBreak@Produce{\cd@TUChar{VerbBreak}\let\cd@IgnoreVerbBreak\relax} + \catcode`\\=13\relax} +\let\cd@IgnoreVerbBreak\relax +\let\UndoVerbBreak@Produce\relax +/ + +\DefineMacro\cd@GobbleOptions +This is useful for "\ShortCode" and also "\NewExample" +/ +\def\cd@GobbleOptions#1[#2]#3{\def\cd@NextChar{#3}\expandafter#1\cd@NextChar} +/\AddBlankLine + +\DefineMacro\ShortCode@Produce +We check for options. +/ +\def\ShortCode@Produce{% + \ifx\cd@NextChar\cd@LeftBracket% + \def\cd@next{\cd@GobbleOptions\ShortCode@Produce}% + \else% + \cd@PrepareChar\cd@MakeShortCode@Produce + \fi\cd@next} +/ + +\DefineMacro\cd@MakeShortcode@Produce +\DefineMacro\cd@ShortWriteFile +\DefineMacro\ActivateShortCode@Produce +\DefineMacro\cd@UndoShortCode@Produce +The "\ShortCode" character in produce mode is similar +to its counterpart in normal mode, except that it +follows what "code" does in this mode. So give a +look at the definition of the code environment to +understand what is going on here. +/ +\begingroup +\catcode`\^^M13% +\gdef\cd@MakeShortCode@Produce#1{% + \cd@TChar{#1}{ShortCode} + \lccode`\~=`#1% + \lowercase{% + \def~{\cd@ProduceLine\inputlineno\cd@ShortCodetrue\cd@CodeWrite}% + \def\ActivateShortCode@Produce{\catcode`#1\active}% + \def\cd@ShortWriteFile##1^^M##2~{% + ^^M##2^^?^^M^^?% + \ifx\cd@NoFileWarning\relax% + \cd@TCode% + \else% + \cd@NoFileWarning% + \fi\egroup}}% + \def\UndoShortCode@Produce{\cd@TUChar{ShortCode}\catcode`#1=12\relax}% + \catcode`\\=13 % + \catcode`#1=13\relax}% +\endgroup +\let\ActivateShortCode@Produce\relax +\let\UndoShortCode@Produce\relax +/\AddBlankLine + +\DefineMacro\VerbCommand@Produce +\DefineMacro\cd@VerbEscape@Produce +\DefineMacro\cd@TempEsc +"\VerbCommand" characters do what they do in +"\CodeOutput" in normal mode. The escape gobble +letters and the braces gobble what they contain. + +First, we store the escape character for the message. +/ +\def\VerbCommand@Produce{\cd@PrepareChar\cd@VerbEscape@Produce\cd@next} +\def\cd@VerbEscape@Produce#1{ + \bgroup\escapechar\m@ne\xdef\cd@TempEsc{\string#1}\egroup +/ + +\DefineMacro\cd@IgnoreEscape@Produce +Then we turn it into a letter gobbler. +/ + \def\cd@IgnoreEscape@Produce{ + \catcode`#1=13 + \lccode`\~=`#1 + \lowercase{\def~{\cd@GobbleLetters}}} +/ + +\noindent This is not what you think it is. +We're not considering whether the character to come +is a left brace, but whether "\cd@NextChar", i.e. the +character following "\VerbCommand", \emph{was} +a left brace; this means that a right brace is to come, +and we want to gobble it before processing what follows. +/ + \ifx\cd@NextChar\cd@LeftBrace + \def\cd@next{\expandafter\cd@VerbBraces@Produce\cd@Gobble} + \else + \let\cd@next\cd@VerbBraces@Produce + \fi\cd@next} +/ + +\DefineMacro\cd@VerbBraces@Produce +\IgnorePrefix{cd@@} +\DefineMacro\cd@@VerbBraces@Produce +\IgnorePrefix{cd@} +\DefineMacro\cd@IgnoreBraces@Produce +\DefineMacro\UndoVerbCommand@Produce +The rest is pretty straightforward and similar +to what we did in normal mode. +/ +\def\cd@VerbBraces@Produce{\catcode`\{=1 \catcode`\}=2 \cd@@VerbBraces@Produce} +\def\cd@@VerbBraces@Produce#1#2{% + \expandafter\cd@TChar\expandafter{\cd@TempEsc', `\string#1' and `\string#2'}{VerbCommand} + \def\cd@IgnoreBraces@Produce{% + \catcode`#1=13 + \lccode`\~=`#1 + \lowercase{\def~####1#2{}}} + \catcode`\\=13 \catcode`\{=12 \catcode`\}=12\relax} +\def\UndoVerbCommand@Produce{ + \cd@TUChar{VerbCommand} + \let\cd@IgnoreEscape@Produce\relax + \let\cd@IgnoreBraces@Produce\relax} +\let\cd@IgnoreEscape@Produce\relax +\let\cd@IgnoreBraces@Produce\relax +/\AddBlankLine + +\DefineMacro\CodeEscape@Produce +\DefineMacro\cd@CodeEscape@Produce +\DefineMacro\cd@ActivateCodeEscape +\DefineMacro\UndoCodeEscape@Produce +"\CodeEscape" is easy: we simply define a macro to turn +the character into an escape in code contexts. +/ +\def\CodeEscape@Produce{\cd@PrepareChar\cd@CodeEscape@Produce\cd@next} +\def\cd@CodeEscape@Produce#1{% + \cd@TChar{#1}{CodeEscape} + \def\cd@ActivateCodeEscape{\catcode`#1=0\relax}\catcode`\\=13\relax} +\let\cd@ActivateCodeEscape\relax +\def\UndoCodeEscape@Produce{\cd@TUChar{CodeEscape}\let\cd@ActivateCodeEscape\relax} +/\AddBlankLine + +\DefineMacro\NewExample@Produce +\DefineMacro\RenewExample@Produce +These two macros launch the option gobbler +if there are any. "\cd@DangerousExample@Produce" +is defined later because it takes its argument +between braces of category 12, like other macros. +/ +\def\NewExample@Produce{% + \ifx\cd@NextChar\cd@LeftBracket% + \def\cd@next{\cd@GobbleOptions\NewExample@Produce}% + \else% + \let\cd@next\cd@DangerousExample@Produce% + \fi\cd@next} +\let\RenewExample@Produce\NewExample@Produce +/\AddBlankLine + +\IgnorePrefix{cd@@} +\DefineMacro\cd@@Evaluate +\IgnorePrefix{cd@} +\DefineMacro\StartIgnore@Produce +\DefineMacro\cd@FindIgnore +\DefineMacro\cd@StopIgnore +Ignoring the input boils down to modifying the +definition of "\cd@Evaluate" until it founds +"\StopIgnore". Meanwhile, it does nothing. +/ +\let\cd@@Evaluate\cd@Evaluate +\def\StartIgnore@Produce{ + \cd@Tracing{\string\StartIgnore\space found. I will ignore everything from now on} + \let\cd@Evaluate\cd@FindIgnore} +\def\cd@FindIgnore{ + \expandafter\ifx\csname cd@\cd@MacroName\endcsname\cd@StopIgnore + \cd@Tracing{\string\StopIgnore\space found. I resume my normal behavior} + \let\cd@Evaluate\cd@@Evaluate + \fi} +\def\cd@StopIgnore{\cd@StopIgnore} +/\AddBlankLine + +\DefineMacro\verb@Produce +\DefineMacro\cd@VerbEater +\IgnorePrefix{cd@@} +\DefineMacro\cd@@VerbEater +\IgnorePrefix{cd@} +The produce version of \LaTeX's "\verb" +gobbles its argument after it has checked for +a star. +/ +\def\verb@Produce{\count@=0 \cd@VerbEater} +\def\cd@VerbEater#1{% + \ifcase\count@ % + \ifx#1* + \count@=1 % + \let\cd@@VerbEater\cd@VerbEater + \else + \def\cd@@VerbEater##1#1{} + \fi + \else + \def\cd@@VerbEater##1#1{} + \fi\cd@@VerbEater} +/\AddBlankLine + +\DefineMacro\DescribeMacro@Produce +\DefineMacro\DefineMacro@Produce +\DefineMacro\DescribeEnvironment@Produce +\DefineMacro\DefineEnvironment@Produce +\DefineMacro\noexpand@Produce +\DefineMacro\string@Produce +\DefineMacro\protect@Produce +The normal counterparts of these might take dangerous +arguments, so we need to neutralize them. The first +four gobble two tokens, i.e. a left brace and"/"or +an escape character, so the following macro won't form. +The last three just gobble the escape character. +/ +\def\DescribeMacro@Produce#1#2{} +\def\DefineMacro@Produce#1#2{} +\def\DescribeEnvironment@Produce#1#2{} +\def\DefineEnvironment@Produce#1#2{} +\def\noexpand@Produce#1{} +\def\string@Produce#1{} +\def\protect@Produce#1{} +/ + +\DefineMacro\begin@Produce +\DefineMacro\end@Produce +"\begin" and "\end" statements are executed\cox[6pt](120,0pt,22pt,Stop executing things!\\They're innocent!) +if and only if there follows a left brace. This +decreases the number of possible errors. The double-"@" +versions take their arguments in `other' braces, so they +are defined later. +/ +\def\begin@Produce{ + \ifx\cd@NextChar\cd@LeftBrace + \expandafter\begin@@Produce + \fi} +\def\end@Produce{ + \ifx\cd@NextChar\cd@LeftBrace + \expandafter\end@@Produce + \fi} +/\AddBlankLine + +\DefineMacro\Gobble@Produce +The produce version of "\Gobble" is similar +to the normal version, except that it take cares +of braces. "\Gobble@@Produce" is defined below. +/ +\def\Gobble@Produce#1{% + \ifx\cd@NextChar\cd@LeftBrace% + \def\cd@next{\expandafter\Gobble@@Produce\cd@NextChar} + \else + \def\cd@next{\chardef\cd@GobbleNum=#1\relax}% + \fi\cd@next} +/ + +\DefineMacro\Header@Produce +\DefineMacro\cd@HeaderEOL +The header is an easy matter. The only thing not to +forget is to change the catcode of \bslash back to 0. +\begin{code} +\newif\ifcd@HeaderFirstLine +\begingroup +\catcode`\^^M=13 % +\catcode`\/=14 % +\catcode`\%=12 / +\gdef\Header@Produce{/ + \bgroup/ + \catcode`\^^M=13 / + \catcode`\%=12 / + \catcode`\\=0 / + \Header@@Produce}/ +\gdef\cd@HeaderEOL{\def^^M{^^J% }} +\endgroup +\end{code}\AddBlankLine + +\DefineMacro\cd@DocumentString +\DefineMacro\cd@CodeString +\DefineMacro\cd@StarCodeString +\DefineMacro\cd@InvisibleString +\DefineMacro\cd@StoredEnvironments +We'll need these presently. +/ +\def\cd@DocumentString{document} +\def\cd@CodeString{code} +\def\cd@StarCodeString{code*} +\def\cd@InvisibleString{invisible} +\def\cd@StoredEnvironments{example,verbatim,Verbatim,BVerbatim,¨LVerbatim,SaveVerbatim,VerbatimOut,Example,CenterExample,¨SideBySideExample,PCenterExample,PSideBySideExample,} +/\AddBlankLine + +Here comes the macros that take their arguments +bewteen braces of category 12. +/ +\begingroup +\catcode`\{=12 % +\catcode`\}=12 % +\catcode`\<=1 % +\catcode`\>=2 % +/ + +\DefineMacro\Header@@Produce +This defines "\cd@Header", which is executed in +"\ProduceFile", to write the text input by the user +to the newly opened file. The group we close was +opened in "\Header@Produce". +/ +\long\gdef\Header@@Produce{#1}< + \gdef\cd@Header<\bgroup\cd@HeaderEOL\cd@ProduceFile<\cd@Comment\space#1>\egroup> + \egroup> +/\AddBlankLine + +\DefineMacro\Gobble@@Produce +This is launched by "\Gobble@Produce" +/ +\gdef\Gobble@@Produce{#1}<\chardef\cd@GobbleNum=#1\relax> +/\AddBlankLine + +\DefineMacro\DangerousEnvironment@Produce +\DefineMacro\cd@DangerousExample@Produce +\DefineMacro\DefineVerbatimEnvironment +Here we add dangerous environments to the list above, +to be checked below. + +\noindent\indent"\cd@DangerousExample@Produce" has such a cumbersome +definition because it is meant to gobble the remaining +three arguments of "\NewExample" and "\RenewExample". +They might be separated by spaces, and since spaces +have category 12 in produce mode, they won't be +skipped and "\cd@DangerousExample@Produce" wouldn't +match its definition, as \TeX\ likes to say. +/ +\gdef\DangerousEnvironment@Produce{#1}< + \cd@Tracing<#1 added to dangerous environments> + \xdef\cd@StoredEnvironments<\cd@StoredEnvironments#1,>> +\gdef\cd@DangerousExample@Produce{#1}#2{#3}#4{#5}#6{#7}< + \cd@Tracing<#1 added to dangerous environments (CodeDoc examples)> + \xdef\cd@StoredEnvironments<\cd@StoredEnvironments#1,>> +\let\DefineVerbatimEnvironment@Produce\DangerousEnvironment@Produce +/\AddBlankLine + +\DefineMacro\begin@@Produce +"\begin" statements simply check their argument: +if it is "code", "code*" or "invisible", it turns +to writing mode. Otherwise, the name of the argument +is checked against the list of dangerous environments. +See below where normal braces are restored. +/ +\gdef\begin@@Produce{#1}< + \def\cd@TempArg<#1> + \ifx\cd@TempArg\cd@CodeString + \let\cd@next\cd@CodeWrite + \else\ifx\cd@TempArg\cd@StarCodeString + \cd@Startrue + \let\cd@next\cd@CodeWrite + \else\ifx\cd@TempArg\cd@InvisibleString + \cd@Invisibletrue + \let\cd@next\cd@CodeWrite + \else + \def\cd@next<\cd@CheckEnvironment<#1>> + \fi\fi\fi\cd@next> +/ + +\DefineMacro\end@Produce +There's only one thing that can wake an "\end" +statement: "document". If it finds "\end{document}", +\CD\ stops. Otherwise, "\end" statements are ignored. +/ +\gdef\end@@Produce{#1}< + \def\cd@TempArg<#1> + \ifx\cd@TempArg\cd@DocumentString + \def\cd@next<\cd@Tracing<\string\end{document}> + \ifnum\cd@tracingmode=0 % + \else + \immediate\write17<^^J*** END OF CODEDOC REPORT ***^^J> + \fi\@@end> + \else + \let\cd@next\relax + \fi\cd@next> +/ + +\DefineMacro\ProduceFile@Produce +\DefineMacro\CloseFile@Produce +We define these right now, to be used later. +/ +\gdef\ProduceFile@Produce{#1}<\ProduceFile@@Produce<#1>> +\gdef\CloseFile@Produce{#1}<\CloseFile@@Produce<#1>> +/\AddBlankLine + +\DefineMacro\input@Produce +\DefineMacro\cd@CurrentSource +We need a terribly boring definition of "\input" +for the default header, so that files are properly +tracked back to their source. Besides, "\input" in +\TeX's way, i.e. without braces, is not allowed anymore, +if it is to be read by \CD\ in produce mode. I feel +like removing the whole thing altogether. +/ +\newcount\cd@InputDepth +\gdef\input@Produce{#1}< + \cd@Tracing<\string\input\space file #1> + \expandafter\let\csname cd@MasterSource\the\cd@InputDepth\endcsname\cd@CurrentSource + \edef\cd@CurrentSource<#1 (\string\input\space in \cd@CurrentSource)> + \advance\cd@InputDepth1\relax + \@@input #1\relax + \advance\cd@InputDepth-1\relax + \expandafter\let\expandafter\cd@CurrentSource\csname cd@MasterSource¨\the\cd@InputDepth\endcsname> +/\AddBlankLine + +\DefineMacro\cd@MakeSpecialEater +\DefineMacro\cd@SpecialEater +If we find a dangerous environment, we launch +this on its name, which eats everything until +"\end"\marg{Name}. +/ +\catcode`\|=0 % +\catcode`\\=13 % +|gdef|cd@MakeSpecialEater#1< + |long|def|cd@SpecialEater##1\end{#1}<> + |cd@SpecialEater> +|endgroup +/\AddBlankLine + +\DefineMacro\cd@CurrentSource +Back to normal braces. This is a default value needed +in "\input@Produce". The extension is just a guess, of +course. +/ +\edef\cd@CurrentSource{\jobname.tex} +/\AddBlankLine + +\DefineMacro\cd@CheckEnvironment +\IgnorePrefix{cd@@} +\DefineMacro\cd@@CheckEnvironment +\IgnorePrefix{cd@} +This is the checking mechanism used in "\begin" +statement to detect dangerous environments. Note +that we check all environments in their starred +version too. +/ +\def\cd@CheckEnvironment#1{ + \def\cd@TempEnv{#1} + \expandafter\cd@@CheckEnvironment\cd@StoredEnvironments cd@end,} +\def\cd@@CheckEnvironment#1,{ + \def\cd@@TempEnv{#1} + \def\cd@@StarTempEnv{#1*} + \ifx\cd@@TempEnv\cd@end + \let\cd@next\relax + \else\ifx\cd@@TempEnv\cd@TempEnv + \def\cd@next{\cd@MakeSpecialEater{#1}} + \else\ifx\cd@@StarTempEnv\cd@TempEnv + \def\cd@next{\cd@MakeSpecialEater{#1*}} + \else + \let\cd@next\cd@@CheckEnvironment + \fi\fi\fi + \cd@next} +/ + + +\subsection{Writing environments} +\CD\ looks for "code", "code*" and "invisible" environments +and process them line by line. + +\DefineMacro\cd@MakeOther +First, we need a recursive catcode changer. +/ +\def\cd@MakeOther#1,{% + \def\cd@TempArg{#1}% + \ifx\cd@TempArg\cd@end% + \else% + \catcode`#1=12 % + \expandafter\cd@MakeOther% + \fi} +/\AddBlankLine + +\DefineMacro\cd@CodeWrite +This is the writing macro, called by "\begin" +when the appropriate argument is found, or +by the "\ShortCode" character. "\dospecials" +is probably useless since all specials are +already done, but at least it changes the +category of the escape and the comment. +/ +\newif\ifcd@Invisible +\begingroup +\catcode`\^^M=13\relax% +\gdef\cd@CodeWrite{% + \bgroup% + \let\do\@makeother% + \dospecials% + \catcode`\^^I=12 % +/ + +\noindent We turn all verb characters (defined +by \textsf{fancyvrb}'s "\DefineShortVerb") into +other characters, ignore the verb break, neutralize +the short code if we're not in a short code environment +(the redefinition of "\cd@TUChar" just prevents an +unwanted message sent to the user if "tracing" is 2) +an reactivate it otherwise, +ignore "\VerbCommand" and activate "\CodeEscape". +We turn ends of lines into proper gobbler once again. +/ + \expandafter\cd@MakeOther\cd@VerbList cd@end,% + \cd@IgnoreVerbBreak% + \ifcd@ShortCode% + \ActivateShortCode@Produce% + \else% + \let\cd@TempTUChar\cd@TUChar + \def\cd@TUChar##1{} + \UndoShortCode@Produce% + \let\cd@TUChar\cd@TempTUChar + \fi% + \cd@IgnoreEscape@Produce% + \cd@IgnoreBraces@Produce% + \cd@ActivateCodeEscape% + \catcode`\^^M=13\relax% + \let^^M\cd@produceEOL% +/ + +\noindent Finally we launch the adequate macro. +They all do the same thing, but they look for +different "\end" statements. +/ + \ifcd@ShortCode% + \global\cd@ShortCodefalse\let\cd@next\cd@ShortWriteFile% + \else\ifcd@Star% + \global\cd@Starfalse\let\cd@next\cd@StarWriteFile% + \else\ifcd@Invisible% + \global\cd@Invisiblefalse\let\cd@next\cd@InvisibleWriteFile% + \else% + \let\cd@next\cd@WriteFile% + \fi\fi\fi\cd@next}% +/ + +\DefineMacro\cd@ProduceEOL +\DefineMacro\cd@LineWrite@Produce +This is similar to the version for examples +without \eTeX\ in normal mode, i.e. it writes +to an external file, specified in "\cd@ProduceFile". +/ +\gdef\cd@produceEOL#1{% + \ifx#1^^?% + \cd@GobbleCount=0 % + \let^^M\relax% + \let\cd@next\relax% + \else\ifx#1^^M% + \cd@GobbleCount=0 % + \def\cd@next{\cd@ProduceFile{}\cd@produceEOL}% + \else\ifnum\cd@GobbleCount=\cd@GobbleNum% + \cd@GobbleCount=0 % + \def\cd@next{\cd@LineWrite@Produce#1}% + \else% + \advance\cd@GobbleCount1 % + \let\cd@next\cd@produceEOL% + \fi\fi\fi\cd@next}% +\gdef\cd@LineWrite@Produce#1^^M{\cd@ProduceFile{#1}\cd@produceEOL}% +/ + +\DefineMacro\cd@WriteFile +\DefineMacro\cd@StarWriteFile +\DefineMacro\cd@InvisibleWriteFile +And here is the end. It is the first "^^M", "\let" +to "\cd@ProduceEOL", which launches everything. +The conditional switches between an error message +(no file in production) and a report (code written). +/ +\catcode`|=0 % +\catcode`<=1 % +\catcode`>=2 % +\catcode`{=12 % +\catcode`}=12 % +\catcode`\\=12 % +|long|gdef|cd@WriteFile#1^^M#2\end{code}<% + ^^M#2^^?^^M^^?% + |ifx|cd@NoFileWarning|relax% + |cd@TCode% + |else% + |cd@NoFileWarning% + |fi|egroup>% +|long|gdef|cd@StarWriteFile#1^^M#2\end{code*}<% + ^^M#2^^?^^M^^?% + |ifx|cd@NoFileWarning|relax% + |cd@TCode% + |else% + |cd@NoFileWarning% + |fi|egroup>% +|long|gdef|cd@InvisibleWriteFile#1^^M#2\end{invisible}<% + ^^M#2^^?^^M^^?% + |ifx|cd@NoFileWarning|relax% + |cd@TCode% + |else% + |cd@NoFileWarning% + |fi|egroup>% +|endgroup +/\AddBlankLine + + + + + +\subsection{File management} +This the final step: handling files in produce mode.\cox[9pt](120,-6cm,30pt,This sounds strange) + +\DefineMacro\cd@Closed +\DefineMacro\cd@Open +\DefineMacro\cd@Wait +First, some keywords. +/ +\def\cd@Closed{closed} +\def\cd@Open{open} +\def\cd@Wait{wait} +/\AddBlankLine + +\DefineMacro\cd@CurrentFile +\DefineMacro\cd@ProduceFile +\DefineMacro\AddBlankLine@Produce +Some basic definitions. "\@unused" is \LaTeX's +unattributed stream for messages. We let it write +to he log file. "\cd@ProduceFile" is the writing +macro (used in writing environments above); as long +as no file is open, it does nothing. +/ +\newcount\cd@ProduceCount + +\def\cd@CurrentFile{} +\chardef\@unused=17 + +\def\cd@ProduceFile#1{} +\def\AddBlankLine@Produce{\cd@ProduceFile{}} +/\AddBlankLine + +\DefineMacro\ProduceFile@@Produce +This is called by "\ProduceFile", via "\ProduceFile@Produce" +above. If the file is closed ore already in production, +we signal it to the user: +/ +\def\ProduceFile@@Produce#1{% + \let\cd@next\relax + \expandafter\ifx\csname #1@Status\endcsname\cd@Closed + \cd@CDError{% + File `#1' has already been closed.^^J% + If I open it again, it will be erased.^^J% + I can't do that. I quit. Sorry.} + \let\cd@next\@@end + \else\expandafter\ifx\csname #1@Status\endcsname\cd@Open + \cd@CDWarning{% + File `#1' is currently in production.^^J% + Why do you try to open it again?} +/ + +\noindent The file is waiting if it has been opened previously +and another one has been opened too afterward, provided +"autoclose" is off. In which case, we set it to "open": +/ + \else\expandafter\ifx\csname #1@Status\endcsname\cd@Wait + \expandafter\let\csname #1@Status\endcsname\cd@Open +/ + +\noindent We disable the warning about the absence of +a file in production and define "\cd@ProduceFile" to +write to this file. +/ + \let\cd@NoFileWarning\relax + \def\cd@ProduceFile{\immediate\write\csname #1@Stream\endcsname} +/ + +\noindent We set the current file to "wait" and define +the one we're dealing with to be the current file. +/ + \expandafter\let\csname \cd@CurrentFile @Status\endcsname\cd@Wait + \def\cd@CurrentFile{#1} +/ + +\noindent Now, if the file has never been opened, we need +an output stream. If they were all allocated, we look whether +some were made available thanks to a "\CloseFile". +/ + \else\ifnum\cd@ProduceCount>15 + \chardef\cd@ProduceStream=16 + \expandafter\cd@FindStream\cd@StreamList cd@end, +/ + +\noindent If no stream is found, \CD\ feels so bad that it quits. +/ + \ifnum\cd@ProduceStream=16 % + \cd@CDError{% + No more stream for a new file. Close one with \string\CloseFile\space^^J% + (or use the `autoclose' option).^^J% + This situation makes me feel bad. I quit.} + \let\cd@next\@@end +/ + +\noindent Else, we're very happy, and if there is +already a file in production, we close it or let it +wait. +/ + \else + \cd@Tracing{I will now produce file #1} + \ifx\cd@CurrentFile\cd@empty + \else + \ifcd@autoclose + \cd@Tracing{I close file \cd@CurrentFile\space (autoclose mode)} + \expandafter\let\csname \cd@CurrentFile @Status\endcsname\cd@Closed + \else + \expandafter\let\csname \cd@CurrentFile @Status\endcsname\cd@Wait + \fi + \fi +/ + +\noindent Then we define our file as the current one, +let the world know that it is open, allocate the stream +to its name, open it, etc., and launch a macro to retrieve +some information if any. +/ + \def\cd@CurrentFile{#1} + \expandafter\let\csname #1@Status\endcsname\cd@Open + \expandafter\chardef\csname #1@Stream\endcsname\cd@ProduceStream + \immediate\openout\cd@ProduceStream=#1 % + \let\cd@NoFileWarning\relax + \def\cd@ProduceFile{\immediate\write\cd@ProduceStream} + \let\cd@next\cd@GetFile@Produce + \fi +/ + +\noindent If there was an available stream in the first +place, we do exactly the same. +/ + \else\chardef\cd@ProduceStream\cd@ProduceCount + \cd@Tracing{I will now produce file #1} + \ifx\cd@CurrentFile\cd@empty + \else + \ifcd@autoclose + \cd@Tracing{I close file \cd@CurrentFile\space (autoclose mode)} + \expandafter\let\csname \cd@CurrentFile @Status\endcsname\cd@Closed + \else + \expandafter\let\csname \cd@CurrentFile @Status\endcsname\cd@Wait + \fi + \fi + \def\cd@CurrentFile{#1} + \expandafter\let\csname #1@Status\endcsname\cd@Open + \expandafter\chardef\csname #1@Stream\endcsname\cd@ProduceStream + \immediate\openout\cd@ProduceStream=#1 % + \let\cd@NoFileWarning\relax + \def\cd@ProduceFile{\immediate\write\cd@ProduceStream} + \ifcd@autoclose + \else + \advance\cd@ProduceCount\@ne + \fi + \let\cd@next\cd@GetFile@Produce + \fi\fi\fi\fi\cd@next} +/\AddBlankLine + +\DefineMacro\cd@GetFile@Produce +\DefineMacro\cd@GetFileName@Produce +\DefineMacro\cd@GetFileVersion@Produce +\DefineMacro\cd@GetFileDate@Produce +This is designed to retrieve optional information +following "\ProduceFile". We undo the "\ShortVerb" +and "\ShortCode" because they might appear there. +(My "\ShortCode" is a slash, which is used in date too.) +We also set the backslash as an escape character, +because control sequences might appear here. + +In all cases, if nothing follows, and if the "noheader" +option is off, we write the header to the file. +/ +\def\cd@GetFile@Produce{ + \bgroup + \UndoShortCode@Produce + \UndoShortVerb@Produce + \catcode`\\\z@ + \gdef\FileName{} + \gdef\FileVersion{} + \gdef\FileDate{} + \@ifnextchar[ + \cd@GetFileName@Produce + {\ifcd@noheader\else\cd@Header\fi}} +\def\cd@GetFileName@Produce[#1]{ + \xdef\FileName{#1} + \@ifnextchar[ + \cd@GetFileVersion@Produce + {\ifcd@noheader\else\cd@Header\fi\egroup}} +\def\cd@GetFileVersion@Produce[#1]{% + \xdef\FileVersion{#1} + \@ifnextchar[ + \cd@GetFileDate@Produce + {\ifcd@noheader\else\cd@Header\fi\egroup}} +\def\cd@GetFileDate@Produce[#1]{% + \xdef\FileDate{#1} + \ifcd@noheader\else\cd@Header\fi\egroup} +/\AddBlankLine + +\DefineMacro\CloseFile@@Produce +Closing a file is a lot of uninteresting testing... +/ +\def\CloseFile@@Produce#1{ + \ifcd@autoclose + \expandafter\ifx\csname #1@Status\endcsname\relax + \cd@CDWarning{% + You haven't opened `#1'. Closing it does nothing.^^J% + Besides, you're in autoclose mode. \string\CloseFile\space is redundant.} + \else\expandafter\ifx\csname #1@Status\endcsname\cd@Closed + \cd@CDWarning{% + `#1' was already closed. Closing it again does nothing.^^J% + Besides, you're in autoclose mode. \string\CloseFile\space is redundant.} + \else + \cd@CDWarning{% + You're in autoclose mode. \string\CloseFile\space is redundant.} + \fi\fi% + \else + \expandafter\ifx\csname #1@Status\endcsname\relax + \cd@CDWarning{% + You haven't opened `#1'. Closing it does nothing.} + \else\expandafter\ifx\csname #1@Status\endcsname\cd@Closed + \cd@CDWarning{% + `#1' was already closed. Closing it again does nothing.} +/ + +\noindent If everything is okay, beside closing +the file, we also define the no-file warning and neutralize +the writing macro. We also add the stream allocated +to that file to "\cd@StreamList", so that it may be retrieved +if all other streams are unavailable. +/ + \else + \cd@Tracing{I close file #1} + \expandafter\let\csname #1@Status\endcsname\cd@Closed + \def\cd@TempFile{#1} + \ifx\cd@TempFile\cd@CurrentFile + \def\cd@NoFileWarning{\cd@CDWarning{No file in production. ¨This code will be lost.}} + \def\cd@ProduceFile##1{}% + \fi + \edef\cd@StreamList{% + \cd@StreamList\expandafter\the\csname #1@Stream\endcsname,} + \fi\fi\fi} +/\AddBlankLine + +\DefineMacro\cd@StreamList +\DefineMacro\cd@BuildList +The last thing to do is to build that list of streams +made available by the closing of a file. +/ +\def\cd@StreamList{} +\def\cd@BuildList#1cd@end,{\def\cd@StreamList{#1}} +/ + +\DefineMacro\cd@FindStream +When we look for a stream, we simply check +the content of "\cd@BuildList", and if we find +the terminator, this means that no stream has been +made available. Otherwise, we define "\cd@ProduceStream", +which will be allocated to the file we're trying to open, +as the first stream we find in the list, and we rebuild +the latter with the remaining numbers. +/ +\newif\ifcd@stream +\def\cd@FindStream#1,{% + \def\cd@TempArg{#1} + \ifx\cd@TempArg\cd@end + \cd@streamfalse + \let\cd@@next\relax + \else + \cd@streamtrue + \chardef\cd@ProduceStream=#1 % + \let\cd@@next\cd@BuildList + \fi\cd@@next} +/\AddBlankLine + +\DefineMacro\cd@Header +Finally, here's the default header. +/ +\catcode`\%=12\relax +\edef\cd@Header{ +\noexpand\cd@ProduceFile{% This is \noexpand\FileName, produced by the CodeDoc class +^^J% with the `produce' option on. +^^J% +^^J% To create the documentation, compile \cd@CurrentSource +^^J% without the `produce' option. +^^J% +^^J% SOURCE: \noexpand\cd@CurrentSource +^^J% DATE: \noexpand\FileDate +^^J% VERSION: \noexpand\FileVersion +}} +\catcode`\%=14\relax +/\AddBlankLine + +\noindent ... and we say goodbye. The end.\cox[6pt](0,-8pt,10pt,\hskip4pt See you!) +/ +\makeatother +/ + +\def\section*#1{\part{#1} +\itshape +This index was generated by the \emph{\texttt{\bslash DescribeMacro}}-like +commands. It only reports where macros are described (page numbers in +normal font) and defined (page numbers in italics). +In the current version, \CD\ does not index macros when used in the code. + +Entries are sorted ignoring the \emph{\texttt{cd@}} and \emph{\texttt{cd@@}} prefixes.\vskip1em} +\let\partname\relax +\let\thepart\relax +\catcode`\Z=0 +\leftskip0pt +\printindex +\catcode`\Z=11 + +\end{document} + diff --git a/Master/texmf-dist/doc/latex/codedoc/README b/Master/texmf-dist/doc/latex/codedoc/README new file mode 100644 index 00000000000..09e5667b32b --- /dev/null +++ b/Master/texmf-dist/doc/latex/codedoc/README @@ -0,0 +1,31 @@ +This is the file README for the CodeDoc class, v.0.1. +You'll find complete documentation in CodeDoc-manual.pdf + +This class produces code and documentation in a single file without departing from LaTeX's ordinary +syntax. + + +TO PRODUCE THE DOCUMENTATION: +Run LaTeX on CodeDoc-manual.tex (better in PDF). +In the document class options of the latter file, +you may uncomment the `obeystop' option and/or +comment out the `index' option to remove the +implementation from the documentation and/or +the index. +Don't forget to run LaTeX and MakeIndex as many +times as necessary. + +TO PRODUCE THE CLASS ITSELF (codedoc.cls): +Uncomment the `produce' option among the +class options and run LaTeX on the same file +(CodeDoc-manual.tex). +This serves as an illustration only, since +to do so you already need codedoc.cls, obviously. +This file should thus be included in any distribution. + + +Licensing of this package is covered by LPPL. + +Any reaction is welcome: zappathustra@free.fr + +Paul Isambert -- cgit v1.2.3