#!/usr/bin/env perl
# $Id: script-csv2html.html,v 1.2 2020/08/17 17:44:19 tom Exp $
# -----------------------------------------------------------------------------
# Copyright 2014-2016,2020 by Thomas E. Dickey
#
# All Rights Reserved
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Except as contained in this notice, the name(s) of the above copyright
# holders shall not be used in advertising or otherwise to promote the
# sale, use or other dealings in this Software without prior written
# authorization.
# -----------------------------------------------------------------------------
# Read a CSV (comma-separated-values) file, and generate an HTML table.
use warnings;
use strict;
use Getopt::Std;
use Text::CSV;
$| = 1;
our ( $opt_b, $opt_d, $opt_o, $opt_u, $opt_R, $opt_W );
our %all_data;
sub cell_of($$) {
my @cols = @{ $_[0] };
my $cell = $_[1];
return ( $cell <= $#cols ) ? $cols[$cell] : "";
}
sub do_file($) {
my $filename = shift;
my $csv = Text::CSV->new( { binary => 1 } ) # should set binary attribute.
or die "Cannot use CSV: " . Text::CSV->error_diag();
my @rows;
my $wide = -1;
open my $fh, "<:encoding(utf8)", $filename or die "$filename: $!";
my $r = 0;
while ( my $row = $csv->getline($fh) ) {
my @cols = @$row;
if ($opt_d) {
for my $c ( 0 .. $#$row ) {
printf STDERR "%d.%d:%s\n", $r, $c, $cols[$c];
}
}
$wide = $#cols if ( $#cols > $wide );
$rows[ $r++ ] = \@cols;
}
$csv->eof or $csv->error_diag();
close $fh;
print <<EOF;
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
<title>generated table from $filename</title>
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
EOF
my $style = 1 if ( $opt_R or $opt_W );
printf "<style>\n", if ($style);
if ($opt_W) {
print <<EOF;
th.rotate {
/* Something you can count on */
height: 140px;
white-space: nowrap;
}
th.rotate > div {
transform:
/* Magic Numbers */
translate(25px, 51px)
/* 45 is really 360 - 45 */
rotate(315deg);
width: 30px;
}
th.rotate > div > span {
border-bottom: 1px solid #ccc;
padding: 5px 10px;
}
EOF
if ($opt_R) {
print <<EOF;
td {
text-align: right;
}
td.left {
text-align: left;
}
th.bottom {
vertical-align: bottom;
}
EOF
}
}
printf "</style>\n", if ($style);
print <<EOF;
</head>
<body>
EOF
printf "<table "
. "border=\"%d\" "
. "summary=\"%d-column table generated from $filename\">\n",
( $opt_b ? 1 : 0 ), $wide;
my $mark = 0;
for my $y ( 0 .. $#rows ) {
my @cols = @{ $rows[$y] };
my $row = ( $y == 0 ? "th" : "td" );
# given a "." in first column, draw a line across table
if ( $y > 0 and &cell_of( $rows[$y], 0 ) eq "." ) {
printf "<tr style=\"border-bottom:1px solid black\">"
. "<td colspan=\"%d\">" . "</td>"
. "</tr>\n", ( $wide + 1 );
printf "<!-- draw a line, row %d of %d -->\n", $y + 1, $#rows + 1;
$mark = $y;
next;
}
printf "<tr>\n";
for my $x ( 0 .. $wide ) {
if ( ( $x > $#cols ) or ( $cols[$x] eq "" ) ) {
my $span = 0;
if ( $y <= ( $mark + 1 )
or &cell_of( $rows[ $y - 1 ], $x ) ne "" )
{
for my $z ( $y .. $#rows ) {
# a "." in first column marks a dividing line
last if ( &cell_of( $rows[$z], 0 ) eq "." );
if ( &cell_of( $rows[$z], $x ) eq "" ) {
++$span;
}
else {
last;
}
}
$span = 1 if ( $span == 0 );
}
if ( $span > 1 ) {
printf "<%s rowspan=%d>\n", $row, $span;
printf "</%s>\n", $row;
}
elsif ( $span == 1 ) {
printf "<%s>\n", $row;
printf "</%s>\n", $row;
}
}
elsif ( $opt_W and $row eq "th" ) {
printf "<th class=\"%s\"><div><span>%s</span></div></th>\n",
$x == 0 ? "bottom" : "rotate", $cols[$x];
}
else {
if ( $opt_R and $row eq "td" and $x == 0 ) {
printf "<%s class=\"left\">\n", $row;
}
else {
printf "<%s>\n", $row;
}
printf "%s\n", $cols[$x];
printf "</%s>\n", $row;
}
}
printf "</tr>\n";
}
print <<EOF;
</table>
</body>
</html>
EOF
}
sub main::HELP_MESSAGE() {
printf <<EOF;
Usage: $0 [options] [file1 [file2 [...]]]
Options:
-b make table have a border
-d debug (trace to STDERR)
-o FILE write data to output file
-u assume input-data is unquoted, as from compare-fkeys
-R right-align data except first cell on each line
-W format headers for wide-table
EOF
}
$Getopt::Std::STANDARD_HELP_VERSION = 1;
&getopts('bdo:RuW');
if ($opt_o) {
open OUT, ">$opt_o" or die "Cannot open $opt_o";
select OUT;
}
if ( $#ARGV >= 0 ) {
while ( $#ARGV >= 0 ) {
&do_file( shift @ARGV );
}
}
else {
die "No filename given";
}
1;