% \iffalse meta-comment % % Copyright (C) 2004 by Robert J Lee % -------------------------------------------------------------- % % This file may be distributed and/or modified under the % conditions of the LaTeX Project Public License, either version 1.2 % of this license or (at your option) any later version. % The latest version of this license is in: % % http://www.latex-project.org/lppl.txt % % and version 1.2 or later is part of all distributions of LaTeX % version 1999/12/01 or later. % % \fi % % \iffalse %<*driver> \ProvidesFile{rjlpshap.dtx} % % \NeedsTeXFormat{LaTeX2e}[1999/12/01] % \ProvidesPackage{rjlpshap} %<*package> [2004/11/05 v1.0 .dtx rjlpshap file] % % %<*driver> \documentclass{ltxdoc} \EnableCrossrefs \CodelineIndex \RecordChanges \usepackage{lipsum} \begin{document} \DocInput{rjlpshap.dtx} \end{document} % % \fi % % \CheckSum{0} % % \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 \~} % % % \changes{v1.0}{2004/11/05}{Initial version} % % \GetFileInfo{rjlpshap.dtx} % % \DoNotIndex{\newcommand,\newenvironment} % % % \title{The \textsf{rjlpshap} class\thanks{This document % corresponds to \textsf{rjlpshap}~\fileversion, dated \filedate.}} % \author{Robert J Lee \\ \texttt{latex@rjlee.homelinux.org}} % % \maketitle % % \section{Introduction} % % This package provides low-level helper macros and environments. It % is intended for authors of \LaTeX\ packages, who wish to % programmatically change the shape of paragraphs. It overcomes several % difficulties with \TeX's \texttt{$\backslash$parshape} register: % % \begin{enumerate} % \item It is not possible to re-use a length register when issuing a % \texttt{$\backslash$parshape} command; this makes it difficult to % calculate the shape of a paragraph in \LaTeX\ using some % algorithms that re-use one or more variables (registers). % \item The number of lines must be known \textit{before} the lengths % of each line, which can lead to difficult calculations. % \item The format of the \texttt{$\backslash$parshape} command is % very strict and evaluated early on by \TeX, and so it doesn't % easily allow for parameter-replacement, making it difficult to use % any calculations at all. % \end{enumerate} % % It differs from the \texttt{shapepar} package, in that it provides % no actual calculations for paragraph shapes. Instead, it provides a % framework by which paragraph shapes can be calculated in a single % run of the document by the author (or package writer). % % The package provides both environments and commands by which the % author can accumulate any number of lengths and then use them in a % \texttt{$\backslash$parshape} command injected into the document, % without the need to re-run \LaTeX. % % \pagebreak[4] % \section{Usage} % % There are two modes of operation: environment mode and command % mode. Environment mode has the advantage that it does not % require the number of lengths to be known in advance, while command % mode provides various options for passing pre-calculated lengths. % % \subsection{Environment Mode} % % Environment mode uses a single environment, % \texttt{parshapecollect}, which starts and ends before the paragraph % of text. The contents of the environment are a \LaTeX\ program, % supplied by the user, that calculates the lengths of each line. % % \DescribeEnv{parshapecollect} The \texttt{parshapecollect} % environment goes at the start of a paragraph, and the entire % environment defines a single \texttt{$\backslash$parshape} command. % Any even number of lengths are collected, and at the end of the % environment, the \texttt{$\backslash$parshape} command is % automatically generated and inserted into the document. % % \DescribeMacro{\parshapelenout} This macro takes one mandatory % parameter, which is the next length in the % \texttt{$\backslash$parshape} command. Note that the parameter is % expanded: the value of the length at the time % \texttt{$\backslash$parshapelenout} is called is the value which is % used --- this means the same length command can be re-used % repeatedly. The value may be a length register, and the same % register may be re-used after changing its contents, for example: % % \begin{quote} % \begin{verbatim} % \newlength{\foo} % \begin{parshapecollect} % \setlength{\foo}{1in}\parshapelenout{\foo} % \setlength{\foo}{3in}\parshapelenout{\foo} % \setlength{\foo}{0.5in}\parshapelenout{\foo} % \setlength{\foo}{3.5in}\parshapelenout{\foo} % \setlength{\foo}{0in}\parshapelenout{\foo} % \setlength{\foo}{4in}\parshapelenout{\foo} % \end{parshapecollect} % \lipsum[1] % \end{verbatim} % Produces: % % \parshape 3 1in 4in 0.5in 4.5in 0in 5in % \lipsum[1] % \end{quote} % % \DescribeMacro{\parshapearrlenout} This macro is the same as % \texttt{$\backslash$parshapelenout}, but allows the programmer to % pass the length as the value from an array (see the % \texttt{arrayjob} package). This is intended for situations where % pre-calculated lengths are to be used alongside calculations; to % pass an array of lengths the various command modes may be % easier. The parameters to the macro are the name of the array and % the name of a counter containing the index. % % For example, the above paragraph could have been created % using: % \begin{quote} % \begin{verbatim} % \newarray{foo} \newcounter{ctr} % \begin{parshapecollect} % \foo(1)={1in}\setcounter{ctr}{1}\parshapearrlenout{foo}{ctr} % \foo(2)={3in}\setcounter{ctr}{2}\parshapearrlenout{foo}{ctr} % \foo(3)={0.5in}\setcounter{ctr}{3}\parshapearrlenout{foo}{ctr} % \foo(1)={3.5in}\setcounter{ctr}{1}\parshapearrlenout{foo}{ctr} % \foo(2)={0in}\setcounter{ctr}{2}\parshapearrlenout{foo}{ctr} % \foo(2)={4in}\parshapearrlenout{foo}{ctr} % \end{parshapecollect} % \lipsum[1] % \end{verbatim} % \end{quote} % % \subsection{Command Mode} % Command mode enables the author to use calculated shapes by % outputting the $\backslash$parshape command as a single operation at % the end of the calculation. % \DescribeMacro{\parshapeary} % This macro takes one parameter, being the name of an array. The % contents of the array are simply expanded and passed directly to % \texttt{$\backslash$parshape} --- the first parameter is the number % of lines, then for each line the left margin and line width are % supplied in subsequent elements. % % For example: % \begin{quote} % \begin{verbatim} % \newcommand{\ltest}{50pt} % \newlength{\test}\setlength{\test}{300pt} % \newarray{sizes}\readarray{sizes}{2&0em&\the\test&\ltest&\test} % \parshapeary{sizes} % \lipsum[1] % \end{verbatim} % produces: % % \parshape 2 0em 300pt 50pt 300pt \lipsum[1] % \end{quote} % % % \DescribeMacro{\parshapearray} This macro takes two parameters. The % first is also the name of an array. The only difference to % \texttt{$\backslash$parshapeary} is that instead of passing the % width of the line, the width of the right margin is passed % instead. This means the macro needs to know the width of the line. % % The second parameter is the length of the line. This is usually % $\backslash$columnwidth, passing any other value will effectively % change the right margin. ($\backslash$columnwidth is often equal to % $\backslash$textwidth, but in multi-column mode, % $\backslash$columnwidth is more likely to be correct, unless you % want to overstrike the text with text in another column --- so % $\backslash$columnwidth is the recommended length to use). % % In a similar vein to the previous example: % \begin{quote} % \begin{verbatim} %\newcommand{\ltest}{50pt} %\newlength{\test}\setlength{\test}{75pt} %\newlength{\cwidth}\setlength{\cwidth}{\columnwidth} %\addtolength{\cwidth}{-50pt} % %\newarray{sizes}\readarray{sizes}{2&0em&\the\test&\ltest&\test} %\parshapearray{sizes}{\cwidth} %\lipsum[1] % % \end{verbatim} % which produces: % % \parshape 2 0.0pt %220.0pt %50.0pt %170.0pt % \lipsum[1] % \end{quote} % % \DescribeMacro{\Parshapearray} % This macro also takes two parameters, and is used to combine % multiple shapes, where the width of the paragraph is not consistent % throughout the paragraph. % % The first parameter is the name of an array, in the same format as % the first parameter to \texttt{$\backslash$parshapeary}. % % The second parameter is the name of a second array. The first % element is the number of lines in this second array, and subsequent % elements are the widths of lines (excluding margins) in that array % --- starting from the first line. As usual, if an insufficient % number of lines are passed, the last line will be re-used. % % The actual width of a line will be the total width excluding margins % (as per the second parameter), minus the left margin (taken from the % first parameter, even indexes), minus the right margin (as per the % first parameter, odd indexes). % % In this way, it is possible to set a shaped paragraph that allows % for non-straight margins or non-rectangular paper --- for example, to % typeset a list item in such a way as to allow for a cut-out on the % page. % % For a larger example, consider that the paper has a sloped shape % that extends 1em wider for every line for the first 15 lines % only. The author wishes to set a text in an quadrilateral, with % margins offset $\frac{1}{8}\verb!"!$ to the right for each line, but % extending equally to follow the width of the paper. % \begin{quote} % \begin{verbatim} % \newarray{quad} % \readarray{quad}{17 & 0.000in & 2.000in & 0.125in & 1.875in & % 0.250in & 1.750in & 0.375in & 1.625in & 0.500in & 1.500in & % 0.625in & 1.375in & 0.750in & 1.250in & 0.875in & 1.125in & % 1.000in & 1.000in & 1.125in & 0.875in & 1.250in & 0.750in & % 1.375in & 0.675in & 1.500in & 0.500in & 1.625in & 0.375in & % 1.750in & 0.250in & 1.875in & 0.125in & 2.000in & 0.000in} % \newarray{papershape} % \readarray{papershape}{15& 25em & 26em & 27em & 28em & 29em & 30em & 31em % & 32em & 33em & 34em & 35em & 36em & 37em & 38em & 39em} % \Parshapearray{quad}{papershape} \lipsum[1] % \end{verbatim} % Produces: % % \parshape 17 % 0.0pt % 105.46039pt % 9.03374pt % 115.46042pt % 18.06749pt % 125.46043pt % 27.10124pt % 135.46045pt % 36.135pt % 145.46045pt % 45.16875pt % 155.46046pt % 54.2025pt % 165.46048pt % 63.23624pt % 175.46051pt % 72.26999pt % 185.46053pt % 81.30374pt % 195.46054pt % 90.3375pt % 205.46054pt % 99.37125pt % 211.84685pt % 108.405pt % 225.46057pt % 117.43874pt % 235.4606pt % 126.47249pt % 245.46062pt % 135.50624pt % 235.4606pt % 144.54pt % 235.46059pt \lipsum[1] % \end{quote} % % \section{Prerequisites} % This package requires the \texttt{arrayjob} package from % CTAN\footnote{http://tug.ctan.org/cgi-bin/ctanPackageInformation.py?id=arrayjob}. Arrays % are used as a convenient mechanism to pass values to functions, % although they may not be used in environment mode. % \section{Limitations and Possible Improvements} % \begin{itemize} % \item Usage of this package can be slow, because two temporary files % are used for each $\backslash$parshape. Theoretically, only one % should be needed and so it should be possible to improve this. % \item There is no support for combining arrays, other than to change % the paper size itself. Extra commands could be provided to % calculate the intersection of two cutouts, or to add margins % together. % \item In a future version, it may be possible to avoid temporary % files completely by using token registers, or % $\backslash$aftergroup, with some form of string processing. % \end{itemize} % \section{Package Name} % The somewhat obscure name ``rjlpshap'' was chosen following the % guidelines given in \textit{\LaTeXe\ for Class and Package % Writers}\footnote{\texttt{http://www.tex.ac.uk/tex-archive/macros/latex/doc/clsguide.pdf}}~(section~2.7.3, % ``Make it Portable''). The common prefix used by these packages % is~''rjl--'', which was chosen as the author's initials as he is % not writing these packages as part of any organisation. % The postfix of ``--pshap'' was chosen as a contraction of % ``parshape'', the \TeX\ command to which this package is a front % end. The name was contracted due to the 5-character length % restriction. It was also considered that that the obvious package % name of ``parshape'' would be best avoided to avoid confusion with % the existing shapepar\footnote{\texttt{http://www.ctan.org/tex-archive/macros/latex/contrib/shapepar/}} package, and also because parshape is a % standard \TeX\ command --- the only requirement that exists is to % avoid the name of a standard package, but avoiding the name of a % standard macro also seems like a good idea as this leaves the name % free for use as a standard package name in the future. % \section{Other References} % The following references were essential in producing this package: % \begin{itemize} % \item The \TeX Book\footnote{ISBN:~978-0201134483} % \item \TeX Live package % contributions\footnote{http://tug.org/texlive/pkgcontrib.html} % \item TDS Guidelines\footnote{http://dante.ctan.org/TDS-guidelines.html} % \end{itemize} % \StopEventually{\PrintChanges\PrintIndex} % % \section{Implementation} % % Arrayjob: we need to pass arrays of lengths and length-commands, % so build on the established array handling functionality. % \begin{macrocode} \RequirePackage{arrayjob} % \end{macrocode} % Forloop: we need to iterate over the arrays that are passed in % \begin{macrocode} \RequirePackage{forloop} % \end{macrocode} % Internal commands use @ as a letter, not a special character, so % switch catcodes % \begin{macrocode} \makeatletter % \end{macrocode} % \subsection{Environment mode} % \begin{environment}{parshapecollect} % Environment to handle writing the file, cleaning up etc. % % Note the importance of the % at the end of each line here: we're % in horizontal mode so any space characters get expanded and added % into the start of the paragraph. Any spaces here are output before % $\backslash$parshape itself, and so will be visible in the output % page. The $\backslash$ignorespaces is a last line of defence % against any extra spaces inadvertently introduced by the user. % % \begin{macrocode} \newenvironment{parshapecollect}{% \immediate\openout\rjlpshap@writer=\jobname.parshape% \setcounter{rjlpshap@linecount}{0}% \setboolean{rjlpshap@isodd}{false}% \ignorespaces }{% \immediate\closeout\rjlpshap@writer% % \end{macrocode} % Because the environment forms a group, we need to use aftergroup to % delay the $\backslash$parshape command. Otherwise the group will end first and % $\backslash$parshape will be discarded. % \begin{macrocode} \rjlpshap@doparshape% \aftergroup\input\aftergroup{\aftergroup\jobname\aftergroup% .\aftergroup% p\aftergroup% a\aftergroup% r\aftergroup% s\aftergroup% h\aftergroup% a\aftergroup% p\aftergroup% e\aftergroup% t\aftergroup% m\aftergroup% p\aftergroup}\ignorespaces } % \end{macrocode} % \end{environment} % \begin{macro}{\rjlpshap@doparshape} % Internal method to handle the final processing of the built % up $\backslash$parshape command. The lengths have been written to % the first temporary file, so write the entire $\backslash$parshape % command to the second one, ready to be input. % \begin{macrocode} \newcommand{\rjlpshap@doparshape}{% \immediate\openout\rjlpshap@finalwriter=\jobname.parshapetmp% \immediate\write\rjlpshap@finalwriter{\noexpand\parshape \arabic{rjlpshap@linecount}}% \openin\rjlpshap@reader=\jobname.parshape% \setboolean{rjlpshap@loop}{true}% \whiledo{\boolean{rjlpshap@loop}}{% \read\rjlpshap@reader to\rjlpshap@temp% % NB: \ifeof matches \loop...\repeat \ifeof\rjlpshap@reader% \setboolean{rjlpshap@loop}{false}% \else \immediate\write\rjlpshap@finalwriter{\rjlpshap@temp }% \fi }% \immediate\closeout\rjlpshap@finalwriter% \immediate\closein\rjlpshap@reader% \let\rjlpshap@temp=\relax% } % \end{macrocode} % \end{macro} % \begin{macro}{\parshapelenout} % Used inside a parshapecollect environment, writes length \#1 to % the $\backslash$parshape command file. (If used anywhere else, % it'll just write to the console since the file will not be open). % \begin{macrocode} \newcommand{\parshapelenout}[1]{% \setlength{\rjlpshap@tempwidth}{#1}% \immediate\write\rjlpshap@writer{\the\rjlpshap@tempwidth}% \ifthenelse{\boolean{rjlpshap@isodd}}{% \setboolean{rjlpshap@isodd}{false}% }{% \stepcounter{rjlpshap@linecount}% \setboolean{rjlpshap@isodd}{true}% }% \ignorespaces } % \end{macrocode} % \end{macro} % \begin{macro}{\parshapearrlenout} % Used inside a parshapecollect environment, writes a length to the % $\backslash$parshape command file. As $\backslash$parshapelenout, % except that the element is passed as the member of an array. % % Length is taken from array with name \#1, element at index \#2 % \begin{macrocode} \newcommand{\parshapearrlenout}[2]{% \testarray{#1}(\arabic{#2})% \parshapelenout{\temp@macro}% \ignorespaces } % \end{macrocode} % \end{macro} % \subsection{Command Mode} % \begin{macro}{\parshapeary} % As $\backslash$parshape, but takes one argument being an array % name defined in arrayjob form. The array contains the arguments, % starting with the count at index 1, then one length per array % element. % \begin{macrocode} \newcommand{\parshapeary}[1]{% \testarray{#1}(1)% \edef\rjlpshap@max{\temp@macro}% \begin{parshapecollect}% \forloop{rjlpshap@ctr}{1}{\not \value{rjlpshap@ctr} > \rjlpshap@max }{% \setcounter{rjlpshap@ctr2}{\value{rjlpshap@ctr}}% \addtocounter{rjlpshap@ctr2}{\value{rjlpshap@ctr}}% \parshapearrlenout{#1}{rjlpshap@ctr2}% \stepcounter{rjlpshap@ctr2}% \parshapearrlenout{#1}{rjlpshap@ctr2}% }% \end{parshapecollect}% \typeout{parshapeary end}% \ignorespaces } % \end{macrocode} % \end{macro} % \begin{macro}{\parshapearray} % As $\backslash$parshapeary, but the second parameter is the name % of a single-parameter macro taking a number and returning the % width of the line on that line % \begin{macrocode} \newcommand{\parshapearray}[2]{% \begin{parshapecollect}% \testarray{#1}(1)% \edef\rjlpshap@max{\temp@macro}% \forloop{rjlpshap@ctr}{1}{\not \value{rjlpshap@ctr} > \rjlpshap@max }{% \setcounter{rjlpshap@ctr2}{\value{rjlpshap@ctr}}% \addtocounter{rjlpshap@ctr2}{\value{rjlpshap@ctr}}% \edef\rjlpshap@pos{\arabic{rjlpshap@ctr2}}% \testarray{#1}(\rjlpshap@pos)% \setlength{\rjlpshap@tempwidth}{\temp@macro}% \setlength{\rjlpshap@templinewidth}{#2}% \addtolength{\rjlpshap@templinewidth}{-1\rjlpshap@tempwidth}% \parshapelenout{\rjlpshap@tempwidth}% \stepcounter{rjlpshap@ctr2}% \edef\rjlpshap@pos{\arabic{rjlpshap@ctr2}}% \testarray{#1}(\rjlpshap@pos)% \setlength{\rjlpshap@tempwidth}{\temp@macro}% \addtolength{\rjlpshap@templinewidth}{-1\rjlpshap@tempwidth}% \parshapelenout{\rjlpshap@templinewidth}% }% \end{parshapecollect}% } % \end{macrocode} % \end{macro} % \begin{macro}{\Parshapearray} % First parameter is as $\backslash$parshapea\{r,rra\}y, but each pair % is left and right margin rather than left margin and text width, % while the second tracks the page width. % % \textit{i.e.} % % The first parameter (an array) is the shape of the paragraph % relative to the page. % \begin{itemize} % \item first element is the number of pairs of lengths in the array % \item subsequent arguments are pairs of lengths, left margin width then % right margin width. % \end{itemize} % % The second parameter is the overall text width. This is given in the % following format: % \begin{itemize} % \item first element is the number lengths % \item subsequent elements are one width per parameter % \end{itemize} % \begin{macrocode} \newcommand{\Parshapearray}[2]{% \testarray{#1}(1)\edef\rjlpshap@maxA{\temp@macro}% \testarray{#2}(1)\edef\rjlpshap@maxB{\temp@macro}% \ifthenelse{\rjlpshap@maxA > \rjlpshap@maxB} {\edef\rjlpshap@max{\rjlpshap@maxA}}{\edef\rjlpshap@max{\rjlpshap@maxB}}% \begin{parshapecollect}% \forloop{rjlpshap@ctr}{1}{\not \value{rjlpshap@ctr} > \rjlpshap@max}{% \ifthenelse{\value{rjlpshap@ctr} > \rjlpshap@maxA}{% \setcounter{rjlpshap@ctr2}{\rjlpshap@maxA}% \addtocounter{rjlpshap@ctr2}{\rjlpshap@maxA}% }{% \setcounter{rjlpshap@ctr2}{\value{rjlpshap@ctr}}% \addtocounter{rjlpshap@ctr2}{\value{rjlpshap@ctr}}% }% % \end{macrocode} % left margin from \#1: % \begin{macrocode} \parshapearrlenout{#1}{rjlpshap@ctr2}% % \end{macrocode} % get the line width % \begin{macrocode} \ifthenelse{\value{rjlpshap@ctr} > \rjlpshap@maxB}{% \edef\rjlpshap@pos{\rjlpshap@maxB}% \setcounter{rjlpshap@ctr3}{\rjlpshap@maxB}% \typeout{A pos=\rjlpshap@pos\space of \rjlpshap@maxB}% \testarray{#2}(\arabic{rjlpshap@ctr3})% \typeout{temp=\temp@macro}% \setlength{\rjlpshap@templinewidth}{\temp@macro}% }{% \stepcounter{rjlpshap@ctr}% \edef\rjlpshap@pos{\arabic{rjlpshap@ctr}}% \typeout{B pos=\rjlpshap@pos}% \addtocounter{rjlpshap@ctr}{-1}% \testarray{#2}(\rjlpshap@pos)% \setlength{\rjlpshap@templinewidth}{\temp@macro}% }% \typeout{width=\the\rjlpshap@templinewidth}% % \end{macrocode} % subtract the left margin from the line width % \begin{macrocode} \addtolength{\rjlpshap@templinewidth}{-1\rjlpshap@tempwidth}% % \end{macrocode} % subtract the right margin from the line width % \begin{macrocode} \stepcounter{rjlpshap@ctr2}% \edef\rjlpshap@pos{\arabic{rjlpshap@ctr2}}% \testarray{#1}(\rjlpshap@pos)% \setlength{\rjlpshap@tempwidth}{\temp@macro}% \addtolength{\rjlpshap@templinewidth}{-1\rjlpshap@tempwidth}% \parshapelenout{\rjlpshap@templinewidth}% }% \end{parshapecollect}% } % \end{macrocode} % \end{macro} % \subsection{Internal Definitions} % rjlpshap@ctr: outermost loop counter: % \begin{macrocode} \newcounter{rjlpshap@ctr} % \end{macrocode} % rjlpshap@ctr2: used for index calculations internally: % \begin{macrocode} \newcounter{rjlpshap@ctr2} % \end{macrocode} % rjlpshap@ctr3: used for index calculations internally: % \begin{macrocode} \newcounter{rjlpshap@ctr3} % \end{macrocode} % rjlpshap@tempwidth: used as a register to read widths from arrays, % and for calculations % \begin{macrocode} \newlength{\rjlpshap@tempwidth} % \end{macrocode} % rjlpshap@templinewidth: used as a register to calculate the line % width when subtracting margins: % \begin{macrocode} \newlength{\rjlpshap@templinewidth} % \end{macrocode} % boolean used for breaking out of loops % \begin{macrocode} \newboolean{rjlpshap@loop} % \end{macrocode} % boolean used to track if the number of lengths output is odd or even % \begin{macrocode} \newboolean{rjlpshap@isodd} % \end{macrocode} % Filehandles needed for reading and writing temporary files % \begin{macrocode} \newwrite\rjlpshap@writer % holds \parshape lengths \newwrite\rjlpshap@finalwriter % holds entire \parshape command \newread\rjlpshap@reader % used to read writer to transfer to finalwriter % \end{macrocode} % rjlpshap@linecount: counts the number of lines read in the environment % \begin{macrocode} \newcounter{rjlpshap@linecount} % \end{macrocode} % Finally, undo the effect of $\backslash$makeatletter, and make @ be % a special character again. % \begin{macrocode} \makeatother % \end{macrocode} % \Finale \endinput