Subject: TeXhax Digest V88 #103
From: TeXhax Digest <[email-masked]>
To: TeXhax-Distribution-List: ;, [email-masked]
Date: Mon, 28 Nov 88 17:45:37 PST

TeXhax Digest    Friday,  November 25, 1988  Volume 88 : Issue 103

Moderators: Tiina Modisett and Pierre MacKay

%%% The TeXhax digest is brought to you as a service of the TeX Users Group %%%
%%%       in cooperation with the UnixTeX distribution service at the       %%%
%%%                      University of Washington                           %%%

%%% Moderator's note:  This issue of the TeXhaX Digest consists of a set of
%%% macros contributed by J.E. Pittman of Texas A&M University.
%%% We have repacked these into Unix Shar format in hopes that a plurality,
%%% at least, of the readers of TeXhax will find that format useful.  
%%% Emulations of the /bin/sh unpacking process exist on several non-Unix
%%% systems, and even where they do not, it is quite easy to find the
%%% boundaries of the actual file between lines containing the target
%%% SHAR_EOF.

%%% CORRECTION <<================PiCTeX Manual=========================!!
%%% 
%%% The information given about the PicTeX manual was out of date.
%%% Merchandizing of the PiCTeX manual has been taken over by TUG. Contact
%%% Karen at [email-masked] or write to TUG at
%%% 
%%%   TeX Users Group
%%%   P.O. Box 9506
%%%   Providence, R.I. 02940-9506
%%% 
%%% TUG is asking $30.00 for the manual, with a $5.00 discount
%%% to members.

Today's Topic:          
           TeX Inputs cellular.tex (table-generating macros)

------------------------------------------------------------------------------

Date: Wed,  9 Nov 88 13:33:46 CST
From: J E PITTMAN <[email-masked]>
Subject:  TeX Inputs cellular.tex (table-generating macros)
Keywords: macros

Several months ago, someone sent in a request for macros that allow vertical
and horizontal spans within a ruled table.  There have also been questions
about `nubs' and `gaps' within ruled tables. 

After thinking about the problem for a while, I realized that a solution was to
abandon the \halign primitive and start from scratch. 

I have finished my first attempt at a set of table generating macros, which I
have chosen to call Cellular.TeX.  These macros allow for both vertical and
horizontal spans and take steps to prevent `nubs' and `gaps' when rules are
used. 

They are, unfortunately, very slow and I have not been able to increase their
speed without sacrificing memory conservation and generality.

I am sending the macros under separate cover since there are nearly 1,000 lines
of code involved, divided into five files.  Detailed comments are available in
the file TeX Inputs cellular.doc. 

J E Pittman                      Bitnet:    JEPTeX@TAMVenus
User Services Group              Internet:  [email-masked]
Computing Services Center
Texas A&M University

-------------------------------------------------------------------------------

#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#-----cut here-----cut here-----cut here-----cut here-----
#!/bin/sh
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	cellular.doc
#	cellular.tex
#	Cell1.tex
#	Cell2.tex
#	Cell3.tex
#	Cell4.tex
# This archive created: Thu Nov 24 11:04:05 1988
echo shar: extracting cellular.doc '(3654 characters)'
cat << \SHAR_EOF > cellular.doc
% File:       TeX Inputs cellular.doc
% Author:     J E Pittman
% Bitnet:     JEPTeX@TAMVenus
% Internet:   [email-masked]
% Date:       November 8, 1988

A cellular table is specified by:

   \begincellular{specifications that change defaults}
      appropriate macro definitions
      column header specifications
      row specifications (header and data)
      \endcellular

The following are examples of specifications that change defaults:

   \pixelwidth=1in
   \divide\pixelwidth by 300

   The pixel width dimension register should be set to the resolution 
   of the device used.  The default is 1/300th of an inch.

   \setverticaladjustment -or- \sethorizontaladjustment

   Some printers (such as the Xerox 9700s and 4050s) produce vertical 
   and horizontal rules that have a different visual thickness for the 
   same specified thickness.  The macros set vertical and set 
   horizontal adjustment specified that vertical or horizontal rules 
   are to be thickened by pixel width, which may correct this problem.   

   \edef\everycolumn{\everycolumn
      \leftrulewidth=0.4pt\relax
      \rightrulewidth=\leftrulewidth
      \leftborderskip=6pt plus 1fil\relax
      \rightborderskip=\leftborderskip
      \columnwidth=\zeropt\relax
      \columnwidth=\zeropt\relax
      }%

   An \edef can be used to add material (usually default overrides) to 
   the every column macro.  The information shown above reflect the 
   defaults.  Care must be exercised to avoid introducing spurous 
   spaces, which will be very visible when output.

   \edef\everyrow{\everyrow
      \toprulewidth=0.4pt\relax
      \bottomrulewidth=\toprulewidth
      \topborderskip=3pt plus 1fil\relax
      \bottomborderskip=\topborderskip
      \rowheight=\zeropt\relax
      }%

   Same as every column.

   \tracingexpansions=1

   This specification will request notes on how column and rows are 
   expanded to accommedate spans.

