diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /macros/latex/contrib/polytable |
Initial commit
Diffstat (limited to 'macros/latex/contrib/polytable')
-rw-r--r-- | macros/latex/contrib/polytable/README | 14 | ||||
-rw-r--r-- | macros/latex/contrib/polytable/polytable.dtx | 2378 | ||||
-rw-r--r-- | macros/latex/contrib/polytable/polytable.ins | 5 | ||||
-rw-r--r-- | macros/latex/contrib/polytable/polytable.pdf | bin | 0 -> 288334 bytes |
4 files changed, 2397 insertions, 0 deletions
diff --git a/macros/latex/contrib/polytable/README b/macros/latex/contrib/polytable/README new file mode 100644 index 0000000000..88ba930183 --- /dev/null +++ b/macros/latex/contrib/polytable/README @@ -0,0 +1,14 @@ +This is the polytable package. The license is LPPL. + +The package depends on lazylist.sty, as available from +"CTAN:/macros/latex/contrib/lazylist.sty". + +To install and get documentation, run the following commands: + +latex polytable.ins +latex polytable.dtx +latex polytable.dtx + +Please report bugs to "polytable@andres-loeh.de". + +Andres Loeh, November 2005 diff --git a/macros/latex/contrib/polytable/polytable.dtx b/macros/latex/contrib/polytable/polytable.dtx new file mode 100644 index 0000000000..fb9219492b --- /dev/null +++ b/macros/latex/contrib/polytable/polytable.dtx @@ -0,0 +1,2378 @@ +% \iffalse +%<*driver> +\ProvidesFile{polytable.drv} +\documentclass{ltxdoc} +\usepackage[info]{polytable} +\begin{document} + \DocInput{polytable.dtx} +\end{document} +%</driver> +% +% Copyright (C) 2003--2013 by Andres Loeh +% +% \fi +% +% \ProvidesFile{polytable.dtx} +% [2013/07/08 v0.8.5 `polytable' package (Andres Loeh)] +% \GetFileInfo{polytable.dtx} +% +% \title{The \textsf{polytable} package} +% \author{Andres L\"oh\\ \texttt{polytable@andres-loeh.de}} +% \date{\filedate} +% +% \maketitle +% +% \begin{abstract} +% This package implements a variant of tabular/tabbing-like environments +% where columns can be given a name and entries can flexibly +% be placed between arbitrary columns. Complex alignment-based +% layouts, for example for program code, are possible. +% \end{abstract} +% +% \changes{v0.1}{2002/11/17}{Works.} +% \changes{v0.2}{2003/04/03}{Added pboxed. Added debug option.} +% \changes{v0.3}{2003/05/26}{Greatly enhanced pboxed.} +% \changes{v0.4}{2003/06/11}{Optional argument for ptable and parray.} +% \changes{v0.4.1}{2003/07/13}{Saving and restoring enhancements.} +% \changes{v0.4.2}{2003/07/16}{Fixed bug that caused infinite reruns.} +% \changes{v0.4.3}{2003/07/20}{Added some missing relaxes.} +% \changes{v0.5}{2003/07/22}{Documentation improved. To be put on CTAN.} +% \changes{v0.6}{2003/07/24}{Depends on lazylist instead of lambda now.} +% \changes{v0.7}{2003/11/20}{Check for undefined columns. Save counters.} +% \changes{v0.7.1}{2003/12/26}{Counters have not been restored correctly.} +% \changes{v0.7.2}{2004/02/27}{Fix for conflict with amsmath package.} +% \changes{v0.7.3}{2004/06/21}{Balance last line in pboxed environment.} +% \changes{v0.8}{2004/06/24}{New environments pmboxed, ptboxed. +% Removed original ptabular and parray. +% Interface overhaul.} +% \changes{v0.8.1}{2004/11/11}{Fixed some problems with the new +% interface, added the external (disk) queue.} +% \changes{v0.8.2}{2005/04/26}{New interface command. +% Minor beautifications.} +% \changes{v0.8.3}{2009/04/28}{Make sorting algorithm stable.} +% \changes{v0.8.4}{2009/11/01}{Make ptb output more stable.} +% \changes{v0.8.5}{2013/07/18}{Work around lazylist name clash +% with unicode-math.} +% +% \section{Introduction} +% +% This package implements a variant of tabular-like environments. +% We will call these environments the |poly|-environments to +% distinguish them from the standard ones as provided by the +% \LaTeX\ kernel or the \textsf{array} package. +% +% Other than in standard tables, each column has a name. For +% instance, the commands\\ +% |\column{foo}{l}|\\ +% |\column{bar}{r}|\\ +% -- when used within a |poly|-environment -- define a column +% with name |foo| that is left-aligned, and a column with name +% |bar| that is right-aligned. +% +% Once a couple of columns have been defined, the text is specified +% in a series of |\fromto| commands. Instead of specifying text +% per column in order, separating columns with |&|, we give the +% name of the column where the content should start, and the name +% of the column before which the content should stop. +% To typeset the text ``I'm aligned!'' in the column |foo|, +% we could thus use the command\\ +% |\fromto{foo}{bar}{I'm aligned}|\\ +% Several |\fromto|-commands can be used to typeset a complete +% line of the table. A new line can be started with |\\|. +% +% The strength of this approach is that it implicitly handles +% cases where different lines have different alignment properties. +% Not all column names have to occur in all lines. +% +% \section{A complete example} +% +% Figure~\ref{tab:example} +% is an example that is designed to show the +% capabilities of this package. In particular, it is \emph{not} +% supposed to look beautiful. +% +% \begin{figure}[htb] +% \centering +% \begin{ptboxed} +% \defaultcolumn{l|}\column{.}{|l|} +% \> left +% \=3 first of three \> second of three \> third of three +% \=r right \\ +% \defaultcolumn{r|}\> left \=2 middle 1/2 \> middle 2/2 \=r right \\ +% \> left \=3 middle 1/3 \> middle 2/3 \> middle 3/3 \=r right \\ +% \> left +% \=2 first of two middle columns \> second of two middle columns +% \=r right \\ +% \end{ptboxed} +% \caption{Example table}% +% \label{tab:example} +% \end{figure} +% +% The example table consists of four lines. All lines have +% some text on the left and on the right, but the middle part +% follows two different patterns: the first and the third line +% have three middle columnss that should be aligned, the second +% and the fourth line have two (right-aligned) middle columns +% that should be aligned, but otherwise independent of the three +% middle columns in the other lines. +% +% Vertical bars are used to clarify where one column ends and +% the next column starts in a particular line. Note that the first +% and the third line are completely aligned. Likewise, the +% second and the fourth line are. However, the fact that the +% bar after the text ``middle 1/2'' ends up between the two +% bars delimiting the column with ``second of three'' in it +% is just determined by the length of the text ``first of two +% middle columns'' in the last line. This text fragment +% is wider than the first of the three middle columns, but not +% wider than the first two of the three middle columns. +% +% Let's have a look at the input for the example table: +% \begin{verbatim} +% \begin{ptboxed} +% \defaultcolumn{l|}\column{.}{|l|} +% \> left +% \=3 first of three \> second of three \> third of three +% \=r right \\ +% \defaultcolumn{r|}\> left \=2 middle 1/2 \> middle 2/2 \=r right \\ +% \> left \=3 middle 1/3 \> middle 2/3 \> middle 3/3 \=r right \\ +% \> left +% \=2 first of two middle columns \> second of two middle columns +% \=r right \\ +% \end{ptboxed} +% \end{verbatim} +% First, columns are declared, including the vertical lines. +% Note that there is a final column |end| being declared +% that is only used as the end column in the |\fromto| statements. +% A future version of this package +% will probably get rid of the need to define +% such a column. +% After the column definitions, the lines are typeset by a +% series of |\fromto| commands, separated by |\\|. +% Note that the first and third column do not use |m12|, |m22|. +% Similarly, the second and fourth column do not use +% |m13|, |m23|, and |m33|. +% +% So far, one could achieve the same with an ordinary |tabular| +% environment. The table would have 6 columns. One left and right, +% the other four for the middle: the first and third line would +% use the first of the four columns, then place the second entry +% in a |\multicolumn| of length 2, and then use the fourth column +% for the third entry. Likewise, the other lines would place both +% their entries in a |\multicolumn| of length 2. In fact, this +% procedure is very similar to the way the |ptabular| environment +% is implemented. +% +% The problem is, though, that we need the information that +% the first of the two middle columns ends somewhere in the middle +% of the second of the three columns, as observed above. If we +% slightly modify the texts to be displayed in the middle columns, +% this situation changes. Figure~\ref{tab:variation} shows +% two variants of the example table. The input is the same, +% only that the texts contained in some columns have slightly +% changed. As you can see, the separator between the first and +% second middle column in the second and fourth lines of the +% tables now once ends up within the first, once within the +% third of the three middle columns of the other lines. +% +% \begin{figure}[htb] +% \centering +% \begin{ptboxed} +% \column{left}{|l|} +% \column{right}{l|} +% \column{m13}{l|} +% \column{m23}{l|} +% \column{m33}{l|} +% \column{m12}{r|} +% \column{m22}{r|} +% \column{end}{l} +% \fromto{left}{m13}{left} +% \fromto{m13}{m23}{first of three} +% \fromto{m23}{m33}{second of three} +% \fromto{m33}{right}{third of three} +% \fromto{right}{end}{right} +% \\ +% \fromto{left}{m12}{left} +% \fromto{m12}{m22}{middle 1/2} +% \fromto{m22}{right}{middle 2/2} +% \fromto{right}{end}{right} +% \\ +% \fromto{left}{m13}{left} +% \fromto{m13}{m23}{middle 1/3} +% \fromto{m23}{m33}{middle 2/3} +% \fromto{m33}{right}{middle 3/3} +% \fromto{right}{end}{right} +% \\ +% \fromto{left}{m12}{left} +% \fromto{m12}{m22}{first of two} +% \fromto{m22}{right}{second of two} +% \fromto{right}{end}{right} +% \end{ptboxed} +% \par\bigskip +% \begin{ptboxed} +% \column{left}{|l|} +% \column{right}{l|} +% \column{m13}{l|} +% \column{m23}{l|} +% \column{m33}{l|} +% \column{m12}{r|} +% \column{m22}{r|} +% \column{end}{l} +% \fromto{left}{m13}{left} +% \fromto{m13}{m23}{first of three} +% \fromto{m23}{m33}{second of three} +% \fromto{m33}{right}{third of three} +% \fromto{right}{end}{right} +% \\ +% \fromto{left}{m12}{left} +% \fromto{m12}{m22}{middle 1/2} +% \fromto{m22}{right}{middle 2/2} +% \fromto{right}{end}{right} +% \\ +% \fromto{left}{m13}{left} +% \fromto{m13}{m23}{middle 1/3} +% \fromto{m23}{m33}{middle 2/3} +% \fromto{m33}{right}{middle 3/3} +% \fromto{right}{end}{right} +% \\ +% \fromto{left}{m12}{left} +% \fromto{m12}{m22}{the first of two middle columns} +% \fromto{m22}{right}{2/2} +% \fromto{right}{end}{right} +% \end{ptboxed} +% \caption{Variants of the example table}% +% \label{tab:variation} +% \end{figure} +% +% If one wants the general case using the |\multicolumn| +% approach, one thus has to measure the widths of the entries +% of the columns to compute their relative position. In essence, +% this is what the package does for you. +% +% \section{Haskell code example} +% +% I have written this package mainly for one purpose: to be able +% to beautifully align Haskell source code. Haskell is a functional +% programming language where definitions are often grouped into +% several declarations. I've seen programmers exhibit symmetric +% structures in different lines by adding spaces in their source +% code files in such a way that corresponding parts in different +% definitions line up. On the other hand, as Haskell allows +% user-defined infix operators, some programmers like their symbols +% to be typeset as \LaTeX\ symbols, not as typewriter code. +% But using \LaTeX\ symbols and a beautiful proportional font +% usually destroys the carefully crafted layout and alignment. +% +% With lhs2\TeX, there is now a preprocessor available that preserves +% the source code's internal alignment by mapping the output onto +% \textsf{polytable}'s environments. +% Figure~\ref{tab:haskell} is an example of how +% the output of lhs2\TeX\ might look like. +% +% \newcommand{\HsVar}[1]{\mathop{\mathit{\strut #1}}} +% \newcommand{\HsCon}[1]{\mathop{\mathsf{\strut #1}}} +% \newcommand{\HsKey}[1]{\mathop{\mathbf{\strut #1}}} +% \newcommand{\map}{\HsVar{map}} +% \newcommand{\round}{\HsVar{round}} +% \newcommand{\TA}{\HsVar{a}} +% \newcommand{\TB}{\HsVar{b}} +% \newcommand{\TF}{\HsVar{f}} +% \newcommand{\TX}{\HsVar{x}} +% \newcommand{\TY}{\HsVar{y}} +% \newcommand{\TN}{\HsVar{n}} +% \newcommand{\TM}{\HsVar{m}} +% \newcommand{\TR}{\HsVar{r}} +% \newcommand{\TXS}{\HsVar{xs}} +% \newcommand{\RealFrac}{\mathop{\mathsf{RealFrac}}} +% \newcommand{\Integral}{\mathop{\mathsf{Integral}}} +% \newcommand{\LET}{\mathop{\mathbf{let}}} +% \newcommand{\IN}{\mathop{\mathbf{in}}} +% \newcommand{\IF}{\mathop{\mathbf{if}}} +% \newcommand{\THEN}{\mathop{\mathbf{then}}} +% \newcommand{\ELSE}{\mathop{\mathbf{else}}} +% \newcommand{\OF}{\mathop{\mathbf{of}}} +% \newcommand{\CASE}{\mathop{\mathbf{case}}} +% \newcommand{\CLASS}{\mathop{\mathbf{class}}} +% \newcommand{\WHERE}{\mathop{\mathbf{where}}} +% \newcommand{\Eq}{\mathop{\mathsf{Eq}}} +% \newcommand{\Ord}{\mathop{\mathsf{Ord}}} +% +% \setlength{\arraycolsep}{.5ex} +% +% \begin{figure} +% \[ +% \begin{pmboxed} +% \column{left}{l} +% \column{body}{l} +% \column{end}{l} +% \column{rel}{c} +% \column{rhs}{l} +% \>[left] \CLASS\ (\Eq\TA)\Rightarrow\Ord\TA\WHERE \\ +% \>[left] \qquad\ +% \>[body] \HsVar{compare} +% \>[rel] :: +% \>[rhs] \TA\rightarrow\TA\rightarrow\HsCon{Ordering} \\ +% \>[left] \qquad\ +% \>[body] (<),(\leq),(\geq),(>) +% \>[rel] :: +% \>[rhs] \TA\rightarrow\TA\rightarrow\HsCon{Bool} +% \\ +% \>[left] \qquad\ +% \>[body] \HsVar{max},\HsVar{min} +% \>[rel] :: +% \>[rhs] \TA\rightarrow\TA\rightarrow\HsCon{Bool} +% \\ +% \\ +% \>[body] \mbox{--- Minimal complete definition: +% $(\leq)$ or $\HsVar{compare}$} +% \\ +% \>[body] \mbox{--- using $\HsVar{compare}$ can be more efficient +% for complex types} +% \\ +% \column{cgrd}{l} +% \>[body] \HsVar{compare}\TX\TY +% \>[cgrd] \vert\ \TX\equiv\TY +% \>[rel] = +% \>[rhs] \HsCon{EQ} +% \\ +% \>[cgrd] \vert\ \TX\leq\TY +% \>[rel] = +% \>[rhs] \HsCon{LT} +% \\ +% \>[cgrd] \vert\ \HsVar{otherwise} +% \>[rel] = +% \>[rhs] \HsCon{GT} +% \\ +% \>[body] \TX\leq\TY +% \>[rel] = +% \>[rhs] \HsVar{compare}\TX\TY\not\equiv\HsCon{GT} +% \\ +% \>[body] \TX < \TY +% \>[rel] = +% \>[rhs] \HsVar{compare}\TX\TY\equiv\HsCon{LT} +% \\ +% \>[body] \TX\geq\TY +% \>[rel] = +% \>[rhs] \HsVar{compare}\TX\TY\not\equiv\HsCon{LT} +% \\ +% \>[body] \TX > \TY +% \>[rel] = +% \>[rhs] \HsVar{compare}\TX\TY\equiv\HsCon{GT} +% \\ +% \>[body] \HsVar{max}\TX\TY +% \>[cgrd] \vert\ \TX\leq\TY +% \>[rel] = +% \>[rhs] \TY +% \\ +% \>[cgrd] \vert\ \HsVar{otherwise} +% \>[rel] = +% \>[rhs] \TX +% \\ +% \>[body] \HsVar{min}\TX\TY +% \>[cgrd] \vert\ \TX\leq\TY +% \>[rel] = +% \>[rhs] \TX +% \\ +% \>[cgrd] \vert\ \HsVar{otherwise} +% \>[rel] = +% \>[rhs] \TY +% \end{pmboxed} +% \] +% \caption{Haskell code example} +% \label{tab:haskell} +% \end{figure} +% +% Of course, this could be useful for other programming languages +% as well. In fact, lhs2\TeX\ can be tweaked to process several +% experimental languages that are based on Haskell, but I can imagine +% that this package could generally prove useful to typeset program +% code. +% +% \section{Other applications} +% +% Although I have written this package for a specific purpose, I +% am very much interested to hear of other potential application +% areas. Please tell me if you found a use for this package and +% do not hesitate to ask for additional features that could convince +% you to use the package for something. +% +% \section{The \textsf{lazylist} package} +% +% Internally, this package makes use of Alan Jeffrey's excellent +% \textsf{lazylist} package, which provides an implementation of +% the lambda calculus using fully expandable control sequences. +% Unfortunately, |lazylist.sty| is not included in most common +% \TeX\ distributions, so you might need to fetch it from CTAN +% separately. +% +% \section{Reference} +% +% \subsection{Setup} +% +% New in v0.8: We allow to implicitly define columns by just +% using the names during table content specification, without +% having declared them formally using |\column| (see below). +% +% \DescribeMacro{\nodefaultcolumn} +% By default, though, this behaviour is turned off, because the +% use of a misspelled column is often an error. Thus, by default +% or after the command |\nodefaultcolumn| is used, all columns +% must be declared. +% +% \DescribeMacro{\defaultcolumn} +% Using a statement of the form +% |\defaultcolumn{|\meta{spec}|}|, implicit columns can +% be activated. All undefined columns that are encountered +% will be assumed to have format string \meta{spec}. +% +% \subsection{The environments} +% +% \DescribeEnv{pboxed} +% \DescribeEnv{ptboxed} +% \DescribeEnv{pmboxed} +% \DescribeEnv{ptabular} +% \DescribeEnv{parray} +% New in v0.8: There are now five environments that this package +% provides: in addition to the former |ptabular|, |parray|, and +% |pboxed|, there is now also |ptboxed| and |pmboxed|. +% The environment |pboxed| +% typesets the material in boxes of the calculated length, but in +% normal paragraph mode. The advantage is that +% there can be page breaks within the table. +% Note that you should start a new (probably nonindented) +% paragraph before beginning a |pboxed|. All lines that a |pboxed| +% produces are of equal length, so it should be possible to center +% or right-align the material. + +% Both |ptboxed| and |pbmoxed| are like |pboxed|, but +% pre-wrapped in a |tabular| or |array| environment, +% respectively, and +% thus not page-breakable but less fragile (or should I just +% say: easier to use) than the unwrapped |pboxed|. +% With those, there +% is no need for |ptabular| and |parray| anymore -- +% which were directly based on (and translated into) usual +% |tabular| and |array| environments as provided by the |array| +% package. The environments are still supported, to ensure +% compatibility, but they are mapped to |ptboxed| and |pmboxed|, +% respectively. +% +% The |pmboxed| and |parray| environments assume math mode, whereas +% |ptboxed| and |ptabular| assume text mode. The |pboxed| environment +% works in both text and math modes and adapts to whatever is +% currently active. +% +% I wrote in previous versions that one additional environment, namely +% |plongtable|, a poly-version of the |longtable| environment, was planned. +% Page-breaking of |pboxed| works fine, and I do not see a +% real need for a |plongtable| environment anymore. If you would like +% it anyway, feel free to mail me and inform me about the advantages +% it would have over |pboxed|. +% +% The interface is the same for all of the environments. +% +% \subsection{The interface} +% +% \begin{center} +% \textbf{(Note: this has changed significantly in v0.8!)} +% \end{center} +% +% In each of the environments, the following commands can be +% used. All other commands should be used with care if placed +% directly inside such an environment: the contents of a polytable +% are processed multiple times; hence, if your commands generate +% output, the output will end up multiple times in the final +% document, and destroy your layout. +% +% \DescribeMacro{\column} +% With |\column[|\meta{dimen}|]{|\meta{columnid}|}{|\meta{spec}|}|, +% a new column +% \meta{columnid} is specified. The name of the column can be +% any sequence of alphanumerical characters. The \meta{spec} is +% a format string for that particular column, and it can contain +% the same constructs that can be used in format strings of normal +% tables or arrays. +% However, it must only contain the description for \emph{one} +% column. +% +% As long as the save/restore feature (explained below) is not used, +% |\column| definitions are local to one table. +% One can define a column multiple times within one table: +% a warning will be produced, +% and the second format string will be used for the complete table. +% +% Columns must be defined before use when implicit columns using +% |\defaultcolumn| are disabled. +% +% A minimal horizontal position \meta{dimen} (relative to the +% beginning of the table) can be specified for a column, which +% defaults to 0pt. +% +% \DescribeMacro{\=} +% The command |\={|\meta{fromid}|}[|\meta{spec}|]| instructs the +% package to prepare for a new entry starting at column \meta{fromid}. +% Everything that follows the command, up to the next +% interface-command (except |\column|) or the end of the environment +% is interpreted as contents of the entry and can be arbitrary +% \LaTeX\ code that has balanced grouping. The column specifier +% \meta{spec} can be used to define a different formatting for this +% particular entry. If the specifier starts with an exclamation mark +% (|!|), it will be used as specifier for all entries of that column. +% The use of multiple exclamation-mark specifiers for the same +% column name gives precedence to the last one, but you should not +% rely on this behaviour as it may change in the future. +% +% Note that, contrary to normal \LaTeX\ behaviour, the second argument +% is the optional argument. Therefore, if an entry starts with an +% opening bracket |([)|, +% and the optional argument is omitted, a |\relax| should be inserted +% between command and opening bracket, as otherwise the entry would +% be treated as the optional argument. +% +% \DescribeMacro{\>} +% The command |\>[|\meta{fromid}|][|\meta{spec}|]| is a variant of +% |\=| where both arguments are optional. If no column name is given +% then the current column name, postfixed by a dot (|.|), is assumed +% as column name. At the beginning of a line, a single dot (|.|) +% will be assumed as a name. The \meta{spec} argument has the same +% behaviour as for |\=|. Note that if the specifier is given, the +% column name must be given as well, but may be left empty if the +% default choice is desired. For instance, |\>[][r]|, will move to +% the next column, which will be typeset right-aligned. +% +% \DescribeMacro{\<} +% The command |\<[|\meta{fromid}|]| ends the current entry at the +% boundary specified by \meta{fromid}. This macro can be used instead +% of |\>| or |\=| if an entry should be ended without immediately +% starting a new one. Differences in behaviour occur if \meta{fromid} +% is associated with a non-trivial column format string. +% TODO: Improve this explanation. +% +% \DescribeMacro{\fromto} +% The call |\fromto{|\meta{fromid}|}{|\meta{toid}|}{|\meta{text}|}| +% will typeset \meta{text} in the current line, starting at column +% \meta{fromid} and ending before column \meta{toid}, using the +% format string specified for \meta{fromid}. +% +% A line of a table usually consists of multiple |\fromto| statements. +% Each statement's starting column should be either the same as the +% end column of the previous statement, or it will be assumed that +% the start column is located somewhere to the right of the previous +% end column. The user is responsible to not introduce cycles in the +% (partial) order of columns. If such a cycle is specified, the +% current algorithm will loop, causing a |dimension too large| error +% ultimately. TODO: catch this error. +% +% \DescribeMacro{\\} +% \DescribeMacro{\nextline} +% The command |\\| (or, now deprecated, |\nextline|) ends one line +% and begins the next. +% There is no need to end the last line. One can pass an optional +% argument, as in |\\[|\meta{dimen}|]|, that will add +% \meta{dimen} extra space between the lines. +% +% \subsection{A warning} +% +% The contents of the table are processed multiple times because +% the widths of the entries are measured. Global assignments that +% modify registers and similar things can thus result in unexpected +% behaviour. +% New in v0.7: \LaTeX\ counters (i.e., counters defined by +% |\newcounter|) are protected now. They will be reset after +% each of the trial runs. +% +% \subsection{Saving column width information} +% +% Sometimes, one might want to reuse not only the same column, but +% exactly the same alignment as in a previous table. An example +% would be a fragment of program code, which has been broken into +% several pieces, with documentation paragraphs added in between. +% +% \DescribeMacro{\savecolumns} +% \DescribeMacro{\restorecolumns} +% With |\savecolumns[|\meta{setid}|]|, one can save the information +% of the current table for later reuse. The name |setid| can be an +% arbitrary sequence of alphanumeric characters. It does \emph{not} share +% the same namespace as the column names. The argument is optional; +% if it is omitted, a default name is assumed. Later, one can restore +% the information (multiple times, if needed) in other tables, by +% issuing a |\restorecolumns[|\meta{setid}|]|. +% +% This feature requires to pass information backwards in the general +% case, as column widths in later environments using one specific +% column set might influence the layout of earlier environments. +% Therefore, information is written into the |.aux| file, and +% sometimes, a warning is given that a rerun is needed. Multiple +% reruns might be required to get all the widths right. +% +% I have tried very hard to avoid producing rerun warnings infinitely +% except if there are really cyclic dependencies between columns. +% Still, if it happens or something seems to be broken, it often +% is a good idea to remove the |.aux| file and start over. Be sure +% to report it as a bug, though. +% +% Figure~\ref{tab:saverestore} is an example of the Haskell code +% example with several comments inserted. The source of this file +% shows how to typeset the example. +% \begin{figure} +% \setlength{\parindent}{0pt}% +% \setlength{\parskip}{1ex}% +% \hrule +% We introduce a new type class $\Ord$ for objects that admit +% an ordering. It is based on the $\Eq$ class: +% +% \( +% \begin{pboxed} +% \savecolumns +% \column{left}{>{\quad}l} +% \column{end}{l} +% \fromto{left}{end}{\CLASS\ (\Eq\TA)\Rightarrow\Ord\TA\WHERE} +% \end{pboxed} +% \) +% +% The next three lines give the type signatures for all +% the methods of the class. +% +% \( +% \begin{pboxed} +% \restorecolumns +% \column{body}{l} +% \column{rel}{c} +% \column{rhs}{l} +% \fromto{left}{body}{\qquad\ } +% \fromto{body}{rel}{\HsVar{compare}} +% \fromto{rel}{rhs}{::} +% \fromto{rhs}{end}{\TA\rightarrow\TA\rightarrow\HsCon{Ordering}} +% \\ +% \fromto{left}{body}{\qquad\ } +% \fromto{body}{rel}{(<),(\leq),(\geq),(>)} +% \fromto{rel}{rhs}{::} +% \fromto{rhs}{end}{\TA\rightarrow\TA\rightarrow\HsCon{Bool}} +% \\ +% \fromto{left}{body}{\qquad\ } +% \fromto{body}{rel}{\HsVar{max},\HsVar{min}} +% \fromto{rel}{rhs}{::} +% \fromto{rhs}{end}{\TA\rightarrow\TA\rightarrow\HsCon{Bool}} +% \\[1ex] +% \fromto{body}{end}{\mbox{--- Minimal complete definition: +% $(\leq)$ or $\HsVar{compare}$}} +% \\ +% \fromto{body}{end}{\mbox{--- using $\HsVar{compare}$ can be more efficient +% for complex types}} +% \end{pboxed} +% \) +% +% As the comment above says, it is sufficient to define either +% $(\leq)$ or $\HsVar{compare}$ to get a complete instance. All +% of the class methods have default definitions. First, we can +% define $\HsVar{compare}$ in terms of $(\leq)$. The result type +% of $\HsVar{compare}$ is an $\HsCon{Ordering}$, a type consisting +% of only three values: $\HsCon{EQ}$ for ``equality'', +% $\HsCon{LT}$ for ``less than'', and $\HsCon{GT}$ for ``greater +% than''. +% +% \( +% \begin{pboxed} +% \restorecolumns +% \column{cgrd}{l} +% \fromto{body}{cgrd}{\HsVar{compare}\TX\TY} +% \fromto{cgrd}{rel}{\vert\ \TX\equiv\TY} +% \fromto{rel}{rhs}{=} +% \fromto{rhs}{end}{\HsCon{EQ}} +% \\ +% \fromto{cgrd}{rel}{\vert\ \TX\leq\TY} +% \fromto{rel}{rhs}{=} +% \fromto{rhs}{end}{\HsCon{LT}} +% \\ +% \fromto{cgrd}{rel}{\vert\ \HsVar{otherwise}} +% \fromto{rel}{rhs}{=} +% \fromto{rhs}{end}{\HsCon{GT}} +% \end{pboxed} +% \) +% +% All the other comparison operators can be defined +% in terms of $\HsCon{compare}$: +% +% \( +% \begin{pboxed} +% \restorecolumns +% \fromto{body}{rel}{\TX\leq\TY} +% \fromto{rel}{rhs}{=} +% \fromto{rhs}{end}{\HsVar{compare}\TX\TY\not\equiv\HsCon{GT}} +% \\ +% \fromto{body}{rel}{\TX < \TY} +% \fromto{rel}{rhs}{=} +% \fromto{rhs}{end}{\HsVar{compare}\TX\TY\equiv\HsCon{LT}} +% \\ +% \fromto{body}{rel}{\TX\geq\TY} +% \fromto{rel}{rhs}{=} +% \fromto{rhs}{end}{\HsVar{compare}\TX\TY\not\equiv\HsCon{LT}} +% \\ +% \fromto{body}{rel}{\TX > \TY} +% \fromto{rel}{rhs}{=} +% \fromto{rhs}{end}{\HsVar{compare}\TX\TY\equiv\HsCon{GT}} +% \end{pboxed} +% \) +% +% Finally, there are default definitions for +% $\HsVar{max}$ and $\HsVar{min}$ in terms of $(\leq)$. +% +% \( +% \begin{pboxed} +% \restorecolumns +% \fromto{body}{cgrd}{\HsVar{max}\TX\TY} +% \fromto{cgrd}{rel}{\vert\ \TX\leq\TY} +% \fromto{rel}{rhs}{=} +% \fromto{rhs}{end}{\TY} +% \\ +% \fromto{cgrd}{rel}{\vert\ \HsVar{otherwise}} +% \fromto{rel}{rhs}{=} +% \fromto{rhs}{end}{\TX} +% \\ +% \fromto{body}{cgrd}{\HsVar{min}\TX\TY} +% \fromto{cgrd}{rel}{\vert\ \TX\leq\TY} +% \fromto{rel}{rhs}{=} +% \fromto{rhs}{end}{\TX} +% \\ +% \fromto{cgrd}{rel}{\vert\ \HsVar{otherwise}} +% \fromto{rel}{rhs}{=} +% \fromto{rhs}{end}{\TY} +% \end{pboxed} +% \) +% \hrule +% \caption{Commented Haskell code example} +% \label{tab:saverestore} +% \end{figure} +% +% \section{The Code} +% \begin{macrocode} +%<*package> +\NeedsTeXFormat{LaTeX2e} +\ProvidesPackage{polytable}% + [2013/07/18 v0.8.5 `polytable' package (Andres Loeh)] +% \end{macrocode} +% New in v0.7.2: +% The \textsf{amsmath} package clashes with \textsf{lazylist}: +% both define the command |\And|. Although it would certainly +% be better to find another name in \textsf{lazylist}, we +% take precautions for now. (Note that this will still fail +% if \textsf{lazylist} is already loaded -- but then it's not +% our problem \dots +% \begin{macrocode} +\let\PT@original@And\And +\let\PT@original@Not\Not +\RequirePackage{lazylist} +\let\PT@And\And +\let\PT@Not\Not +\def\PT@prelazylist + {\let\And\PT@And + \let\Not\PT@Not} +\def\PT@postlazylist + {\let\And\PT@original@And + \let\Not\PT@original@Not} +\PT@postlazylist +\RequirePackage{array} +% \end{macrocode} +% +% The option debug will cause (a considerable amount of) +% debugging output to be printed. The option info is a +% compromise, printing some status information for each table, +% but no real debugging information. The option silent, on +% the other hand, will prevent certain warnings from being +% printed. +% \begin{macrocode} +\DeclareOption{debug} {\AtEndOfPackage\PT@debug} +\DeclareOption{info} {\AtEndOfPackage\PT@info} +\DeclareOption{silent}{\AtEndOfPackage\PT@silent} +% \end{macrocode} +% +% First, we declare a couple of registers that we will need later. +% \begin{macrocode} +\newdimen\PT@colwidth +\newcount\PT@cols +\newcount\PT@table +\newtoks\PT@toks +\newif\ifPT@changed +\newread\PT@in +\newwrite\PT@out +% \end{macrocode} +% In |\PT@allcols|, we will store the list of all columns, as a +% list as provided by the \textsf{lazylist} package. We initialise +% it to the empty list, which is represented by |\Nil|. In v0.9, +% we will have a second list that only contains the public columns. +% \begin{macrocode} +\def\PT@allcols{\Nil} +%\def\PT@allpubliccols{\Nil} +\let\PT@infromto\empty +% \end{macrocode} +% These are flags and truth values. TODO: Reduce and simplify. +% \begin{macrocode} +\let\PT@currentwidths\empty +\def\PT@false{0} +\def\PT@true{1} +\let\PT@inrestore\PT@false +% \end{macrocode} +% +% \begin{macro}{\defaultcolumn} +% \begin{macro}{\nodefaultcolumn} +% \begin{macro}{\PT@defaultcolumnspec} +% The macro |\PT@defaultcolumnspec| contains, if defined, the +% current default specifier that is assumed for undefined columns. +% The other two commands can be used to set the specifier. +% \begin{macrocode} +\newcommand{\defaultcolumn}[1]{\gdef\PT@defaultcolumnspec{#1}} +\newcommand{\nodefaultcolumn}{\global\let\PT@defaultcolumnspec\undefined} +\DeclareOption{defaultcolumns}{\defaultcolumn{l}} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\memorytables} +% \begin{macro}{\disktables} +% \begin{macro}{\PT@add} +% \begin{macro}{\PT@split} +% \begin{macro}{\PT@prearewrite} +% \begin{macro}{\PT@preareread} +% \begin{macro}{\PT@finalize} +% These macros steer where the end-column queue is stored, which +% can be either in memory or on disk. The default is on disk, +% because that's more reliable for large tables. There is a package +% option |memory| to make |\memorytables| the default. +% \begin{macrocode} +\newcommand{\memorytables}{% + \let\PT@preparewrite\@gobble + \let\PT@add \PT@addmem + \let\PT@prepareread \PT@preparereadmem + \let\PT@split \PT@splitmem + \let\PT@finalize \relax +} +\newcommand{\disktables}{% + \let\PT@preparewrite\PT@preparewritefile + \let\PT@add \PT@addfile + \let\PT@prepareread \PT@preparereadfile + \let\PT@split \PT@splitfile + \let\PT@finalize \PT@finalizefile +} +\DeclareOption{memory}{\AtEndOfPackage\memorytables} +\ProcessOptions +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\PT@debug} +% \begin{macro}{\PT@info} +% \begin{macro}{\PT@debug@} +% \begin{macro}{\PT@typeout@} +% \begin{macro}{\PT@silent} +% \begin{macro}{\PT@warning} +% Similar to the \textsf{tabularx} package, we add macros to +% print debugging information to the log. Depending on package +% options, we can set or unset them. +% \begin{macrocode} +\newcommand*{\PT@debug} + {\def\PT@debug@ ##1{\typeout{(polytable) ##1}} + \PT@info} +\newcommand*{\PT@info} + {\def\PT@typeout@ ##1{\typeout{(polytable) ##1}}} +\let\PT@debug@\@gobble +\let\PT@typeout@\@gobble +\def\PT@warning{\PackageWarning{polytable}}% +\def\PT@silent + {\let\PT@typeout@\@gobble\let\PT@warning\@gobble} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\PT@aligndim} +% \begin{macro}{\PT@aligncol} +% The first is (almost) stolen from the \textsf{tabularx}-package, to nicely +% align dimensions in the log file. TODO: fix some issues. +% The other command is for column names. +% \begin{macrocode} +\def\PT@aligndim#1#2#3\@@{% + \ifnum#1=0 + \if #2p% + \PT@aligndim@0.0pt\space\space\space\space\space\@@ + \else + \PT@aligndim@#1#2#3\space\space\space\space\space\space\space\space\@@ + \fi + \else + \PT@aligndim@#1#2#3\space\space\space\space\space\space\space\space\@@ + \fi} + +\def\PT@aligndim@#1.#2#3#4#5#6#7#8#9\@@{% + \ifnum#1<10 \space\fi + \ifnum#1<100 \space\fi + \ifnum#1<\@m\space\fi + \ifnum#1<\@M\space\fi + #1.#2#3#4#5#6#7#8\space\space} + +\def\PT@aligncol#1{% + \PT@aligncol@#1\space\space\space\space\space\space\space\space\@@} + +\def\PT@aligncol@#1#2#3#4#5#6#7#8#9\@@{% + #1#2#3#4#5#6#7#8\space\space} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\PT@rerun} +% This macro can be called at a position where we know that +% we have to rerun \LaTeX\ to get the column widths right. It +% issues a warning at the end of the document. +% \begin{macrocode} +\def\PT@rerun + {\PT@typeout@{We have to rerun LaTeX ...}% + \AtEndDocument + {\PackageWarning{polytable}% + {Column widths have changed. Rerun LaTeX.\@gobbletwo}}% + \global\let\PT@rerun\relax} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\PT@currentcol} +% \begin{macro}{\PT@currentcolumn} +% Both macros are used during typesetting to store the current +% column. The differences are subtle. TODO: remove +% one of the two, if possible. The |\PT@currentcol| variant +% contains the internal name, whereas the |\PT@currentcolumn| +% variant contains the external name. +% \end{macro} +% \end{macro} +% +% \subsection{Macro definition tools} +% +% \begin{macro}{\PT@listopmacro} +% \begin{macro}{\PT@consmacro} +% \begin{macro}{\PT@appendmacro} +% This assumes that |#2| is a list macro and |#3| is a new list element. +% The macro |#2| should, after the call, expand to the list with the +% new element |#1|ed. Because we don't know the number of tokens in |#3|, +% we use a temporary macro |\PT@temp| (which is used frequently throughout +% the package). +% \begin{macrocode} +\def\PT@listopmacro #1#2#3% #1 #3 to the list #2 + {\def\PT@temp{#1{#3}}% + \expandafter\expandafter\expandafter + \def\expandafter\expandafter\expandafter + #2\expandafter\expandafter\expandafter + {\expandafter\PT@temp\expandafter{#2}}} + +\def\PT@consmacro{\PT@listopmacro\Cons} +\def\PT@appendmacro{\PT@listopmacro\Cat} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% The follwing macro can be used to add something to +% the end of a control structure. +% \begin{macrocode} +\def\PT@gaddendmacro #1#2% add #2 to the end of #1 + {\PT@expanded{\gdef #1}{#1#2}} +% \end{macrocode} +% \begin{macro}{\PT@expanded} +% This macro expands its second argument once before passing +% it to the first argument. It is like |\expandafter|, but +% works on grouped arguments instead of tokens. +% \begin{macrocode} +\def\PT@expanded #1#2% + {\expandafter\Twiddle\expandafter\Identity\expandafter{#2}{#1}} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\PT@enamedef} +% This is much like |\@namedef|, but it expands |#2| once. +% \begin{macrocode} +\def\PT@enamedef #1% sets name #1 to the expansion of #2 + {\PT@expanded{\@namedef{#1}}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\PT@addoptargtomacro} +% \begin{macro}{\PT@addargtomacro} +% \begin{macrocode} +\def\PT@addoptargtomacro + {\PT@add@argtomacro\PT@makeoptarg} +\def\PT@addargtomacro + {\PT@add@argtomacro\PT@makearg} + +\def\PT@add@argtomacro#1#2#3% + {\PT@expanded{\PT@expanded{\gdef\PT@temp}}{\csname #3\endcsname}% + #1% + \PT@expanded{\PT@gaddendmacro{#2}}{\PT@temp}} + +\def\PT@makeoptarg% + {\PT@expanded{\def\PT@temp}{\expandafter[\PT@temp]}} +\def\PT@makearg% + {\PT@expanded{\def\PT@temp}{\expandafter{\PT@temp}}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\PT@gobbleoptional} +% Gobbles one optional argument. Ignores spaces. +% \begin{macrocode} +\newcommand*{\PT@gobbleoptional}[1][]{\ignorespaces} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\PT@addmem} +% \begin{macro}{\PT@splitmem} +% \begin{macro}{\PT@addfile} +% \begin{macro}{\PT@splitfile} +% \begin{macro}{\PT@preparereadmem} +% \begin{macro}{\PT@preparereadfile} +% \begin{macro}{\PT@preparewrite} +% \begin{macro}{\PT@finalizefile} +% \begin{macro}{\PT@queuefilename} +% The following macros handle a simple queue of names. +% With |\PT@addmem|, a name is added to the end of the queue. Using +% |\PT@splitmem|, the first element of the queue is bound to another +% command. As a replacement, we also define |\PT@addfile| and +% |\PT@splitfile|, that implement the queue in a file. +% \begin{macrocode} +\def\PT@addmem#1#2{\PT@gaddendmacro #2{\PT@elt{#1}}} +\def\PT@splitmem#1#2{#1\PT@nil{#2}{#1}} + +\def\PT@elt#1#2\PT@nil#3#4{\gdef #3{#1}\gdef #4{#2}} + +\def\PT@queuefilename{\jobname.ptb} + +% the \empty at the end consumes the newline space +\def\PT@addfile#1#2{% + \immediate\write #2{\string\def\string\PTtemp{#1}\string\empty}} + +\def\PT@splitfile#1#2{% + \ifeof #1% + \let #2=\empty + \else + \read #1 to#2% + %\show #2% + #2% hack, because it essentially ignores #2 + \PT@expanded{\def #2}{\PTtemp}% + %\show #2% + \fi} + +%\def\strip#1{\def #1{\expandafter\@strip #1\@dummy}} +%\def\@strip#1\@dummy{#1} + +\def\PT@preparereadmem#1#2{% + \global\let #1=#2} + +\def\PT@preparewritefile#1{% + \immediate\openout\PT@out\PT@queuefilename\relax + \let #1\PT@out} + +\def\PT@preparereadfile#1#2{% + \immediate\closeout\PT@out + \openin\PT@in\PT@queuefilename\relax + \let #1\PT@in} + +\def\PT@finalizefile{% + \closein\PT@in} + +\disktables +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{The environment} +% +% The general idea is to first scan the contents of the environment +% and store them in a token register. In a few test runs, the positions +% of the column borders are determined. After that, the table is +% typeset by producing boxes of appropriate size. +% +% \begin{macro}{\beginpolytable} +% This macro starts the environment. It should, however, not +% be called directly, but rather in a \LaTeX\ environment. +% We initialize the +% token register to the empty string and then start scanning. +% \begin{macrocode} +\newcommand*{\beginpolytable}% +% \end{macrocode} +% We save the current enclosing \LaTeX\ environment in +% |\PT@environment|. This will be the |\end| we will be +% looking for, and this will be the environment we manually +% close in the end. +% \begin{macrocode} + {\edef\PT@environment{\@currenvir}% + \begingroup + % new in v0.7: save counters + \PT@savecounters + \PT@toks{}% initialise token register + \PT@scantoend} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\endpolytable} +% This is just defined for convenience. +% \begin{macrocode} +\let\endpolytable=\relax +% \end{macrocode} +% \end{macro} +% \begin{macro}{\PT@scantoend} +% Whenenver an |\end| is encountered, we check if it really +% ends the current environment. We store the tokens we have +% read. Once we have found the end of the environment, we +% initialize the column queue and column reference, +% |\PT@columnqueue| and |\PT@columnreference|. The new interface +% commands build the queue during the first test run, containing +% the end columns of specific entries of the table. Later, the +% queue is copied to be the reference, and in the typesetting run, +% the information is used to compute the correct box widths. +% We start with an empty queue, and set the reference to |\undefined|, +% because it is not yet needed. TODO: queue and reference must be +% global variables at the moment; try to change that. +% \begin{macrocode} +\newcommand{\PT@scantoend}% LaTeX check +\long\def\PT@scantoend #1\end #2% + {\PT@toks\expandafter{\the\PT@toks #1}% + \def\PT@temp{#2}% + \ifx\PT@temp\PT@environment + \global\let\PT@columnqueue \empty + \global\let\PT@columnreference \undefined + \PT@preparewrite\PT@columnqueue + \expandafter\PT@getwidths + \else + \PT@toks\expandafter{\the\PT@toks\end{#2}}% + \expandafter\PT@scantoend + \fi} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\PT@getwidths} +% Here, we make as many test runs as are necessary to +% determine the correct column widths. +% \begin{macrocode} +\def\PT@getwidths +% \end{macrocode} +% We let the |\column| command initialize a column +% in the first run. +% \begin{macrocode} + {\let\column \PT@firstrun@column +% \end{macrocode} +% There is the possibility to save or restore columns. +% This is new in v0.4. +% \begin{macrocode} + \let\savecolumns \PT@savewidths + \let\restorecolumns \PT@restorewidths +% \end{macrocode} +% We \emph{always} define a pseudo-column |@begin@|. +% This denotes the begin of a row. We also define a +% pseudo-column |@end@| denoting the end of a row (as +% of v0.8; and I'm not sure if |@begin@| is still +% needed). +% \begin{macrocode} + \column{@begin@}{@{}l@{}}% + \column{@end@}{}% + \PT@cols=0\relax% +% \end{macrocode} +% The two other commands that are allowed inside of the +% environment, namely |\fromto| and |\\| are +% initialized. The |\fromto| command may increase the +% current widths of some columns, if necessary, whereas +% |\\| just resets the counter that keeps track +% of the ``current'' column, to |0|. The command +% |\nextline| is an old name for |\\|. +% \begin{macrocode} + \let\fromto \PT@fromto + \let\PT@processentry \PT@checkwidth + \let\PT@scanbegin \PT@scanbeginfree + \let\\= \PT@resetcolumn + \let\nextline \PT@resetcolumn + \let\>= \PT@fromopt + \let\== \PT@from + \let\<= \PT@toopt + \global\PT@changedfalse % nothing has changed so far + \PT@resetcolumn % we are at the beginning of a line +% \end{macrocode} +% Now we are ready for a test run. +% \begin{macrocode} + \the\PT@toks + \@ifundefined{PT@scanning}% + {}{\PT@resetcolumn\relax}% +% \end{macrocode} +% After the first run, we print extra information. +% We use the contents of the macro |\column| to check +% whether we are in the first run, because it will be +% reset below for all other runs to do nothing. +% \begin{macrocode} + \ifx\column\PT@otherrun@column + \else + % we are in first run, print extra info + \PT@prelazylist + \PT@typeout@{\PT@environment: \the\PT@cols\space columns, % + \PT@Print\PT@allcols}% + \PT@postlazylist + \fi +% \end{macrocode} +% The columns are initialised after the first run. +% Therefore, we make sure that the |\column| command +% won't do much in the other runs. Also, saving and +% restoring columns is no longer needed. +% \begin{macrocode} + \let\PT@firstrun@column \PT@otherrun@column + \let\savecolumns \PT@gobbleoptional + \let\restorecolumns \PT@gobbleoptional + \let\PT@savewidths \PT@gobbleoptional + \let\PT@restorewidths \PT@gobbleoptional +% \end{macrocode} +% New in v0.7.1: restore counters after each trial run. +% \begin{macrocode} + \PT@restorecounters +% \end{macrocode} +% If some column widths have indeed changed in the +% test run, this will be indicated by the flag +% |\ifPT@changed|. Depending on this flag, we will +% either loop and rerun, or we will continue in +% |\PT@sortcols|. +% \begin{macrocode} + \ifPT@changed + % we need to rerun if something has changed + \PT@typeout@{There were changes; another trial run needed.}% + \expandafter\PT@getwidths + \else + % we are done and can do the sorting + \PT@typeout@{There were no changes; reached fixpoint.}% + \expandafter\PT@sortcols + \fi} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\PT@savecounters} +% Save all \LaTeX\ counters so that they can be restored after a +% trial run. +% \begin{macrocode} +\def\PT@savecounters + {\begingroup + \def\@elt ##1% + {\global\csname c@##1\endcsname\the\csname c@##1\endcsname}% + \xdef\PT@restorecounters{\cl@@ckpt}% + \endgroup} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\PT@sortcols} +% The column borders are sorted by their horizontal +% position on the page (width). The they get numbered +% consecutively. After that, we are well prepared to +% typeset the table. +% \begin{macrocode} +\def\PT@sortcols +% \end{macrocode} +% First, we sort the list. To make sure that the +% computation is only executed once, we save the +% sorted list by means of an |\edef|. Sorting happens +% with \textsf{lazylist}'s |\Insertsort| which expects +% an order and a list. As order, we provide |\PT@ltwidth|, +% which compares the widths of the columns. +% To prevent expansion of the list structure, given by +% |\Cons| and |\Nil|, we fold the list with the +% |\noexpand|ed versions of the list constructors. +% \begin{macrocode} + {\PT@prelazylist + \edef\PT@sortedlist + {\Foldr{\noexpand\Cons}{\noexpand\Nil}% + {\Insertsort\PT@ltmax\PT@allcols}}% + \PT@typeout@{Sorted columns:}% + \PT@PrintWidth\PT@sortedlist + \PT@postlazylist +% \end{macrocode} +% Now, each column is assigned a number, starting from +% zero. +% \begin{macrocode} + \PT@cols=0\relax% + \PT@prelazylist + \PT@Execute{\Map\PT@numbercol\PT@sortedlist}% + \PT@postlazylist + \edef\PT@lastcol@{\PT@StripColumn\PT@lastcol}% + \PT@typeout@{Numbered successfully, % + last column is \PT@lastcol@}% +% \end{macrocode} +% Now is a good time to save table information, if needed later. +% We will also compare our computed information with the restored +% maximum widths. +% \begin{macrocode} + \ifx\PT@currentwidths\empty + \else + \PT@typeout@{Saving table information for \PT@currentwidths .}% + \PT@expanded\PT@saveinformation\PT@currentwidths + \fi +% \end{macrocode} +% Finally, we can typeset the table. +% \begin{macrocode} + \PT@typeset} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\PT@typeset} +% We redefine |\fromto| and |\\| to their +% final meaning in the typesetting process. The +% |\fromto| statements will be replaced by appropriate +% calls to |\multicolumn|, whereas the |\\| will +% again reset the counter for the current column, but +% also call the table environment's newline macro. +% Again, |\nextline| is allowed as an old name for |\\|. +% \begin{macrocode} +\def\PT@typeset + {\PT@typeout@{Typesetting the table ...}% + \let\PT@processentry \PT@placeinbox + \let\PT@scanbegin \PT@scanbeginwidth + \let\\= \PT@resetandcr + \let\nextline \PT@resetandcr + \PT@prepareread\PT@columnreference\PT@columnqueue +% \end{macrocode} +% The environment that will be opened soon, can, if +% if happens to be |tabular| or |array|, redefines |\\| +% once more, and will redefine it to |\@arraycr|. To +% prevent this, we also set |\@arraycr| to our command. +% \begin{macrocode} + \let\@arraycr \PT@resetandcr +% \end{macrocode} +% The array environments keep each line in a group; therefore +% |\PT@resetcolumn|, when executed during the linebreak, will +% not affect the current column counters. By having +% |\PT@resetcolumn| before entering the environment, we ensure +% that the group reset will have the correct effect anyway. +% \begin{macrocode} + \PT@resetcolumn % we are at the beginning of a line +% \end{macrocode} +% Now we start the tabular environment with the +% computed preamble. We redefine the |\\| to whatever +% the environment dictates. +% \begin{macrocode} + \PT@begin% +% \end{macrocode} +% Run, and this time, typeset, the contents. +% \begin{macrocode} + \the\PT@toks + \PT@fill% new in 0.7.3: balance the last line +% \end{macrocode} +% End the array, close the group, close the environment. +% We are done! +% \begin{macrocode} + \PT@finalize% finalize the queue (possibly close file) + \PT@end + \endgroup + \PT@typeout@{Finished.}% + \expandafter\end\expandafter{\PT@environment}}% +% \end{macrocode} +% \end{macro} +% +% \subsection{New interface} +% +% From v0.8 on, we offer a more convenient user interface +% for the programming of the columns. +% +% \begin{macro}{\PT@from} +% \begin{macro}{\PT@fromopt} +% \begin{macro}{\PT@toopt} +% The macro |\PT@from| is bound to |\=| in a polytable environment, +% and used to move to the named column specified by its argument. The +% previous column is closed. The variant |\PT@fromopt| is bound to +% |\>| and takes an optional argument instead of a mandatory, which defaults +% to the current column name followed by a single dot |.|. We use an +% empty default which is then redefined to make it easier for the +% user to use the default definition (TODO: explain better). +% Otherwise, it is like |\PT@from|. +% +% The macro |\PT@toopt| is bound to |\<|. Where |\PT@from| ends an +% entry if one is active, and starts a new one, the |\PT@toopt| +% variant only ends the currently active entry. +% \begin{macrocode} +\newcommand{\PT@from}[1]% + {\PT@checkendentry{#1}\PT@dofrom{#1}} + +\newcommand{\PT@fromopt}[1][]% + {\def\PT@temp{#1}% + \ifx\PT@temp\empty + % set default column name + \def\PT@temp{\PT@currentcolumn .}% + \fi + \PT@expanded\PT@from\PT@temp} + +\newcommand{\PT@toopt}[1][]% + {\def\PT@temp{#1}% + \ifx\PT@temp\empty + % set default column name + \def\PT@temp{\PT@currentcolumn .}% + \fi + \PT@expanded\PT@checkendentry\PT@temp + \let\PT@scanning\undefined} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\PT@dofrom} +% \begin{macrocode} +\newcommand*{\PT@dofrom}[1]% + {\edef\PT@currentcolumn{#1}% + \let\PT@scanning\PT@currentcolumn + \let\PT@currentpreamble\relax% necessary for preparescan + \@ifnextchar[%] + {\PT@expanded\PT@dospecfrom\PT@currentcolumn}% + {\PT@expanded\PT@dodofrom \PT@currentcolumn}} + +\newcommand*{\PT@dospecfrom}{}% LaTeX check +\def\PT@dospecfrom #1[#2]% + {\PT@checkglobalfrom #2\PT@nil{#1}% + \PT@dodofrom{#1}} + +\newcommand*{\PT@checkglobalfrom}{}% LaTeX check +\def\PT@checkglobalfrom + {\@ifnextchar!\PT@getglobalfrom\PT@ignorefrom} + +\newcommand*{\PT@getglobalfrom}{}% LaTeX check +\def\PT@getglobalfrom!#1\PT@nil#2% + {\column{#2}{#1}} + +\newcommand*{\PT@ignorefrom}{}% LaTeX check +\def\PT@ignorefrom #1\PT@nil#2% + {\def\PT@currentpreamble{#1}} + +\newcommand*{\PT@dodofrom}[1]% + {\@ifundefined{PT@columnreference}% + {% trial run + \ifx\column\PT@otherruncolumn + \else + % first run + \let\PT@storeendcolumn\PT@add + \fi + \def\PT@temp{@end@}}% + {% final run + \PT@split\PT@columnreference\PT@temp + %\PT@typeout@{splitted: \PT@temp} + }% + \PT@expanded{\PT@expanded\PT@preparescan\PT@currentcolumn}\PT@temp + \PT@scanbegin} + +\let\PT@storeendcolumn\@gobbletwo +% \end{macrocode} +% Here, |\PT@scanbegin| will scan free or using the width, depending +% on the run we are in. +% \end{macro} +% +% \begin{macro}{\PT@fromto} +% This is the implementation for the old explicit |\fromto| +% macro. It takes the start and end columns, and the contents. +% It can be used for all runs. +% \begin{macrocode} +\newcommand*{\PT@fromto}[3]% +% \end{macrocode} +% We allow a |\fromto| to follow a new-style command, but we reset +% the current column to undefined, so no text may immediately +% follow a |\fromto| command. +% \begin{macrocode} + {\PT@checkendentry{#1}% + \let\PT@scanning\undefined +% \end{macrocode} +% We check a switch to prevent nested |\fromto|s. +% \begin{macrocode} + \PT@infromto + \def\PT@infromto{% + \PackageError{polytable}{Nested fromto}{}}% +% \end{macrocode} +% Here, the real work is done: +% \begin{macrocode} + \let\PT@currentpreamble\relax% necessary for preparescan + \PT@preparescan{#1}{#2}% + \PT@scanbegin #3\PT@scanend% defines \@curfield + \PT@processentry{#1}{#2}% +% \end{macrocode} +% The commands |\PT@scanbegin| and |\PT@processentry| will perform +% different tasks depending on which run we are in. +% +% We ignore spaces after the |\fromto| command. +% \begin{macrocode} + \let\PT@infromto\empty + \ignorespaces} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\PT@checkendentry} +% This macro checks if we are currently scanning an entry. If so +% (this is detected by checking if |\PT@scanning| is defined), +% we close the entry and handle it (in |\PT@endentry|) +% before returning. The argument +% is the name of the column from which this macro is called. +% \begin{macrocode} +\newcommand*{\PT@checkendentry}% takes one argument + {\@ifundefined{PT@scanning}% + {\let\PT@temp\@gobble}% + {\let\PT@temp\PT@endentry}% + \PT@temp} +%\newcommand*{\PT@checkendentry}% takes one argument +% {\@ifundefined{PT@post@preamble}% +% {\let\PT@temp\PT@discardentry}% +% {\let\PT@temp\PT@endentry}% +% \PT@temp} + +%\newcommand*{\PT@discardentry}[1]% +% {\let\PT@postpreamble=\empty\PT@scanend} + +\newcommand*{\PT@endentry}[1]% + {\PT@scanend + \edef\PT@temp{#1}% + \PT@expanded\PT@storeendcolumn\PT@temp\PT@columnqueue + \let\PT@storeendcolumn\@gobbletwo + \PT@expanded{\PT@expanded\PT@processentry\PT@currentcolumn}\PT@temp} +% \end{macrocode} +% \end{macro} +% +% \subsection{The trial runs} +% +% For each column, we store information in macros that are +% based on the column name. We store a column's type (i.e., its +% contribution to the table's preamble), its current width +% (i.e., its the horizontal position where the column will start +% on the page), and later, its number, which will be used for +% the |\multicolumn| calculations. +% +% \begin{macro}{\PT@firstrun@column} +% During the first trial run, we initialise all the columns. We +% store their type, as declared in the |\column| command inside +% the environment, and we set their initial width to 0pt. +% Furthermore, we add the column to the list of all available +% columns, increase the column counter, and tell \TeX\ to ignore +% spaces that might follow the |\column| command. +% New in v0.4.1: We make a case distinction on an empty type +% field to prevent warnings for columns that have been defined +% via |\PT@setmaxwidth| -- see there for additional comments. +% New in v0.4.2: We allow redefinition of width if explicitly +% specified, i.e., not equal to 0pt. +% \begin{macrocode} +\newcommand\PT@firstrun@column[3][0pt]% + {\@ifundefined{PT@col@#2.type}% + {\PT@typeout@{Defining column \PT@aligncol{#2} at #1.}% + \@namedef{PT@col@#2.type}{#3}% + \@namedef{PT@col@#2.width}{#1}% initialize the width of the column + % add the new column to the (sortable) list of all columns + \PT@consmacro\PT@allcols{PT@col@#2}% + \advance\PT@cols by 1\relax}% + {\expandafter\ifx\csname PT@col@#2.type\endcsname\empty + \relax % will be defined in a later table of the same set + \else + \begingroup + \def\PT@temp{PT@col@#2}% + \ifx\PT@temp\PT@endcol + \relax % end column is always redefined + \else + \PT@warning{Redefining column #2}% + \fi + \endgroup + \fi + \@namedef{PT@col@#2.type}{#3}% + \expandafter\ifdim#1>0pt\relax + \PT@typeout@{Redefining column #2 at #1.}% + \@namedef{PT@col@#2.width}{#1}% + \fi + }% +% \end{macrocode} +% For the case that we are saving and there is not yet information +% from the |.aux| file, we define the |.max| and |.trusted| fields +% if they are undefined. If information becomes available later, it +% will overwrite these definitions. +% \begin{macrocode} + \@ifundefined{PT@col@#2.max}% + {\@namedef{PT@col@#2.max}{#1}% + \expandafter\let\csname PT@col@#2.trusted\endcsname\PT@true}{}% + \ignorespaces} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\PT@otherrun@column} +% In all but the first trial run, we do not need any additional +% information about the columns any more, so we just gobble the +% two arguments, but still ignore spaces. +% \begin{macrocode} +\newcommand\PT@otherrun@column[3][]% + {\ignorespaces} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\PT@checkcoldefined} +% This macro verifies that a certain column is defined and +% produces an error message if it is not. New in v0.8: this +% macro implicitly defines the column if we have a default +% column specifier. +% \begin{macrocode} +\def\PT@checkcoldefined #1% + {\@ifundefined{PT@col@#1.type}% + {\@ifundefined{PT@defaultcolumnspec}% + {\PackageError{polytable}{Undefined column #1}{}} + {\PT@debug@{Implicitly defining column #1}% + \PT@expanded{\column{#1}}{\PT@defaultcolumnspec}}}{}% +% \end{macrocode} +% We also have to define columns with empty specifiers. This +% situation can occur if save/restoring columns that are defined +% by default specifiers. +% \begin{macrocode} + \expandafter\ifx\csname PT@col@#1.type\endcsname\empty\relax + \@ifundefined{PT@defaultcolumnspec}{}% + {\PT@debug@{Implicitly defining column #1}% + \PT@expanded{\column{#1}}{\PT@defaultcolumnspec}}% + \fi} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\PT@checkwidth} +% Most of the work during the trial runs is done here. We increase +% the widths of certain columns, if necessary. Note that there +% are two conditions that have to hold if |\fromto{A}{B}| is encountered: +% \begin{itemize} +% \item the width of |A| has to be at least the width of the current +% (i.e., previous) column. +% \item the width of |B| has to be at least the width of |A|, plus the +% width of the entry. +% \end{itemize} +% \begin{macrocode} +\def\PT@checkwidth #1#2% + {\PT@checkcoldefined{#2}% first column should have been checked before +% \end{macrocode} +% Here, we check the first condition. +% \begin{macrocode} + \def\PT@temp{PT@col@#1}% + \ifx\PT@currentcol\PT@temp + \PT@debug@{No need to skip columns.}% + \else + \PT@colwidth=\expandafter\@nameuse\expandafter + {\PT@currentcol.width}\relax + \ifdim\PT@colwidth>\csname PT@col@#1.width\endcsname\relax + % we need to change the width + \PT@debug@{s \PT@aligncol{#1}: % + old=\expandafter\expandafter\expandafter + \PT@aligndim\csname PT@col@#1.width\endcsname\@@% + new=\expandafter\PT@aligndim\the\PT@colwidth\@@}% + \PT@changedtrue + \PT@enamedef{PT@col@#1.width}{\the\PT@colwidth}% + \fi +% \end{macrocode} +% The same for the untrusted |.max| values. +% \begin{macrocode} + \PT@colwidth=\expandafter\@nameuse\expandafter + {\PT@currentcol.max}\relax + \ifdim\PT@colwidth>\csname PT@col@#1.max\endcsname\relax + % we need to change the width + \PT@debug@{S \PT@aligncol{#1}: % + old=\expandafter\expandafter\expandafter + \PT@aligndim\csname PT@col@#1.max\endcsname\@@% + new=\expandafter\PT@aligndim\the\PT@colwidth\@@}% + \PT@changedtrue + \PT@checkrerun + \PT@enamedef{PT@col@#1.max}{\the\PT@colwidth}% + \fi + \ifnum\csname PT@col@#1.trusted\endcsname=\PT@false\relax + \ifdim\PT@colwidth=\csname PT@col@#1.max\endcsname\relax + \PT@debug@{#1=\the\PT@colwidth\space is now trusted}% + \expandafter\let\csname PT@col@#1.trusted\endcsname\PT@true% + \fi + \fi + \fi +% \end{macrocode} +% We assume that the current field is typeset in |\@curfield|; we +% can thus measure the width of the box and then test the second condition. +% \begin{macrocode} + \PT@expanded{\def\PT@temp}{\the\wd\@curfield}% + \global\PT@colwidth=\@nameuse{PT@col@#1.width}% + \global\advance\PT@colwidth by \PT@temp\relax% + \ifdim\PT@colwidth>\csname PT@col@#2.width\endcsname\relax + % we need to change the width + \PT@debug@{#2 (width \PT@temp) starts after #1 (at \csname PT@col@#1.width\endcsname)}% + \PT@debug@{c \PT@aligncol{#2}: % + old=\expandafter\expandafter\expandafter + \PT@aligndim\csname PT@col@#2.width\endcsname\@@% + new=\expandafter\PT@aligndim\the\PT@colwidth\@@}% + \PT@changedtrue + \PT@enamedef{PT@col@#2.width}{\the\PT@colwidth}% + \fi +% \end{macrocode} +% And again, we have to do the same for the untrusted maximums. +% \begin{macrocode} + \global\PT@colwidth=\@nameuse{PT@col@#1.max}% + \global\advance\PT@colwidth by \PT@temp\relax% + \ifdim\PT@colwidth>\csname PT@col@#2.max\endcsname\relax + % we need to change the width + \PT@debug@{C \PT@aligncol{#2}: % + old=\expandafter\expandafter\expandafter + \PT@aligndim\csname PT@col@#2.max\endcsname\@@% + new=\expandafter\PT@aligndim\the\PT@colwidth\@@}% + \PT@changedtrue + \PT@checkrerun + \PT@enamedef{PT@col@#2.max}{\the\PT@colwidth}% + \fi + \ifnum\csname PT@col@#2.trusted\endcsname=\PT@false\relax + \ifdim\PT@colwidth=\csname PT@col@#2.max\endcsname\relax + \PT@debug@{#2=\the\PT@colwidth\space is now trusted}% + \expandafter\let\csname PT@col@#2.trusted\endcsname\PT@true% + \fi + \fi +% \end{macrocode} +% Finally, we update the current column to |#2|. +% \begin{macrocode} + \def\PT@currentcol{PT@col@#2}} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\PT@checkrerun} +% If we have changed something with the trusted widths, we have +% to check whether we are in a situation where we are using previously +% defined columns. If so, we have to rerun \LaTeX. +% \begin{macrocode} +\def\PT@checkrerun + {\ifnum\PT@inrestore=\PT@true\relax + \PT@rerun + \fi} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\PT@resetcolumn} +% If the end of a line is encountered, we stop scanning the current +% entry, and reset the current column. +% \begin{macrocode} +\newcommand*{\PT@resetcolumn}[1][]% + {\PT@checkendentry{@end@}% + \let\PT@currentcolumn\empty% + \let\PT@scanning\undefined + \let\PT@currentcol\PT@nullcol + % TODO: remove these lines if they don't work + %\let\PT@pre@preamble\empty + %\PT@scanbeginfree + } +% \end{macrocode} +% \end{macro} +% \begin{macro}{\PT@nullcol} +% The name of the |@begin@| column as a macro, to be able to compare +% to it with |\ifx|; dito for the |@end@| column. +% \begin{macrocode} +\def\PT@nullcol{PT@col@@begin@} +\def\PT@endcol{PT@col@@end@} +% \end{macrocode} +% \end{macro} +% +% \subsection{Sorting and numbering the columns} +% +% Not much needs to be done here, all the work is done by the +% macros supplied by the \textsf{lazylist} package. +% We just provide a few additional commands to facilitate +% their use. +% +% \begin{macro}{\PT@Execute} +% \begin{macro}{\PT@Sequence} +% With |\PT@Execute|, a list of commands (with sideeffects) can +% be executed in sequence. Usually, first a command will be +% mapped over a list, and then the resulting list will be +% executed. +% \begin{macrocode} +\def\PT@Execute{\Foldr\PT@Sequence\empty} +\def\PT@Sequence #1#2{#1#2} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \begin{macro}{\PT@ShowColumn} +% This is a debugging macro, that is used to output the list +% of columns in a pretty way. The columns internally get +% prefixes to their names, to prevent name conflicts with +% normal commands. In the debug output, we gobble this prefix +% again. +% \begin{macrocode} +\def\PT@ShowColumn #1#2% + {\PT@ShowColumn@{#1}#2\PT@ShowColumn@} +\def\PT@ShowColumn@ #1PT@col@#2\PT@ShowColumn@ + {#1{#2} } +\def\PT@ShowColumnWidth #1% + {\PT@typeout@{% + \PT@ShowColumn\PT@aligncol{#1}: + \expandafter\expandafter\expandafter + \PT@aligndim\csname #1.max\endcsname\@@}} +\def\PT@StripColumn #1% + {\expandafter\PT@StripColumn@#1\PT@StripColumn@} +\def\PT@StripColumn@ PT@col@#1\PT@StripColumn@ + {#1} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\PT@Print} +% Prints a list of columns, using |\PT@ShowColumn|. +% \begin{macrocode} +\def\PT@Print#1{\PT@Execute{\Map{\PT@ShowColumn\Identity}#1}} +\def\PT@PrintWidth#1{\PT@Execute{\Map\PT@ShowColumnWidth#1}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\PT@TeXif} +% This is an improved version of \textsf{lazylist}'s |\TeXif|. +% It does have an additional |\relax| to terminate the condition. +% The |\relax| is gobbled again to keep it fully expandable. +% \begin{macrocode} +\def\PT@TeXif #1% + {\expandafter\@gobble#1\relax + \PT@gobblefalse + \else\relax + \gobbletrue + \fi} +\def\PT@gobblefalse\else\relax\gobbletrue\fi #1#2% + {\fi #1} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\PT@ltmax} +% The order by which the columns are sorted is given by +% the order on their (untrusted) widths. +% \begin{macrocode} +\def\PT@ltmax #1#2% + {\Not{\PT@TeXif{\ifdim\csname #1.max\endcsname>\csname #2.max\endcsname}}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\PT@numbercol} +% This assigns the next consecutive number to a column. +% We also reassign |PT@lastcol| to remember the final column. +% \begin{macrocode} +\def\PT@numbercol #1% + {%\PT@typeout@{numbering #1 as \the\PT@cols}% + \PT@enamedef{#1.num}{\the\PT@cols}% + \def\PT@lastcol{#1}% + \advance\PT@cols by 1\relax} +% \end{macrocode} +% \end{macro} +% +% \subsection{Typesetting the table} +% +% Remember that there are three important macros that +% occur in the body of the polytable: |\column|, |\fromto|, +% and |\\|. The |\column| macro is only really used +% in the very first trial run, so there is nothing new +% we have to do here, but the other two have to be +% redefined. +% +% \begin{macro}{\PT@resetandcr} +% This is what |\\| does in the typesetting phase. +% It resets the current column, but it also calls the surrounding +% environment's newline macro |\PT@cr| \dots +% If we are \emph{not} in the last column, we insert +% an implicit |fromto|. This is needed for the boxed environment to +% make each column equally wide. Otherwise, if the boxed environment +% is typeset in a centered way, things will go wrong. +% \begin{macrocode} +\newcommand{\PT@resetandcr}% + {\PT@expanded\PT@checkendentry\PT@lastcol@% + \ifx\PT@currentcol\PT@lastcol + \else + \ifx\PT@currentcol\PT@nullcol + \edef\PT@currentcol{\Head{\Tail\PT@sortedlist}}% + \fi + \edef\PT@currentcol@{\PT@StripColumn\PT@currentcol}% + \PT@typeout@{adding implicit fromto at eol from \PT@currentcol@ + \space to \PT@lastcol@}% + \PT@expanded{\PT@expanded\fromto\PT@currentcol@}\PT@lastcol@ + \fi + \PT@typeout@{Next line ...}% + \let\PT@scanning\undefined% needed for resetcolumn + \PT@resetcolumn\PT@cr} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\PT@fill} +% This variant of |\PT@resetandcr| is used at the end of +% the environment, to insert a blank box for the |pboxed| +% environment to balance the widths of all lines. It does +% not start a new line, and does nothing if the current +% column is |@begin@|. TODO: extract commonalities with +% |\PT@resetandcr| into a separate macro. +% \begin{macrocode} +\newcommand{\PT@fill}% + {\PT@expanded\PT@checkendentry\PT@lastcol@% + \ifx\PT@currentcol\PT@lastcol + \else + \ifx\PT@currentcol\PT@nullcol + \else + \edef\PT@currentcol@{\PT@StripColumn\PT@currentcol}% + \PT@typeout@{adding implicit fromto from \PT@currentcol@ + \space to \PT@lastcol@}% + \PT@expanded{\PT@expanded\fromto\PT@currentcol@}\PT@lastcol@ + \fi\fi} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\PT@placeinbox} +% This macro is the final-run replacement for |\PT@checkwidth|. We use +% the precomputed width information to typeset the contents of the +% table in aligned boxes. The arguments are the same as for +% |\PT@checkwidth|, i.e., the start and the end columns, and the assumption +% that the entry is contained in the box |\@curfield|. +% \begin{macrocode} +\def\PT@placeinbox#1#2% +% \end{macrocode} +% We start by computing the amount of whitespace that +% must be inserted before the entry begins. We then insert that amount +% of space. +% \begin{macrocode} + {\PT@colwidth=\@nameuse{PT@col@#1.max}% + \advance\PT@colwidth by -\expandafter\csname\PT@currentcol.max\endcsname + \leavevmode + \edef\PT@temp{\PT@StripColumn\PT@currentcol}% + \PT@typeout@{adding space of width % + \expandafter\PT@aligndim\the\PT@colwidth\@@ + (\expandafter\PT@aligncol\expandafter{\PT@temp} % + -> \PT@aligncol{#1})}% + \hb@xt@\PT@colwidth{% + {\@mkpream{@{}l@{}}\@addtopreamble\@empty}% + \let\CT@row@color\relax% colortbl compatibility + \let\@sharp\empty% + %\show\@preamble + \@preamble}% +% \end{macrocode} +% The important part is to use the pre-typeset box |\@curfield|. +% This produces real output! +% \begin{macrocode} + \PT@typeout@{adding box \space\space of width % + \expandafter\PT@aligndim\the\wd\@curfield\@@ + (\PT@aligncol{#1} -> \PT@aligncol{#2})}% + \box\@curfield +% \end{macrocode} +% Finally, we have to reset the current column and +% ignore spaces. +% \begin{macrocode} + \def\PT@currentcol{PT@col@#2}% + \ignorespaces}% +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\PT@preparescan} +% The macro |\PT@preparescan| sets the two macros |\PT@scanbegin| +% and |\PT@scanend| in such a way that they scan the input between +% those two macros and place it in a box. The width of the box is +% determined from the given column names. The name |@end@| can be +% used as a column name is a free scan (a scan without knowing the +% real end column) is desired. To allow redefinition of the preamble, +% we assume that |\PT@currentpreamble| is defined to |\relax| if +% we want it set normally dugin |\PT@preparescan|. +% \begin{macrocode} +\def\PT@preparescan#1#2% +% First, we check that both columns are defined. This will +% actually define the columns if implicit column definitions are +% enabled. +% \begin{macrocode} + {\PT@checkcoldefined{#1}% + \PT@checkcoldefined{#2}% + \PT@colwidth=\@nameuse{PT@col@#2.max}% + \advance\PT@colwidth by -\@nameuse{PT@col@#1.max}\relax% + \ifmmode + \PT@debug@{*math mode*}% + \let\d@llarbegin=$%$ + \let\d@llarend=$%$ + \let\col@sep=\arraycolsep + \else + \PT@debug@{*text mode*}% + \let\d@llarbegin=\begingroup + \let\d@llarend=\endgroup + \let\col@sep=\tabcolsep + \fi + \ifx\PT@currentpreamble\relax + \PT@expanded{\PT@expanded{\def\PT@currentpreamble}}% + {\csname PT@col@#1.type\endcsname}% + \fi +% \end{macrocode} +% Now, we make a preamble using the macro |\@mkpream| from the +% \textsf{array} package. This macro takes a format string as +% argument, and defines |\@preamble| as a result, where |\@sharp| +% occurs in the positions of the column contents. +% We perform the operation in a group to prevent certain redefinitions +% from escaping. The |\@preamble| is set globally anyway. +% \begin{macrocode} + {\PT@expanded\@mkpream\PT@currentpreamble% + \@addtopreamble\@empty}% + \let\CT@row@color\relax% colortbl compatibility +% \end{macrocode} +% We split the preamble at the position of the |\@sharp|, using +% some tricks to make sure that there really is precisely one +% occurrence of |\@sharp| in the resulting preamble code, and +% producing an error otherwise. The splitting defines +% |\PT@pre@preamble| and |\PT@post@preamble|. With those and +% the computed |\PT@colwidth|, the scan is successfully prepared. +% \begin{macrocode} + \expandafter\PT@splitpreamble\@preamble\@sharp\PT@nil} +% \end{macrocode} +% +% We now define the splitting of the preamble. +% \begin{macrocode} +\def\PT@splitpreamble #1\@sharp #2\PT@nil{% + \let\@sharp=\relax% needed for the following assignment + \def\PT@terp{#2}% + \ifx\PT@terp\empty% + \PackageError{polytable}{Illegal preamble (no columns)}{}% + \fi + \PT@splitsplitpreamble{#1}#2\PT@nil} + +\def\PT@splitsplitpreamble #1#2\@sharp #3\PT@nil{% + \def\PT@temp{#3}% + \ifx\PT@temp\empty% + \else + \PackageError{polytable}{Illegal preamble (multiple columns)}{}% + \fi + \def\PT@pre@preamble{#1}% + \def\PT@post@preamble{#2}}% +% \end{macrocode} +% +% Finally, we can define the scan environment, which depends on +% all the other macros being defined correctly. The macro +% |\PT@scanbegin| is not defined directly, but will be set +% to |\PT@scanbeginfree| during the trial runs and to +% |\PT@scanbeginwidth| during the final run. +% \begin{macrocode} +\def\PT@scanbeginwidth + {\PT@scanbegin@{\hbox to \PT@colwidth}} + +\def\PT@scanbeginfree + {\PT@scanbegin@{\hbox}} + +\def\PT@scanbegin@#1% + {\setbox\@curfield #1% + \bgroup + \PT@pre@preamble\strut\ignorespaces} + +\def\PT@scanend + {\PT@post@preamble + \egroup} +% \end{macrocode} +% \end{macro} +% +% \subsection{Saving and restoring column widths} +% +% Column width information can be saved under a name and thus +% be reused in other tables. The idea is that the command +% |\savecolumns| can be issued inside a polytable to save the +% current column information, and |\restorecolumns| can be used +% to make that information accessible in a later table. All tables +% using the same information should have the same column widths, +% which means that some information might need to be passed back. +% Therefore, we need to write to an auxiliary file. +% +% Both |\savecolumns| and |\restorecolumns| are mapped to the internal +% commands |\PT@savewidths| and |\PT@restorewidths|. Both take an +% optional argument specifying a name for the column width +% information. Thereby, multiple sets of such information can be +% used simultaneously. +% +% One important thing to consider is that the widths read from the +% auxiliary file must not be trusted. The user may have edited the +% source file before the rerun, and therefore, the values read might +% actually be too large (or too small, but this is less dangerous). +% +% The way we solve this problem is to distinguish two width values +% per column: the trusted width, only using information from the +% current run, and the untrusted width, incorportating information +% from the |.aux| file. An untrusted width can become (conditionally) +% trusted if it is reached in the computation with respect to an +% earlier column. (Conditionally, because its trustworthiness still +% depends on the earlier columns being trustworthy.) In the end, we +% can check whether all untrusted widths are conditionally trusted. +% +% We write the final, the maximum widths, into the auxiliary file. +% We perform the +% write operation when we are sure that a specific set is +% no longer used. This is the case when we save a new set under the +% same name, or at the end of the document. The command +% |\PT@verifywidths| takes care of this procedure. +% This command will also check if a rerun is necessary, and issue +% an appropriate warning if that should be the case. +% +% \begin{macro}{\PT@setmaxwidth} +% First, we need a macro to help us interpreting the contents of +% the |.aux| file. New v0.4.1: We need to define the restored +% columns with the |\column| command, because otherwise we will +% have problems in the case that later occurences of tables in +% the document that belong to the same set, but define additional +% columns. (Rerun warnings appear ad infinitum.) +% In v0.4.2: columns with width 0.0 are now always trusted. +% \begin{macrocode} +\newcommand*{\PT@setmaxwidth}[3][\PT@false]% #2 column name, #3 maximum width + {\@namedef{PT@col@#2.max}{#3}% + \ifdim#3=0pt\relax + \expandafter\let\csname PT@col@#2.trusted\endcsname=\PT@true% + \else + \expandafter\let\csname PT@col@#2.trusted\endcsname=#1% + \fi + \column{#2}{}}% +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\PT@loadtable} +% Now, we can load table information that has been read from the +% |.aux| file. Note that a |\csname| construct expands to |\relax| +% if undefined. +% \begin{macrocode} +\def\PT@loadtable#1% #1 table id number + {%\expandafter\show\csname PT@restore@\romannumeral #1\endcsname + %\show\column + \PT@typeout@ + {Calling \expandafter\string + \csname PT@restore@\romannumeral #1\endcsname.}% + \let\maxcolumn\PT@setmaxwidth + %\expandafter\show\csname PT@load@\romannumeral #1\endcsname + \csname PT@restore@\romannumeral #1\endcsname} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\PT@loadtablebyname} +% Often, we want to access table information by a column width set +% name. +% \begin{macrocode} +\def\PT@loadtablebyname#1% #1 set name + {\PT@typeout@{Loading table information for column width set #1.}% + \PT@loadtable{\csname PT@widths@#1\endcsname}}% +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\PT@saveinformation} +% In each table for which the widths get reused (i.e., in all tables +% that use either |\savecolumns| or |\restorecolumns|, we have to store +% all important information for further use. +% \begin{macrocode} +\def\PT@saveinformation#1% #1 set name + {\PT@expanded{\def\PT@temp}{\csname PT@widths@#1\endcsname}% + \PT@expanded{\def\PT@temp}% + {\csname PT@restore@\romannumeral\PT@temp\endcsname}% + \expandafter\gdef\PT@temp{}% start empty + % this is: \PT@Execute{\Map{\PT@savecolumn{\PT@temp}}{\Reverse\PT@allcols}} + \expandafter\PT@Execute\expandafter{\expandafter + \Map\expandafter{\expandafter\PT@savecolumn + \expandafter{\PT@temp}}{\Reverse\PT@allcols}}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\PT@savecolumn} +% A single column is saved by this macro. +% \begin{macrocode} +\def\PT@savecolumn#1#2% #1 macro name, #2 column name + {\PT@typeout@{saving column #2 in \string #1 ...}% + \def\PT@temp{#2}% + \ifx\PT@temp\PT@nullcol + \PT@typeout@{skipping nullcol ...}% +% This was a bug: end column cannot be skipped, because +% it can change. +% \else\ifx\PT@temp\PT@endcol +% \PT@typeout@{skipping endcol ...}% + \else + \PT@typeout@{max=\csname #2.max\endcsname, % + width=\csname #2.width\endcsname, % + trusted=\csname #2.trusted\endcsname}% + % we need the column command in here + % we could do the same in \column, but then the location of + % \save / \restore matters ... + \PT@gaddendmacro{#1}{\maxcolumn}% + \ifnum\csname #2.trusted\endcsname=\PT@true\relax + \PT@gaddendmacro{#1}{[\PT@true]}% + \fi + \edef\PT@temp{\PT@StripColumn{#2}}% + \PT@addargtomacro{#1}{PT@temp}% + \PT@addargtomacro{#1}{#2.max}% + \PT@gaddendmacro{#1}{\column}% + \PT@addoptargtomacro{#1}{#2.width}% + \edef\PT@temp{\PT@StripColumn{#2}}% + \PT@addargtomacro{#1}{PT@temp}% + \PT@addargtomacro{#1}{#2.type}% + %\show#1% +% \fi + \fi + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\PT@savewidths} +% If we really want to save column width information, then the first +% thing we should worry about is that there might already have been +% a set with the name in question. Therefore, we will call +% |\PT@verifywidths| for that set. In the case that there is no set +% of this name yet, we will schedule the set for verification at the +% end of document. +% \begin{macrocode} +\newcommand*{\PT@savewidths}[1][default@] + {\PT@typeout@{Executing \string\savecolumns [#1].}% + \def\PT@currentwidths{#1}% + \PT@verifywidths{#1}% +% \end{macrocode} +% We now reserve a new unique number for this column width set +% by increasing the |\PT@table| counter. We then associate +% the given name (or |default@|) with the counter value and +% restore the widths from the |.aux| file if they are present. +% \begin{macrocode} + \global\advance\PT@table by 1\relax + \expandafter\xdef\csname PT@widths@#1\endcsname + {\the\PT@table}% + \PT@loadtable{\PT@table}% + \ignorespaces} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\PT@restorewidths} +% Restoring information is quite simple. We just load all information +% available. +% \begin{macrocode} +\newcommand*{\PT@restorewidths}[1][default@] + {\PT@typeout@{Executing \string\restorecolumns [#1].}% + \def\PT@currentwidths{#1}% + \let\PT@inrestore\PT@true + \PT@loadtablebyname{#1}% + \ignorespaces} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\PT@comparewidths} +% \begin{macrocode} +\def\PT@comparewidths#1% #1 full column name + {\@ifundefined{#1.max}% + {\PT@typeout@{computed width for #1 is fine ...}}% + {\ifdim\csname #1.max\endcsname>\csname #1.width\endcsname\relax + \PT@typeout@{Preferring saved width for \PT@StripColumn{#1}.}% + \PT@changedtrue + \PT@colwidth=\@nameuse{#1.max}\relax + \PT@enamedef{#1.width}{\the\PT@colwidth}% + \fi}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\PT@trustedmax} +% \begin{macrocode} +\def\PT@trustedmax#1% + {\PT@TeXif{\ifnum\csname #1.trusted\endcsname=\PT@true}} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\PT@equalwidths} +% \begin{macrocode} +\def\PT@equalwidths#1% #1 full column name + {\@ifundefined{#1.max}{}% + {\ifdim\csname #1.max\endcsname=\csname #1.width\endcsname\relax + \PT@typeout@{col #1 is okay ...}% + \else + \PT@rerun% a rerun is needed + \fi}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\PT@verifywidths} +% \begin{macrocode} +\def\PT@verifywidths#1% #1 column width set name + {\@ifundefined{PT@widths@#1}% + {\PT@typeout@{Nothing to verify yet for set #1.}% + \PT@typeout@{Scheduling set #1 for verification at end of document.}% + \AtEndDocument{\PT@verifywidths{#1}}}% + {\PT@typeout@{Verifying column width set #1.}% + \PT@expanded\PT@verify@widths{\csname PT@widths@#1\endcsname}{#1}}} + +\def\PT@verify@widths#1#2% #1 set id number, #2 set name + {\@ifundefined{PT@restore@\romannumeral #1}{}% + {\begingroup + \let\column\PT@firstrun@column + \PT@cols=0\relax% + \def\PT@allcols{\Nil}% + \PT@loadtablebyname{#2}% + \PT@table=#1\relax + % nullcolumn is not loaded, therefore: + \@namedef{\PT@nullcol .width}{0pt}% + % checking trust + \PT@prelazylist + \All{\PT@trustedmax}{\PT@allcols}% + {\PT@typeout@{All maximum widths can be trusted -- writing .max!}% + \PT@save@table{.max}}% + {\PT@typeout@{Untrustworthy maximums widths -- writing .width!}% + \PT@rerun + \PT@save@table{.width}}% + \PT@postlazylist + \endgroup}% + \PT@typeout@{Verification for #2 successful.}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\PT@save@table} +% Here we prepare to write maximum column widths to the +% |.aux| file. +% \begin{macrocode} +\def\PT@save@table#1% + {\PT@typeout@{Saving column width information.}% + \if@filesw + \PT@prelazylist + {\immediate\write\@auxout{% + \gdef\expandafter\noexpand + \csname PT@restore@\romannumeral\PT@table\endcsname + {\PT@Execute{\Map{\PT@write@column{#1}}{\Reverse\PT@allcols}}}}}% + \PT@postlazylist + \fi} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\PT@write@column} +% We define the column command to write to the file. +% \begin{macrocode} +\def\PT@write@column #1#2% + {\noexpand\maxcolumn^^J% + {\PT@StripColumn{#2}}% + {\@nameuse{#2#1}}}% +% \end{macrocode} +% \end{macro} +% +% \subsection{The user environments} +% +% It remains to define the environments to be +% called by the user. +% New in v0.8: we add the environments +% |ptboxed| and |pmboxed| for text-mode and math-mode +% boxed environments. In turn, we remove |ptabular| and +% |parray|, and make the point to their new counterparts. +% \begin{macrocode} +\def\pboxed{% + \let\PT@begin \empty + \let\PT@end \empty +% \end{macrocode} +% The following assignment is a hack. If |pboxed| is called +% from within another |tabular|- or |array|-environment, then +% this sometimes does the right thing. +% \begin{macrocode} + \ifx\\\PT@arraycr + \let\PT@cr \PT@normalcr + \else + \let\PT@cr \\% + \fi + \expandafter\beginpolytable\ignorespaces} + +\let\endpboxed\endpolytable + +\def\ptboxed{% + \def\PT@begin {\tabular{@{}l@{}}}% + \let\PT@end \endtabular + \let\PT@cr \@arraycr + \expandafter\beginpolytable\ignorespaces} + +\let\endptboxed\endpolytable + +\def\pmboxed{% + \def\PT@begin {\array{@{}l@{}}}% + \let\PT@end \endarray + \let\PT@cr \@arraycr + \expandafter\beginpolytable\ignorespaces} + +\let\endpmboxed\endpolytable + +\let\ptabular \ptboxed +\let\endptabular \endptboxed +\let\parray \pmboxed +\let\endparray \endpmboxed + +% \end{macrocode} +% +% That is all. +% \begin{macrocode} +%</package> +% \end{macrocode} +% +% \Finale +\endinput diff --git a/macros/latex/contrib/polytable/polytable.ins b/macros/latex/contrib/polytable/polytable.ins new file mode 100644 index 0000000000..70b0b83a88 --- /dev/null +++ b/macros/latex/contrib/polytable/polytable.ins @@ -0,0 +1,5 @@ +\def\batchfile{polytable.ins} +\input docstrip +\preamble +\endpreamble +\generate{\file{polytable.sty}{\from{polytable.dtx}{package}}} diff --git a/macros/latex/contrib/polytable/polytable.pdf b/macros/latex/contrib/polytable/polytable.pdf Binary files differnew file mode 100644 index 0000000000..2f267be0e5 --- /dev/null +++ b/macros/latex/contrib/polytable/polytable.pdf |