#!/usr/bin/perl
# vim:ft=perl:cindent:ts=8:et:fdm=marker:cms=\ #\ %s
#
# dwww-build -- build HTML pages for dwww
#
# Part of the dwww package. Written by Lars Wirzenius.
# Rewritten in perl by Robert Luberda <robert@debian.org> on Sep, 2003.
#
# "@(#)dwww:$Id: dwww-build,v 1.45 2006-05-07 18:30:06 robert Exp $"
use strict;
use File::Glob ':glob';
use File::Path qw/rmtree mkpath/;
use File::Temp qw/tempfile tempdir/;
use File::NCopy qw/copy/;
use Cwd qw/realpath/;
use IO::Handle;
use Debian::Dwww::Utils;
use Debian::Dwww::Initialize;
use Debian::Dwww::Common;
my $conf = &DwwwInitialize("/etc/dwww/dwww.conf");
my $dwww_lib_dir = "/usr/share/dwww";
my $template_mbs_start = "$dwww_lib_dir/man-in-section.start";
my $template_mbs_end = "$dwww_lib_dir/man-in-section.end";
my $template_mbn_start = "$dwww_lib_dir/man-begins-with.start";
my $template_mbn_end = "$dwww_lib_dir/man-begins-with.end";
my $template_midx_start = "$dwww_lib_dir/man-index.start";
my $template_midx_end = "$dwww_lib_dir/man-index.end";
my $template_index_main = "$dwww_lib_dir/dwww.template";
my $verbose = "no";
if ( "x$ARGV[0]" eq "x--verbose" ) {
$verbose="yes";
shift @ARGV;
}
my ($tgt, $tgttmp) = undef;
if (($#ARGV < 0) or ("x$ARGV[0]" eq "x--default" )) {
$tgt=$conf->{'DWWW_DOCROOTDIR'} . "/dwww";
} else {
$tgt="$ARGV[0]";
}
my $tgtupdir = $conf->{'DWWW_TMPDIR'};
umask 077;
$tgttmp = tempdir('dwww-build.XXXXXX', DIR => "$tgtupdir", CLEANUP => 1);
my $manlist_fh = tempfile('manlist.XXXXX', DIR => "$tgttmp", UNLINK => 0);
undef $tgtupdir;
my $sepr = " // "; # manlist file output separator
umask 022;
my @manpages = ();
my $sections = {};
my $letters = {};
$tgttmp = "$tgttmp/data/";
&mkpath("$tgttmp") or die "Can't create temporary directory: $tgttmp";
&mkpath("$tgttmp/man") or die "Can't create temporary directory: $tgttmp";
&mkpath("$tgttmp/menu") or die "Can't create temporary directory: $tgttmp";
#########################################
#
# MAIN PROGRAM
#
#########################################
STDOUT->autoflush(1);
print "Building dwww pages (a-g):\n";
print " a) list of manual pages... ";
&find_man();
print "done\n";
print " b) list of sections and names... ";
&find_sections_and_letters();
print "done\n";
print " c) manual pages by name... ";
&man_by_name();
print "done\n";
print " d) manual pages by section... ";
&man_by_section();
print "done\n";
print " e) manual pages index... ";
&man_index();
print "done\n";
print " f) front page... ";
&make_front_page();
print "done\n";
print " g) copying files... ";
©("$dwww_lib_dir/*.png", $tgttmp);
# copying menu directory;
( -d "$tgt/menu" ) && ©(\1, "$tgt/menu", $tgttmp);
# rename dirs
&RenameDir($tgttmp, $tgt);
print "done\n";
#
# For wn, special handling is required:
if ( -x "/usr/bin/wndex" ) {
&make_wnindex("$tgt");
&make_wnindex("$tgt/man");
&make_wnindex("$tgt/menu");
}
print "The dwww pages have been re-built.\n";
exit (0);
sub debug() { # {{{
local $_ = shift;
print STDERR "$_\n";
} # }}}
sub GetBTSDocUrl() { # {{{
my $btsdoclocal = "/usr/share/doc/debian/bug-reporting.txt";
my $btsdocexturi = "http://www.debian.org/Bugs/Reporting";
return (-r $btsdoclocal ) ? &GetURL('file', $btsdoclocal) : $btsdocexturi;
} # }}}
sub GetSectionDescription() { # {{{
my $section = shift;
my $desc="";
if ($section eq "1") { $desc="User commands"; }
elsif ($section eq "1a") { $desc="User commands"; } # rss2email
elsif ($section eq "1bind") { $desc="DNS tools"; }
elsif ($section eq "1db") { $desc="Berkeley database routines"; }
elsif ($section eq "1emacs21") { $desc="Emacs 21"; }
elsif ($section eq "1fun") { $desc="Funny man pages"; }
elsif ($section eq "1gmt") { $desc="Generic Mapping Tools"; } # gmt-manpages
elsif ($section eq "1l") { $desc="User commands"; }
elsif ($section eq "1m") { $desc="Ncurses - terminfo utilities"; }
elsif ($section eq "1mh") { $desc="Mh (a mail user agent)"; }
elsif ($section eq "1n") { $desc="Drawmap"; } # drawmap
elsif ($section eq "1nas") { $desc="Network Audio System programs"; }
elsif ($section eq "1netpbm") { $desc="Netpbm (graphics tools)"; }
elsif ($section eq "1osd_clock") { $desc="Clock using the XOSD library"; } # osdclock
elsif ($section eq "1p") { $desc="Perl"; }
elsif ($section eq "1pccts") { $desc="The Purdue Compiler Construction Tool Set"; } # pccts
elsif ($section eq "1pvm") { $desc="Parallel Virtual Machine"; }
elsif ($section eq "1olvwm") { $desc="OpenLook virtual window manager"; } # olvwm
elsif ($section eq "1sr") { $desc="Surfraw"; } # surfraw
elsif ($section eq "1ssl") { $desc="SSL programs"; }
elsif ($section eq "1vga") { $desc="Svgalib programs"; }
elsif ($section eq "1wn") { $desc="WordNet lexical database"; }
elsif ($section eq "1x") { $desc="X Window System programs"; }
elsif ($section eq "2") { $desc="System calls"; }
elsif ($section eq "2fun") { $desc="Funny man pages"; }
elsif ($section eq "3") { $desc="Library functions"; }
elsif ($section eq "3abz") { $desc="Abz library"; } # libabz0-dev
elsif ($section eq "3alleg") { $desc="Allegro library"; } # liballegro-doc
elsif ($section eq "3ber") { $desc="Basic Encoding Rules library"; }
elsif ($section eq "3bind") { $desc="Internet name resolution (DNS) routines"; }
elsif ($section eq "3blt") { $desc="BLT Library"; }
elsif ($section eq "3caca") { $desc="Colour AsCii Art library"; } # libcaca-dev
elsif ($section eq "3cc") { $desc="CommonC++ / Bayonne"; } # libcommoncpp2-dev, bayonne-doc
elsif ($section eq "3curses") { $desc="Ncurses - curses routines"; }
elsif ($section eq "3debug") { $desc="Debug library"; } # libdebug0-dev
elsif ($section eq "3diet") { $desc="Reimplementation of Daniel Bernstein's interfaces"; } # libowfat-dev
elsif ($section eq "3db") { $desc="Berkeley db database routines"; }
elsif ($section eq "3el") { $desc="BSD editline and history libraries"; } # libedit-dev
elsif ($section eq "3erl") { $desc="Erlang programming language"; } # erlang-manpages
elsif ($section eq "3form") { $desc="SVR4 compatible screen forms - ncurses"; }
elsif ($section eq "3fun") { $desc="Funny man pages"; }
elsif ($section eq "3gii") { $desc="General Input Interface library"; }
elsif ($section eq "3ggi") { $desc="General Graphics Interface library"; }
elsif ($section eq "3gdbm") { $desc="GNU dbm database routines"; }
elsif ($section eq "3gle") { $desc="OpenGL tubing and extrusion library"; } # libgle3-dev
elsif ($section eq "3itcl") { $desc="OOP extension for Tcl"; } # itk3.1-doc
elsif ($section eq "3itk") { $desc="OOP extension for Tcl"; } # itk3.1-doc
elsif ($section eq "3iv") { $desc="Open Inventor toolkit"; } # inventor-doc
elsif ($section eq "3iwidgets") { $desc="OOP extension for Tcl [incr Widgets]"; } # iwidgets3.1-doc
elsif ($section eq "3l") { $desc="Langband"; } # langband-engine
elsif ($section eq "3m17n") { $desc="Multilingual text processing library"; } # m17n-docs
elsif ($section eq "3menu") { $desc="Ncurses - SVR4 compatible screen menus"; }
elsif ($section eq "3mm") { $desc="Msql database routines"; }
elsif ($section eq "3nas") { $desc="Network Audio System library"; }
elsif ($section eq "3ncurses") { $desc="Ncurses (terminal screen painting)"; }
elsif ($section eq "3ncp") { $desc="NetWare Core Protocol librabary"; } # libncp-dev
elsif ($section eq "3netpbm") { $desc="Netpbm graphics library"; }
elsif ($section eq "3o") { $desc="Objective Caml library"; } # ocaml-nox, liblablgtk2-ocaml-doc
elsif ($section eq "3ossp") { $desc="OSSP uuid ISO-C"; } # libossp-uuid-dev
elsif ($section eq "3paper") { $desc="Paper handling library"; }
elsif ($section eq "3pm") { $desc="Perl modules"; }
elsif ($section eq "3perl") { $desc="Perl modules"; }
elsif ($section eq "3plplot") { $desc="PLplot, a plotting library"; } # plplot-doc
elsif ($section eq "3pub") { $desc="Lars Wirzenius' publib routines"; }
elsif ($section eq "3pvm") { $desc="Parallel Virtual Machine"; } # pvm-dev
elsif ($section eq "3qt") { $desc="Trolltech's QT library "; }
elsif ($section eq "3readline") { $desc="GNU readline prompt routine"; }
elsif ($section eq "3ruby") { $desc="Ruby Class to use HTML Templates"; } # libhtml-template-ruby
elsif ($section eq "3snmp") { $desc="Simple Network Management Protocol"; } # libsnmp5-dev
elsif ($section eq "3ssl") { $desc="SSL library"; }
elsif ($section eq "3tiff") { $desc="Libtiff graphics library"; }
elsif ($section eq "3tcl") { $desc="Tcl (Tool Command Language) library"; }
elsif ($section eq "3tclrl") { $desc="GNU readline for Tcl library"; }
elsif ($section eq "3tclx") { $desc="TclX (Extended Tcl) library"; }
elsif ($section eq "3tcsh") { $desc="TENEX C Shell (tcsh)"; }
elsif ($section eq "3thr") { $desc="Pthreads library"; }
elsif ($section eq "3tix") { $desc="Tix widget library for Tk"; }
elsif ($section eq "3tk") { $desc="Tk widget library"; }
elsif ($section eq "3tnm") { $desc="Tcl shell including the Tnm extensions"; }
elsif ($section eq "3vga") { $desc="Svgalib library"; }
elsif ($section eq "3x") { $desc="X Window System library"; }
elsif ($section eq "3xp") { $desc="X Print Client library"; }
elsif ($section eq "4") { $desc="Device files"; }
elsif ($section eq "4b") { $desc="Device files"; } # emwin
elsif ($section eq "4x") { $desc="X Window System"; }
elsif ($section eq "5") { $desc="File formats"; }
elsif ($section eq "5bind") { $desc="DNS"; }
elsif ($section eq "5el") { $desc="BSD editline and history libraries"; } # libedit-dev
elsif ($section eq "5fun") { $desc="Funny man pages"; }
elsif ($section eq "5g") { $desc="File formats"; } # sam
elsif ($section eq "5heimdal") { $desc="Heimdal Kerberos"; } # heimdal-docs
elsif ($section eq "5l") { $desc="File formats"; }
elsif ($section eq "5rad") { $desc="Radius server"; } # radiusd-cistron
elsif ($section eq "5mh") { $desc="Mh (mail user agent)"; }
elsif ($section eq "5mm") { $desc="Msql database"; }
elsif ($section eq "5nas") { $desc="Network Audio System"; }
elsif ($section eq "5snmp") { $desc="Net-SNMP library"; }
elsif ($section eq "5ssl") { $desc="SSL library"; }
elsif ($section eq "5vga") { $desc="Svgalib library"; }
elsif ($section eq "5x") { $desc="X Window System file formats"; }
elsif ($section eq "6") { $desc="Games"; }
elsif ($section eq "6fun") { $desc="Funny man pages"; }
elsif ($section eq "6vga") { $desc="Svgalib games"; }
elsif ($section eq "6x") { $desc="X Window System games"; }
elsif ($section eq "7") { $desc="Miscellaneous"; }
elsif ($section eq "7bind") { $desc="DNS terms"; }
elsif ($section eq "7ctrlproxy") { $desc="IRC proxy with multiserver support"; } # ctrlproxy
elsif ($section eq "7g") { $desc="Miscellaneous"; } # sam
elsif ($section eq "7gcc") { $desc="GNU C compiler library"; }
elsif ($section eq "7gii") { $desc="General Input Interface library"; }
elsif ($section eq "7ggi") { $desc="General Graphics Interface library"; }
elsif ($section eq "7ssl") { $desc="SSL library"; }
elsif ($section eq "7vga") { $desc="Svgalib library"; }
elsif ($section eq "7x") { $desc="X Window System"; }
elsif ($section eq "8") { $desc="System administration commands"; }
elsif ($section eq "8bind") { $desc="DNS commands"; }
elsif ($section eq "8fun") { $desc="Funny man pages"; }
elsif ($section eq "8c") { $desc="System administration commands"; } # ipopd, nntp
elsif ($section eq "8l") { $desc="System administration commands"; } # tua
elsif ($section eq "8lvm-10") { $desc="Logical Volume Manager"; } # lvm10
elsif ($section eq "8mailutils") { $desc="Mailutils"; }
elsif ($section eq "8mh") { $desc="Mh (mail user agent)"; }
elsif ($section eq "8p") { $desc="Perl scripts"; }
elsif ($section eq "8postfix") { $desc="Postfix mail transport agent"; }
elsif ($section eq "8rad") { $desc="Radius server"; } # radiusd-cistron
elsif ($section eq "8x") { $desc="X Window System programs"; } # powertweak-gtk, chos
elsif ($section eq "8vga") { $desc="Svgalib library"; }
elsif ($section eq "9") { $desc="Linux kernel functions"; }
elsif ($section eq "9gii") { $desc="General Input Interface library"; }
elsif ($section eq "l") { $desc="Local man pages"; }
elsif ($section =~ /^[0-9]posix$/) { $desc="Posix man pages" ; }
elsif ($section =~ /^[157]wn$/) { $desc="WordNet lexical database" ; }
elsif ($section =~ /^[1-4]rtl$/) { $desc="Real-Timer-Linux" ; }
elsif ($section =~ /^[158]cn$/) { $desc="C News server" ; }
return $desc;
} # }}}
sub GetSectionDescriptionInBrakes() { # {{{
my $section = shift;
my $desc=&GetSectionDescription($section);
my $desc = "($desc)" unless $desc eq "";
return $desc;
} # }}}
# Encodes given $name to be used as a file name or a href name
sub FileEncode() { # {{{
my ($type, $name) = @_;
$name = &URLEncode($name);
$name =~ s/_/%5f/g;
$name =~ s/%/_/g;
return $type . $name;
} # }}}
sub GetIndex() { # {{{
my ($type, $vars) = @_;
my $ret = '';
my @list = ();
my $l = 0;
my $max_l = 65;
foreach my $i ( sort keys %$vars ) {
$l += length($i) + 3;
if ($l > $max_l) {
$ret .= join (' | ', @list) . "<BR>\n";
@list = ();
$l = length($i) + 3;
}
push(@list, '<A href="#' . &FileEncode($type, $i) . '">' . &HTMLEncode($i) . '</A>');
}
$ret .= join (' | ', @list) . "\n" unless $#list < 0;
return $ret;
} # }}}
#
# Find all manual page files.
#
sub find_man() { # {{{
my @manpath = ();
my @manpages = ();
my @mantmp = ();
@manpath = split (/:/ , `manpath -q`);
foreach my $i (@manpath) {
chomp $i;
next if ( "$i" eq "" );
next unless ( -d "$i" );
$i = &realpath($i);
next if ( "$i" eq "");
push(@mantmp, &bsd_glob("$i/man*/*", GLOB_MARK|GLOB_NOSORT));
}
foreach my $index (0 .. $#mantmp) {
$_ = $mantmp[$index];
next unless (-f $_);
s/\.(gz|Z|bz2)$//;
next unless (m;^.*man([1-9nl])/([^/])([^/]*)\.(\1[^./]*)$;);
push(@manpages, join( $sepr, lc($4), uc($2), "$2$3", &URLEncode($mantmp[$index])));
};
@mantmp = undef;
@manpages = sort { uc($a) cmp uc($b) } @manpages;
seek ($manlist_fh, 0, 0);
foreach (@manpages) {
print $manlist_fh $_ . "\n";
}
$manlist_fh -> flush();
} # }}}
#
# Output a list of sections.
#
sub find_sections_and_letters() { # {{{
seek ($manlist_fh, 0, 0);
while (<$manlist_fh>){
chomp;
my ($section, $letter, undef, $path) = split ($sepr, $_, 4);
$sections->{$section}->{$letter} = 1;
$letters->{$letter}->{$section} = 1;
}
} # }}}
#
# Build lists of manual pages according to first letter.
###
sub man_by_name() { # {{{
my $type = 'n';
foreach my $letter ( keys( %$letters ) ) {
open M, ">$tgttmp/man/" . &FileEncode($type, $letter) . ".html";
print M &TemplateFile($template_mbn_start,
{ 'TITLE' => $conf->{'DWWW_TITLE'},
'LETTER' => &HTMLEncode($letter),
'HREFLETTER' => &FileEncode($type, $letter),
'SECTIONS' => &GetIndex('s', $letters->{$letter})
});
close M;
}
my %lastsections = ();
my %tables = ();
my $lastletter = '';
seek ($manlist_fh, 0, 0);
while (<$manlist_fh>) {
chomp();
my ($section, $letter, $name, $file) = split ($sepr, $_, 4);
if ($lastletter ne $letter) {
if ($lastletter ne '') {
&EndTable(\*M, $tables{$lastletter});
close M;
}
open M, ">>$tgttmp/man/" . &FileEncode($type, $letter) . ".html";
$lastletter = $letter;
}
if ((not exists $lastsections{$letter}) or
($lastsections{$letter} ne $section)) {
my $capt='<A name="' . &FileEncode('s', $section) . '">' .
"- in section " . &HTMLEncode($section) . "</A>";
my $desc = &GetSectionDescriptionInBrakes($section);
$capt .= ":" if $desc eq '';
$desc = " ${desc}:" if $desc ne '';
$tables{$letter} = &BeginTable(\*M, $capt, 4, $desc);
$lastsections{$letter} = $section;
}
&AddToTable(\*M, $tables{$letter}, "<A href=\"" . &GetURL('man', $file, $TRUE) . "\">" . &HTMLEncode($name) . "</A>");
}
if ($lastletter ne '') {
&EndTable(\*M, $tables{$lastletter});
close M;
}
foreach my $letter ( keys( %$letters ) ) {
open M, ">>$tgttmp/man/" . &FileEncode($type, $letter) . ".html";
print M &TemplateFile($template_mbn_end,
{ 'TITLE' => $conf->{'DWWW_TITLE'},
'SECTIONS' => &GetIndex('s', $letters->{$letter})
});
close M;
}
} # }}}
#
# Build lists of manual pages according to section
###
sub man_by_section() { # {{{
my $type = 's';
my $section = undef;
# Start a file for each section
foreach $section ( keys( %$sections ) ) {
open M, ">$tgttmp/man/" . &FileEncode($type, $section) . ".html";
print M &TemplateFile($template_mbs_start,
{ 'TITLE' => $conf->{'DWWW_TITLE'},
'SECTION' => &HTMLEncode($section),
'SECTIONDESC' => &GetSectionDescriptionInBrakes($section),
'HREFSECTION' => &FileEncode($type, $section),
'LETTERS' => &GetIndex('n', $sections->{$section})
});
close M;
}
my $table = undef;
my $lastsection = '';
my $lastletter = '';
seek ($manlist_fh, 0, 0);
while (<$manlist_fh>) {
chomp();
my ($section, $letter, $name, $file) = split ($sepr, $_, 4);
# Note that records are sorted by section
# and for each section - by the letter
if ($lastsection ne $section) {
if (defined $table) {
&EndTable(\*M, $table);
close M;
}
open M, ">>$tgttmp/man/" . &FileEncode($type, $section) . ".html";
$lastsection = $section;
$lastletter = '';
$table = undef;
}
if ($lastletter ne $letter) {
my $capt='<A name="' . &FileEncode('n', $letter) . '">' .
"- starting with " . &HTMLEncode($letter) . ":</A>";
if (defined $table) {
&EndTable(\*M, $table);
}
$table = &BeginTable(\*M, $capt, 4);
$lastletter = $letter;
}
die ('Internal error: $table should be defined! ($file=' . $file .')')
unless (defined $table);
&AddToTable(\*M, $table, "<A href=\"" . &GetURL('man', $file, $TRUE) . "\">" . &HTMLEncode($name) . "</A>");
}
if ($lastsection ne '') {
if (defined $table) {
&EndTable(\*M, $table);
}
close M;
}
foreach $section ( keys( %$sections ) ) {
open M, ">>$tgttmp/man/" . &FileEncode($type, $section) . ".html";
print M &TemplateFile($template_mbs_end,
{ 'TITLE' => $conf->{'DWWW_TITLE'},
'LETTERS' => &GetIndex('n', $sections->{$section})
});
close M;
}
} # }}}
sub man_index() { # {{{
open M, ">>$tgttmp/man/index.html";
print M &TemplateFile($template_midx_start,
{ 'TITLE' => $conf->{'DWWW_TITLE'},
});
my $table = &BeginTable(\*M, '<A name="n">Man pages by first letter:</A>', 8, '', [3,3,3,3,3,3,3,'*']);
foreach my $letter ( sort keys( %$letters ) ) {
my $fname = &FileEncode('n', $letter);
&AddToTable(\*M, $table, "<A name=\"$fname\" href=\"$fname.html\">"
. &HTMLEncode($letter) . "</A>");
}
&EndTable(\*M, $table);
print M "<BR><HR><BR>\n";
$table = &BeginTable(\*M, '<A name="s">Man pages by section:</A>', 3, '', [4, 10, '*']);
my $lastsectionbase = "";
my $sectionbase = "";
foreach my $section ( sort keys( %$sections ) ) {
$sectionbase = substr($section, 0, 1);
if ($sectionbase ne $lastsectionbase)
{
if ($lastsectionbase ne "") {
# empty row separating sections
&AddToTable(\*M, $table, ' ');
&AddToTable(\*M, $table, '');
&AddToTable(\*M, $table, '');
}
if ($sectionbase ne $section) {
&AddToTable(\*M, $table, '<B>' . &HTMLEncode($sectionbase) . '</B>');
&AddToTable(\*M, $table, '');
&AddToTable(\*M, $table, '<B>' . &GetSectionDescription($sectionbase.'</B>'));
}
$lastsectionbase = $sectionbase;
}
my $desc = &GetSectionDescription($section);
my ($bs, $be) = undef;
if ($sectionbase eq $section) {
$bs = '<B>';
$be = '</B>';
} else {
$bs = '';
$be = '';
$desc = ' ' . $desc unless $desc eq '';
&AddToTable(\*M, $table, '');
}
my $fname = &FileEncode('s', $section);
&AddToTable(\*M, $table, "<A name=\"$fname\" href=\"$fname.html\">"
. $bs . &HTMLEncode($section) . $be . "</A>");
&AddToTable(\*M, $table, '') if ($sectionbase eq $section);
&AddToTable(\*M, $table, $bs . $desc . $be);
}
&EndTable(\*M, $table);
print M &TemplateFile($template_midx_end,
{ 'BTSDOCURL' => &GetBTSDocUrl()
});
} # }}}
#
# Create the front page.
#
sub make_front_page() { # {{{
open M, ">$tgttmp/index.html" or die "Cannot open file $tgttmp/index.html: $!";
print M &TemplateFile($template_index_main,
{ 'TITLE' => $conf->{'DWWW_TITLE'},
'BTSDOCURL' => &GetBTSDocUrl()
});
close M;
} # }}}
# This is a special routine for the wn webserver
#
sub make_wnindex # {{{
{
my $dir = shift;
chdir("$dir");
if ( ! -e "index" ) {
open I, ">index";
print I "Attribute=serveall\n";
close I;
}
&system("/usr/bin/wndex >/dev/null");
} # }}}