% \iffalse meta-comment
% Line endings: UNIX
% Tab size:     4
%
% Copyright 2004 Jonathan Sauer
%
% This work may be distributed and/or modified under the
% conditions of the LaTeX Project Public License, either version 1.3
% of this license or (at your option) any later version.
% The latest version of this license is in
%
%   http://www.latex-project.org/lppl.txt
%
% and version 1.3 or later is part of all distributions of LaTeX
% version 2003/12/01 or later.
%
% This work has the LPPL maintenance status "maintained".
%
% The Current Maintainer of this work is Jonathan Sauer
% (<jonathan.sauer@gmx.de>).
%
% This work consists of the files parcolumns.dtx and parcolumns.ins
% and the derived file parcolumns.sty.
%
% \fi
%
% \iffalse
%
%<*driver>
\documentclass{ltxdoc}
\usepackage{parcolumns}
\EnableCrossrefs
\CodelineIndex
\RecordChanges
% Modification of verbatim for tabs in listings
\makeatletter
{\catcode`\ =\active%
\catcode`\^^I=\active%
\gdef\@vobeyspaces{%
\catcode`\ \active\let \@xobeysp%
\catcode`\^^I\active\def^^I{~~}%
}}%
\makeatother
\begin{document}
	\DocInput{\jobname.dtx}