Any sort of macros can be defined within a cellular table.  An obvious 
example is abbrevations for commonly used control sequence names.

A column header is specified as:

   \column{specifications}

   The specifications are the same as for every column.  Note:  There 
   is a considerable amount of processing required for these 
   specifications, wise selection of defaults can decrease execution 
   time significantly.

   Column headers are optional.

Rows are specified as a row header (similiar to a column header) and a 
series of entry specifications.

An entry specification can be any of the following:

   \blank

   A blank entry specification creates a completely blank spot in the 
   table (no rules or text).

   \mergeright
   
   A merge right specification merges the width of the entry into the 
   width of the entry to the right.  It is used to create column 
   spans.

   \mergedown
   
   Similar to merge right.  Note:  The overhead for a merge down 
   specification is considerably higher than a merge right.  
   Therefore, when specifing an entry that spans both rows and 
   columns, merge rights should be used as much as possible.  For 
   example:

                  > > > V                  V V V V
                  > > > V      rather      V V V V
                  > > > V       than       V V V V
                  > > > *                  > > > *

   \entry{horizontal mode material}

   An entry macro takes the specified material and formats it as 
   appropriate.

It is not necessary to complete every row.

Vertical mode material can be added after a row by specifying:

   \noalign{vertical mode material}

at any point in the row.  Multiple no aligns are permitted.
SHAR_EOF
if test 3654 -ne "`wc -c cellular.doc`"
then
echo shar: error transmitting cellular.doc '(should have been 3654 characters)'
fi
echo shar: extracting cellular.tex '(933 characters)'
cat << \SHAR_EOF > cellular.tex
% File:       TeX Inputs cellular.tex
% Author:     J E Pittman
% Bitnet:     JEPTeX@TAMVenus
% Internet:   [email-masked]
% Date:       November 8, 1988
%
% This file defines the main macro for cellular table construction.  
% For commentary, please see the file cellular.doc.
%
\message{Cellular.TeX version 0.}%
%
\def\begincellular#1#2\endcellular{\relax
   \begingroup
      \input Cell1                                % set up enviroment
      #1\relax
      \input Cell2                                % set up for scan
      \ignorespaces
      #2\relax                                    % scan the cells
      \input Cell3                                % compute spans
      \input Cell4                                % set up for output
      \offinterlineskip
      \parskip=\zeropt
      \ignorespaces
      #2\relax                                    % output cells
      \par
      \endgroup
   }%
