I ended up looking at three possible solutions, all in Perl.
All three use Text::CSV as a base, to read in the CSV.
Before I settled on a prepared Table package, I just tried doing it manually.  This was straightforward, but a little tedious.  I had to manually determine max field lengths and draw the required pieces.  Even so, a well-spaced Perl script doing this only took 78 lines.
I then looked at the Perl Text::Table package, at http://search.cpan.org/~shlomif/Text-Table-1.131/lib/Text/Table.pm .  From a very quick look, this looked like what I needed.  However, what I discovered is that I really didn't understand the documentation, and the examples didn't help.  I gave up on this.
I then discovered Text::ASCIITable, at http://search.cpan.org/~lunatic/Text-ASCIITable-0.20/lib/Text/ASCIITable.pm .  There were enough examples showing what I needed to do so that it was easy to build the script I needed.  The only problem I ran into was that the "draw()" method didn't appear to work (did nothing), although just "print $table" worked fine.  The resulting solution was only 31 lines long.
This is the entire script:
#! /bin/perl
use strict;
use Text::CSV;
use Text::ASCIITable;
my $csv = Text::CSV->new();
my $filename = shift @ARGV;
my $fh;
if (defined $filename) {
    open $fh, "<$filename";
}
else {
    $fh = *STDIN;
}
my $asciitable  = Text::ASCIITable->new();
$asciitable->setOptions('reportErrors', 1);
my $firstRow = $csv->getline($fh);
my @firstRowFields = @$firstRow;
my $numColumns = $#firstRowFields + 1;
$asciitable->setCols(@firstRowFields);
while (my $row = $csv->getline($fh)) {
    $asciitable->addRow($row);
}
print $asciitable;
exit(0);