% \iffalse meta-comment % % Copyright 1994 the LaTeX3 project and the individual authors. % All rights reserved. For further copyright information see the file % legal.txt, and any other copyright indicated in this file. % % This file is part of the LaTeX2e system. % ---------------------------------------- % % This system is distributed in the hope that it will be useful, % but WITHOUT ANY WARRANTY; without even the implied warranty of % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. % % % IMPORTANT NOTICE: % % For error reports in case of UNCHANGED versions see bugs.txt. % % Please do not request updates from us directly. Distribution is % done through Mail-Servers and TeX organizations. % % You are not allowed to change this file. % % You are allowed to distribute this file under the condition that % it is distributed together with all files mentioned in manifest.txt. % % If you receive only some of these files from someone, complain! % % You are NOT ALLOWED to distribute this file alone. You are NOT % ALLOWED to take money for the distribution or use of either this % file or a changed version, except for a nominal charge for copying % etc. % \fi \def\filename{docstrip.dtx} \def\fileversion{2.2h} \def\filedate{1994/02/26} \def\docdate {1994/06/09} % \CheckSum{1504} %% \CharacterTable %% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z %% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z %% Digits \0\1\2\3\4\5\6\7\8\9 %% Exclamation \! Double quote \" Hash (number) \# %% Dollar \$ Percent \% Ampersand \& %% Acute accent \' Left paren \( Right paren \) %% Asterisk \* Plus \+ Comma \, %% Minus \- Point \. Solidus \/ %% Colon \: Semicolon \; Less than \< %% Equals \= Greater than \> Question mark \? %% Commercial at \@ Left bracket \[ Backslash \\ %% Right bracket \] Circumflex \^ Underscore \_ %% Grave accent \` Left brace \{ Vertical bar \| %% Right brace \} Tilde \~} %% % %\iffalse % %% The docstrip program for use with TeX. %% Copyright (C) 1989-1991 Frank Mittelbach %% Copyright (C) 1992-1994 Johannes Braams, Denys Duchier, %% Frank Mittelbach %% All rights are reserved. %% % % \fi % % \changes{2.0b}{1991/05/29}{Added bugfix from Denys} % \changes{2.0c}{1991/05/29}{Allow almost all characters in guard (DD)} % \changes{2.0d}{1991/05/31}{Started merging in some of Franks code} % \changes{2.0j}{1992/03/05}{Wrote introduction} % \changes{2.0m}{1992/04/21}{Renamed all macros that deal with the % parsing of boolean expressions} % \changes{2.0m}{1992/04/25}{Removed dependency from ltugboat, % incorporated driver file into source.} % \changes{2.0m}{1992/04/25}{Added some missing percents; corrected some % typos} % \changes{2.0m-DL}{1992/05/08}{Various small corrections to English and % typos} % \changes{2.0q}{1992/07/01}{Changed all dates to yy/mm/dd for better % sorting} % \changes{2.2a}{1993/12/02}{Update for LaTeX2e} % \changes{2.2c}{1993/12/17}{Renamed texsys.tex to texsys.cfg.} % % \DoNotIndex{\#,\$,\%,\&,\@,\\,\{,\},\^,\_,\~,\ } % \DoNotIndex{\@ne} % \DoNotIndex{\advance,\begingroup,\catcode,\closein,\closeout} % \DoNotIndex{\day,\def,\edef,\else,\empty,\endgroup,\errmessage} % \DoNotIndex{\expandafter,\fi,\futurelet,\gdef,\global,\if,\ifeof} % \DoNotIndex{\ifx,\immediate,\let,\loop,\m@ne,\message,\month} % \DoNotIndex{\newcount} % \DoNotIndex{\newif,\newlinechar,\newread,\newtoks,\newwrite} % \DoNotIndex{\noexpand,\openin,\openout,\par,\read,\relax,\repeat} % \DoNotIndex{\space,\the,\undefined,\write,\xdef,\year,\z@} % % ^^A some definitions for this documentation % % \newcommand{\ds}{\textsf{DocStrip}} ^^A maybe? % \newcommand{\bsl}{\protect\bslash} % \newcommand{\note}[1]{\marginpar{\textbf{#1}}} % \newcommand{\netaddress}[1]{\texttt{#1}} % % ^^A override the default in doc.sty % \makeatletter % \renewenvironment{theglossary}{% % \glossary@prologue% % \GlossaryParms \let\item\@idxitem \ignorespaces}% % {} % \makeatother % % % \changes{2.1c}{1993/02/25}{Added a setting for StandardModuleDepth} % \setcounter{StandardModuleDepth}{1} % % \title{The \ds{} program% % \thanks{This file has version number \fileversion, % last revised \filedate, % documentation dated \docdate.}} % % \changes{2.1b}{1993/02/23}{modified mailaddress of Johannes} % \author{% % Frank Mittelbach \\ % \netaddress{Mittelbach@mzdmza.zdv.uni-mainz.de} % \and % Denys Duchier \\ % \netaddress{duchier-denys@cs.yale.edu} % \and % Johannes Braams \\ % PTT Research Neher Laboratories\\ % P.O. Box 421\\ % 2260 AK Leidschendam\\ % \netaddress{J.L.Braams@research.ptt.nl}} % % \date{Printed \today} % % \maketitle % % \begin{abstract} % This document describes the implementation of the \ds{} program. % The original version of this program was developed by Frank % Mittelbach to accompany his \texttt{doc.sty} which enables literate % programming in \LaTeX\@. Denys Duchier rewrote it to run either % with \TeX\ or of \LaTeX, and to allow full boolean expressions in % conditional guards instead of just comma-separated lists. % Johannes Braams re-united the two implementations, documented and % debugged the code. % \end{abstract} % % \section{Introduction} % % \subsection{Why the \ds{} program?} When Frank Mittelbach created % the \texttt{doc} package, he invented a way to combine \TeX\ code % and its documentation. From then on it was more or less possible % to do literate programming in \TeX. % % This way of writing \TeX\ programs obviously has great % advantages, especially when the program becomes larger than a % couple of macros. There is one drawback however, and that is % that such programs may take longer than expected to run because % \TeX\ is an interpreter and has to decide for each line of the % program file what it has to do with it. Therefore, \TeX\ programs % may be speeded up by removing all comments from them. % % By removing the comments from a \TeX\ program a new problem is % introduced. We now have two versions of the program and both of % them {\em have\/} to be maintained. Therefore it would be nice to % have a possibility to remove the comments automatically, instead % of doing it by hand. So we need a program to remove comments from % \TeX\ programs. This could be programmed in any high level % language, but maybe not everybody has the right compiler to % compile the program. Everybody who wants to remove comments from % \TeX\ programs has \TeX\@. Therefore the \ds{} program is % implemented entirely in \TeX. % % \subsection{Functions of the \ds{} program} % % Having created the \ds{} program to remove comment lines from % \TeX\ programs\footnote{Note that only comment lines, that is % lines that start with a single \texttt{\%} character, are removed; % all other comments st in the code.} it became feasible to do more % than just strip comments.\\ Wouldn't it be nice to have a way to % include parts of the code only when some condition is set true? % Wouldn't it be as nice to have the possibility to split the % source of a \TeX\ program into several smaller files and combine % them later into one `executable'?\\ Both these wishes have been % implemented in the \ds{} program. % % \subsection{How to use the \ds{} program} % A number of ways exist to use the \ds{} program: % \begin{enumerate} % \item The easiest way is to instruct \TeX\ to read the file % \texttt{docstrip.tex} and to see what happens. \TeX\ will ask % you a few questions about the file you would like to be % processed. When you have answered these questions it does % its job and strips the comments from your \TeX\ code. % \item When you would like to be able to process more than one % file with one command, or you would like to add a couple of % lines to the beginning (or end) of the stripped file you can % write a `batch file' for \ds{}. The default name for such a % file is \texttt{docstrip.cmd}. When a file by that name % exists in your current directory when you instruct \TeX\ to % read \texttt{docstrip.tex} it will verify (by asking you) % that you want to use {\em that\/} file and if so, will % process the commands in it. % % You do not need to use the default name, however. You can % give a batch file any name you like such as, say, % \texttt{foo.bar} and then run \TeX\ by using a command such as: % \begin{verbatim} % TeX \def\batchfile{foo.bar}\input docstrip % \end{verbatim} % % \item You may use yet another way that is only slightly different % from the previous method. You can write a batch file in such % a way that it can be directly processed by \TeX{}. This % allows you to set up a distribution where you can instruct % the user to simply run % \begin{quote} % \texttt{TEX} \meta{batch file} % \end{quote} % to generate the executable versions of your files from the % distribution sources. All distributions from Mainz are set up % in this way (also this one); look, for example, at the % installation file for this distribution. To produce such a % batch file include a statement in your `batch file' that % instructs \TeX\ to read \texttt{docstrip.tex}. You should then % also define \verb=\batchfile= to contain the name of that % `batch file'. The beginning of such a file would look like: % \begin{verbatim} % \def\batchfile{install.me} % \input docstrip % ... % \end{verbatim} % \end{enumerate} % % \section{The user interface} % % \subsection{The main program} % \DescribeMacro{\processbatchFile} The `main program' starts with % trying to process a batch file, this is accomplished by calling % the macro |\processbatchFile|. It counts the number of batch % files it processes, so that when the number of files processed is % still zero after the call to |\processbatchFile| appropriate % action can be taken. % % \DescribeMacro{\interactive} When no batch files have been processed % the macro |\interactive| is called. It prompts the user for % information. First the extensions of the input and output files % is determined. Then a question about optional code is asked and % finally the user can give a list of files that have to be % processed. % % \DescribeMacro{\ReportTotals} When the \texttt{stats} option is % included in the \ds{}-program it keeps a record of the number of % files and lines that are processed. Also the number of comments % removed and passed as well as the number of code lines that were % passed to the output are accounted. The macro |\ReportTotals| % shows a summary of this information. % % \subsection{Batchfile commands} % % The commands described in this section are available to build a % batch file. % % \DescribeMacro{\showprogress} % \DescribeMacro{\keepsilent} % When the option \texttt{stats} is included in \ds{} it can % write message to the terminal as each line of the input file(s) is % processed. This message consists of a single character, indicating % what the program does with that particular line. We use the % following characters: % \begin{itemize} % \item[\texttt{\%}] Whenever an input line is removed a % \texttt{\%}-character is written to the terminal. % \item[\texttt{.}] Whenever a code line is passed on to the output file % a \texttt{.}-character is written on the terminal. % \item[\texttt{/}] When a number of empty lines appear in a row in the % input file, at most one of them is retained. The \ds{} % program signals the removal of an empty line with the % \texttt{/}-character. % \item[\texttt{<}] When a `guard line' is found in the input and it % starts a block of optionally included code, this is signalled % on the terminal by showing the \texttt{<}-character, together % with the boolean expression of the guard. % \item[\texttt{>}] The end of a conditionally included block of code is % indicated by showing the \texttt{>}-character. % \end{itemize} % This feature is turned on by default when the option % \texttt{stats} is included, otherwise it is turned of. The % feature can be toggled with the commands |\showprogress| and % |\keepsilent| % % \DescribeMacro{\preamble} % \DescribeMacro{\endpreamble} % \DescribeMacro{\postamble} % \DescribeMacro{\endpostamble} % It is possible to add a number of lines to the output of % the \ds{} program. The information you want to add to the % start of the output file should be listed between the |\preamble| % and |\endpreamble| commands; the lines you want to add to the end % of the output file should be listed between the |\postamble| and % |\endpostamble| commands. Everything that \ds{} finds % for both the pre- and postamble it writes to the output file, but % preceded with two \%-characters. If you include a |^^M| character % in one of these lines, everything that follows it on the same line % is written to a new line in the output file. % This `feature' can be used to add a |\typeout| or |\message| to the % the stripped file. % % \DescribeMacro{\generateFile} % The main reason for constructing a \ds{} command file is that % one doesn't want to type in the instructions for \TeX\ each time % a macro file is stripped of its comments. The macro |\generateFile| % is used to tell \TeX\ what to do. Its syntax is: % \begin{quote} % |\generateFile{|\meta{output}|}{|\meta{ask}|}{|[|\from{|^^A % \meta{input}|}{|\meta{optionlist}|}|]*|}| % \end{quote} % The \meta{output} and \meta{input} are normal file specifications % as are appropriate for your computer system. The \meta{optionlist} % is a comma separated list of `options' that specify which % optional code fragments in \meta{input} should be included in % \meta{output}. With \meta{ask} you can instruct \TeX\ to either % silently overwrite a previously existing file (|f|) or to issue a % warning and ask you if it should overwrite the existing file % (|t|). % % It is possible to specify multiple input files, each with its own % \meta{optionlist}. This is indicated by the notation [\ldots]*. % % \DescribeMacro{\include} % \DescribeMacro{\processFile} % The earlier version of the \ds{} program supported a % different kind of command to tell \TeX\ what to do. This command % is less powerful than |\generateFile|; it can be used when % \meta{output} is created from one \meta{input}. The syntax is: % \begin{quote} % |\include{|\meta{optionlist}|}| % % |\processFile{|\meta{name}|}{|\meta{inext}^^A % |}{|\meta{outext}^^A % |}{|\meta{ask}|}| % \end{quote} % This command is based on environments where filenames are % constructed of two parts, the name and the extension, separated % with a dot. The syntax of this command assumes that the % \meta{input} and \meta{output} share the same name and only % differ in their extension. This command is retained to be % backwards compatible with the older version of \ds{}, but its use % is not encouraged. % % \DescribeMacro{\input} % \DescribeMacro{\batchinput} % The batch file commands can be put into several batch files which % are then executed from a master batch file. This is, for example, % useful if a distribution consists of several distinct parts. You % can then write individual batch files for every part and in % addition a master file that simply calls the batch files for the % parts. For this, call the individual batch files from the master % file with the command |\batchinput{|\meta{file}|}|. You can nest % batch files up to a nesting level of ten which is more than % sufficient. Don't use |\input| for this purpose, this command % should be used only for calling the \ds{} program as explained % above and is ignored when used for any other purpose. % % \DescribeMacro{\ifToplevel} % When batch files are nested you may want to suppress certain % commands in the lower-level batch files such as terminal % messages. For this purpose you can use the |\ifToplevel| command % which executes its argument only if the current batch file is the % outermost one. Make sure that you put the opening brace of the % argument into the same line as the command itself, otherwise the % \ds{} program will get confused. % % \section{Conditional inclusion of code} % % When you use the \ds{} program to strip comments out of % \TeX\ macro files you have the possibility to make more than one % stripped macro file from one documented file. This is achieved by % the support for optional code. The optional code is marked % in the documented file with a `guard'. % % A guard is a boolean expression that is enclosed in |<| and |>|. % It also {\em has\/} to follow the |%| at the beginning of the line. % For example: %\begin{verbatim} % ... % %\TeX code % ... %\end{verbatim} % In this example the line of code will be included in \meta{output} % if the option \texttt{bool} is present in the \meta{optionlist} of % the |\generateFile| command. % % The syntax for the boolean expressions is: % %\DeleteShortVerb\| % \begin{tabular}{lcl} % \meta{Expression} & $::=$ & \meta{Primary} % [\{\texttt{|}, \texttt{,}\} % \meta{Primary}]*\\ % \meta{Primary} & $::=$ & % \meta{Secondary} [\texttt{\&} % \meta{Secondary}]*\\ % \meta{Secondary} & $::=$ & % \meta{Terminal} $|$ \texttt{!}\meta{Secondary} % $|$ \texttt{(}\meta{Expression}\texttt{)}\\ % \end{tabular} % % The \texttt{|} stands for disjunction, the \texttt{\&} stands for % conjunction and the \texttt{!}\ stands for negation. The % \meta{Terminal} is any sequence of letters and evaluates to % \meta{true} iff\footnote{iff stands for `if and only if'} it % occurs in the list of options that have to be included. %\MakeShortVerb\| % % Two kinds of optional code are supported: one can either have % optional code that `fits' on one line of text, like the example % above, or one can have blocks of optional code. % % To distinguish both kinds of optional code the `guard modifier' % has been introduced. The `guard modifier' is one character that % immediately follows the |<| of the guard. It can be either |*| % for the beginning of a block of code, or |/| for the end of a % block of code\footnote{To be compatible with the earlier version % of \ds{} also \texttt{+} and \texttt{-} are supported as `guard % modifiers'. However, there is an incompatibility with the % earlier version since a line with a \texttt{+}-modified guard is % not included inside a block with a guard that evaluates to false, % in contrast to the previous behaviour.}. The beginning and % ending guards for a block of code have to be on a line by % themselves. % % When a block of code is {\em not\/} included, any guards that occur % within that block are {\em not\/} evaluated. % %\StopEventually{% %^^A \section{Conclusion} % \PrintIndex % \PrintChanges %^^A \makesignature % } % % \section{Producing the documentation} % % We provide a short driver file that can be extracted by the % \ds{} program using the the conditional `\textsf{driver}'. To % allow the use of \texttt{docstrip.dtx} as a program at Ini\TeX{} % time (e.g., to strip % off its own comments) we need to add a bit of primitive code. % With this extra checking it is still possible to process this % file with \LaTeXe{} to typeset the documentation. % \changes{2.1b}{1993/02/23}{Added fontdefinitions for doc to the driver % file, in order to get the layout of the code % right; also added the layout definitions % that are in effect in \texttt{doc.drv}} % \changes{2.1c}{1993/02/23}{Remove definitions for fonts again} % \changes{2.2f}{1994/02/26}{Allow direct processing of source} % \begin{macrocode} %<*driver> % \end{macrocode} % If |\documentclass| is undefined, e.g., if Ini\TeX{} or plain % \TeX{} is used for formatting, we bypass the driver file. % \begin{macrocode} \ifx\documentclass\undefined \else % \end{macrocode} % Otherwise we process the following lines which will result in % formatting the documentation. % \begin{macrocode} \documentclass{ltxdoc} \EnableCrossrefs % \DisableCrossrefs % use \DisableCrossrefs if the % index is ready \RecordChanges % \OnlyDescription \typeout{Expect some Under- and overfull boxes} \begin{document} \DocInput{docstrip.dtx} % \end{macrocode} % We cannot call |\end{document}| at this point because this would % leave the |\ifx| from above unfinished and the user would get a % warning message. Therefore we do some |\expandafter| processing; % hiding the |\end{document}| for a moment in a scratch macro for % easier processing. % \begin{macrocode} \renewcommand\next{\end{document}} \expandafter\next\fi % % \end{macrocode} % % % \section{The implementation} % % \subsection{Declarations and initializations} % % In order to be able to include the \texttt{@}-sign in control % sequences its category code is changed to \meta{letter}. The % `program' guard here allows most of the code to be excluded when % extracting the driver file. % \begin{macrocode} %<*program> \catcode`\@=11 % \end{macrocode} % % When we want to write multiple lines to the terminal with one % statement, we need a character that tells \TeX\ to break the lines. % We use \verb=^^J= for this purpose. % \begin{macrocode} \newlinechar=`\^^J % \end{macrocode} % % \subsubsection{Token registers} % \begin{macro}{\TerminalString} % \changes{2.0m}{1992/04/22}{Renamed from \texttt{\bsl boolToks}} % A token register is allocated that will be used to accumulate % the tokens that make up a \meta{Terminal} in the process % of scanning guards. % \begin{macrocode} \newtoks\TerminalString % \end{macrocode} % \end{macro} % % \subsubsection{Switches} % \begin{macro}{\ifOff} % \begin{macro}{\ifGenerate} % The switch \verb=\ifOff= will be used to signal if code lines % have to be included in the output. The program will check if a % file of the same name as the file it would be creating already % exists. The switch \verb=\ifGenerate= is used to indicate if the % stripped file has to be generated. % \begin{macrocode} \newif\ifOff \newif\ifGenerate % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\ifContinue} % The switch \verb=\ifContinue= is used in various places in the % program to indicate if a \verb=\loop= has to end. % \begin{macrocode} \newif\ifContinue % \end{macrocode} % \end{macro} % % \begin{macro}{\ifTerminal} % The macros that parse the boolean expression in the guards need % a switch to indicate if a \meta{Terminal} has been found. % \changes{2.0l}{1992/04/17}{Renamed from \texttt{\bsl ifName}.} % \begin{macrocode} \newif\ifTerminal % \end{macrocode} % \end{macro} % % \begin{macro}{\ifForlist} % \changes{2.0g}{1991/06/05}{Macro added.} % The program contains an implementation of a for-loop, based on % plain \TeX{}'s \verb=\loop= macros. The implementation needs a % switch to terminate the loop. % \begin{macrocode} \newif\ifForlist % \end{macrocode} % \end{macro} % % \begin{macro}{\ifDefault} % The switch \verb=\ifDefault= is used to indicate whether the % default batch file has to be used. % \changes{2.0f}{1991/06/04}{Macro added.} % \begin{macrocode} \newif\ifDefault % \end{macrocode} % \end{macro} % % \begin{macro}{\ifMoreFiles} % The switch \verb=\ifMoreFiles= is used to decide if the user % wants more files to be processed. It is used only in interactive % mode; initially it evaluates to \meta{true}. % \changes{2.0h}{1991/06/19}{Macro added.} % \begin{macrocode} \newif\ifMoreFiles \MoreFilestrue % \end{macrocode} % \end{macro} % % \subsubsection{Count registers} % \begin{macro}{\blockLevel} % Optionally included blocks of code can be nested. The counter % \verb=\blockLevel= will be used to keep track of the level of % nesting. Its initial value is zero. % \begin{macrocode} \newcount\blockLevel \blockLevel\z@ % \end{macrocode} % \end{macro} % % \begin{macro}{\offLevel} % The count register \verb=\offLevel= is used to % count the number of levels since the first block whose guard % evaluated to false. When this number reaches zero again we set the % switch \verb=\ifOff= to false again. % \begin{macrocode} \newcount\offLevel \offLevel \z@ % \end{macrocode} % \end{macro} % % \begin{macro}{\emptyLines} % The count register \verb=\emptyLines= is used to count the number % of consecutive empty input lines. Only the first will be copied % to the output file. % \changes{2.0i}{1990/06/27}{Macro added} % \begin{macrocode} \newcount\emptyLines \emptyLines \z@ % \end{macrocode} % \end{macro} % % \begin{macro}{\processedLines} % \begin{macro}{\commentsRemoved} % \begin{macro}{\commentsPassed} % \begin{macro}{\codeLinesPassed} % To be able to provide the user with some statistics about the % stripping process four counters are allocated if the statistics % have been included when this program was \ds{}ped. The number of % lines processed is stored in the counter \verb=\processedLines=. % The number of lines containing comments that are not written on % the output file is stored in the counter \verb=\commentsRemoved=; % the number of comments copied to the output file is stored in the % counter \verb=\commentsPassed=. The number of lines containing % macro code that are copied to the output file is stored in the % counter \verb=\codeLinesPassed=. % \begin{macrocode} %<*stats> \newcount\processedLines \processedLines \z@ \newcount\commentsRemoved \commentsRemoved \z@ \newcount\commentsPassed \commentsPassed \z@ \newcount\codeLinesPassed \codeLinesPassed \z@ % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\NumberOfFiles} % When more than one file is processed, the number of files is % stored in the count register \verb=\NumberOfFiles= when % statistics are included. % \begin{macrocode} \newcount\NumberOfFiles \NumberOfFiles\z@ % \end{macrocode} % \end{macro} % % \changes{2.0e}{1991/05/31}{Added counter allocation for the processing % of multiple files} % \begin{macro}{\TotalprocessedLines} % \begin{macro}{\TotalcommentsRemoved} % \begin{macro}{\TotalcommentsPassed} % \begin{macro}{\TotalcodeLinesPassed} % When more than one file is processed and when statistics have % been included we provide the user also with information about the % total amount of lines processed. For this purpose four more count % registers are allocated here. % \begin{macrocode} \newcount\TotalprocessedLines \TotalprocessedLines \z@ \newcount\TotalcommentsRemoved \TotalcommentsRemoved \z@ \newcount\TotalcommentsPassed \TotalcommentsPassed \z@ \newcount\TotalcodeLinesPassed \TotalcodeLinesPassed \z@ % % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \subsubsection{I/O streams} % \begin{macro}{\inFile} % \begin{macro}{\outFile} % For reading the file with documented \TeX-code, an input stream % \verb=\inFile= is allocated. The stripped code is written on % the output stream \verb=\outFile=. % \begin{macrocode} \newread\inFile \newwrite\outFile % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\ttyin} % \begin{macro}{\ttyout} % For the communication with the user an input stream, \verb=\ttyin= % and an output stream, \verb=\ttyout= are allocated. % \begin{macrocode} \newread\ttyin \newwrite\ttyout % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\currbatchFile} % \changes{2.0e}{1991/05/31}{Added allocation of extra input stream % for batch files} % \changes{2.1a}{1993/02/22}{Renamed from `batchFile to `currbatchFile} % \changes{2.1a}{1993/02/22}{Logic changed} % For batch file processing we need a number of input streams so % that a batch file can open further batch files using % |\batchinput|. % % We begin by allocating ten anonymous read streams. % \begin{macrocode} \newread\@tempa % \end{macrocode} % \begin{macro}{\lowestbatchFile} % We save the lowest number allocated in |\lowestbatchFile|, of % course this code highly depends on the implementation of the % plain allocation routines. % \begin{macrocode} \let\lowestbatchFile\@tempa \newread\@tempa \newread\@tempa \newread\@tempa \newread\@tempa \newread\@tempa \newread\@tempa \newread\@tempa \newread\@tempa \newread\@tempa % \end{macrocode} % \begin{macro}{\highestbatchFile} % Same for the highest number. % \begin{macrocode} \let\highestbatchFile\@tempa % \end{macrocode} % Now we allocate a count register which is supposed to hold the % the number of the batch file stream we are currently reading % from. Initially this will contain the number for the first read % stream allocated for this reason. % \begin{macrocode} \newcount\currbatchFile \currbatchFile=\highestbatchFile \advance\currbatchFile by -9 % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\ifToplevel} % Execute the argument if current batch file is the outermost one. % Otherwise suppress it. % \begin{macrocode} \def\ifToplevel{\relax\ifnum\currbatchFile=\lowestbatchFile \expandafter\iden \else \expandafter\gobble\fi} % \end{macrocode} % \end{macro} % % \begin{macro}{\batchinput} % \changes{2.0n}{1992/04/26}{Added macro} % \changes{2.1a}{1993/02/22}{Completely redefined (so that it works)} % % When the file \texttt{docstrip.tex} is read because of an % \verb=\input= statement in a batch file we have to prevent an % endless loop (well, limited by \TeX's stack). Therefore we save % the original primitive \verb=\input= and define a new macro with % an argument delimited by \verb*= = (i.e.\ a space) that just % gobbles the argument. Since the end-of-line character is % converted by \TeX{} to a space. This means that |\input| is not % available as a command within batch files. In fact it would be % dangerous to use it anyway, since it would mean mixing line for % line reading with unlimited file reading. % % \begin{macro}{\@@input} % \changes{2.1a}{1993/02/22}{Macro added} % We therefore keep a copy of the original under the name % |\@@input| for internal use. If \ds{} runs under \LaTeX{} this % command is already defined, so we make a quick test. % \begin{macrocode} \ifx\undefined\@@input \let\@@input\input\fi % \end{macrocode} % \end{macro} % % To allow the nesting of batch files the |\batchinput| command is % provided it takes one argument, the name of the batch file to % switch to. % \begin{macrocode} \def\batchinput#1{% % \end{macrocode} % We start a new group and locally redefine |\batchFile| to hold % the new batch file name and advance |\currbatchFile| by one to % get a new read stream. If the batch files are too deeply nested % there may be no further stream available so we better check for % this. The currently supported number is 10 which is generous % enough even for large installation procedures. % \begin{macrocode} \begingroup \def\batchfile{#1}% \advance\currbatchFile\@ne \ifnum\currbatchFile>\highestbatchFile \errhelp{Only up to ten levels of nesting for \noexpand\batchinput commands are supported}% \errmessage{Batchfiles too deeply nested}% \fi % \end{macrocode} % After this test we can simply call |\processbatchFile| which will % open the new batch file and does a line for line reading until it % is exhausted. Note that if the batch file is not available, or % misspelled this routine will produce a warning and returns. % \begin{macrocode} \processbatchFile % \end{macrocode} % The closing |\endgroup| will then restore the values for % |\batchfile| and |\currbatchFile| so that further processing % continues in the calling batch file. % \begin{macrocode} \endgroup } % \end{macrocode} % \begin{macro}{\skip@input} % \changes{2.0j}{1992/03/03}{Added macro} % \changes{2.0n}{1992/04/26}{Argument delimited by space not `relax} % \changes{2.0n}{1992/04/26}{Macro renamed from `skipinput} % And here is the promised redefinition of |\input|: % \begin{macrocode} \def\skip@input#1 {} \let\input\skip@input % \end{macrocode} % \end{macro} % \end{macro} % % \subsubsection{Empty macros and macros that expand to a string} % \begin{macro}{\guardStack} % \changes{2.0k}{1992/04/06}{Renamed from \texttt{\bsl blockStack}} % Because blocks of code that will conditionally be included in the % output can be nested, a stack is maintained to keep track of % these blocks. The main reason for this is that we want to be able % to check if the blocks are properly nested. The stack itself is % stored in |\guardStack|. % \begin{macrocode} \def\guardStack{} % \end{macrocode} % \end{macro} % % \begin{macro}{\blockHead} % The macro \verb=\blockHead= is used for storing and retrieving % the boolean expression that starts a block. % \begin{macrocode} \def\blockHead{} % \end{macrocode} % \end{macro} % % \begin{macro}{\Options} % \begin{macro}{\lastOption} % The list of options to include in the output is stored in % \verb=\Options=. The macro \verb=\lastOption= is used to remember % which option was started. % \begin{macrocode} \def\Options{} \def\lastOption{} % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\TrueExpression} % \begin{macro}{\FalseExpression} % In the evaluation of the boolean expressions a representation is % needed for \meta{true} and \meta{false}. This representation is % realized by the definition of |\TrueExpression| and % |\FalseExpression|. These macros are meant to be used with \TeX's % |\if|-test. When the expression |\if\TrueExpression...| is % expanded by \TeX\ it yields |\if TT...|. This test is true and % all instructions following the test (until |\else| or |\fi| is % encountered) will examined. % \begin{macrocode} \def\TrueExpression{TT} \def\FalseExpression{TF} % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\yes} % \begin{macro}{\y} % When the user is asked a question that he has to answer with either % \meta{yes} or \meta{no}, his response has to be evaluated. For this % reason the macros \verb=\yes= and \verb=\y= are defined. % \begin{macrocode} \def\yes{yes} \def\y{y} % \end{macrocode} % \begin{macro}{\n} % We also define \verb=\n= for use in \ds{} command files. % \changes{v2.1e}{1993/03/09}{Macro added} % \begin{macrocode} \def\n{n} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\Defaultbatchile} % \changes{2.0f}{1991/06/04}{Macro added.} % When the \ds{} program has to process a batch file it % can look for a batch file with a default name. This name % is stored in \verb=\DefaultbatchFile=. % \begin{macrocode} \def\DefaultbatchFile{docstrip.cmd} % \end{macrocode} % \end{macro} % % \begin{macro}{\perCent} % \begin{macro}{\DoubleperCent} % To be able to display percent-signs on the terminal, a \texttt{\%} % with category code 12 is stored in \verb=\perCent=. The macro % \verb=\DoubleperCent= is used to write two percent-signs when % writing the preamble of the output file. % \begin{macrocode} {\catcode`\%=12 \gdef\perCent{%} \gdef\DoubleperCent{%% } } % \end{macrocode} % \end{macro} % \end{macro} % In order to allow formfeeds in the input we define a one-character % control sequence \verb=^^L=. % \begin{macrocode} \def^^L{ } % \end{macrocode} % % \subsubsection{Miscellaneous variables} % \begin{macro}{\inFileName} % The macro \verb=\inFileName= is used to store the name of the % current input file. % \end{macro} % \begin{macro}{\outFileName} % The macro \verb=\outFileName= is used to store the name of the % current output file. % \end{macro} % \begin{macro}{\batchfile} % The macro \verb=\batchfile= is used to store the name of the % batch file. % \end{macro} % \begin{macro}{\inLine} % The macro \verb=\inLine= is used to store the lines, read from % the input file, before further processing. % \end{macro} % \begin{macro}{\batchLine} % The macro \verb=\batchLine= is used to store the lines, read from % the batch file, before further processing. % \end{macro} % \begin{macro}{\nextToken} % In this \TeX-program a lot of `peeking ahead' using the % \verb=\futurelet= instruction is done. In such cases the % character that appears first in the input stream is stored in % \verb=\nextToken=. % \end{macro} % \begin{macro}{\doNext} % Another aspect of this program is that quite often the next action % depends on the evaluation of an \verb=\if= construct. In such cases % the control sequence \verb=\doNext= is \verb=\let= to the macro % that has to be executed. % \end{macro} % \begin{macro}{\answer} % When some interaction with the user is needed the macro % \verb=\answer= is used to store his response. % \end{macro} % \begin{macro}{\tmp} % Sometimes something has to be temporarily stored in a control % sequence. For these purposes the control sequence \verb=\tmp= is % used. % \end{macro} % % \subsection{Support macros} % \subsubsection{The stack mechanism} % % It is possible to have `nested guards'. This means that within a % block of optionally included code a subgroup is only included % when an additional option is specified. To keep track of the % nesting of the guards the currently `open' guard can be pushed on % the stack |\guardStack| and later popped off the stack again. The % macros that implement this stack mechanism are loosely based on % code that is developed in the context of the \LaTeX3 project. % % To be able to implement a stack mechanism we need a couple of % support macros. % \begin{macro}{\eltStart} % \changes{2.0k}{1992/04/06}{Macro added} % \begin{macro}{\eltEnd} % \changes{2.0k}{1992/04/06}{Macro added} % The macros |\eltStart| and |\eltEnd| are used to delimit a stack % element. They are both empty. % \begin{macrocode} \def\eltStart{} \def\eltEnd{} % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\qStop} % \changes{2.0k}{1992/04/06}{Macro added} % The macro |\qStop| is a so-called `quark', a macro that expands to % itself\footnote{The concept of `quarks' is developed for the % \LaTeX3 project.}. % \begin{macrocode} \def\qStop{\qStop} % \end{macrocode} % \end{macro} % % \begin{macro}{\pop} % \changes{2.0k}{1992/04/06}{Macro added} The macro % |\pop|\meta{stack}\meta{cs} `pops' the top element from the % stack. It assigns the value of the top element to \meta{cs} and % removes it from \meta{stack}. When \meta{stack} is empty a % warning is issued and \meta{cs} is assigned an empty value. % \begin{macrocode} \def\pop#1#2{% \ifx#1\empty \Msg{Warning: Found end guard without matching begin}% \let#2\empty \else % \end{macrocode} % To be able to `peel' off the first guard we use an extra macro % |\popX| that receives both the expanded and the unexpanded stack % in its arguments. The expanded stack is delimited with the quark % |\qStop|. % \begin{macrocode} \def\tmp{\expandafter\popX #1\qStop #1#2}% \expandafter\tmp\fi} % \end{macrocode} % \begin{macro}{\popX} % \changes{2.0k}{1992/04/06}{Macro added} When the stack is expanded % the elements are surrounded with |\eltStart| and |\eltEnd|. The % first element of the stack is assigned to |#4|. % \begin{macrocode} \def\popX\eltStart #1\eltEnd #2\qStop #3#4{\def#3{#2}\def#4{#1}} % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\push} % \changes{2.0k}{1992/04/06}{Macro added} % Guards can be pushed on the stack using the macro % |\push|\meta{stack}\meta{guard}. Again we need a secondary macro % (|\pushX|) that has both the expanded and the unexpanded stack as % arguments. % \begin{macrocode} \def\push#1#2{\expandafter\pushX #1\qStop #1{\eltStart #2\eltEnd}} % \end{macrocode} % \begin{macro}{\pushX} % \changes{2.0k}{1992/04/06}{Macro added} % The macro |\pushX| picks up the complete expansion of the stack as % its first argument and places the guard in |#3| on the `top'. % \begin{macrocode} \def\pushX #1\qStop #2#3{\def #2{#3#1}} % \end{macrocode} % \end{macro} % \end{macro} % % \subsubsection{Programming structures} % % \begin{macro}{\forlist} % \changes{2.0g}{1991/06/05}{Macro added.} % When the program is used in interactive mode the % user can supply a list of files that have to be processed. % In order to process this list a for-loop is needed. This % implementation of such a programming construct is based on the % use of the \verb=\loop{=\meta{body}\verb=}\repeat= macro that % is defined in plain \TeX\@. The syntax for this loop is: % \begin{flushleft} % \verb=\for=\meta{control sequence} \verb|:=| \meta{list} % \verb=\do=\\ % \meta{body}\\ % \verb=\od= % \end{flushleft} % The \meta{list} should be a comma separated list. % % The first actions that have to be taken are to set the switch % \verb=\ifForlist= to \meta{true} and to store the loop condition % in the macro \verb=\ListCondition=. This is done using an % \verb=\edef= to allow for a control sequence that contains a % \meta{list}. % \begin{macrocode} \def\forlist#1:=#2\do#3\od{% \edef\ListCondition{#2}% \Forlisttrue % \end{macrocode} % Then we start the loop. % We store the first element from the \verb=\ListCondition= in the % macro that was supplied as the first argument to \verb=\forlist=. % This element is then removed from the \verb=\ListCondition=. % \begin{macrocode} \loop \edef#1{\expandafter\FirstElt\ListCondition,\empty.}% \edef\ListCondition{\expandafter\OtherElts\ListCondition,\empty.}% % \end{macrocode} % When the first element from the \meta{list} is empty, we are done % processing, so we switch \verb=\ifForlist= to \meta{false}. % When it is not empty we execute the third argument that should % contain \TeX\ commands to execute. % \begin{macrocode} \ifx#1\empty \Forlistfalse \else#3\fi % \end{macrocode} % Finally we test the switch \verb=\ifForlist= to decide whether the % loop has to be continued. % \begin{macrocode} \ifForlist \repeat} % \end{macrocode} % \begin{macro}{\FirstElt} % \changes{2.0g}{1991/06/05}{Macro added.} % The macro \verb=\FirstElt= is used to get the first element from a % comma-separated list. % \begin{macrocode} \def\FirstElt#1,#2.{#1} % \end{macrocode} % \end{macro} % \begin{macro}{\OtherElts} % \changes{2.0g}{1991/06/05}{Macro added.} % The macro \verb=\OtherElts= is used to get all elements {\em but\/} % the first element from a comma-separated list. % \begin{macrocode} \def\OtherElts#1,#2.{#2} % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\whileswitch} % \changes{2.0h}{1991/06/19}{Macro added.} When the program is used in % interactive mode the user might want to process several files % with different options or extensions. This goal could be reached % by running the program several times, but it is more % user-friendly to ask if he would like to process more files when % we are done processing his last request. To accomplish this we % need the implementation of a \texttt{while}-loop. Again plain % \TeX's \verb=\loop{=\meta{body}\verb=}\repeat= is used to % implement this programming structure. % % The syntax for this loop is: % \begin{flushleft} % \verb=\whileswitch=\meta{switch} \verb|\fi| \meta{list} % \verb={=\meta{body}\verb=}=\\ % \end{flushleft} % The first argument to this macro has to be a switch, defined % using \verb=\newif=; the second argument contains the statements % to execute while the switch evaluates to \meta{true}. % \begin{macrocode} \def\whileswitch#1\fi#2{#1\loop#2#1\repeat\fi} % \end{macrocode} % \end{macro} % % \subsubsection{Input and Output} % % \begin{macro}{\maybeMsg} % \begin{macro}{\showprogress} % \begin{macro}{\keepsilent} % When this program is used it can optionally show its progress on % the terminal. In that case it will write a special character to % the terminal (and the transcript file) for each input line. This % option is on by default when statistics are included in % \texttt{docstrip.tex}. It is off when statistics are excluded. The % commands \verb=\showprogress= and \verb=\keepsilent= can be used % to choose otherwise. % \begin{macrocode} \def\showprogress{\let\maybeMsg\message} \def\keepsilent{\let\maybeMsg\gobble} %<*stats> \showprogress % %<-stats>\keepsilent % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\Msg} % For displaying messages on the terminal the macro \verb=\Msg= is % defined to write {\em immediately\/} to \verb=\ttyout=. % \begin{macrocode} \def\Msg{\immediate\write\ttyout} % \end{macrocode} % \end{macro} % % \begin{macro}{\Ask} % The macro % \verb=\Ask{=\meta{cs}\texttt{\}\{}\meta{string}\texttt{\}} is a % slightly modified copy of the \LaTeX\ macro \verb=\typein=. It is % used to ask the user a question. The \meta{string} will be % displayed on his terminal and the response will be stored in the % \meta{cs}. The trailing space left over from the carriage return % is stripped off by the macro \verb=\strip=. If the user just % types a carriage return, the result will be an empty macro. % \changes{2.0i}{1991/06/27}{Added check for just \protect\meta{CR}} % \begin{macrocode} \def\iden#1{#1} \def\strip#1#2 \gobble{\def #1{#2}} \def\@defpar{\par} \def\Ask#1#2{% \message{#2}\read\ttyin to #1\ifx#1\@defpar\def#1{}\else \iden{\expandafter\strip\expandafter#1#1\gobble\gobble} \gobble\fi} % \end{macrocode} % \end{macro} % % \begin{macro}{\WriteOut} % \changes{2.0e}{1991/06/01}{Macro added.} When a line has to be written % on the output file this can be done using the macro % \verb=\WriteOut=. It writes a `\texttt{.}' on the terminal and % \verb=\immediate=ly writes it argument to \verb=\outFile=. % \begin{macrocode} \def\WriteOut#1{\maybeMsg{.}\immediate\write\outFile{#1}} % \end{macrocode} % \end{macro} % % \subsubsection{Miscellaneous} % \begin{macro}{\OffStart} % When the start of a block of code that has to be excluded from % the output is encountered the macro \verb=\Offstart= is called. % This macro sets the switch \verb=\ifOff= to \meta{true} and % increments the counter \verb=\offLevel= by $1$. % \begin{macrocode} \def\OffStart{\Offtrue\advance\offLevel\@ne} % \end{macrocode} % \end{macro} % % \begin{macro}{\OffEnd} % At the end of a block of code that is excluded the macro % \verb=\OffEnd= is called. It decrements the counter by $1$ and if % the value of the counter is $0$, it switches \verb=\ifOff= to % \meta{false}. % \begin{macrocode} \def\OffEnd{% \advance\offLevel\m@ne \ifnum\offLevel=\z@ \Offfalse \fi} % \end{macrocode} % \end{macro} % % \begin{macro}{\gobble} % \changes{2.0a}{1991/05/25}{Macro added.} % A macro that has an argument and puts it in the bitbucket. % \begin{macrocode} \def\gobble#1{} % \end{macrocode} % \end{macro} % % \begin{macro}{\Endinput} % \changes{2.0f}{1991/06/04}{Macro added.} When a \texttt{doc} file % contains a \verb+\endinput+ on a line by itself this normally % means that anything following in this file should be ignored. % Therefore we need a macro containing \verb=\endinput= as its % replacement text to check this against \verb=\inLine= (the % current line from the current input file). Of course the % backslash has to have the correct \verb=\catcode=. One way of % doing this is feeding \verb=\\= to the \verb=\string= operation % and afterwards removing one of the \verb=\= characters. % \begin{macrocode} \edef\Endinput{\expandafter\gobble\string\\endinput} % \end{macrocode} % \end{macro} % % \begin{macro}{\makeOther} % During the process of reading a file with \TeX\ code the category % code of all special characters has to be changed to \meta{other}. % The macro \verb=\makeOther= serves this purpose. % \begin{macrocode} \def\makeOther#1{\catcode`#1=12\relax} % \end{macrocode} % \end{macro} % % \begin{macro}{\end} % \changes{2.0h}{1991/06/19}{Macro added.} For now we want the \ds{} % program to be compatible with both plain \TeX\ and \LaTeX\@. % \LaTeX\ version 2.09 hides plain \TeX{}'s \verb=\end= command and % calls it \verb=\@@end=. We unhide it here. % \begin{macrocode} \ifx\undefined\@@end\else\let\end\@@end\fi % \end{macrocode} % \end{macro} % % \subsection{The evaluation of boolean expressions} % % For clarity we repeat here the syntax for the boolean expressions % as it was given before: % %\DeleteShortVerb\| % \begin{tabular}{lcl} % \meta{Expression} & $::=$ & \meta{Primary} % [\{\texttt{|}, \texttt{,}\} % \meta{Primary}]*\\ % \meta{Primary} & $::=$ & % \meta{Secondary} [\texttt{\&} % \meta{Secondary}]*\\ % \meta{Secondary} & $::=$ & % \meta{Terminal} $|$ \texttt{!}\meta{Secondary} % $|$ % \texttt{(}\meta{Expression}\texttt{)}\\ % \end{tabular} % % The \texttt{|} stands for disjunction, the \texttt{\&} stands for % conjunction and the \texttt{!}\ stands for negation. The % \meta{Terminal} is any sequence of letters and evaluates to % \meta{true} iff it occurs in the list of options that have to be % included. %\MakeShortVerb\| % % \subsubsection{Parsing intermediate results} The parsing of the % boolean expressions has to be carried out very carefully. The % parsing of an expression starts at the `left side'. Each term in % the expression is fully parsed before the next term is examined. % This parsing occurs inside a group, so macros can be redefined % without affecting the result of the total evaluation. As a % consequence of this, the result of the evaluation has to be % passed to the outer level. For this purpose the control sequence % |\expressionValue| is used. % % This is done as follows:\\ A macro |\doNext| is defined using the % |\edef| command. It closes the group that was started when the % evaluation of this term started; then it calls the macro % |\PropagateValue| with the result of the evaluation as its % argument. Note that because of the use of |\edef| the control % sequence |\expressionValue| will be replaced by either \texttt{TT} % or \texttt{TF} in the replacement text for |\doNext|. The macro is % then executed. %\begin{verbatim} % \edef\doNext{\endgroup\noexpand\PropagateValue{\ExpressionValue}}% % \doNext %\end{verbatim} % % \begin{macro}{\PropagateValue} % The `top level' definition of the macro |\PropagateValue| just % stores its (expanded) argument in |\expressionValue|. Note that % this macro is redefined during various phases of the parsing % process. % \begin{macrocode} \def\PropagateValue#1\qStop{% \edef\ExpressionValue{#1}} % \end{macrocode} % % \begin{macro}{\ContinueExpression} % During the parsing of an \meta{Expression} the control sequence % |\PropagateValue| is |\let| to |\ContinueExpression|. The % argument of this macro is either \texttt{TT} or \texttt{TF}, % being the result of the parsing of the current term. % \begin{macrocode} \def\ContinueExpression#1{% % \end{macrocode} % A logical-or of this result and the accumulated result of all % previous terms is performed. This means that if the result so far % was \meta{true} it remains \meta{true}, otherwise the current % term determines the total result so far. % \begin{macrocode} \if\ExpressionValue \else \def\ExpressionValue{#1}% \fi % \end{macrocode} % Then we peek at the next token using |\futurelet| and call % |\ContinueExpressionX| to decide what to do, depending on the % next token. % \begin{macrocode} \futurelet\nextToken\ContinueExpressionX} % \end{macrocode} % \end{macro} % % \begin{macro}{\ContinueExpressionX} % When the macro |\ContinueExpressionX| is called, the next token % is stored in the control sequence |\nextToken|. % \begin{macrocode} \def\ContinueExpressionX{% % \end{macrocode} %\DeleteShortVerb\| % If it is either \texttt{|} or \texttt{,} the % parsing has to continue and the next \meta{Primary} term is % considered. % \begin{macrocode} \ifx|\nextToken \def\doNext|{\Primary}% \else \ifx,\nextToken \def\doNext,{\Primary}% \else % \end{macrocode} % The only other character that can be encountered is the \texttt{)} % that closes the expression. In that case we propagate the value % accumulated so far to the outer level. % \begin{macrocode} \edef\doNext){\endgroup\noexpand\PropagateValue{\ExpressionValue}} \fi \fi \doNext} % \end{macrocode} % Note that the characters \texttt{|}, \texttt{,} and \texttt{)} % have remained in \TeX's input and have to be removed. This is % accomplished by including the character in the parameter text of % the definition of the macro \verb=\doNext=. % \end{macro} %\MakeShortVerb\| % % \begin{macro}{\ContinuePrimary} % During the parsing of a \meta{Primary} term the control sequence % |\PropagateValue| is |\let| to |\ContinuePrimary|. The argument % of this macro is either \texttt{TT} or \texttt{TF}, being the % result of the parsing of the current term. % \begin{macrocode} \def\ContinuePrimary#1{% % \end{macrocode} % A logical-and of this result and the accumulated result of all % previous terms is performed. This means that if the result so far % was \meta{false} it remains \meta{false}, otherwise the current % term determines the total result so far. % \begin{macrocode} \if\ExpressionValue \def\ExpressionValue{#1}% \fi % \end{macrocode} % Then we peek at the next token using |\futurelet| and call % |\ContinuePrimaryX| to decide what to do, depending on the % next token. % \begin{macrocode} \futurelet\nextToken\ContinuePrimaryX} % \end{macrocode} % \end{macro} % % \begin{macro}{\ContinuePrimaryX} % When the macro |\ContinuePrimaryX| is called, the next token is % stored in the control sequence |\nextToken|. Because this macro % needs to check if the next token is a `\texttt{\&}' we have to % change its category code before |\ContinuePrimaryX| is defined. % \begin{macrocode} {\catcode`\&=12 \gdef\ContinuePrimaryX{% % \end{macrocode} % If the next token is \texttt{\&} the parsing has to continue and % the next \meta{Secondary} term is considered. % \begin{macrocode} \ifx&\nextToken \def\doNext&{\Secondary}% \else % \end{macrocode} % Any other character indicates the end of the current term. % In that case we propagate the value accumulated % so far to the outer level. % \begin{macrocode} \edef\doNext{\endgroup\noexpand\PropagateValue{\ExpressionValue}}% \fi \doNext}} % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\PropagateNegatedValue} % When a \meta{Secondary} term is preceded by a \texttt{!}\ % character the the control sequence |\PropagateValue| is |\let| to % |\PropagateNegatedValue|. The only function of this macro is to % propagate the negation of its argument. % \begin{macrocode} \def\PropagateNegatedValue#1{% \edef\doNext{\endgroup \noexpand\PropagateValue {\if#1% \noexpand\FalseExpression \else \noexpand\TrueExpression \fi}}% \doNext} % \end{macrocode} % \end{macro} % % \subsubsection{The evaluation of the boolean expression} % % \begin{macro}{\Evaluate} % To start the parsing of a boolean expression the macro |\Evaluate| % is called by the macros |\testOption| and |\starOption| % % |\Evaluate| encloses its argument with \texttt{()} and appends % |\qStop|. The result is passed on to \verb=\Expression= for % further processing. The parentheses are added to ease the % parsing by |\Expression|. % \begin{macrocode} \def\Evaluate#1{% \Expression(#1)\qStop} % \end{macrocode} % \end{macro} % % \begin{macro}{\Expression} % The definition of the macro |\Expression| includes a `\texttt{(}' % in the parameter text of the macro; this causes the immediate % removal of the first parenthesis that encloses the expression. % \begin{macrocode} \def\Expression({% % \end{macrocode} % It then starts a group, % \begin{macrocode} \begingroup % \end{macrocode} % initializes the % |\ExpressionValue| to \meta{false} % \begin{macrocode} \let\ExpressionValue\FalseExpression % \end{macrocode} % and calls |\Primary| to % continue the parsing process. % \begin{macrocode} \let\PropagateValue\ContinueExpression \Primary} % \end{macrocode} % |\ExpressionValue| is set to \meta{false} because the logical-or % of this value and the result of the first term will be performed. % \end{macro} % % \begin{macro}{\Primary} % The macro |\Primary| is used to parse \meta{Primary} terms. Like % |\expression| it starts a group. It then initiates the % |ExpressionValue| appropriately and calls |\Secondary| to % continue the parsing process. % \begin{macrocode} \def\Primary{% \begingroup \let\ExpressionValue\TrueExpression \let\PropagateValue\ContinuePrimary \Secondary} % \end{macrocode} % \end{macro} % % \begin{macro}{\Secondary} % As can be seen in the syntax of boolean expressions a % \meta{Secondary} term can contain three different kinds of term. % When the first token of the \meta{Secondary} is a `\texttt{!}' the % result of the parsing of the term should be negated; when the % first token is a `\texttt{(}'it indicates the start of a % subexpression. Any other token is part of a \meta{Terminal}. % % Therefore we have to inspect the first token of the term and decide % what to do. This is achieved by using |\futurelet| and calling % |\SecondaryX|. % \begin{macrocode} \def\Secondary{% \futurelet\nextToken\SecondaryX} % \end{macrocode} % % \begin{macro}{\SecondaryX} % When this macro is called, the control sequence |\nextToken| % contains a copy of the first character of the term being inspected. % \begin{macrocode} \def\SecondaryX{% % \end{macrocode} % When |\nextToken| contains a `\texttt{(}' we make sure that calling % |\doNext| is actually a call of |\Expression| to % parse the subexpression. % \begin{macrocode} \ifx\nextToken(\let\doNext\Expression\else % \end{macrocode} % When |\nextToken| contains a `\texttt{!}' we make sure that calling % |\doNext| is actually a call of |\Negate| to negate the result % of the following term. % \begin{macrocode} \ifx\nextToken!\let\doNext\Negate\else % \end{macrocode} % If |\nextToken| contains anything else |\doNext| is |\let| % to |\Terminal|. % \begin{macrocode} \let\doNext\Terminal\fi\fi % \end{macrocode} % The call of |\doNext| will now start the proper macro. % \begin{macrocode} \doNext} % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\Negate} % When during the parsing of a \meta{Secondary} term a `|!|' is % encountered the result has to be negated. Therefore a new group % is started, |\PropagateValue| is made equivalent to % |\PropagateNegatedValue| and |\Secondary| is called again. % \begin{macrocode} \def\Negate!{% \begingroup \let\PropagateValue\PropagateNegatedValue \Secondary} % \end{macrocode} % \end{macro} % % \begin{macro}{\Terminal} % The parsing of a \meta{Terminal} is done token by token. Therefore % we accumulate the tokens that make up the \meta{Terminal} in % the token register |\TerminalString|. This register is cleared and % processing starts with calling |\TerminalX|. % \begin{macrocode} \def\Terminal{% \global\TerminalString{}\TerminalX} % \end{macrocode} % % \begin{macro}{\TerminalX} % The macro |\TerminalX| scoops up the next token and appends it to % |\TerminalString|. It can do that because the token has been % examined before by another macro, either |\Secondary| (at the start % of this process) or |\TerminalXX| (during this process). % \begin{macrocode} \def\TerminalX#1{% \global\TerminalString\expandafter{\the\TerminalString#1}% % \end{macrocode} % Now we have to peek at the next token again to decide what the % next action should be. The decision will be taken by |\TerminalXX|. % \begin{macrocode} \futurelet\nextToken\TerminalXX} % \end{macrocode} % % \begin{macro}{\TerminalXX} %\DeleteShortVerb\|\MakeShortVerb\+ % The macro +\TerminalXX+ uses the % contents of +\nextToken+ to decide what the next action should % be. When +\nextToken+ contains one of `\texttt{\&}', % `\texttt{|}', `\texttt{,}', `\texttt{!}', `\texttt{(}' or % `\texttt{)}' the end of the \meta{Terminal} has been found and % processing should stop; when +\nextToken+ contains any other % character it is part of the \meta{Terminal}. % % During the definition of the macro the `\texttt{\&}' should be % \texttt{\&$_{12}$} so its category code needs to be changed. % \begin{macrocode} {\catcode`\&=12 \gdef\TerminalXX{% % \end{macrocode} % A couple of +\ifx+ tests are needed to decide whether the % \meta{Terminal} that is being accumulated has ended. We use % the switch +\ifTerminal+ to indicate whether this has happened % or not. It is initialized to \meta{false} (meaning: ``the end has % been found''). % \begin{macrocode} \Terminalfalse \ifx &\nextToken \else \ifx |\nextToken \else \ifx ,\nextToken \else \ifx !\nextToken \else \ifx (\nextToken \else \ifx )\nextToken \else % \end{macrocode} % If none of the above tests are \meta{true} the end of the % \meta{Terminal} has {\em not\/} been found, so the switch is % set to \meta{true}. % \begin{macrocode} \Terminaltrue \fi\fi\fi\fi\fi\fi % \end{macrocode} % If the \meta{Terminal} has not ended the next character can be % appended to +\TerminalString+. This is accomplished by the % (recursive) call of +\TerminalX+. % \begin{macrocode} \ifTerminal \let\doNext\TerminalX % \end{macrocode} % When, on the other hand, the end {\em was\/} found, we have to % check whether the option (that is now stored in % +\TerminalString+) was amongst the options that needed to be % included in the output. This check is performed by the macro % +\SetValue+. It gives +\ExpressionValue+ the appropriate value. % The token register is cleared when its contents are no longer % needed. % \begin{macrocode} \else \edef\doNext{\noexpand\SetValue{\the\TerminalString}}% \global\TerminalString{}% \fi % \end{macrocode} % At this point the macro +\doNext+ `points' to the macro that % should be executed, so we call it. The second brace closes the % group that was started to keep the category change of the % character `\texttt{\&}' local. % \begin{macrocode} \doNext} } % \end{macrocode} %\MakeShortVerb\|\DeleteShortVerb\+ % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\SetValue} % The macro |\Setvalue| has to check whether its argument is included % in the option list, stored in |\Options| as a comma-separated list. % \begin{macrocode} \def\SetValue#1{% % \end{macrocode} % The actual check will be performed by a temporary macro |\tmp|. % The argument of |\SetValue| is made part of its argument text. % The argument text is delimited by |\qStop|. When |\tmp| is % executed it will have both the expanded optionlist and the % argument of |\SetValue| amongst its parameters. When the argument % of |\Setvalue| does {\em not\/} appear in |\Options| the second % argument of |\tmp| will be empty. % \begin{macrocode} \def\tmp##1,#1,##2\qStop{% % \end{macrocode} % To be able to check if the second argument is empty, we store it % in a temporary control sequence |\tmp|. % \begin{macrocode} \def\tmp{##2}% % \end{macrocode} % Then we define |\doNext|, using |\edef|, to propagate the value % of this expression to the outer level. Because we use |\edef|, % the replacement text of |\doNext| will contain either %\begin{verbatim} % \PropagateValue{TF} %\end{verbatim} % or %\begin{verbatim} % \PropagateValue{FF} %\end{verbatim} % \begin{macrocode} \edef\doNext{\noexpand\PropagateValue {\ifx\tmp\empty\FalseExpression\else\TrueExpression\fi}}% % \end{macrocode} % The last action of |\tmp| is to call the macro |\doNext| that it % has just defined. % \begin{macrocode} \doNext}% % \end{macrocode} % As stated before, we need the expansion of |\Options| in the % arguments of |\tmp|, therefore we have to delay the expansion of % |\tmp| using |\expandafter| until |\Options| has been expanded. % \begin{macrocode} \expandafter\tmp\expandafter,\Options,#1,\qStop} % \end{macrocode} % \end{macro} % % \subsection{Processing the input lines} % % \begin{macro}{\copyLine} % The macro \verb=\copyLine= writes its argument (which has to be % delimited with \verb=\endLine=) on the output file using the % macro \verb=\WriteOut=. If statistics are included, the counter % \verb=\codeLinesPassed= is incremented by $1$. % \begin{macrocode} \def\copyLine#1\endLine{% %<*stats> \advance\codeLinesPassed\@ne % \WriteOut{#1}} % \end{macrocode} % \end{macro} % % \begin{macro}{\removeLine} % The macro |\removeLine| throws its argument (which has to be % delimited with |\endLine|) away. It writes a `\texttt{\%}' on the % terminal if messages are enabled. % \begin{macrocode} \def\removeLine#1\endLine{% \maybeMsg{\perCent}} % \end{macrocode} % \end{macro} % % \begin{macro}{\removeComment} % The macro \verb=\removeComment= has nearly the same function as the % macro \verb=\removeLine=, except that when statistics are included % in the program the removed comment is counted. If statistics are % {\em not\/} included the macro \verb=\removeComment= is \verb=\let= % to \verb=\removeLine=. % \begin{macrocode} %<*stats> \def\removeComment#1\endLine{% \advance\commentsRemoved\@ne \maybeMsg{\perCent}} % %<-stats>\let\removeComment\removeLine % \end{macrocode} % \end{macro} % % \begin{macro}{\putMetaComment} % If a line starts with two consecutive percent signs, it is % considered to be a {\em MetaComment\/}. Such a comment line is % passed on to the output file unmodified. % \begin{macrocode} \def\putMetaComment#1\endLine{% % \end{macrocode} % To `close' a pending option the macro \verb=\closeOption= is % called. % \begin{macrocode} \closeOption% % \end{macrocode} % If statistics are included the line is counted. % \begin{macrocode} %<*stats> \advance\commentsPassed\@ne % % \end{macrocode} % The macro \verb=\putMetaComment= has one argument, delimited with % \verb=\endLine=. But because of earlier processing the argument % is discarded and \verb=\inLine=, which contains the complete line % as it was read from \verb=\inFile=, is written on % \verb=\outFile=. % \begin{macrocode} \WriteOut{\inLine}} % \end{macrocode} % \end{macro} % % \begin{macro}{\processLine} % Each line that is read from the input stream has to be processed % to see if it has to be written on the output stream. This task % is performed by calling the macro \verb=\processLine=. % The macro increments the counter \verb=\processedLines= by $1$ if % statistics are included. Then it peeks at the next character % in the input stream by using \verb=\futurelet= and calling % \verb=\processLineX= to do the work. % \begin{macrocode} \def\processLine{% %<*stats> \advance\processedLines\@ne % \futurelet\nextToken\processLineX} % \end{macrocode} % \end{macro} % % \begin{macro}{\processLineX} % The macro \verb=\processLineX= has to check whether the current % line has to be included in the output or not. In order to do % that, it needs to check whether the line starts with a % `\texttt{\%}'. Therefore the macro is globally defined within a % group. Within this group the category code of `\texttt{\%}' is % changed to 12 (other). Because a comment character is needed, % the category code of `\texttt{\#}' is changed to 14 (comment % character). % % When this macro is executed \TeX\ has stored the next token in % the input stream in \verb=\nextToken=. If it is a `\texttt{\%}' % further processing has to be done by \verb=\processLineXX=; % otherwise we close the current option.\\ The setting of the % switch \verb=\ifOff= determines whether the current line is % either removed or copied. Whatever action has to be taken, it % will be stored in the macro \verb=\doNext=, after the processing % of the \verb=\if=-statements is finished. % \begin{macrocode} \begingroup \catcode`\%=12 \catcode`\#=14 \gdef\processLineX{# \ifx%\nextToken \let\doNext\processLineXX \else \closeOption \ifOff \let\doNext\removeLine \else \let\doNext\copyLine \fi \fi \doNext} \endgroup % \end{macrocode} % \end{macro} % % \begin{macro}{\processLineXX} % The macro \verb=\processLineXX= simply peeks at the next token and % calls \verb=\processLineXXX= to do whatever is necessary. % \begin{macrocode} \def\processLineXX#1{% \futurelet\nextToken\processLineXXX} % \end{macrocode} % \end{macro} % % \begin{macro}{\processLineXXX} % This macro is also defined within a group, like the macro % \verb=\processLineX=, because it also has to check if the next % token in the input stream is a `\texttt{\%}' character. % % If the second token in the current line happens to be a % `\texttt{\%}', a \meta{MetaComment} has been found. This has to % be copied in its entirety to the output. Another possible second % character is `\texttt{<}', which introduces a guard expression. % The processing of such an expression is started by calling % \verb=\checkOption=. % % When the token was neither a `\texttt{\%}' nor a `\texttt{<}', % the line contains a normal comment that has to be removed. In % that case the current option is closed. The execution of the % macro \verb=\doNext= will have the desired effect. Note that the % group is closed, so that all characters will have the category % code that was in effect when the group was started. % \begin{macrocode} \begingroup \catcode`\%=12 \catcode`\#=14 \gdef\processLineXXX{# \ifx%\nextToken \let\doNext\putMetaComment \else \ifx<\nextToken \let\doNext\checkOption \else \closeOption \let\doNext\removeComment \fi\fi \doNext} \endgroup % \end{macrocode} % \end{macro} % % \subsection{The handling of options} % % \begin{macro}{\checkOption} % When the macros that process a line have found that the line % starts with `\texttt{\%<}', a guard line has been encountered. % The first character of a guard can be an asterisk (\texttt{*}), a % slash (\texttt{/}) a plus (\texttt{+}), a minus (\texttt{-}) or % any other character that can be found in an option name. This % means that we have to peek at the next token and call % \verb=\checkOptionsX= to decide what kind of guard we have. Note % that the way that \verb=\checkOption= is defined, means it % removes the `\texttt{<}' from the input stream. % \begin{macrocode} \def\checkOption<{% \futurelet\nextToken\checkOptionsX} % \end{macrocode} % \end{macro} % % \begin{macro}{\checkOptionsX} % The macro \verb=\checkOptionsX= compares the contents of % \verb=\nextToken= with the four possible leading characters and % decides what to do. When the switch \verb=\ifOff= is \meta{true}, % the current line will simply be removed. % \begin{macrocode} \def\checkOptionsX{% \ifx*\nextToken \let\doNext\starOption \else \ifx/\nextToken \let\doNext\slashOption \else \ifOff \let\doNext\removeLine \else \ifx+\nextToken \let\doNext\plusOption \else \ifx-\nextToken \let\doNext\minusOption \else \let\doNext\doOption \fi\fi\fi\fi\fi \doNext} % \end{macrocode} % \end{macro} % % \begin{macro}{\closeOption} % The macro \verb=\closeOption= is used to `close' options. This % means nothing more than writing a `\texttt{>}' on the terminal when % necessary. % % If \verb=\lastOption= is \verb=\empty= nothing has to be done % because no option has started since the last one was closed. In % the other case, the `\texttt{>}' is written on the terminal if % messages are enabled. Also, the \verb=\lastOption= is made % \verb=\empty=. % \begin{macrocode} \def\closeOption{% \ifx\lastOption\empty\else \maybeMsg{>}\let\lastOption\empty\fi} % \end{macrocode} % \end{macro} % % \begin{macro}{\doOption} % When no guard modifier is found by \verb=\checkOptionsX=, the % macro \verb=\doOption= is called. It calls \verb=\testOption= % with an empty first argument to evaluate the boolean expression. % The result of this evaluation is stored in % \verb=\ExpressionValue=. This guard only affects the current % line, so depending on the result of the test % \verb=\if\ExpressionValue=, the current line is either copied to % the output stream or removed. % \begin{macrocode} \def\doOption#1>{% \testOption{}{#1}% \if\ExpressionValue \expandafter\copyLine \else \expandafter\removeLine \fi} % \end{macrocode} % \end{macro} % % \begin{macro}{\plusOption} % When a `\texttt{+}' is found as a guard modifier, % \verb=\plusOption= is called. This macro is very similar to % \verb=\doOption=, the only difference being that the `\texttt{+}' % is now passed as the first argument to \verb=\testOption=. % \begin{macrocode} \def\plusOption+#1>{% \testOption+{#1}% \if\ExpressionValue \expandafter\copyLine \else \expandafter\removeLine \fi} % \end{macrocode} % \end{macro} % % \begin{macro}{\minusOption} % When a `\texttt{-}' is found as a guard modifier, % \verb=\minusOption= is called. This macro is very similar to % \verb=\plusOption=, the difference is that \verb=\removeLine= and % \verb=\copyLine= have been interchanged. % \begin{macrocode} \def\minusOption-#1>{% \testOption-{#1}% \if\ExpressionValue \expandafter\removeLine \else \expandafter\copyLine \fi} % \end{macrocode} % \end{macro} % % \begin{macro}{\starOption} % When a `\texttt{*}' is found as a guard modifier, % \verb=\starOption= is called. In this case a block of code will % be included in the output on the condition that the guard % expression evaluates to \meta{true}. % \begin{macrocode} \def\starOption*#1>{% % \end{macrocode} % First we close any pending option and optionally write % a message to the terminal to indicate that a new option starts % here. % \begin{macrocode} \closeOption \maybeMsg{<*#1}% % \end{macrocode} % Then we push the current contents of \verb=\blockHead= on the % stack of blocks, \verb=\guardStack= and increment the counter % \verb=\blockLevel= to indicate that we are now one level of % nesting deeper. % \changes{2.0k}{1992/04/06}{Use new stack mechanism} % \changes{2.0k}{1992/04/09}{The macro that holds the guard needs to be % expanded} % \begin{macrocode} \expandafter\push\expandafter\guardStack\expandafter{\blockHead}% \advance\blockLevel\@ne % \end{macrocode} % The guard for this block of code is now stored in % \verb=\blockHead=. % \begin{macrocode} \def\blockHead{#1}% % \end{macrocode} % If this block of code occurs inside another block of code that is % {\em not\/} included in the output, we increment the counter % |\offLevel|. In that case the guard expression will not be % evaluated, because a block inside another block that is excluded % from the output will also be excluded, regardless of the % evaluation of its guard. % \begin{macrocode} \ifOff \advance\offLevel\@ne % \end{macrocode} % When the switch \verb=\ifOff= has the value \meta{false}, we have % to evaluate the guard expression. This is done by calling % |\Evaluate|. That macro leaves the result in |\ExpressionValue|. % If the result turns out to be \meta{false}, we start an `Off' % section by calling \verb=\Offstart=. % \begin{macrocode} \else \Evaluate{#1}% \if\ExpressionValue\else\OffStart\fi \fi % \end{macrocode} % The current line always has to be removed, because it only contains % the guard and possibly a comment. % \begin{macrocode} \removeLine} % \end{macrocode} % \end{macro} % % \begin{macro}{\slashOption} % The macro \verb=\slashOption= is the counter part to % \verb=\starOption=. It indicates the end of a block of % conditionally included code. We store the argument in the % temporary control sequence \verb=\tmp=. % \begin{macrocode} \def\slashOption/#1>{% \def\tmp{#1}% % \end{macrocode} % When the counter \verb=\blockLevel= has a value less than $1$, % this `end-of-block' line has no corresponding `start-of-block'. % Therefore we signal an error and ignore this end of block. % \begin{macrocode} \ifnum\blockLevel<\@ne \errmessage{Spurious end block ignored}% % \end{macrocode} % Next we compare the contents of \verb=\tmp= with the contents % of \verb=\blockHead=. The latter macro contains the last guard for % a block of code that was encountered. If the contents match, we % pop the previous guard from the stack. % \changes{2.0k}{1992/04/06}{Use new stack mechanism} % \begin{macrocode} \else \ifx\tmp\blockHead \pop\guardStack\blockHead % \end{macrocode} % When the contents of the two macros don't match something is % amiss. We signal this to the user, but accept the `end-of-block'. %\note{Is this the desired behaviour??} % \begin{macrocode} \else \errmessage{Found instead of <*\blockHead>}% \fi % \end{macrocode} % When the end of a block of optionally included code is encountered % we optionally signal this on the terminal and decrement the counter % \verb=\offLevel=. % \begin{macrocode} \maybeMsg{>}% \advance\blockLevel\m@ne % \end{macrocode} % The last check that has to be made is for the value of the switch % \verb=\ifOff=. If it is \meta{true} we call \verb=\Offend= to % take the appropriate actions. Finally we remove the current line. % \begin{macrocode} \ifOff\OffEnd\fi \fi \removeLine} % \end{macrocode} % \end{macro} % % \begin{macro}{\testOption} % The macro \verb=\testOption= is used by the macros that process % the one line guards. First it checks if the guard expression % is present. To accomplish that, it stores the second argument % in a temporary control sequence. % \begin{macrocode} \def\testOption#1#2{% \def\tmp{#2}% % \end{macrocode} % When the macro \verb=\tmp= is empty, something is missing. % We signal this to the user and use a dummy guard. % \begin{macrocode} \ifx\tmp\empty \errmessage{Missing option expression!}% \def\tmp{MISSING OPTION}% % \end{macrocode} % When the guard is present we store a `\texttt{<}', the guard % modifier and the guard in \verb=\tmp= for future use. % \begin{macrocode} \else \def\tmp{<#1#2}% \fi % \end{macrocode} % The complete guard is now stored in \verb=\tmp=. We use it to % compare with the last guard encountered. If they are the same, % there is nothing more to do. % \begin{macrocode} \ifx\tmp\lastOption % \end{macrocode} % If they are {\em not\/} the same the current line belongs to a % different option than the last line with a guard that has been % processed. Therefore we close a possibly pending option and make % \verb=\lastOption= point to the contents of \verb=\tmp=. % \begin{macrocode} \else \closeOption \let\lastOption\tmp % \end{macrocode} % Then we optionally signal the start of a new option on the % terminal and evaluate the guard expression. % \begin{macrocode} \maybeMsg{\lastOption}% \Evaluate{#2}% \fi} % \end{macrocode} % \end{macro} % % \subsection{Batchfile commands} % % \begin{macro}{\generateFile} % The macro \verb=\generateFile= can be used in batch files to % instruct the \ds{} program to generate an output file from % possibly multiple input files. The first argument is the file to % produce, the second argument indicates if the user has to be % consulted before an existing file is overwritten. The third % argument contains the list of input files. Each entry should have % the format % \verb=\from{=\meta{filename.ext}\verb=}{=\meta{options}\verb=}=. % % The macro starts by displaying a message on the terminal to % indicate which file is going to be made. The switch % \verb=\ifGenerate= is initially set to \meta{true}. % % \changes{2.0e}{1991/06/01}{changed interface to % \texttt{\bsl generatefileX}} % \changes{2.0e}{1991/06/01}{Added pre- and postamble support} % \begin{macrocode} \def\generateFile#1#2#3{{% \Msg{^^JGenerating file \WriteToDir#1^^J}% \Generatetrue % \end{macrocode} % Next we decide if we have to be careful about overwriting % existing files. If the user specified `\texttt{t}' we will ask him % if he wants to overwrite an existing file. If he specified anything % else we simply go ahead. % % In order to prevent havoc when \verb=#2= contains garbage or when % it is empty we use a comparison of control sequences instead % of the direct comparison with \verb=\if#2t=. % \begin{macrocode} \def\tmp{#2}\def\t{t}% \ifx\tmp\t % \end{macrocode} % When the second argument to \verb=\generateFile= was `\texttt{t}' % we try to open a file with the name of the output file for % reading. If this succeeds the file exists and we ask the user if % he wants to overwrite the file. % \changes{2.0p}{1992/06/26}{Added `WriteToDir (FMi).} % \begin{macrocode} \immediate\openin\inFile\WriteToDir#1\relax \ifeof\inFile\else \Ask\answer{File \WriteToDir#1 already exists \ifx\@empty\WriteToDir somewhere \fi on the system.^^J% Overwrite it% \ifx\@empty\WriteToDir\space if necessary\fi ? [y/n]}% % \end{macrocode} % We set the switch \verb=\ifGenerate= according to his answer. We % allow for both ``\texttt{y}'' and ``\texttt{yes}''. % \begin{macrocode} \ifx\y \answer \Generatetrue \else \ifx\yes\answer \Generatetrue \else \Generatefalse\fi\fi\fi % \end{macrocode} % Don't forget to close the file just opened as we want to write % to it. % \begin{macrocode} \immediate\closein\inFile \fi % \end{macrocode} % We store the name of the output file in the macro % \verb=\outFileName= for future use. % \begin{macrocode} \ifGenerate \def\outFileName{#1}% % \end{macrocode} % The macro |\from| will be used for multiple purposes in the % following code. % % First |\from| is defined to write a line to the output file, % containing the name of the input file, together with the % options that are included for that file. % \changes{2.2g}{1994/03/13}{Use $>$ instead of ! for empty test.} % \begin{macrocode} \def\from##1##2{\WriteOut{\DoubleperCent ##1 \if>##2>\else \space (with options: `##2')\fi}}% % \end{macrocode} % Older versions of the previous code contained \verb=\if!##2!= % which has a funny effect if you use \verb=\from= with a negated % (\verb=!=) module. % % The macro \verb=\ReferenceLines= is defined using an \verb=\edef= % instruction. This means that all macros in the replacement text % will be expanded. The third argument to \verb=\generateFile= is % included in the replacement text for \verb=\ReferenceLines=, % while the above definition of \verb=\from= is still valid. Thus, % for each occurrence of |\from| in the third argument of % |\generateFile| the current replacement text of |\from| is % included in |\ReferenceLines|. % \begin{macrocode} \edef\ReferenceLines{% \WriteOut{\DoubleperCent ^^J% \DoubleperCent The original source files were:^^J% \DoubleperCent }% #3}% \def\from##1##2{\edef\inFileName{\inFileName##1\space}} \def\inFileName{}#3 % \end{macrocode} % The macro \verb=\ReferenceLines= will be called by % \verb=\WritePreamble=. Because it was defined using an expanded % definition we can now safely give \verb=\from= another meaning. % This time it is to define the macros \verb=\inFileName= and % \verb=\Options= to contain its two arguments. These macros are % then used by \verb=\generateFileX=. % \changes{2.0f}{1991/06/04}{Allow for a control sequence as options % argument} % \begin{macrocode} \def\from##1##2{\def\inFileName{##1}% \edef\Options{##2}% \generateFileX}% % \end{macrocode} % Now we can finally open the output file, this time for writing. % \changes{2.0q}{1992/07/01}{Preceded filename by `WriteToDir} % \begin{macrocode} \immediate\openout\outFile\WriteToDir#1\relax % \end{macrocode} % First we write a preamble to the file, % \begin{macrocode} \WritePreamble % \end{macrocode} % then we execute the commands that are in the third % argument to \verb=\Generatefile=. % \begin{macrocode} #3% % \end{macrocode} % The last action is to write a postamble to the file and close it. % \begin{macrocode} \WritePostamble \immediate\closeout\outFile \let\ReferenceLines\OriginalRefs \else % \end{macrocode} % In case we were not allowed to overwrite an existing file % we inform the user that we are {\em not\/} generating his file. % \begin{macrocode} \Msg{Not generating file #1^^J}% \fi}} % \end{macrocode} % % \begin{macro}{\WriteToDir} % The macro |\WriteToDir| is either empty or holds the prefix % necessary to read a file from the current directory. Under UNIX % this is |./| but a lot of other systems addopted this concept. If % we can prefix the % \changes{2.0p}{1992/06/26}{Macro added (FMi).} % \changes{2.2a}{1993/12/02}{check texsys file} % \changes{2.2d}{1994/01/20}{do not read dircheck/texsys file} % \begin{macrocode} \ifx\@currdir\@undefined \def\WriteToDir{} \else \let\WriteToDir\@currdir \fi % \end{macrocode} % \end{macro} % % To support command files that were written for the first version % of \ds{} the commands |\include| and |\processFile| % are defined here. The use of this interface is not recommended % as it may be removed in a future release of \ds{}. % % \begin{macro}{\include} % \changes{2.0f}{1991/06/04}{Macro added} To provide the \ds{} program % with a list of options that should be included in the output the % command \verb=\include{=\meta{Options}\verb=}= can be used. This % macro is meant to be used in conjunction with the % \verb=\processFile= command. % \begin{macrocode} \def\include#1{\def\Options{#1}} % \end{macrocode} % \end{macro} % % \begin{macro}{\processFile} % \changes{2.0f}{1991/06/04}{Supply \texttt{\bsl generateFile} with % \texttt{\bsl Options}} %\DeleteShortVerb\| % The macro % \verb=\processFile{=\meta{filename}\verb=}{=\meta{inext}\verb=}{=% %\unskip\meta{outext}\verb=}{=\meta{t{\fontshape{n}\ttfamily|}f}\verb=}= % can be used when a single input file is used to produce % a single output file. The macro is also used in the interactive % mode of the \ds{} program. %\MakeShortVerb\| % % The arguments \meta{inext} and \meta{outext} denote the % extensions of the input and output files respectively. The fourth % argument can be used to specify if an existing file should be % overwritten without asking. If \meta{t} is specified the program % will ask for permission before overwriting an existing file. % % This macro is defined using the more generic macro |\generateFile|. % \begin{macrocode} \def\processFile#1#2#3#4{% \generateFile{#1.#3}{#4}{\from{#1.#2}{\Options}}} % \end{macrocode} % \end{macro} % % \begin{macro}{\processfile} % \begin{macro}{\generatefile} % \changes{2.0m}{1991/04/23}{Now issue a warning when \texttt{\bsl % processfile} or \texttt{\bsl generatefile} are used} An earlier % version of \ds{} used the commands |\processfile| and % |\generatefile| instead of the commands as they are defined in % this version. To remain upwards compatible, we still provide % these commands, but issue a warning when they are used. % \begin{macrocode} \def\processfile{\Msg{% ^^Jplease use \string\processFile\space instead of \string\processfile!^^J}% \processFile} \def\generatefile{\Msg{% ^^Jplease use \string\generateFile\space instead of \string\generatefile!^^J}% \generateFile} % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\generateFileX} % \changes{2.0f}{1991/06/04}{Added check for lines with \texttt{\bsl % endinput}} This macro is called by |\generateFile| for each % occurrence in its third argument of the control sequence |\from|. % % A line is displayed on the terminal, telling the user what we are % about to do. % \begin{macrocode} \def\generateFileX{{% \Msg{Processing File \inFileName \ifx\Options\empty\else\space(\Options)\fi \space -> \outFileName^^J}% % \end{macrocode} % Then we try to open the input file. If this doesn't succeed, we % tell the user so and nothing else happens. % \begin{macrocode} \immediate\openin\inFile\inFileName\relax \ifeof\inFile \errmessage{Cannot find file \inFileName}% \else % \end{macrocode} % When the input file was successfully opened, we change the category % code of a lot of characters to \meta{other} and make sure that % no extra spaces appear in the lines read by setting the % |\endlinechar| to $-1$. % \begin{macrocode} \makeOther\ \makeOther\\\makeOther\$% \makeOther\#\makeOther\^\makeOther\^^K% \makeOther\_\makeOther\^^A\makeOther\%% \makeOther\~\makeOther\{\makeOther\}\makeOther\&% \endlinechar-1\relax % \end{macrocode} % Then we start a loop to process the lines in the file one by one. % \begin{macrocode} \loop \read\inFile to\inLine % \end{macrocode} % The first thing we check is whether the current line % contains an |\endinput|. To allow also real |\endinput| % commands in the source file, |\endinput| is only recognized % when it occurs directly at the beginning of a line. % \begin{macrocode} \ifx\inLine\Endinput % \end{macrocode} % In this case we output a message to inform the programmer (in % case this was a mistake) and end the loop immediately by setting % \verb=Continue= to \meta{false}. Note that \verb=\endinput= is % not placed into the output file. This is important in cases where % the output file is generated from several \texttt{doc} files. % \begin{macrocode} \Msg{File \inFileName\space ended by \string\endinput.}% \Continuefalse \else % \end{macrocode} % \changes{2.0j}{1992/03/03}{First check for end of file before check % for empty lines} When the end of the file is found we have to % interrupt the loop. % \begin{macrocode} \ifeof\inFile \Continuefalse % \end{macrocode} % \changes{2.0i}{1991/06/27}{Added check for consecutive empty lines} % If the file did not end we check if the input line is empty. % If it is, the counter \verb=\emptyLines= is incremented. % \begin{macrocode} \else \Continuetrue \ifx\inLine\empty \advance\emptyLines\@ne \else \emptyLines\z@ \fi % \end{macrocode} % When the number of empty lines seen so far exceeds 1, we skip them. % If it doesn't, the expansion of |\inLine| is fed to |\processLine| % with |\endLine| appended to indicate the end of the line. % \begin{macrocode} \ifnum \emptyLines<2 \expandafter\processLine\inLine\endLine \else \maybeMsg{/}% \fi \fi \fi % \end{macrocode} % When the processing of the line is finished, we check if there is % more to do, in which case we repeat the loop. % \begin{macrocode} \ifContinue \repeat % \end{macrocode} % Any option that was not properly `closed' is closed now and the % input file is closed. % \begin{macrocode} \closeOption \immediate\closein\inFile % \end{macrocode} % If the user was interested in statistics, we inform him of the % number of lines processed, the number of comments that were % either removed or passed and the number of codelines that were % written to the output file. Also the totals are updated. % \begin{macrocode} %<*stats> \Msg{Lines \space processed: \the\processedLines^^J% Comments removed: \the\commentsRemoved^^J% Comments \space passed: \the\commentsPassed^^J% Codelines passed: \the\codeLinesPassed^^J}% \global\advance\TotalprocessedLines by \processedLines \global\advance\TotalcommentsRemoved by \commentsRemoved \global\advance\TotalcommentsPassed by \commentsPassed \global\advance\TotalcodeLinesPassed by \codeLinesPassed \global\advance\NumberOfFiles by \@ne % \fi}} % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\WritePreamble} % \changes{2.0e}{1991/06/01}{Macro added.} % If there is no \verb=\preamble= command in the batch file, or % the \ds{} program is used in interactive mode a % default preamble will be written to the output file. All % lines in this preamble are preceded by two percent characters % to prevent them from being removed from the file by the \ds{} % program. % % First a couple of lines, stating what file it is and how it was % created. % \begin{macrocode} \def\WritePreamble{% \WriteOut{% \DoubleperCent ^^J% \DoubleperCent This is file `\outFileName', generated % on <\the\year/\the\month/\the\day> ^^J% \DoubleperCent with the docstrip utility (\fileversion).% }% % \end{macrocode} % Then the |\ReferenceLines| that tell from what source file(s) the % stripped file was created. % \begin{macrocode} \ReferenceLines % \end{macrocode} % Then, a statement that this file should {\em not\/} be distributed % on its own. % \begin{macrocode} \WriteOut{% \DoubleperCent ^^J% \DoubleperCent IMPORTANT NOTICE:^^J% \DoubleperCent You are not allowed to distribute this file.^^J% \DoubleperCent For distribution of the original source see^^J% \DoubleperCent the copyright notice in the file \inFileName.^^J% \DoubleperCent }} % \end{macrocode} % \end{macro} % % \begin{macro}{\OriginalRefs} % \changes{2.0e}{1991/06/01}{Macro added.} % The macro \verb=\OriginalRefs= can be used to include information % in the output file about the documented source files it was % created from. % \begin{macrocode} \def\OriginalRefs{% \WriteOut{\DoubleperCent }% \WriteOut{\DoubleperCent The original source file was `\inFileName'.}% \ifx\Options\empty\else \WriteOut{\DoubleperCent Included options: `\Options'.}\fi \WriteOut{\DoubleperCent }} % \end{macrocode} % \end{macro} % % \begin{macro}{\ReferenceLines} % \changes{2.0e}{1991/06/01}{Macro added.} The macro % \verb=\ReferenceLines= is used by the macro \verb=\WritePreamble= % to include some information on the original source files in the % output file. When the user does not supply a preamble, a default % preamble is used, so also a default value for % \verb=\ReferenceLines= has to be supplied. The macro % \verb=\OriginalRefs= supplies such a default. % \begin{macrocode} \let\ReferenceLines\OriginalRefs % \end{macrocode} % \end{macro} % % \begin{macro}{\WritePostamble} % \changes{2.0e}{1991/06/01}{Macro added.} % The default definition of \verb=\WritePostamble= is to write % a line containing \verb=\endinput= to the output file. The % last line written identifies the file again. % \begin{macrocode} \def\WritePostamble{% \WriteOut{\string\endinput}% \WriteOut{\DoubleperCent ^^J% \DoubleperCent End of file `\outFileName'.}} % \end{macrocode} % \end{macro} % % \begin{macro}{\preamble} % \changes{2.0e}{1991/06/01}{Macro added.} When a batch file is used the % user can specify a preamble of his own that will be written to % each file that is created. This can be useful to include an extra % copyright notice in the stripped version of a file. Also a % warning that both versions of a file should {\em always\/} be % distributed together could be written to a stripped file by % including it in such a preamble. % % Every line that is written to \verb=\outFile= that belongs to the % preamble is preceded by two percent characters. This will prevent % \ds{} from stripping these lines off the file. % % The preamble should be started with the macro \verb=\preamble=; % it is ended by \verb=\endpreamble=. All processing is done within % a group in order to be able to locally redefine some macros. % \begin{macrocode} \def\preamble{\begingroup % \end{macrocode} % If the preamble contains an empty line this will end up in % the macro \verb=\batchLine= as \verb=\par=. To be able to % recognize a \verb=\par= we define \verb=\tmp= to contain % \verb=\par=. The macro \verb=\Endpreamble= is defined to contain % \verb=\endpreamble=, which ends the processing of preamble lines. % \begin{macrocode} \def\tmp{\par}% \def\Endpreamble{\endpreamble}% % \end{macrocode} % The preamble lines will be read inside a \verb=\loop=. When % a line is found that contains \verb=\endpreamble= the processing % has to stop. This is controlled by the switch \verb=\ifContinue=. % We initialize it to \meta{true}. % \begin{macrocode} \Continuetrue % \end{macrocode} % The macro \verb=\WritePreamble= will be defined to contain % commands to write all preamble lines to \verb=\outFile=. We start % it off with a couple of lines identifying the file. More lines % will be added as processing continues, therefore the macros % \verb=\inFileName= and \verb=\outFileName= are \verb=\let= to % \verb=\relax=. If this was not done their contents would now be % hard-coded in \verb=\WritePreamble=, which is {\em not\/} what we % want. % \changes{2.0h}{1991/06/19}{Removed opening of output file as a side % effect.} % \begin{macrocode} \let\inFileName\relax \let\outFileName\relax \let\ReferenceLines\relax \gdef\WritePreamble{% \WriteOut{\DoubleperCent ^^J% \DoubleperCent This is file `\outFileName', generated ^^J% \DoubleperCent on <\the\year/\the\month/\the\day> with the docstrip utility (\fileversion).}% \ReferenceLines}% % \end{macrocode} % Now each line in the preamble has to be added to % \verb=\WritePreamble=, therfore we start a \verb=\loop= to % \verb=\read= the lines. The control sequence \verb=\batchLine= % is used to store each line. % \begin{macrocode} \loop \read\currbatchFile to \batchLine % \end{macrocode} % We check to see if the end of the preamble has been found. In that % case the \verb=\loop= has to come to an end, so we set the switch % \verb=\ifContinue= to \meta{false}. % \begin{macrocode} \ifx\batchLine\Endpreamble \Continuefalse \else % \end{macrocode} % If an extra line has been read we add the appropriate % instructions to \verb=\WritePreamble= using \verb=\xdef= (which % does a global expanded definition). If the \verb=\batchLine= was % empty, we write just the two percent characters; otherwise the % complete line is written, preceded by the two percent characters. % \begin{macrocode} \xdef\WritePreamble{% \WritePreamble \WriteOut{\DoubleperCent \ifx\batchLine\tmp\else\batchLine\fi}}% \fi % \end{macrocode} % The setting of the switch \verb=\ifContinue= will decide if the % \verb=\loop= continues. If we end the \verb=\loop=, we also have to % close the group. % \begin{macrocode} \ifContinue\repeat \endgroup} % \end{macrocode} % \end{macro} % % \begin{macro}{\postamble} % \changes{2.0e}{1991/06/01}{Macro added.} Just as a preamble can be % specified in a batch file, the same can be done for a {\em % post\/}amble. % % The definition for \verb=\postamble= is very much like the one for % \verb=\preamble=; the processing takes place inside a group and % the switch \verb=\ifContinue= is used to control the \verb=\loop=. % \begin{macrocode} \def\postamble{\begingroup \Continuetrue % \end{macrocode} % The end of the postamble is indicated by \verb=\endpostamble= and % the postamble can contain empty lines so we have to be able % to check if \verb=\batchLine= contains a \verb=\par=. % \begin{macrocode} \def\Endpostamble{\endpostamble}% \def\tmp{\par}% % \end{macrocode} % We initially define \verb=\WritePostamble= as an empty macro. % Commands will be added to it as we go along. % \begin{macrocode} \gdef\WritePostamble{}% % \end{macrocode} % We start a loop to read lines from the batch file until % \verb=\postamble= is encountered. % \begin{macrocode} \loop \read\currbatchFile to \batchLine \ifx\batchLine\Endpostamble \Continuefalse % \end{macrocode} % The line just read will be written to \verb=\outFile=, prepended % with two percent characters. The command to do this is appended % to the definition of \verb=\WritePostamble=. % \begin{macrocode} \else \xdef\WritePostamble{% \WritePostamble \WriteOut{\DoubleperCent \ifx\batchLine\tmp\else\batchLine\fi}}% \fi % \end{macrocode} % The setting of the switch \verb=\ifContinue= decides if we have % to stop the \verb=\loop=. % \begin{macrocode} \ifContinue\repeat \endgroup} % \end{macrocode} % \end{macro} % % \subsection{Interaction with the user} % % \begin{macro}{\processbatchFile} % \changes{2.0f}{1991/06/04}{Macro added.} % When \ds{} is run it always tries to use a batch file. % For this purpose it calls the macro |\processbatchFile|. The first % thing this macro does, is check wether the user has defined the % control sequence |\batchfile|. If he did, it should contain the % name of the file to process. If he didn't a default name is tried. % Whether or not the default batch file is used is remembered by % setting the switch |\ifDefault| to \meta{true} or \meta{false}. % \begin{macrocode} \def\processbatchFile{% \ifx\undefined\batchfile \let\batchfile\DefaultbatchFile \Defaulttrue \else \Defaultfalse \fi % \end{macrocode} % Now we try to open the batch file for reading. % \begin{macrocode} \openin\currbatchFile \batchfile\relax \ifeof\currbatchFile % \end{macrocode} % If we didn't succeed in opening the file, we assume that it does % not exist. If we tried the default filename, we silently % continue; the \ds{} program will switch to interactive mode in % this case. % \begin{macrocode} \ifDefault \else % \end{macrocode} % If we failed to open the user-supplied file, something is wrong % and we warn him about it. This will also result in a switch to % interactive mode. % \begin{macrocode} \Msg{**************************************************^^J% * Could not find your \string\batchfile=\batchfile^^J% * Try to continue without it^^J% **************************************************}% \fi \else % \end{macrocode} % When we were successful in opening a file, we again have to check % whether it was the default file. In that case we tell the user % we found that file and ask him if he wants to use it. % \begin{macrocode} \ifDefault \Msg{**************************************************^^J% * Batchfile \DefaultbatchFile\space found Use it? (y/n)?}% \Ask\answer{% **************************************************}% \else % \end{macrocode} % When it was the user-supplied file we can safely assume he wants % to use it so we set |\answer| to \texttt{y}. % \begin{macrocode} \let\answer\y \fi % \end{macrocode} % At this point we have successfully opened a batch file for % reading. If the macro |\answer| contains a \texttt{y} we can % proceed. We do that by setting the switch |\ifContinue| to true. % When the batch file contains an |\endinput| we shouldn't % continue, so we make it switch |\ifContinue| to \meta{false}. % \begin{macrocode} \ifx\answer\y \Continuetrue \let\endinput\Continuefalse % \end{macrocode} % The contents of the batch file are read in a loop, line by line. % When the end of the file is found processing should stop. % \begin{macrocode} \loop \ifeof\currbatchFile \Continuefalse \else % \end{macrocode} % A line is read into the macro |\batchLine|, which is subsequently % executed. % \begin{macrocode} \read\currbatchFile to \batchLine \batchLine \fi % \end{macrocode} % When the execution of |\batchLine| is finished we check the switch % |\ifContinue| to see if have to continue reading. % \begin{macrocode} \ifContinue \repeat \fi \fi} % \end{macrocode} % \end{macro} % % \begin{macro}{\ReportTotals} % \changes{2.0g}{1991/06/05}{Macro added.} The macro % \verb=\ReportTotals= can be used to report total statistics for % all files processed. This code is only included in the program if % the option \texttt{stats} is included. % \begin{macrocode} %<*stats> \def\ReportTotals{% \ifnum\NumberOfFiles>\@ne \Msg{Overall statistics:^^J% Files \space processed: \the\NumberOfFiles^^J% Lines \space processed: \the\TotalprocessedLines^^J% Comments removed: \the\TotalcommentsRemoved^^J% Comments \space passed: \the\TotalcommentsPassed^^J% Codelines passed: \the\TotalcodeLinesPassed}% \fi} % % \end{macrocode} % \end{macro} % % \begin{macro}{\SetFileNames} % The macro \verb=\SetFileNames= is used when the program runs in % interactive mode and the user was asked to supply extensions and % a list of filenames. % \begin{macrocode} \def\SetFileNames{% \edef\inFileName{\MainFileName.\infileext}% \edef\outFileName{\MainFileName.\outfileext}} % \end{macrocode} % \end{macro} % % \begin{macro}{\CheckFileNames} % In interactive mode, the user gets asked for the extensions for % the input and output files. Also the name or names of the input % files (without extension) is asked for. Then the names of the % input and output files are constructed from this information by % |\SetFileNames|. This assumes that the name of the input file is % the same as the name of the output file. But we should not write % to the same file we're reading from so the extensions should % differ. % % The macro |\CheckFileNames| makes sure that the output goes to a % different file to the one where the input comes from. % \begin{macrocode} \def\CheckFileNames{% \ifx\inFileName\outFileName % \end{macrocode} % If input and output files are the same we signal an error and stop % processing. % \begin{macrocode} \Msg{^^J% !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!^^J% ! It is not possible to read from and write to the same file !^^J% !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!^^J}% \Continuefalse \else % \end{macrocode} % If they are not the same we check if the input file exists by % trying to open it for reading. % \begin{macrocode} \Continuetrue \immediate\openin\inFile \inFileName\relax \ifeof\inFile % \end{macrocode} % If an end of file was found, the file couldn't be opened, so we % signal an error and stop processing. % \begin{macrocode} \Msg{^^J% !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!^^J% ! Your input file `\inFileName' was not found !^^J% !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!^^J}% \Continuefalse \else % \end{macrocode} % The last check we have to make is if the output file already % exists. Therefore we try to open it for reading. % As a precaution we first close the input stream. % \changes{2.0p}{1992/06/26}{Added `WriteToDir (FMi).} % \changes{2.0r}{1992/08/17}{Use `inFile for reading} % \changes{2.0r}{1992/08/17}{Moved `closein statements} % \begin{macrocode} \immediate\closein\inFile \immediate\openin\inFile\WriteToDir \outFileName\relax \ifeof\inFile % \end{macrocode} % If this fails, it didn't exist and all is well. % \begin{macrocode} \Continuetrue \else % \end{macrocode} % If opening of the output file for reading succeeded we have to % ask the user if he wants to overwrite it. We assume he doesn't % want to overwrite it, so the switch |\ifContinue| is initially % set to \meta{false}. Only if he answers the question positively % with `\texttt{y}' or `\texttt{yes}' we set the switch back to % \meta{true}. % \changes{2.0p}{1992/06/26}{Changed question about overwriting.} % \begin{macrocode} \Continuefalse \Ask\answer{File \WriteToDir\outFileName\space already exists \ifx\@empty\WriteToDir somewhere \fi on the system.^^J% Overwrite it% \ifx\@empty\WriteToDir\space if necessary\fi ? [y/n]}% \ifx\y \answer \Continuetrue \else \ifx\yes\answer \Continuetrue \else \fi\fi \fi % \end{macrocode} % All checks have been performed now, so we can close any file that % was opened just for this purpose. % \begin{macrocode} \fi \fi \immediate\closein\inFile} % \end{macrocode} % \end{macro} % % \begin{macro}{\interactive} % The macro |\interactive| implements the interactive mode of the % \ds{} program. The macro is implemented using the % \meta{while} construction. While the switch |\ifMoreFiles| remains % true, we continue processing. % \begin{macrocode} \def\interactive{% \whileswitch\ifMoreFiles\fi% % \end{macrocode} % To keep macro redefinitions local we start a group and ask the % user some questions about what he wants us to do. % \begin{macrocode} {\begingroup \AskQuestions % \end{macrocode} % The names of the files that have to be processed are stored as a % comma-separated list in the macro |\filelist| by |\AskQuestions|. % We use a \meta{for} loop to process the files one by one. % \begin{macrocode} \forlist\MainFileName:=\filelist \do % \end{macrocode} % First the names of the input and output files are constructed % and a check is made if all filename information is correct. % \begin{macrocode} \SetFileNames \CheckFileNames \ifContinue % \end{macrocode} % If everything was well, we can open the output file for writing, % \changes{2.0q}{1992/07/01}{Preceded filename by `WriteToDir} % \begin{macrocode} \immediate\openout\outFile\WriteToDir\outFileName\relax % \end{macrocode} % write the preamble to it, % \begin{macrocode} \WritePreamble % \end{macrocode} % process the input file, % \begin{macrocode} \generateFileX % \end{macrocode} % write a postamble % \begin{macrocode} \WritePostamble % \end{macrocode} % and close the output file again. % \begin{macrocode} \immediate\closeout\outFile \fi% % \end{macrocode} % This process is repeated until |\filelist| is exhausted. % \begin{macrocode} \od \endgroup % \end{macrocode} % Maybe the user wants more files to be processed, possibly with % another set of options, so we give him the opportunity. % \begin{macrocode} \Ask\answer{More files to process (y/n)?}% \ifx\y \answer\MoreFilestrue \else \ifx\yes\answer\MoreFilestrue \else % \end{macrocode} % If he didn't want to process any more files, the switch % |\ifMoreFiles| is set to \meta{false} in order to interrupt the % \meta{while} loop. % \begin{macrocode} \MoreFilesfalse\fi\fi }} % \end{macrocode} % \end{macro} % % \begin{macro}{\AskQuestions} % \changes{2.0e}{1991/06/01}{Macro added.} % The macro |\AskQuestions| is called by |\interactive| to get % some information from the user concerning the files that need % to be processed. % \begin{macrocode} \def\AskQuestions{% \Msg{^^J% ****************************************************}% % \end{macrocode} % We want to know the extension of the input files, % \begin{macrocode} \Ask\infileext{% * First type the extension of your input file(s): \space *}% \Msg{****************************************************^^J^^J% ****************************************************}% % \end{macrocode} % the extension of the output files, % \begin{macrocode} \Ask\outfileext{% * Now type the extension of your output file(s) \space: *}% \Msg{****************************************************^^J^^J% ****************************************************}% % \end{macrocode} % if options are to be included and % \begin{macrocode} \Ask\Options{% * Now type the name(s) of option(s) to include \space\space: *}% \Msg{****************************************************^^J^^J% ****************************************************^^J% * Finally give the list of input file(s) without \space\space*}% % \end{macrocode} % the name of the input file or a list of names, separated by commas. % \begin{macrocode} \Ask\filelist{% * extension seperated by commas if necessary % \space\space\space\space: *}% \Msg{****************************************************^^J}}% % \end{macrocode} % \end{macro} % % \subsection{The main program} % When \TeX\ processes the \ds{} program it displays % a message about the version of the program and its function % on the terminal. % \begin{macrocode} \Msg{Utility: `docstrip' \fileversion\space <\filedate>^^J% English documentation \space\space\space <\docdate>}% \Msg{^^J% **********************************************************^^J% * This program converts documented macro-files into fast *^^J% * loadable files by stripping off (nearly) all comments! *^^J% **********************************************************^^J}% % \end{macrocode} % % First we try to process a batch file. % \begin{macrocode} \processbatchFile % \end{macrocode} % % When the number of files processed is still zero, % no batch file was specified and the default % batch file was not found, so we try interactive mode. % \begin{macrocode} \ifnum\NumberOfFiles=\z@ \interactive \fi % \end{macrocode} % When we're done and statistics are included we provide a statistics % report about the complete run. Then we \verb=\end= the \TeX-run. % \begin{macrocode} %<*stats> \ReportTotals % \end % % \end{macrocode} % % % % \Finale \endinput