%
\endinput
SHAR_EOF
if test 933 -ne "`wc -c cellular.tex`"
then
echo shar: error transmitting cellular.tex '(should have been 933 characters)'
fi
echo shar: extracting Cell1.tex '(3751 characters)'
cat << \SHAR_EOF > Cell1.tex
% File:       TeX Inputs Cell1.tex
% Author:     J E Pittman
% Bitnet:     JEPTeX@TAMVenus
% Internet:   [email-masked]
% Date:       October 11, 1988
%
% Set up the cellular environment
%
\catcode`_=11 % Protect local macros.
%
\ifx\forcount\undefined \input loopy \fi
\ifx\declarecount\undefined \input declare \fi
%
% Handy abbreviations
%
\def\half{0.5}%
\def\by{by}%
\def\height{height}%
\def\depth{depth}%
\def\width{width}%
\def\to{to}%
\def\zeropt{0pt}%
\let\x_after=\expandafter
%
% When using the Xerox 9700s or 4050, use \setverticaladjustment for 
% portrait output and \sethorizontaladjustment for landscape output 
% due to the differences in the way that vertical and horizontal lines 
% of the same weight are printed.
%
\declaredimen\pixelwidth
\pixelwidth=1in
\divide\pixelwidth by 300                         % assume 300dpi
%
\declaredimen\horizontal_rule_adjust
\horizontal_rule_adjust=\zeropt
\def\sethorizontaladjustment{\horizontal_rule_adjust=\pixelwidth}%
%
\declaredimen\vertical_rule_adjust
\vertical_rule_adjust=\zeropt
\def\setverticaladjustment{\vertical_rule_adjust=\pixelwidth}%
%
% The left, right, bottom, and top rule widths are used to determine
% the widths of the box around each cell.
%
\declaredimen\leftrulewidth
\declaredimen\rightrulewidth
\declaredimen\bottomrulewidth
\declaredimen\toprulewidth
%
% The left, right, bottom, and top border skips are used to position 
% the text of a cell within it, relative to the centers of the rulers.
%
\declareskip\leftborderskip
\declareskip\rightborderskip
\declareskip\bottomborderskip
\declareskip\topborderskip
%
\declarecount\last_column
\declaredimen\columnwidth
\declarecount\merge_columns
\declaredimen\merge_width
%
\declarecount\last_row
\declaredimen\rowheight
\declarecount\merge_rows
\declaredimen\merge_height
\declarecount\rowpenalty
%
% The row info and column info token registers contain a list of 
% tokens of the form /number/info, where number is the number of a 
% row or column of interest and info is information, usually register 
% assignments, that pertains to the row or column.
%
\declaretoks\column_info
\column_info={/}%
%
\declaretoks\row_info
\row_info={/}%
%
\def\everycolumn{\leftrulewidth=0.4pt\relax
   \rightrulewidth=\leftrulewidth
   \leftborderskip=6pt plus 1fil\relax
   \rightborderskip=\leftborderskip
   \columnwidth=\zeropt\relax
   \merge_rows=0\relax
   \merge_height=\zeropt\relax
   \columnwidth=\zeropt\relax
   }%
%
\def\everyrow{\toprulewidth=0.4pt\relax
   \bottomrulewidth=\toprulewidth
   \topborderskip=3pt plus 1fil\relax
   \bottomborderskip=\topborderskip
   \rowheight=\zeropt\relax
   \merge_columns=0\relax
   \merge_width=\zeropt\relax
   }%
%
\def\get_data#1<#2{\relax
   \def\temp##1/#1/##2/##3***{\relax
      \def\temp{##2}%
      \ifnum1=0\temp
         #2={##1/#1//}%
      \else
%        \message{extracted ##2}% debug
         ##2%
      \fi
      }%
   \x_after\temp\the#2#1/1/***%
   }%
%
\def\add_data#1>#2#3{\relax
   \def\temp##1/#1/##2/##3***{\relax
      #2={##1/#1/##2#3/##3}%
%     \message{\string#2=\the#2}% debug
      }%
   \x_after\temp\the#2***%
   }%
%
\def\add_column_number_data{\relax
   \x_after \add_data \the\column_number>\column_info
   }%
%
\def\get_column_number_data{\relax
   \x_after \get_data \the\column_number<\column_info
   }%
%
\def\add_row_number_data{\relax
   \x_after \add_data \the\row_number>\row_info
   }%
%
\def\get_row_number_data{\relax
   \x_after \get_data \the\row_number<\row_info
   }%
%
\declarebox\temp_box
\declarebox\scratch_box
\declaredimen\temp_dimen
\declaredimen\scratch_dimen
\declareskip\temp_skip
\declarecount\temp_count
%
\declarecount\tracingexpansions
\tracingexpansions=0
%
\catcode`_=8 % Return to normal.
%
\endinput
SHAR_EOF
if test 3751 -ne "`wc -c Cell1.tex`"
then
echo shar: error transmitting Cell1.tex '(should have been 3751 characters)'
fi
echo shar: extracting Cell2.tex '(5966 characters)'
cat << \SHAR_EOF > Cell2.tex
% File:       TeX Inputs Cell2.tex
% Author:     J E Pittman
% Bitnet:     JEPTeX@TAMVenus
% Internet:   [email-masked]
% Date:       November 8, 1988
%
% Prepare to scan the data, taking notes as to span sizes, row and 
% column dimensions, et cetera.
%
\catcode`_=11 % Used to protect local control sequence names.
%
% The span info tokens contain sets of entries of the form \process 
% {position}{number}{dimension}, where position is the terminal column 
% or row, number is the number of columns or rows leading into the 
% column or row, and dimension is the size of the information.
% 
\declaretoks\column_span_info
\column_span_info={}%
\declaretoks\row_span_info
\row_span_info={}%
%
\let\process=\relax
%
\declarecount\column_number
\column_number=0
%
% Create a column information entry and put the user's specifications 
% into it.
%
\def\column#1{\relax
   \advance\column_number \by 1
   \last_column=\column_number
   \get_column_number_data
   \add_column_number_data {#1}%
   \ignorespaces
   }%
%
\declarecount\row_number
\row_number=0
%
% Same as \column.
%
\def\row#1{\relax
   \advance\row_number \by 1
   \message{Scanning row \the\row_number.}%
   \last_row=\row_number
   \everyrow
   \get_row_number_data
   \add_row_number_data {#1}%
   \column_number=0
   \ignorespaces
   }%
%
% \blank is used to generate a cell without a border or data.  In this 
% context, all it does is absorb merges.
%
\def\blank{\relax
   \advance\column_number \by 1
   \if\column_number>\last_column
      \advance\column_number \by -1
      \column{}%
   \fi
   \everycolumn
   \get_column_number_data
   \ifnum\merge_rows>1
      \add_column_number_data {\merge_rows=0\relax}%
   \fi
   \merge_columns=0
   }%
%
% \cell is used to generate a normal, ruled cell.  In this context, it 
% merely measures the cell and makes the appropriate notes.
%
\def\cell#1{\relax
   \advance\column_number \by 1
   \if\column_number>\last_column
      \advance\column_number \by -1
      \column{}%
   \fi
   \everycolumn
   \get_column_number_data
%
% Typeset the information into temp box.
%
   \setbox\temp_box=\vbox \bgroup
      \begingroup
         \ifnum\merge_rows>0
            \advance\row_number \by -\merge_rows
            \get_row_number_data
         \fi
         \vskip \topborderskip
         \endgroup
      \hbox \bgroup
         \begingroup
            \ifnum\merge_columns>0
               \advance\column_number \by -\merge_columns
               \get_column_number_data
            \fi
            \hskip \leftborderskip
            \endgroup
         #1\vphantom{)}%
         \hskip \rightborderskip
         \egroup
      \vskip \bottomborderskip
      \egroup
%
% If it is a row merger, record it for later processing.
%
   \ifnum \merge_rows>0
      \edef\temp{\process
         {\the\merge_rows}{\the\ht\temp_box}{\the\row_number}%
         \the\row_span_info
         }%
      \x_after\row_span_info\x_after=\x_after{\temp}%
%     \message{\string\row_span_info=\the\row_span_info}% debug
      \add_column_number_data {\merge_rows=0\relax}%
   \else
%
% Not a merger, record the height if max.
%
      \ifdim\ht\temp_box>\rowheight
         \let\info=\relax
         \edef\temp{\the\row_number>\info
               {\rowheight=\the\ht\temp_box\relax}}%
         \let\info=\row_info
         \x_after \add_data \temp
%        \message{\string\row_info=\the\row_info}% debug
         \rowheight=\ht\temp_box
      \fi
   \fi
%
% Same as above for column merger and width.
%
   \ifnum \merge_columns>0
      \edef\temp{\process
         {\the\merge_columns}{\the\wd\temp_box}{\the\column_number}%
         \the\column_span_info
         }%
      \x_after\column_span_info\x_after=\x_after{\temp}%
%     \message{\string\column_span_info=\the\column_span_info}% debug
      \merge_columns=0
   \else
      \ifdim\wd\temp_box>\columnwidth
         \let\info=\relax
         \edef\temp{\the\column_number>\info
               {\columnwidth=\the\wd\temp_box\relax}}%
         \let\info=\column_info
         \x_after \add_data \temp
%        \message{\string\column_info=\the\column_info}% debug
      \fi
   \fi
   }%
%
% \mergeright specifies that the corresponding position is to be 
% merged with the cell to its right.
%
\def\mergeright{\relax
   \advance\column_number \by 1
   \if\column_number>\last_column
      \advance\column_number \by -1
      \column{}%
   \fi
   \everycolumn
   \get_column_number_data
   \advance\merge_columns \by 1
%
% Cancel a row merge, if present.
%
   \ifnum\merge_rows>1
      \add_column_number_data {\merge_rows=0\relax}%
   \fi
   }%
%
% Same as \mergeright, except down.
%
\def\mergedown{\relax
   \advance\column_number \by 1
   \if\column_number>\last_column
      \advance\column_number \by -1
      \column{}%
   \fi
   \everycolumn
   \get_column_number_data
   \add_column_number_data {\advance\merge_rows \by 1\relax}%
   \merge_columns=0
   }%
%
% The horizontal and vertical stretch macros allow the user to specify 
% an explicit stretch that will subsequently be processed like a span.  
% User-specified stretches are processed after span caused ones.  The 
% parameters are the starting column/row, the ending column/row, and 
% the size of the stretch.
%
\def\horizontalstretch#1#2#3{\relax
   \temp_count=#2\relax
   \advance\temp_count \by -#1\relax
   \edef\temp{\the\column_span_info\process{\the\temp_count}{#3}{#2}}%
   \x_after \column_span_info\x_after=\x_after{\temp}%
%  \message{\string\column_span_info=\the\column_span_info}% debug
   \ignorespaces
   }%
%
\def\verticalstretch#1#2#3{\relax
   \temp_count=#2\relax
   \advance\temp_count \by -#1\relax
   \edef\temp{\the\row_span_info\process{\the\temp_count}{#3}{#2}}%
   \x_after \row_span_info\x_after=\x_after{\temp}%
%  \message{\string\row_span_info=\the\row_span_info}% debug
   \ignorespaces
   }%
%
\def\noalign#1{\ignorespaces}% don't do anything for the first pass
%
\catcode`_=8 % Return to normal.
%
\endinput
SHAR_EOF
if test 5966 -ne "`wc -c Cell2.tex`"
then
echo shar: error transmitting Cell2.tex '(should have been 5966 characters)'
fi
echo shar: extracting Cell3.tex '(4169 characters)'
cat << \SHAR_EOF > Cell3.tex
% File:       TeX Inputs Cell3.tex
% Author:     J E Pittman
% Bitnet:     JEPTeX@TAMVenus
% Internet:   [email-masked]
% Date:       October 11, 1988
%
% Process the column and row span info.
%
\declaredimen\expansion
%
\edef\everycolumn{\everycolumn\expansion=\zeropt\relax}%
\edef\everyrow{\everyrow\expansion=\zeropt\relax}%
%
\catcode`_=11 % used to protect local control sequence names.
%
%\message{\string\row_span_info=\the\row_span_info}% debug
%\message{\string\column_span_info=\the\column_span_info}% debug
%
\def\process#1#2#3{\relax
   \last_cell=#3\relax
   \first_cell=\last_cell
   \advance \first_cell \by -#1\relax
   \span_size=#2\relax
%
% Compute the gap between the size of the span and the total size of 
% the cells spanned.
%
   \gap=\span_size
   \forcount \cell_number=\first_cell to \last_cell by 1 do
      \everycell
      \get_cell_number_data
      \advance \gap \by -\cell_size
      \advance \gap \by -\expansion
      \endfor \cell_number
%  \message{\string\first_cell=\the\first_cell}% debug
%  \message{\string\last_cell=\the\last_cell}% debug
%  \message{\string\span_size=\the\span_size}% debug
%  \message{\string\gap=\the\gap}% debug
%
% If the gap is 0pt or less, nothing needs to be done, else search for 
% the minimum expansion that can be applied to every cell with a 
% current expansion less than the expansion found such that the span 
% is properly accomadated.
%
   \ifdim \gap>\zeropt
      \expandable_cells=#1\relax
      \advance \expandable_cells \by 1
      \trial_expansion=\zeropt
      \whilenot\search \ifdim\gap=\zeropt do
%        \message{\string\gap=\the\gap}% debug
         \ifnum \expandable_cells=0
            \advance \trial_expansion \by \expansion
         \else
            \multiply \trial_expansion \by \expandable_cells
            \advance \trial_expansion \by \gap
            \divide \trial_expansion \by \expandable_cells
            \expandable_cells=0
         \fi
         \gap=\span_size
%        \message{\string\trial_expansion=\the\trial_expansion}% debug
         \forcount \cell_number=\first_cell to \last_cell by 1 do
            \everycell
            \get_cell_number_data
            \advance \gap \by -\cell_size
            \ifdim \expansion>\trial_expansion
               \advance \gap \by -\expansion
            \else
               \advance \gap \by -\trial_expansion
               \advance \expandable_cells \by 1
            \fi
            \endfor \cell_number
         \temp_dimen=1sp
         \multiply \temp_dimen \by \expandable_cells
         \ifdim \gap>-\temp_dimen
            \ifdim \gap<\temp_dimen
               \gap=\zeropt
            \fi
         \fi
         \endwhilenot \search
      \forcount \cell_number=\first_cell to \last_cell by 1 do
         \everycell
         \get_cell_number_data
         \ifdim \expansion<\trial_expansion
            \let\info=\relax
            \edef\temp{\the\cell_number>\info
                  {\expansion=\the\trial_expansion\relax}}%
            \let\info=\cell_info
            \x_after \add_data \temp
            \ifnum\tracingexpansions>0
               \message{Expanded \the\cell_number}%
               \message{by \the\trial_expansion}%
               \message{from \the\cell_size}%
               \advance \cell_size \by \trial_expansion
               \message{to \the\cell_size.}%
            \fi
         \fi
         \endfor \cell_number
   \fi
   }%
%
\declarecount\first_cell
\declarecount\last_cell
\declaredimen\span_size
\let\expandable_cells=\temp_count
\declaredimen\trial_expansion
\let\gap=\scratch_dimen
%
\let\cell_number=\row_number
\let\everycell=\everyrow
\let\get_cell_number_data=\get_row_number_data
\let\cell_info=\row_info
\let\cell_size=\rowheight
\ifnum\tracingexpansions>0
   \message{Checking row expansions.}%
\fi
\the\row_span_info
%
\let\cell_number=\column_number
\let\everycell=\everycolumn
\let\get_cell_number_data=\get_column_number_data
\let\cell_info=\column_info
\let\cell_size=\columnwidth
\ifnum\tracingexpansions>0
   \message{Checking column expansions.}%
\fi
\the\column_span_info
%
\let\process=\relax
%
\catcode`_=8 % back to normal
%
\endinput
SHAR_EOF
if test 4169 -ne "`wc -c Cell3.tex`"
then
echo shar: error transmitting Cell3.tex '(should have been 4169 characters)'
fi
echo shar: extracting Cell4.tex '(10292 characters)'
cat << \SHAR_EOF > Cell4.tex
% File:       TeX Inputs Cell4.tex
% Author:     J E Pittman
% Bitnet:     JEPTeX@TAMVenus
% Internet:   [email-masked]
% Date:       November 8, 1988
%
% Set up to output the data.
%
\catcode`_=11 % Protect local control sequence names.
%
% The user supplied information about the column has already been 
% processed.
%
\def\column #1{\relax\ignorespaces}%
%
\row_number=0
\rowpenalty=0
%
% This routine is used for horizontal kerning when there might be a 
% kern to the left of the current position.
%
\def\move_right_via_lastkern #1{\relax
   \temp_dimen=#1\relax
   \ifdim \lastkern>\zeropt
      \advance \temp_dimen \by \lastkern
      \unkern
   \else
   \fi
   \kern \temp_dimen
   }%
%
% \row begins a row by getting its specifications, terminating the 
% previous row (if any) and going into horizontal mode.
%
\def\row #1{\relax
   \advance \row_number \by 1
   \everyrow
   \get_row_number_data
   \advance \rowheight \by \expansion
   \ifdim \bottomrulewidth>\zeropt
      \advance \bottomrulewidth \by \horizontal_rule_adjust
   \fi
   \column_number=0
   \par
   \ifnum \rowpenalty=0
   \else
      \penalty \rowpenalty
      \rowpenalty=0
   \fi
   \noindent
   \ignorespaces
   \message{Outputting row \the\row_number.}%
   }%
%
% \blank creates a blank cell by kerning the appropriate amount.
%
\def\blank {\relax
   \advance \column_number \by 1
   \everycolumn
   \get_column_number_data
   \advance \columnwidth \by \expansion
   \advance \merge_width \by \expansion
   \move_right_via_lastkern \merge_width
%
% Terminate merger(s).
%
   \merge_width=\zeropt
   \merge_columns=0
   \ifnum \merge_rows>0
      \add_column_number_data
            {\merge_rows=0\relax\merge_height=\zeropt\relax}%
   \fi
   }%
%
% \cell outputs a cell.  The components of the cell are (in the order 
% output) the entry, the top ruler, the bottom ruler, and the left and 
% right rulers.
%
\def\cell #1{\relax
   \advance \column_number \by 1
   \everycolumn
   \get_column_number_data
   \advance \columnwidth \by \expansion
   \advance \merge_height \by \rowheight
   \advance \merge_width \by \columnwidth
   \ifdim \leftrulewidth>\zeropt
      \advance \leftrulewidth \by \vertical_rule_adjust
   \fi
   \ifdim \rightrulewidth>\zeropt
      \advance \rightrulewidth \by \vertical_rule_adjust
   \fi
%
% Get the correct top border skip and rule width.  Note that it is 
% necessary to extract this informaion even if a row merger is not 
% present because a previous row merger might have left the wrong 
% values.
%
   \begingroup
      \advance \row_number \by -\merge_rows
      \everyrow
      \get_row_number_data
      \xdef\globaltemp{\topborderskip=\the\topborderskip\relax
         \toprulewidth=\the\toprulewidth\relax
         }%
      \aftergroup \globaltemp
      \endgroup
   \ifdim \toprulewidth>\zeropt
      \advance \toprulewidth \by \horizontal_rule_adjust
   \fi
%
% Same procedure for the left border skip and rule width except that 
% extraction is necessary only in the presense of a column merger due 
% to the execution of an every column and a get at the start of \cell.  
%
   \ifnum \merge_columns>0
      \begingroup
         \advance \column_number \by -\merge_columns
         \everycolumn
         \get_column_number_data
         \xdef\globaltemp{\leftrulewidth=\the\leftrulewidth\relax
            \leftborderskip=\the\leftborderskip\relax
            }%
         \aftergroup \globaltemp
         \endgroup
      \ifdim \leftrulewidth>\zeropt
         \advance \leftrulewidth \by \vertical_rule_adjust
      \fi
   \fi
%
% Typeset the entry into temp box horizontally first, trying kerns 
% before glue in case the cell does not require horizontal stretching 
% and taking advantage of an empty cell by doing nothing, if such is 
% the case.
%
   \setbox\temp_box=\hbox{#1}%
   \ifdim\wd\temp_box>\zeropt
      \setbox\temp_box=\hbox \bgroup
         \kern \leftborderskip
         \box\temp_box
         \egroup
      \temp_dimen=\wd\temp_box
      \advance\temp_dimen \by \rightborderskip
      \wd\temp_box=\temp_dimen
%
      \ifdim\wd\temp_box=\merge_width
%
% then the kerns can be used instead of skips.
%
      \else
         \setbox\temp_box=\hbox \to \merge_width \bgroup
            \hskip \leftborderskip
            #1%
            \hskip \rightborderskip
            \egroup
      \fi
%
% Hide the width of temp box and put a phantom into it the hard way.
%
      \wd\temp_box=\zeropt
      \setbox\scratch_box=\hbox{#1)}%
      \ifdim \dp\scratch_box>\dp\temp_box
         \dp\temp_box=\dp\scratch_box
      \fi
      \ifdim \ht\scratch_box>\ht\temp_box
         \ht\temp_box=\ht\scratch_box
      \fi
%
      \temp_dimen=\ht\temp_box
      \advance \temp_dimen \by \dp\temp_box
      \advance \temp_dimen \by \bottomborderskip
      \advance \temp_dimen \by \topborderskip
      \ifdim \temp_dimen=\merge_height
%
% then the entry can be positioned vertically via a raise statement.  
% The total height of the material output should be equal to the row 
% height, thus acting as a strut.
%
         \temp_dimen=\bottomborderskip
         \advance \temp_dimen \by \dp\temp_box
         \scratch_dimen=\rowheight
         \advance\scratch_dimen by -\temp_dimen
         \ht\temp_box=\scratch_dimen
         \raise \temp_dimen \box\temp_box
      \else % have to do it via a box
         \setbox\temp_box=\vbox \to \rowheight \bgroup
%
% Subtracting merge height - row height from top border skip allows 
% the cell to stick up into the next row by an appropriate amount.
%
            \advance \topborderskip \by \rowheight
            \advance \topborderskip \by -\merge_height
            \vskip \topborderskip
            \box\temp_box
            \vskip \bottomborderskip
            \egroup
         \box\temp_box
      \fi
   \fi
%
% All of the rules are typeset with an overlap of at least pixel width 
% which insures that there will be no gaps.
%
% Typeset the top rule into an hbox and use a raise statement to put 
% it into position.
%
   \ifdim \toprulewidth>\zeropt
      \setbox\temp_box=\hbox \bgroup
         \temp_dimen=\merge_width
         \ifdim \half\leftrulewidth<\pixelwidth
            \kern -\pixelwidth
         \else
            \kern -\half\leftrulewidth
         \fi
         \advance \temp_dimen \by -\lastkern
         \vrule \height \half\toprulewidth
                \depth  \half\toprulewidth
                \width  \temp_dimen
         \ifdim \half\rightrulewidth<\pixelwidth
            \temp_dimen=\pixelwidth
         \else
            \temp_dimen=\half\rightrulewidth
         \fi
         \kern -\temp_dimen
         \vrule \height \half\toprulewidth
                \depth  \half\toprulewidth
                \width  2\temp_dimen
         \egroup
      \wd\temp_box=\zeropt
      \temp_dimen=\rowheight
      \advance\temp_dimen \by -\merge_height
      \ht\temp_box=\temp_dimen
      \dp\temp_box=\merge_height
      \raise \merge_height \box\temp_box
   \fi
%
% Output the bottom rule using the same methods.
%
   \ifdim \bottomrulewidth>\zeropt
      \setbox\temp_box=\hbox \bgroup
         \temp_dimen=\merge_width
         \ifdim \half\leftrulewidth<\pixelwidth
            \kern -\pixelwidth
         \else
            \kern -\half\leftrulewidth
         \fi
         \advance \temp_dimen \by -\lastkern
         \vrule \height \half\bottomrulewidth
                \depth  \half\bottomrulewidth
                \width  \temp_dimen
         \ifdim \half\rightrulewidth<\pixelwidth
            \temp_dimen=\pixelwidth
         \else
            \temp_dimen=\half\rightrulewidth
         \fi
         \kern -\temp_dimen
         \vrule \height \half\bottomrulewidth
                \depth  \half\bottomrulewidth
                \width  2\temp_dimen
         \egroup
      \wd\temp_box=\zeropt
      \dp\temp_box=\zeropt
      \ht\temp_box=\rowheight
      \box\temp_box
   \fi
%
% Test to see if the left inclusive-or right rule width is non-zero.
%
   \ifdim \leftrulewidth=\zeropt
      \temp_dimen=\rightrulewidth
   \else
      \temp_dimen=\leftrulewidth
   \fi
   \ifdim \temp_dimen>\zeropt
      \setbox\temp_box=\hbox \bgroup
         \temp_dimen=\merge_height
         \advance \merge_height \by \pixelwidth
         \ifdim \leftrulewidth>\zeropt
            \kern -\half\leftrulewidth
            \vrule \height \temp_dimen
                   \depth  \pixelwidth
                   \width  \leftrulewidth
         \fi
         \ifdim \rightrulewidth>\zeropt
            \scratch_dimen=\merge_width
            \advance \scratch_dimen \by -\half\leftrulewidth
            \advance \scratch_dimen \by -\half\rightrulewidth
            \kern \scratch_dimen
            \vrule \height \temp_dimen
                   \depth  \pixelwidth
                   \width  \rightrulewidth
         \fi
         \egroup
      \wd\temp_box=\merge_width
      \ht\temp_box=\rowheight
      \dp\temp_box=\zeropt
      \box\temp_box
   \else
      \move_right_via_lastkern \merge_width
   \fi
%
% Cancel the mergers.
%
   \merge_width=\zeropt
   \merge_columns=0
   \ifnum \merge_rows>0
      \add_column_number_data
            {\merge_rows=0\relax\merge_height=\zeropt\relax}%
   \fi
   \ignorespaces
   }%
%
% No surprises here.
%
\def\mergeright {\relax
   \advance \column_number \by 1
   \everycolumn
   \get_column_number_data
   \advance \columnwidth \by \expansion
   \advance \merge_width \by \columnwidth
   \advance \merge_columns \by 1
   \ifnum \merge_rows>0
      \add_column_number_data
            {\merge_rows=0\relax\merge_height=\zeropt\relax}%
   \fi
   }%
%
% No surprises here.
%
\def\mergedown {\relax
   \advance \column_number \by 1
   \everycolumn
   \get_column_number_data
   \advance \columnwidth \by \expansion
   \advance \merge_width \by \columnwidth
   \move_right_via_lastkern \merge_width
   \merge_width=\zeropt
   \merge_columns=0
   \advance \merge_height \by \rowheight
   \let\info=\relax
   \edef\temp{\the\column_number>\info
         {\merge_height=\the\merge_height\relax
         \advance\merge_rows \by 1\relax}}%
   \let\info=\column_info
   \x_after \add_data \temp
   \rowpenalty=10000 % do not allow a break over a row merge.
   }%
%
\catcode`_=8 % Back to normal.
%
\def\noalign#1{\relax
   \vadjust{#1}%
   \ignorespaces
   }%
%
\endinput
SHAR_EOF
if test 10292 -ne "`wc -c Cell4.tex`"
then
echo shar: error transmitting Cell4.tex '(should have been 10292 characters)'
fi
#	End of shell archive
exit 0

-------------------------------------------------------------------------------

%%% The TeXhax digest is brought to you as a service of the TeX Users Group
%%%       in cooperation with the UnixTeX distribution service at the 
%%%                      University of Washington
%%%
%%% Concerning subscriptions, address changes, unsubscribing:
%%%  BITNET: send a one-line mail message to [email-masked]
%%%         SUBSCRIBE TEXHAX <your name>    % to subscribe
%%%
%%%     All others: send mail to
%%%           [email-masked]
%%%     please send a valid internet address!!
%%%        in the form name@domain or name%routing@domain
%%%
%%%
%%% All submissions to: [email-masked]
%%%
%%% Back issues available for FTPing as:
%%%          machine:              directory:  filename:
%%%   JUNE.CS.WASHINGTON.EDU         TeXhax/TeXhaxyy.nn
%%%              yy = last two digits of current year
%%%                       nn = issue number
%%%\bye
%%%

------------------------------

End of TeXhax Digest
**************************
-------