\end{document}
%</driver>
%
%<package>\NeedsTeXFormat{LaTeX2e}
%<package>\ProvidesPackage{parcolumns}
%<package>   [2004/11/25 v1.2 Typeset multiple parallel columns]
%<package>\RequirePackage{processkv}[2004/08/05]
%
% \fi
%
% \CheckSum{368}
% \CharacterTable
%  {Upper-case    \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
%   Lower-case    \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
%   Digits        \0\1\2\3\4\5\6\7\8\9
%   Exclamation   \!     Double quote  \"     Hash (number) \#
%   Dollar        \$     Percent       \%     Ampersand     \&
%   Acute accent  \'     Left paren    \(     Right paren   \)
%   Asterisk      \*     Plus          \+     Comma         \,
%   Minus         \-     Point         \.     Solidus       \/
%   Colon         \:     Semicolon     \;     Less than     \<
%   Equals        \=     Greater than  \>     Question mark \?
%   Commercial at \@     Left bracket  \[     Backslash     \\
%   Right bracket \]     Circumflex    \^     Underscore    \_
%   Grave accent  \`     Left brace    \{     Vertical bar  \|
%   Right brace   \}     Tilde         \~}
%
% \DoNotIndex{\@clubpenalty,\@doendpe,\@ehc,\@ifundefined,\@M,\@ne}
% \DoNotIndex{\@one,\@nobreakfalse,\@plus,\@tempa,\@tempb,\@tempboxa}
% \DoNotIndex{\@tempcnta,\@tempdima,\@tempdimb,\@tempdimc}
% \DoNotIndex{\@tempswafalse,\@testopt,\advance,\afterassignment}
% \DoNotIndex{\box,\brokenpenalty,\clubpenalty,\count@,\csname}
% \DoNotIndex{\def,\define@key,\displaywidowpenalty,\divide,\dp,\edef}
% \DoNotIndex{\else,\endcsname,\endgraf,\everypar,\expandafter}
% \DoNotIndex{\fi,\global,\hbadness,\hb@xt@,\hfill,\hsize,\hskip}
% \DoNotIndex{\if@tempswa,\ifnum,\ifvoid,\ifx,\interlinepenalty}
% \DoNotIndex{\lastbox,\leavevmode,\let,\linewidth,\long,\loop}
% \DoNotIndex{\m@ne,\multiply,\newbox,\newcommand,\newcount}
% \DoNotIndex{\newdimen,\newenvironment,\newif,\newtoks}
% \DoNotIndex{\number,\PackageError,\PackageInfo,\processkeyvalues}
% \DoNotIndex{\relax,\repeat,\setbox,\setkeys,\space,\spaceskip}
% \DoNotIndex{\splittopsep,\splittopskip,\strut,\strutbox,\the}
% \DoNotIndex{\toks@,\tolerance,\unvbox,\vbadness,\vbox,\vfuzz}
% \DoNotIndex{\vrule,\vsplit,\widowpenalty,\z@,\z@skip,\\}
%
% \GetFileInfo{\jobname.sty}
%
% \title{The \textsf{parcolumns} package\thanks{This document
% corresponds to \textsf{\filename}~\fileversion, dated \filedate.}}
%
% \author{Jonathan Sauer \\ \texttt{jonathan.sauer@gmx.de}}
%
% \date{\filedate}
%
% \maketitle
%
% \begin{abstract}
% This file describes the \textsf{parcolumns} package that provides an
% environment for typesetting text in two or more columns columns in
% parallel.
%
% \end{abstract}
%
% \tableofcontents
%
% \section{Introduction}
%
% Sometimes it is necessary to typeset text in two or more columns in
% parallel, i.e. when typesetting a text in its original language and
% in its translation(s). This package provides the \verb|parcolumns|
% environment for typesetting text in several columns, where the text
% of all columns is aligned vertically.
%
% Text in the |parcolums| environment is typeset in chunks, where the
% chunks of one row are aligned vertically. A chunk consists of one or
% more paragraphs of text, including \TeX\ macros.
%
%
% \section{Usage}\label{sec:Usage}
%
% \DescribeEnv{parcolumns} Usage: |parcolumns| \oarg{options}
% \marg{number of colums}.
%
% Inside the |parcolumns| environment text can be typeset in two or
% more columns in parallel via the |\parchunk| macro. Normal text can
% also be included.
%
% The \verb|parcolumns| environment takes an optional parameter that
% specifies the options for the environment using the \textsf{keyval}
% and \textsf{processkv} packages. The following options exist:
%
% \begin{description}
% 	\item[\emph{colwidths}]		Sets the widths of the columns. The
% 								widths are specified as key-values,
% 								\meta{columnnumber}=\meta{width}.
% 								Columns start at `1'. Note that in
% 								order to be ignored by the
% 								\textsf{keyval} package, the complete
% 								value has to be surrounded by braces,
% 								i.e. `|colwidths={1=2cm,3=5cm,4=2cm}|'
% 								to set the first column to a width of
% 								2~cm, the third to 5~cm and the fourth
% 								to 2~cm. (the second column is
% 								calculated)
%
% 								Columns not set this way will be
% 								distributed evenly across the remaining
% 								horizontal space of the page.
%
% 	\item[distance]				Sets the distance between two columns.
%								If omitted set to \verb|2em|.
%
% 	\item[rulebetween]			(Flag)\footnote{Meaning that if you
% 								just say \texttt{rulebetween}, you set the
% 								flag, as well as when you say
% 								\texttt{rulebetween=true}. Saying
% 								\texttt{rulebetween=false} clears the flag,
% 								even though this does not make much sense,
% 								as it is the default.}
% 								Typeset a vertical bar between two
% 								columns.
%
% 								|false| if omitted.
%
%	\item[nofirstindent]		(Flag) Suppress the indentation of the first
%								paragraph in the environment.
%
%								|false| if omitted.
%
%	\item[sloppy]				(Flag) Typeset text in the columns in a
%								more sloppy way, preventing overfull
%								hboxes at the cost of larger
%								interword spacing.
%
%								|false| if omitted.
%
%	\item[sloppyspaces]			(Flag) Makes spaces in the columns
%								stretchable, preventing overfull
%								hboxes at the cost of even larger
%								interword spacing that |sloppy|.
%
%								|false| if omitted.
%
% \end{description}
%
%
% \DescribeMacro{\colchunk} Usage: |\colchunk| \oarg{column}
% \marg{chunk}.
%
% The macro |\colchunk| sets a chunk of text for the next column. You
% don't have to set chunks for all columns; the colums not set remain
% empty. However, the columns are filled from left to right, so if a
% column inbetween should remain empty, you must say |\colchunk{}| or
% specify the column to set using the optional parameter (columns
% start at 1): |\colchunk[2]{|\ldots|}| sets the text of the second
% column. Following calls to |\colchunk| without optional parameter
% fill the third, fourth et cetera column.
%
% After a call to |\colplacechunks|, the column number is reset to
% one.
%
%
%
% \DescribeMacro{\colplacechunks} Usage: |\colplacechunks|.
%
% The macro |\colplacechunks| places the chunks added with |\colchunk|
% on the page. If there are no chunks to place, it does nothing.
%
%
%
% \section{Examples}
%
% Two columns, option |rulebetween=true| (which is the same as
% just saying |rulebetween|):
%
% \addvspace{\baselineskip}
% \begin{parcolumns}[rulebetween=true]{2}
% \colchunk{Erwarten Sie von mir, dass ich rede? -- Nein, Mister
% Bond, ich erwarte von Ihnen, dass Sie sterben!}
%
% \colchunk{Do you expect me to talk? -- No, Mister Bond, I expect you
% to die!}
%
% \colplacechunks
%
% \colchunk{Erwarten Sie von mir, dass ich rede? -- Nein, Mister
% Bond, ich erwarte von Ihnen, dass Sie sterben!}
%
% \colchunk{Do you expect me to talk? -- No, Mister Bond, I expect you
% to die!}
%
% \colplacechunks
%
% \end{parcolumns}
% \addvspace{\baselineskip}
% As the german text is slightly longer, let's make the left column
% alittle bit larger using |colwidths={1=.55\linewidth}|:
%
% \addvspace{\baselineskip}
% \begin{parcolumns}[rulebetween=true,colwidths={1=.55\linewidth}]{2}
% \colchunk{Erwarten Sie von mir, dass ich rede? -- Nein, Mister
% Bond, ich erwarte von Ihnen, dass Sie sterben!}
%
% \colchunk{Do you expect me to talk? -- No, Mister Bond, I expect you
% to die!}
%
% \colplacechunks
%
% \colchunk{Erwarten Sie von mir, dass ich rede? -- Nein, Mister
% Bond, ich erwarte von Ihnen, dass Sie sterben!}
%
% \colchunk{Do you expect me to talk? -- No, Mister Bond, I expect you
% to die!}
%
% \colplacechunks
%
% \end{parcolumns}
% \addvspace{\baselineskip}
% Three columns, option |nofirstindent=true|:
%
% \addvspace{\baselineskip}
% \begin{parcolumns}[nofirstindent]{3}
% \colchunk{This is just a short english text, just long enough to fill
% a few lines.}
%
% \colchunk{Dies ist nur ein kurzer deutscher Text, gerade lang genug,
% um ein paar Zeilen zu fuellen.}
%
% \colchunk{This is another short english text, as my french is not
% that good anymore.}
%
% \colplacechunks
%
% \end{parcolumns}
% \addvspace{\baselineskip}
% There was an overfull |\hbox| in the previous text. Let's
% try that again with the option |sloppy|:
%
% \addvspace{\baselineskip}
% \begin{parcolumns}[nofirstindent,sloppy]{3}
% \colchunk{This is just a short english text, just long enough to fill
% a few lines.}
%
% \colchunk{Dies ist nur ein kurzer deutscher Text, gerade lang genug,
% um ein paar Zeilen zu fuellen.}
%
% \colchunk{This is another short english text, as my french is not
% that good anymore.}
%
% \colplacechunks
%
% \end{parcolumns}
% \addvspace{\baselineskip}
% No overfull hbox this time, but the spacing in the first column
% is not optimal. You just have to pick what's better. Or you could
% try the interword spacing provided by the \textsf{soul} package.
%
% \addvspace{\baselineskip}\noindent Maybe we do not want to fill the
% first column, but do not want to type |\colchunk{}| either. Then we
% can say |\colchunk[2]| to directly start with the second column
% (note that we are using the option |sloppy|, too):
%
% \addvspace{\baselineskip}
% \begin{parcolumns}[nofirstindent,sloppy]{3}
% \colchunk[2]{This is just a short english text, just long enough to fill
% a few lines.}
%
% \colchunk{Dies ist nur ein kurzer deutscher Text, gerade lang genug,
% um ein paar Zeilen zu fuellen.}
%
% \colplacechunks
%
% \end{parcolumns}
% \addvspace{\baselineskip}
% Note that \texttt{parcolumns} does not insert vertical space
% before or after the environment! In these examples, the space has
% manually been added with |\addvspace|.
%
%
%
% \section{Notes}\label{sec:Notes}
%
% \begin{itemize}
% 	\item	The columns will always fill the complete width of the
% 			page by stretching or shrinking the space between the columns.
% 			That means that if the total width of all columns is set
% 			to about half the page width, the space between the columns
% 			will take up the rest, ignoring whatever was set with the
% 			key |distance|.\footnote{The key \texttt{distance} is only
% 			used for calculating the width of the columns and is ignored
% 			afterwards.}
%
% 	\item	Footnotes are not set in columns.
%
%	\item	\textsf{parcolumns} does not work very well with displayed
%			formula. The best way to typeset a |displaymath| et.al.
%			environment is to include it in separate |\colchunk|
%			commands, i.e. (assuming two columns and the same formula
%			in both):
%
% \begin{verbatim}
% ... some text placed using \colchunk ...
% \colchunk{ % Left column
% \begin{displaymath}
% x^2 + y^2 = z^2
% \end{displaymath}
% }
% \colchunk{ % Right column
% \begin{displaymath}
% x^2 + y^2 = z^2
% \end{displaymath}
% }
% \colplacechunks
% ... some more text placed using \colchunk ...
% \end{verbatim}
%
% \end{itemize}
%
%
%
% \StopEventually{}
%
% \section{Implementation}
%
% \subsection{Allocation}
%
% The current column (starting with one):
%
%    \begin{macrocode}
\newcount\pc@columnctr
%    \end{macrocode}
%
% The total number of columns in the current |parcolums| environment.
%
%    \begin{macrocode}
\newcount\pc@columncount
%    \end{macrocode}
%
% Place a vertical rule between two columns?
%
%    \begin{macrocode}
\newif\ifpc@rulebetween
%    \end{macrocode}
%
% Stores |\everypar| for use in |\parparagraphs|.
%
%    \begin{macrocode}
\newtoks\pc@everypar
%    \end{macrocode}
%
% Note that additional allocations are performed later on-demand in
% |\pc@alloccolumns|.
%
%
%
% \subsection{\textsf{keyvalue} keys}
%
% \begin{macro}{\pc@boolkey}
%
% Sets an \verb|if|-condition in \marg{\#1} to the value passed as
% \marg{\#2}. If \verb|#2| is \verb|false|, set \verb|if#1| to
% \verb|false|, else (any other value) to \verb|true|.
%
% Usage: |\pc@boolkey| \marg{ifcondition} \marg{value}
%
%    \begin{macrocode}
\def\pc@boolkey#1#2{%
	\edef\@tempa{#2}%
	\edef\@tempb{false}%
	\ifx\@tempa\@tempb%
		\csname #1false\endcsname%
	\else%
		\csname #1true\endcsname%
	\fi%
}
%    \end{macrocode}
% \end{macro}
%
%
% Define the keys for the options of |parcolumns|.
%
%    \begin{macrocode}
\define@key{parcolumns}{distance}{%
	\@tempdimc#1\relax%
}
\define@key{parcolumns}{rulebetween}[true]{%
	\pc@boolkey{pc@rulebetween}{#1}%
}
\define@key{parcolumns}{nofirstindent}[true]{%
	\pc@boolkey{@tempswa}{#1}%
%    \end{macrocode}
%
% If the indentation of the first line of the first paragraph should
% be suppressed, change |\pc@everypar| accordingly. The token register
% is reset after the placing of the first row of chunks in
% |\colplacechunks|.
%
% What exactly are we doing? First we assign box 0 the contents of
% |\lastbox|. At the beginning of a paragraph |\lastbox| contains
% the glue inserted for the indentation of the first line. By
% assigning this box to box 0, we remove the indentation. We do
% this in a group as not to change the contents of box 0.
%
% Afterwards we set |\everypar| to nothing. This is necessary because
% we only want to suppress the indentation for the first paragraph of
% the |parcolumns| environment, not every paragraph. We set
% |\everypar| and not |\pc@everypar| to nothing, because
% |\pc@everypar| is only a temporary storage that will be assigned to
% |\everypar| when used.
%
%    \begin{macrocode}
	\if@tempswa\pc@everypar{{\setbox\z@\lastbox}\everypar{}}\fi%
}
\define@key{parcolumns}{sloppy}[true]{%
	\pc@boolkey{@tempswa}{#1}%
%    \end{macrocode}
%
% If sloppy typesetting is asked for, we set |\hbadness| and
% |\tolerance| to 10000, so that \TeX\ breaks lines whenever possible,
% even if this means high interword spacing.
%
%    \begin{macrocode}
	\if@tempswa%
		\hbadness\@M%
		\tolerance\@M%
	\fi%
}
\define@key{parcolumns}{sloppyspaces}[true]{%
	\pc@boolkey{@tempswa}{#1}%
%    \end{macrocode}
%
% If sloppy spaces are asked for, we make the space stretchable:
%
%    \begin{macrocode}
	\if@tempswa%
		\spaceskip.3333em\@plus1em %
	\fi%
}
%    \end{macrocode}
%
%
% We save the key-value-list containing widths of the columns in
% |\toks@| for later use in |\pc@setcolumnwidths|.
%
%    \begin{macrocode}
\define@key{parcolumns}{colwidths}{%
	\toks@{#1}%
}
%    \end{macrocode}
%
%
% \subsection{Main environments and macros}
%
% \begin{environment}{parcolumns}
%
% Environment for a number of columns of text set in parallel (see
% section \ref{sec:Usage} on page \pageref{sec:Usage} for the possible
% options)
%
% Usage: |\begin{parcolumns}| \oarg{options} \marg{number of columns}
% \ldots\ |\end{parcolums}|
%
%    \begin{macrocode}
\newenvironment{parcolumns}[2][]{%
	\pc@rulebetweenfalse%
%    \end{macrocode}
%
% |\if@tempswa| is |true|, if the indentation of the first line
% should be suppressed, otherwise |false|. Default is |false|:
%
%    \begin{macrocode}
	\@tempswafalse%
%    \end{macrocode}
%
% |\@tempdimc| contains the space between two columns. Default
% is |2em|:
%
%    \begin{macrocode}
	\@tempdimc2em\relax%
%    \end{macrocode}
%
% We set the options:
%
%    \begin{macrocode}
	\toks@{}%
	\setkeys{parcolumns}{#1}%
%    \end{macrocode}
%
% We store the total number of columns and reset the counter for
% the current column:
%
%    \begin{macrocode}
	\pc@columncount#2 %
	\pc@columnctr\z@%
%    \end{macrocode}
%
% We allocate the columns and set their widths:
%
%    \begin{macrocode}
	\pc@alloccolumns%
	\pc@setcolumnwidths%
%    \end{macrocode}
%
% We switch to vertical mode:
%
%    \begin{macrocode}
	\endgraf%
%    \end{macrocode}
%
% As we are changing |\everypar|, we need to make sure that the most
% important flag is reset, which normally happens in the |\everypar|
% of a |\section|-command: |\if@nobreak|. (otherwise the next section
% is typeset directly after the text of the previous section instead
% of leaving some space)\footnote{I discovered this the hard way,
% spending one or two hours wondering why the spacing between two
% sections was much too small.}
%
%    \begin{macrocode}
	\@nobreakfalse%
%    \end{macrocode}
%
% We reset |\everypar|, as it is of no use for us and can only screw
% up things badly:
%
%    \begin{macrocode}
	\global\everypar{}%
}{%
%    \end{macrocode}
%
% At the end of the |parcolumns|-environment \ldots\ just in case, we
% place the last chunks, if not already done so:
%
%    \begin{macrocode}
	\colplacechunks%
	\endgraf%
%    \end{macrocode}
%
% We reset |\clubpenalty| globally to its normal value (the |\global|
% makes sure that if |\everypar| should have reset |\clubpenalty|, it
% is reset now).
%
%    \begin{macrocode}
	\global\clubpenalty\@clubpenalty%
%    \end{macrocode}
%
% We suppress the indentation of the next paragraph immediately
% following the environment:
%
%    \begin{macrocode}
	\@doendpe%
}
%    \end{macrocode}
% \end{environment}
%
%
% \begin{macro}{\colchunk}
%
% Sets the text for the next chunk of the next column.
%
% Usage: |\colchunk| \oarg{column} \marg{chunk}. (note that the |{|
% and |}| are \emph{not} optional, even if the chunk consists of only
% one token!)
%
% We need two macros for handling the optional parameter
% \meta{column}, |\colchunk| and |\colchunk@|. First we define
% |\colchunk|:
%
% \changes{1.1}{2004/08/22}{Optional parameter added.}
%
%    \begin{macrocode}
\newcommand{\colchunk}{\@testopt\colchunk@{}}%
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\colchunk@}
%
% What are we doing now? By suffixing the last (optional) parameter by
% |#|, we tell \TeX\ that the last parameter of |\colchunk| is to be
% delimited by a right brace |{|, or \TeX\ will complain with a more
% comprehensible message that without the |#|: `Use of |\colchunk|
% doesn't match its definition.' instead of `Missing |{| inserted.'
%
% \changes{1.0.1}{2004/08/10}{Parameter added.}
% \changes{1.1}{2004/08/22}{Optional parameter added.}
%
%    \begin{macrocode}
\long\def\colchunk@[#1]#{%
%    \end{macrocode}
%
% We check if the optional parameter is not empty. Then we use it as
% the column number, otherwise we simply pick the next column:
%
%    \begin{macrocode}
	\ifx\\#1\\%
		\advance\pc@columnctr\@ne%
	\else%
		\pc@columnctr#1\relax%
	\fi%
%    \end{macrocode}
%
% If we try to add a column past the last one, we display an error
% message:
%
%    \begin{macrocode}
	\ifnum\pc@columnctr>\pc@columncount%
		\PackageError{parcolumns}{The column \number\pc@columnctr\space%
			is too large}{Only \number\pc@columncount\space columns are%
			\space allowed.}
%    \end{macrocode}
%
% As we cannot simply skip the chunk (we could gobble what follows
% after the macro, but this would require a lot of jumping, and just
% for handling a small mistake \ldots), we simply set the last column:
%
% \changes{1.0.1}{2004/08/10}{Error handling somewhat improved.}
%
%    \begin{macrocode}
		\pc@columnctr\pc@columncount%
	\fi%
%    \end{macrocode}
%
% We zero the |\clubpenalty| that could have been changed, i.e. by
% |\everypar| of a |\section|-command: |\section| changes the
% clubpenalty to prevent a break between the first two lines of the
% paragraph following immediately after the section; as we split off
% line after line when typesetting the two columns, this would make
% splitting of a single line impossible (|\vsplit| uses the same logic
% as page-breaking), thus resulting in a lot of overfull vboxes and
% weird spacing inbetween, as \emph{two} lines would be split off.
%
% We do this every time we add chunks just in case some macro in the
% chunks has changed |\clubpenalty|. Note that we cannot prevent a
% macro in the text of the chunk to change the
% |\clubpenalty|.\footnote{Well we could, by redefining the
% clubpenalty to be a macro that simply throws its parameter away, and
% using some tricks to make this macro behave like a register,
% therefore completely ignoring any change of the clubpenalty.} But if
% it is changed, at least it will not stay changed (though the typeset
% columns will still look bad).
%
% \changes{1.0.1}{2004/08/09}{clubpenalty is always reset before
% adding chunks}
%
%    \begin{macrocode}
	\clubpenalty\z@%
%    \end{macrocode}
% 
% The same goes for the other penalties \TeX\ will insert between two
% lines, as we absolutely, positively \emph{must} be able to break
% between any two lines:\footnote{C.f. chapter 14 of the \TeX book}
% 
% \changes{1.2}{2004/11/25}{other penalties added}
% 
%    \begin{macrocode}
	\interlinepenalty\z@%
	\displaywidowpenalty\z@%
	\widowpenalty\z@%
	\brokenpenalty\z@%
%    \end{macrocode}
%
% We set |\everypar| to our self-defined |\pc@everypar| to suppress
% the indentation of the first paragraph if so desired:
%
%    \begin{macrocode}
	\everypar\expandafter{\the\pc@everypar}%
%    \end{macrocode}
%
% After the next assignment, insert the width of the column:
%
%    \begin{macrocode}
	\afterassignment\pc@setcolumnwidth%
%    \end{macrocode}
%
% We typeset the chunk's text into the box |\pc@column@|\meta{column
% counter}. The text of the chunk follows the macro, meaning that the
% last line looks like this: |\vbox{|\meta{chunk text}|}|.
%
% But what about the width of the box? |\hsize| must be set in the
% vbox in order to make it the correct width! We achieve this using
% the |\afterassignment| above: After the assignment of the chunk's
% text to the box, we are inside the box, therefore the contents of
% |\pc@setcolumnwidth| is inserted at the very beginning of the vbox,
% setting the correct width.
%
% Why don't we simply make |\colchunk| take one parameter that
% contains the text of the chunk? Because in that case, macros that
% change catcodes like |\verb| would be prohibited, which would
% restrict this package somewhat. Also it would be slower and would
% use more memory.
%
%    \begin{macrocode}
	\expandafter\setbox\csname pc@column@\number\pc@columnctr\endcsname%
		\vbox%
}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\colplacechunks}
%
% Places all chunks set with |\colchunk|.
%
%    \begin{macrocode}
\newcommand{\colplacechunks}{%
%    \end{macrocode}
%
% If there are any chunks to place:
%
%    \begin{macrocode}
	\ifnum\pc@columnctr>\z@%
%    \end{macrocode}
%
% We place them:
%
%    \begin{macrocode}
		\pc@placeboxes%
%    \end{macrocode}
%
% We reset the column counter:
%
%    \begin{macrocode}
		\pc@columnctr\z@%
%    \end{macrocode}
%
% We clear |\pc@everypar|, because we only want to suppress the
% indentation of the first paragraph of each column at the very top of
% the |parcolumns| environment, not of the first paragraph of every
% call to |\colchunk|.
%
%    \begin{macrocode}
		\pc@everypar{}%
	\fi%
}
%    \end{macrocode}
% \end{macro}
%
%
%
%
% \subsection{Internal environments and macros}
%
% \begin{macro}{\pc@placeboxes}
%
% Places the prepared boxes (containing the chunks) on the page.
%
%    \begin{macrocode}
\def\pc@placeboxes{%
%    \end{macrocode}
%
% We assume we don't have to perform another line (|\@tempa| contains
% what we have to to after we are finished with this macro). The
% assignment is global because later on when changing |\@tempa| we are
% in a group:
%
%    \begin{macrocode}
	\global\let\@tempa\relax%
	\count@\z@%
%    \end{macrocode}
%
% We create a hbox. Inside a hbox, vboxes are put horizontally
% next to each other and are aligned on their baseline:
%
%    \begin{macrocode}
	\hb@xt@\linewidth{%
%    \end{macrocode}
%
% Before doing any work, we change a few parameters:
%
% \changes{1.2}{2004/11/22}{moved parameter changes from begin of
% environment}
%
% We prevent warnings of overfull and underfull vboxes as they can
% happen, but we do not really care (happens when we |\vsplit| the top
% off the chunks, this is okay):
%
% \changes{1.2}{2004/11/22}{vfuzz increased to prevent warnings with
% math}
%
% \changes{1.2}{2004/11/22}{vbadness set}
%
%    \begin{macrocode}
		\vfuzz30ex %
		\vbadness\@M%
%    \end{macrocode}
%
% We prevent vertical glue to be insert when |vsplit|ting a vbox
% (otherwise it screws up the spacing).
%
%    \begin{macrocode}
		\splittopskip\z@skip%
%    \end{macrocode}
%
% Now we loop over all the prepared boxes. We can use |\loop| here as
% we are in a group (begun by |\hbox|). Otherwise we would have to
% open a group manually or loop manually, as to not screw up a |\loop|
% outside the macro:
%
%    \begin{macrocode}
		\loop\ifnum\count@<\pc@columncount%
			\advance\count@\@ne%
%    \end{macrocode}
%
% If the box |\pc@column@|\meta{counter} is empty, we simply insert a
% hskip the width of the box (saved in
% |\pc@column@width@|\meta{counter}):
%
%    \begin{macrocode}
			\expandafter\ifvoid\csname pc@column@\number\count@%
				\endcsname%
				\hskip\csname pc@column@width@\number\count@\endcsname%
			\else%
%    \end{macrocode}
%
% Otherwise we |\vsplit| the first line of the box (at the same time
% removing it from |\pc@column@|\meta{counter}) and save it in
% |\@tempboxa|. Then, we strip this resulting box of its enclosing
% vbox and put it into another vbox, which we put into the hbox begun
% a few lines ago.
%
% Why is this so complicated? To ensure that proper vertical glue is
% inserted (otherwise the spacing between the lines would be wrong).
%
%    \begin{macrocode}
				\expandafter\setbox\expandafter\@tempboxa\expandafter%
					\vsplit\csname pc@column@\number\count@\endcsname%
						to \dp\strutbox%
				\vbox{\unvbox\@tempboxa}%
			\fi%
%    \end{macrocode}
%
% If the remaining box is not empty, we have to perform at least
% another line:
%
%    \begin{macrocode}
			\expandafter\ifvoid\csname pc@column@\number\count@%
				\endcsname\else%
				\global\let\@tempa\pc@placeboxes%
			\fi%
%    \end{macrocode}
%
% If this is not the last column, we put a strut into the hbox to
% ensure propery vertical spacing:
%
%    \begin{macrocode}
			\ifnum\count@<\pc@columncount%
				\strut%
%    \end{macrocode}
%
% If a vertical line should be placed between two columns, we insert
% it now, centering it between two |\hfill|s. Otherwise, we simply
% insert a |\hfill| that stretches as much as possible, pushing the
% right column to the right margin. (see also section \ref{sec:Notes}
% on page \pageref{sec:Notes})
%
%    \begin{macrocode}
				\hfill%
				\ifpc@rulebetween%
					\vrule%
					\hfill%
				\fi%
			\fi%
		\repeat%
	}%
%    \end{macrocode}
%
% If necessary, we perform another line:
%
%    \begin{macrocode}
	\@tempa%
}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\pc@alloccolumns}
%
% Allocates a number of |\box|es, named |\pc@column@1|, |\pc@column@2|
% et cetera, if not already allocated.
%
% Also allocates a number of |\dimen|s, named |\pc@column@width@1| et
% cetera.
%
% If the |\box|es and |\dimen|s are already allocated, they are
% cleared (|\box|es) or set to zero (|\dimen|s).
%
%    \begin{macrocode}
\def\pc@alloccolumns{%
	\count@\z@%
	\loop\ifnum\count@<\pc@columncount%
		\advance\count@\@ne%
		\@ifundefined{pc@column@\number\count@}{%
			\expandafter\newbox\csname pc@column@\number\count@%
				\endcsname%
			\expandafter\newdimen\csname pc@column@width@\number%
				\count@\endcsname%
		}{%
			\setbox0\box\csname pc@column@\number\count@\endcsname%
			\csname pc@column@width@\number\count@\endcsname\z@%
		}%
	\repeat%
}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\pc@setcolumnwidths}
%
% Sets the widths of all columns. The defined widths have been
% temporarily stored in |\toks@|. |\@tempdimc| contains the space
% between two columns.
%
%    \begin{macrocode}
\def\pc@setcolumnwidths{%
	\expandafter\processkeyvalues\expandafter{\the\toks@}%
		\pc@setsinglecolwidth%
%    \end{macrocode}
%
% |\@tempdima| will contain the total width of all columns that have a
% known width (read: have had their width set via the parameter
% |colwidths|)
%
%    \begin{macrocode}
	\@tempdima\z@%
%    \end{macrocode}
%
% |\@tempcnta| will contain the count of columns that an unknown width
% (read: have had their width \emph{not} set via the parameter
% |colwidths|, thus now having a width of zero points, as the widths
% of all columns have been reset in |\pc@alloccolumns|):
%
%    \begin{macrocode}
	\@tempcnta\z@%
%    \end{macrocode}
%
% We calculate the total width of all columns known. We count how many
% columns have an unknown width:
%
%    \begin{macrocode}
	\count@\z@%
	\loop\ifnum\count@<\pc@columncount%
		\advance\count@\@ne%
		\@tempdimb\csname pc@column@width@\number\count@\endcsname%
		\advance\@tempdima\@tempdimb%
		\ifnum\@tempdimb=\z@%
			\advance\@tempcnta\@ne%
		\else%
			\PackageInfo{parcolumns}{Width of column \number\count@%
				\space set to \the\@tempdimb}
		\fi%
	\repeat%
%    \end{macrocode}
%
% If at least one column has an unknown width:
%
%    \begin{macrocode}
	\ifnum\@tempcnta>\z@%
%    \end{macrocode}
%
% |\@tempdimc| contains the distance between columns. We calculate the
% space left for the columns with an unknown width.
%
% |\@tempdimb| will contain the sum of the space between all the
% columns \ldots
%
%    \begin{macrocode}
		\@tempdimb\@tempdimc%
		\multiply\@tempdimb\pc@columncount%
		\advance\@tempdimb-\@tempdimc%
%    \end{macrocode}
%
% \ldots\ plus the sum of the width of all columns with a known width:
%
%    \begin{macrocode}
		\advance\@tempdimb\@tempdima%
%    \end{macrocode}
%
% |\@tempdima| will contain the space for each column with an unknown
% width:
%
%    \begin{macrocode}
		\@tempdima\linewidth%
		\advance\@tempdima-\@tempdimb%
		\divide\@tempdima\@tempcnta%
%    \end{macrocode}
%
% We set the widths of the colums with an unknown width:
%
%    \begin{macrocode}
		\count@\z@%
		\loop\ifnum\count@<\pc@columncount%
			\advance\count@\@ne%
			\ifnum\csname pc@column@width@\number\count@\endcsname=\z@%
				\csname pc@column@width@\number\count@\endcsname\@tempdima%
				\PackageInfo{parcolumns}{Width of column \number\count@%
					\space calculated as \the\@tempdima}
			\fi%
		\repeat%
	\fi%
}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\pc@setsinglecolwidth}
%
% Usage: |\pc@setsinglecolwidth| \marg{column} \marg{width}.
%
% Sets the width of the column \meta{column} to the width
% \meta{width}. Displays an error message if the column is not valid.
%
%    \begin{macrocode}
\def\pc@setsinglecolwidth#1#2{%
	\@ifundefined{pc@column@width@\number#1}{
		\PackageError{parcolumns}{`#1' is not a valid column number!}%
			{\@ehc}%
	}{%
		\csname pc@column@width@\number#1\endcsname=#2\relax%
	}%
}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\pc@setcolumnwidth}
%
% Sets |\hsize| to the width of a column (stored in
% |\pc@column@width@|\meta{pc@columnctr}) and enters horizonal mode.
%
% \changes{1.2}{2004/11/22}{linewidth set, too}
%
%    \begin{macrocode}
\def\pc@setcolumnwidth{%
	\hsize\csname pc@column@width@\number\pc@columnctr\endcsname%
	\linewidth\hsize%
	\leavevmode%
}
%    \end{macrocode}
% \end{macro}
%
%
% \Finale
% \PrintChanges
% \PrintIndex
\endinput