--- lib/TWiki.pm.orig	2003-01-08 02:05:11.000000000 -0500
+++ lib/TWiki.pm	2003-01-17 02:38:51.000000000 -0500
@@ -2198,48 +2198,132 @@
 
     return $result;
 }
 
-# =========================
+# ========================
+sub initTableData {
+    my ( $tableData ) = @_;
+    %$tableData = ("rows"=>[], "cols"=>[], "rowspan"=>[]);
+}
+
+# ========================
 sub emitTR {
-    my ( $thePre, $theRow, $insideTABLE ) = @_;
+    my ( $row ) = @_;
+
+    my $result = "<tr>";
+    foreach my $col (@$row) {
+        my $tag = $$col{"tag"};
+        my $attr = $$col{"attr"};
+        my $text = $$col{"text"};
+        if ($tag) {
+            $result .= "<$tag$attr> $text </$tag>";
+        }
+    }
+    $result .= "</tr>\n";
+
+    return $result;
+}
+
+# ========================
+sub doTableRowspan {
+    my ( $rows, $span, $col ) = @_;
+
+    my $numRows = scalar(@$rows);
+    $$rows[$numRows - $span][$col]{"attr"} .= " rowspan=\"$span\"";
+}
+
+# ========================
+sub flushTable {
+    my ( $tableData ) = @_;
+
+    my $rows = $$tableData{"rows"};
+    my $rowspan = $$tableData{"rowspan"};
+
+    for(my $i = 0; $i < @$rowspan; $i++) {
+        if ($$rowspan[$i] > 0) {
+            my $span = $$rowspan[$i]+1;
+            doTableRowspan($rows, $span, $i);
+        }
+    }
+    
+    my $result = "";
+    foreach my $row (@$rows) {
+        $result .= emitTR($row);
+    }
+    $result .= "</table>\n";
+    initTableData($tableData);
+    return $result;
+}
+
+# ========================
+sub processTR {
+    my ( $thePre, $theRow, $insideTABLE, $tableData ) = @_;
 
     my $text = "";
-    my $attr = "";
-    my $l1 = 0;
-    my $l2 = 0;
-    if( $insideTABLE ) {
-        $text = "$thePre<tr>";
-    } else {
-        $text = "$thePre<table border=\"1\" cellspacing=\"0\" cellpadding=\"1\"> <tr>";
+    unless( $insideTABLE ) { # start a new table if necessary
+        $text .= "<table border=\"1\" cellspacing=\"0\" cellpadding=\"1\"> ";
     }
     $theRow =~ s/\t/   /g;  # change tabs to space
     $theRow =~ s/\s*$//;    # remove trailing spaces
     $theRow =~ s/(\|\|+)/$TranslationToken . length($1) . "\|"/ge;  # calc COLSPAN
+
+    my $colnum = 0;
+    my $rowData = [];
+    my $rows = ${$tableData}{"rows"};
+    
     foreach( split( /\|/, $theRow ) ) {
-        $attr = "";
+        my $l1 = 0;
+        my $l2 = 0;
+        my $attr = "";
+        my $colData = {};
+        my $colInc = 1;
         #AS 25-5-01 Fix to avoid matching also single columns
         if ( s/$TranslationToken([0-9]+)// ) { # No o flag for mod-perl compatibility
             $attr = " colspan=\"$1\"" ;
+            $colInc = $1;
         }
-        s/^\s+$/ &nbsp; /;
-        /^(\s*).*?(\s*)$/;
-        $l1 = length( $1 || "" );
-        $l2 = length( $2 || "" );
-        if( $l1 >= 2 ) {
-            if( $l2 <= 1 ) {
-                $attr .= ' align="right"';
+        if (/^\s*\^\s*$/) {
+            $$tableData{"rowspan"}[$colnum]++;
+        } else {
+            for (my $c = $colnum; $c < ($colnum+$colInc); $c++) {
+                if ($$tableData{"rowspan"}[$c]) {
+                    my $span = $$tableData{"rowspan"}[$c] + 1;
+                    $$tableData{"rowspan"}[$c] = 0;
+                    doTableRowspan($rows, $span, $c);
+                }
+            }
+            s/^\s+$/ &nbsp; /;
+            /^(\s*).*?(\s*)$/;
+            $l1 = length( $1 || "" );
+            $l2 = length( $2 || "" );
+            if( $l1 >= 2 ) {
+                if( $l2 <= 1 ) {
+                    $attr .= ' align="right"';
+                } else {
+                    $attr .= ' align="center"';
+                }
+            }
+            if( /^\s*(\*.*\*)\s*$/ ) {
+                $$colData{"text"} = $1;
+                $$colData{"tag"} = "th";
+                $$colData{"attr"} = $attr . " bgcolor=\"#99CCCC\"";
             } else {
-                $attr .= ' align="center"';
+                $$colData{"text"} = $_;
+                $$colData{"tag"} = "td";
+                $$colData{"attr"} = $attr;
             }
+            $$rowData[$colnum] = $colData;
         }
-        if( /^\s*(\*.*\*)\s*$/ ) {
-            $text .= "<th$attr bgcolor=\"#99CCCC\"> $1 </th>";
-        } else {
-            $text .= "<td$attr> $_ </td>";
-        }
+        $colnum+=$colInc;
+    }
+    push @$rows, $rowData;
+    my $maxSpan = 0;
+    foreach my $span (@{$$tableData{"rowspan"}}) {
+        $maxSpan = $span if $span > $maxSpan;
+    }
+    while ($maxSpan < (@$rows-1)) {
+        $text .= emitTR(shift @$rows);
     }
-    $text .= "</tr>";
     return $text;
 }
 
 # =========================
@@ -2475,9 +2559,10 @@
 
 # =========================
 sub getRenderedVersion {
     my( $text, $theWeb, $meta ) = @_;
-    my( $head, $result, $extraLines, $insidePRE, $insideTABLE, $insideNoAutoLink );
+    my( $head, $result, $extraLines, $insidePRE, $insideTABLE,
+        $insideNoAutoLink, $noParagraphTag, %tableData );
 
     return "" unless $text;  # nothing to do
 
     # FIXME: Get $theTopic from parameter to handle [[#anchor]] correctly
@@ -2496,8 +2581,9 @@
     $insideNoAutoLink = 0;      # PTh 02 Feb 2001: Added Codev.DisableWikiWordLinks
     $isList = 0;
     @listTypes = ();
     @listElements = ();
+    initTableData(\%tableData);
 
     # Initial cleanup
     $text =~ s/\r//g;
     $text =~ s/(\n?)$/\n<nop>\n/s; # clutch to enforce correct rendering at end of doc
@@ -2594,17 +2680,21 @@
 
 # Table of format: | cell | cell |
             # PTh 25 Jan 2001: Forgiving syntax, allow trailing white space
             if( $_ =~ /^(\s*)\|.*\|\s*$/ ) {
-                s/^(\s*)\|(.*)/&emitTR($1,$2,$insideTABLE)/e;
+                s/^(\s*)\|(.*)/processTR($1,$2,$insideTABLE,\%tableData)/e;
                 $insideTABLE = 1;
+                $noParagraphTag = 1;
             } elsif( $insideTABLE ) {
-                $result .= "</table>\n";
+                $_ = flushTable(\%tableData) . $_;
                 $insideTABLE = 0;
             }
 
 # Lists and paragraphs
-            s/^\s*$/<p \/>/o                 && ( $isList = 0 );
+            unless ($noParagraphTag) {
+                s/^\s*$/<p \/>/o             && ( $isList = 0 );
+            }
+            $noParagraphTag = 0;
             m/^(\S+?)/o                      && ( $isList = 0 );
             s/^(\t+)(\S+?):\s/<dt> $2<\/dt><dd> /o && ( $result .= &emitList( "dl", "dd", length $1 ) );
             s/^(\t+)\* /<li> /o              && ( $result .= &emitList( "ul", "li", length $1 ) );
             s/^(\t+)\d+\.? ?/<li> /o         && ( $result .= &emitList( "ol", "li", length $1 ) );
