diff --git a/tools/progdoc b/tools/progdoc
new file mode 100755
index 00000000..ebb97db3
--- /dev/null
+++ b/tools/progdoc
@@ -0,0 +1,77 @@
+#!/usr/bin/perl
+
+$srcdir = $ARGV[0];
+
+open(OUT, ">prog/index.html") || die "Cannot create output file";
+html_header(*OUT{IO}, "BIRD: The Developer's Guide");
+print OUT "
BIRD: The Developer's Guide
\n";
+print OUT "\n";
+process("");
+html_footer(*OUT{IO});
+print OUT "
\n";
+close OUT;
+exit 0;
+
+sub process {
+ my $dir = shift @_;
+ print "$dir/Doc\n";
+ open(IN, "$srcdir/$dir/Doc") || die "Unable to read $dir/Doc";
+ my @docfile = ;
+ my @stack = ();
+ close IN;
+ push @docfile, "X\n";
+ foreach $_ (@docfile) {
+ chomp;
+ /^#/ && next;
+ /^(\.*)([A-Z]+)\s*(.*)/ || die "Parse error: $_";
+ $indent = length $1;
+ $cmd = $2;
+ $arg = $3;
+ while (@stack > $indent) {
+ $x = pop @stack;
+ if ($x eq "H") { print OUT "\n"; }
+ elsif ($x eq "F") { html_footer(*AUX{IO}); close AUX; }
+ else { print STDERR "Unknown stack element $x\n"; }
+ }
+ (@stack == $indent) or die "Invalid nesting: $_";
+ if ($cmd eq "C") { process("$dir/$arg"); }
+ elsif ($cmd eq "H") {
+ push @stack, "H";
+ print OUT "$arg";
+ print OUT "\n";
+ } elsif ($cmd eq "F") {
+ $arg =~ /^(\S+)\s+(.*)$/ || die "Invalid command: $_";
+ push @stack, "F";
+ print " $1\n";
+ open(AUX, ">prog/$1.html") || die "Unable to create output file";
+ print OUT "- $2\n";
+ html_header(*AUX{IO}, "BIRD: $2");
+ } elsif ($cmd eq "S") {
+ print " $arg\n";
+ open(DOC, "cd $srcdir/$dir ; $srcdir/doc/kernel-doc -html $arg |") || die "Unable to start kernel-doc";
+ while () { print AUX; }
+ close DOC;
+ } elsif ($cmd eq "X") {
+ } else { die "Unknown command: $cmd"; }
+ }
+}
+
+sub html_header {
+ my $out = shift @_;
+ my $title = shift @_;
+ print $out <
+$title
+
+
+EOF
+;
+}
+
+sub html_footer {
+ my $out = shift @_;
+ print $out <
+EOF
+;
+}