#! /usr/bin/perl -w
use strict;

# Copyright (c) 2001, 2002 Ognyan Kulev <ogi@fmi.uni-sofia.bg>.
# 
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# The GNU General Public License text can be found at
# http://www.gnu.org/copyleft/gpl.txt
#
# 2001-06-26
#	Initial version 1.0.  Supports plain text, HTML and
#	a page for each question (fancy html).
# 2001-09-26  Marcus Brinkmann <marcus@gnu.org>
#	Modify the format of the web pages to match the Hurd web site.
#	This lead to some changes in the code as well.
# 2001-10-25  Lars Weber <me@lars.in-berlin.de>
#	Made localization of the "Table of Contents" heading possible
#	by introducing the new directive toc-header.

=head1 NAME

gen-faq.pl - generating FAQ

=head1 SYNOPSIS

 gen-faq.pl FAQ-FILE text > TEXT-FILE
 gen-faq.pl FAQ-FILE html > HTML-FILE
 gen-faq.pl FAQ-FILE html fancy DIRECTORY

=head1 DESCRIPTION

This is a program to convert FAQ to plain text, one html file or a
web of html pages.

=head2 Paragraphs

The whole text is a sequence of I<paragraphs>.  Each paragraph is
separated with others by empty line(s).  The only exception of this
rule is that lines starting with C<*> or C<-> followed by space mark a
new paragraph.  (These are the list item paragraphs.)

=head2 Directives    

Before the text is split into paragraphs, all directives
C<?{NAME=VALUE}> are processed.  These directives are not shown in any
output.  They must be the first thing in the line.  Currently there
are three directives recognized:

=over

=item C<?{charset=VALUE}>

This is the charset that is stored in the META element of all html. 
Useful for translations of the FAQ.

=item C<?{title-prefix=VALUE}>

When FAQ is stored in multiple html files, this text is prefix for all
titles of pages.

=item C<?{toc-header=VALUE}>

This defines a replacement header for the table of contents, which is
mostly useful for translating it into a different language.  (It only
helps for single file output, though.)

=back

=head2 Structure

Second special syntax is for the C<^L> character.  It is used to
separate the parts of the FAQ.  A FAQ is expected to look like this:

    TITLE (the first paragraph)
    TOP TEXT (what is this FAQ for, etc)
    ^L
    QUESTIONS
    ^L
    BOTTOM TEXT (who contribute, etc)
    ^L
    (the rest is ignored)

=head2 Sections and questions

I<Questions> are grouped into I<sections>.  Paragraph that start with
C<?> followed by space is considered start of a new section.  The
content of the paragraph is the name of the section.  Paragraph that
start with C<??> followed by tab is considered question.
Optionally after the C<??> you can put identifier (sequence of
alpha-numeric characters) that can be used
elsewhere to refer to this question.  The rest of the lines of
question must start with tab.  This is needed for better plain text
output.  After the question all ordinary text is considered answer to
this question. 

=head2 Paragraphs

They can contain hyperlinks to http and ftp resources.  E-mails are
recognized too.  All occurences of C<?IDENTIFIER> are replaced with
link to the question with this IDENTIFIER.

=head2 Verbatim paragraphs

Each line of them must start with at least 3 spaces (or tab).  Useful
for programs.

=head2 List paragraphs

Making lists is easy.  Every list item is a paragraph that start with
C<-> or C<*> followed by space.  You can write list items without
blank lines between them.  If you want to have a list item with many
paragraphs, each line of the paragraphs must be prefixed by 2 spaces.
If a line doesn\'t have 2 spaces it is considered out of the list
item.  You can verbatim paragraphs too.  All is summarized in the
following example:

	|* First item
	|* Second item.
	|  Second line of the second item.
	|
        |  Second paragraph of the second item.
	|
	|	Verbatim paragraph of the second item.
	|* Third item.
	|
	|	Verbatim paragraph of the third item.
        |
	|Paragraph out of the list.

=head2 History

This program is a rewrite by Ognyan Kulev
(http://debian.fmi.uni-sofia.bg/~ogi/) of a similar program
by Andreas Jaeger (http://www.suse.de/~aj/) that was used
to convert GNU C Library FAQ to HTML.  His program was a hack
of a program in the GNU C Library that converts glibc FAQ to
plain text with Table Of Content.

The license is GPL.

=cut
    ;
    
# THE NOTES BELOW ARE OLD.  SEE THE POD.

# First all directives ?{name=content} are found, processed and removed.
# The one directive for now is `charset'.
# Text is split into parts by two ^L: top, questions, bottom.
# After the third ^L all is ignored.
# Text is split into paragraphs.  The first paragraph is the title.
# Paragraphs begin with `\n?[?[keyword]] ',
# `[-|*] ', `\n {4,}', '\n{author[,author...]} ' or `\n'.
# Sections and questions go to special arrays.  The rest are ordered
# and belong to answer.
# In the text the following is transformed:
# `\'		-> `\\'
# `{'		-> `\{'
# `}'		-> `\}'
# `?keyword'	-> `{ref=keyword}'
# `name@domain'	-> `{mail=name@domain}'
# `http://...'	-> `{href=url}'
# `ftp://...'	-> `{href=url}'
#
# Sections are rendered to `SECTION. PARAGRAPH'.
# Questions are rendered to `SECTION.QUESTION.\tPARAGRAPH'

sub usage {
    print STDERR
    "Usage: gen-faq.pl FAQ-FILENAME OUTPUT-FORMAT
(text in square brackets is optional)
where OUTPUT-FORMAT is one of the following:
	text
	xhtml [fancy DIRECTORY]
";
    exit 1;
}    

use vars qw($charset $linenum $TEXT_WIDTH
	    $partnum $sectionnum $questionnum
	    $title @content %ref $tochead
	    $para $lastpara $item $dir $prefix);

$TEXT_WIDTH	= 72;

########################################################################
# Read the FAQ file

if ($#ARGV < 1) { usage; }
open IN, $ARGV[0];

$prefix		= "";
$tochead	= "";
$dir		= "";
$charset	= "";
$linenum	= 0;
$partnum	= 0;
$sectionnum	= 0;
$questionnum	= 0;
$title		= "";
@content	= ();		# list of all paragraphs
%ref		= ();		# $hash{"$SECTION.$QUESTION"}
$para		= "";
$lastpara	= "";
while (<IN>) {
    $linenum++;
    &process_line;
}
$partnum	= 0;
$_		= "";
&process_line;

sub process_line {

    # Process directives
    if (/^\?\{([-\w]+)=(.*?)\}/) {
	if ($1 eq "charset") {
	    $charset	= $2;
	} elsif ($1 eq "title-prefix") {
	    $prefix	= $2;
	} elsif ($1 eq "toc-header") {
	    $tochead	= $2;
	} else {
	    print STDERR "line $linenum: Unknown directive \`$1'\n";
	}
	s/^.*?\}//;		# cut the directive
    }

    return if $partnum > 2;

    # Parts: 0=top, 1=questions, 2=bottom, rest is ignored
    if (/\f/) {
	s/\f//;
	if (/\f/) {
	    print STDERR "line $linenum: Illegal use of parts";
	    s/\f//g;
	}
	$partnum++;
	push @content, "bottom:"	if $partnum == 2;
	return				if $partnum > 2;
    }
    
    # End of paragraph
    my $line	= $_;
    if ($para ne "" && (/^\s*$/ || /^[*-]\s/)) {
	# Escape special characters
	$para	=~ s/\\/\\\\/g;
	$para	=~ s/\{/\\{/g;
	$para	=~ s/\}/\\}/g;
	# Disable references:
	#$para	=~ s/(\W)\?(\w+)/$1\{ref=$2\}/g;
	$para	=~ s/(\W)(\w[\w.-]+\@[\w-]+(\.[\w-]+)+)/$1\{mail=$2\}/g;
	$para
	    =~ s/(\W)((ftp|http):\/\/[^.)>\s]+(\.[^.)>\s]+)*)/$1\{href=$2\}/g;
	# Store the paragraph and prepare for the next one
        if ($title) {
            push @content, $para;
	} else {
	    $title	= $para;
	}
	$lastpara	= $para;
	$para		= "";
    }
    $_	= $line;

    # Start of section
    if ($para eq "" && /^\?\s/) {
	s/^\?\s+//;
	$para		= "section ".++$sectionnum.":".$_;
	$questionnum	= 0;
    }
    # Start of question
    elsif ($para eq "" && /^\?\?(\w*)/) {
	$questionnum++;
	if ($1 ne "") {
	    $ref{$1}	= "$sectionnum.$questionnum";
	}
	s/^\?\?\w*//;
	$para	= "question $sectionnum.$questionnum:".$_;
    }
    # Start of list item
    elsif (/^[*-]\s/) {
	$para		= "item-start:".$_;
    }
    # Start of verbatim paragraph
    elsif (/^(\t|\s{3,})/) {
	if ($para eq "") {
	    if (substr($lastpara,0,4) eq "item") {
		$para	= "item-verbatim:";
	    } else {
		$para	= "verbatim:";
	    }
	}
        $para	.= $_;
    }
    elsif (/\S/) {
	if ($para eq "") {
	    if (substr($lastpara,0,4) eq "item" && /^\s/) {
		$para	= "item-normal:";
	    } else {
		$para	= "normal:";
	    }
	}
	$para	.= $_;
    }
}

sub output_text;
sub output_xhtml;
sub output_xhtml_fancy;

if	($ARGV[1] eq "text" && $#ARGV == 1) { output_text; }
elsif	($ARGV[1] eq "html") {
    if		($#ARGV == 1) { output_xhtml; }
    elsif	($#ARGV == 3 && $ARGV[2] eq "fancy") {
	output_xhtml_fancy ($ARGV[3]);
    } else { usage; }
} else { usage; }

########################################################################
# Text output

sub output_text_text {
    $_		= " ".$_[0];	# Begin with space to easen REs.
    # Replace references
    while (/[^\\]\{ref=(\w+)\}/) {
	my $keyword	= $1;
	my $answer	= $ref{$keyword};
	s/([^\\])\{ref=$keyword\}/$1Q$answer/g;
    }
    # Replace mail addresses and URLs
    s/([^\\])\{(mail|href)=(.*?)\}/$1$3/g;	
    # Common escaping
    s/\\\\/\\/g;
    s/\\\{/\{/g;
    s/\\\}/\}/g;
    # Cut the starting space
    s/^\s//s;
    print;
}

sub output_text_para {

    $_		= $_[0];
    if (/^bottom:/) {
	print "\f";
	return;
    }
    s/^.*?:/\n/s;
    output_text_text ($_);
}

sub output_text_centered {

    my $text	= $_[0];
    my $new_text= $text;
    $new_text	=~ s/^(.*?:)[\s\S]*$/$1/s;
    $text	=~ s/^.*?://s;
    my @lines	= split /\n/, $text;
    foreach my $line (@lines) {
	$line		=~ s/^\s*(.*)\s*$/$1/;
	$new_text	.=
	    (" " x (($TEXT_WIDTH - length($line)) / 2)) .$line."\n";
    }
    return $new_text;
}

sub output_text {

    my $i;

    # Preprocessing.  Title and sections are centered.
    # Sections and questions are numbered.
    output_text_para (output_text_centered ($title));
    foreach (@content) {
	# Sections and questions are numbered
	if (/^section/s || /^question/s) { s/^(.*?([\d.]*):)/$1$2\. /s; }
	# Title and sections are centered.
	if (/^section/s) {
	    $_	= output_text_centered ($_);
	}
    }

    # Top text.  Ends by reaching the first section.
    for ($i = 0; $i < $#content && $content[$i] !~ /^section/; $i++) {
	output_text_para ($content[$i]);
    }
    my $start_sections = $i;

    # Table Of Contents.  Only sections and questions.
    print "\n\f\n";
    if ($tochead) {
	output_text_para
	    (output_text_centered
	     ("toc:$tochead\n-----------------"));
    } else {
	output_text_para
	    (output_text_centered
	     ("toc:Table Of Contents\n-----------------"));
    }
    for $i ($start_sections .. $#content) {
	$_ = $content[$i];
	if (/^section/s || /^question/s) {
	    output_text_para ($_);
	}
    }

    # Body
    print "\n\f\n";
    for $i ( $start_sections .. $#content) {
	output_text_para ($content[$i]);
    }
}

########################################################################
# XHTML output

sub re_escape {

    my @result	= split(//,$_[0]);
    foreach my $c (@result) {
	if ($c =~ /\W/) {
	    $c	= "\\$c";
	}
    }
    return join("",@result);
}

sub output_xhtml_element {

    my ($element, $content, $aname, $head) = @_;

    local $_	= $content;	# Insert blank space to easen REs.
    s/^.*?:/ /s;		# Remove meta-info
    # Special characters in HTML
    s/\</\&lt;/g;
    s/\>/\&gt;/g;
    # References
    while (/[^\\]\{ref=(\w+)\}/) {
	my $keyword	= $1;
	my $answer	= $ref{$keyword};
	if ($answer eq "") {
	    print STDERR "Reference to \`$keyword' is not valid";
	} else {
	    if ($dir eq "") {
		$answer		=~
		    s/^(\d+)\.(\d+)$/<a href=\"\#q$1-$2\">Q$1.$2<\/a>/;
	    } else {
		$answer		=~
		    s/^(\d+)\.(\d+)$/<a href=\"q$1-$2.html\">Q$1.$2<\/a>/;
	    }
	    s/([^\\])\{ref=$keyword\}/$1$answer/g;
	}
    }
    # Mail addresses and URLs
    while (/[^\\]\{(mail|href)=([^\}]*(\\\}[^\}]*)*)\}/) {
	my $type	= $1;
	my $url		= $2;
	my $text_url	= $url;
	my $test_url	= re_escape ($url);
	if ($type eq "mail") {
	    $url	= "mailto:".$url;
	}
        $url =~ s,^http://www.gnu.org,,;
	s/([^\\])\{$type=$test_url\}/$1<a href=\"$url\">$text_url<\/a>/g;
    }
    # Common escaping
    s/\\\\/\\/g;
    s/\\\{/\{/g;
    s/\\\}/\}/g;
    s/^ //s;
    # Print it as XHTML wills
    print "<$element>" if $element;
    print "$head " if defined $head;
    if (defined $aname) {
	print "<a ";
	if ($aname =~ /^\#/ || $aname =~ /\.html$/) {
	    print "href";
	} else {
	    print "name";
	}
	print "=\"$aname\">";
    }
    print;
    print "</a>" if defined $aname;
    print "</$element>\n\n" if $element;
}

sub output_xhtml_toc {

    my $first_section	= 1;
    print "<hr>\n\n";
    if ($tochead) {
	output_xhtml_element ("H3", "toc:$tochead", "toc");
    } else {
	output_xhtml_element ("H3", "toc:Table Of Content", "toc");
    }
    $first_section	= 1;
    foreach my $p (@content) {
	if ($p =~ /^section (\d+):\s*([\s\S]*)$/s) {
	    print "</blockquote>\n\n" unless $first_section;
	    $first_section	= 0;
	    print "<p>";
	    output_xhtml_element ("strong", $p, "#s$1", "$1.");
	    print "</p>\n\n<blockquote>";
	} elsif ($p =~ /^question (\d+)\.(\d+):\s*([\s\S]*)$/s) {
	    output_xhtml_element ("p", $p, "#q$1-$2", "$1.$2.");
	}
    }
    print "</blockquote>\n\n" unless $first_section;
    print "<hr>\n\n";
}

sub output_xhtml_start {

    my $title	= $_[0];
    my $title_content	= $title;

    print <<'ENDOFINC';
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Strict//EN">
<HTML>
<HEAD>
<TITLE>The GNU Hurd - GNU Project - Free Software Foundation (FSF)</TITLE>
<LINK REV="made" HREF="mailto:web-hurd@gnu.org">
<META NAME="keywords" CONTENT="hurd">
ENDOFINC

    if ($charset) {
	print "<meta http-equiv=\"Content-Type\" ".
	    "content=\"$charset\">\n";
    }
    # $title_content	=~ s/^.*?:([\s\S]*)$/$1/s;
    # output_xhtml_element ("title", "x:".$prefix.$title_content);

    print <<'ENDOFINC';
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#1F00FF" ALINK="#FF0000" VLINK="#9900DD">
<TABLE width="100%" border="0" cellspacing="5" cellpadding="15">
<TR>
<TD COLSPAN="2">
<IMG SRC="/graphics/hurd_sm_mf.jpg" ALT=" [image of the Hurd logo] ">
[
  <A HREF="/software/hurd/faq.en.html">English</A>
| <A HREF="/software/hurd/faq.fr.html">French</A>
| <A HREF="/software/hurd/faq.de.html">German</A>
| <A HREF="/software/hurd/faq.ja.html">Japanese</A>
| <A HREF="/software/hurd/faq.es.html">Spanish</A>
| <A HREF="/software/hurd/faq.it.html">Italian</A>
]
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP" BGCOLOR="#eeeeee">
<A HREF="/software/hurd/whatsnew.html"><STRONG>What\'s New</STRONG></A><BR>
&nbsp;<BR>
<A HREF="/software/hurd/changelogs.html">ChangeLogs</A><BR>
<A HREF="/software/hurd/hurd.html"><STRONG>The&nbsp;GNU&nbsp;Hurd</STRONG></A><BR>
&nbsp;<BR>
<A HREF="/software/hurd/docs.html">Documentation</A><BR>
<A HREF="/software/hurd/install.html">Installation</A><BR>
<A HREF="/software/hurd/help.html">Getting&nbsp;Help</A><BR>
<A HREF="/software/hurd/download.html">Source&nbsp;Code</A><BR>
<A HREF="/software/hurd/devel.html">Development</A><BR>
<A HREF="/software/hurd/history.html">History</A><BR>
&nbsp;<BR>
<A HREF="/software/hurd/gnumach.html"><STRONG>GNU&nbsp;Mach</STRONG></A><BR>
&nbsp;<BR>
<A HREF="/software/hurd/gnumach-docs.html">Documentation</A><BR>
<A HREF="/software/hurd/gnumach-install.html">Installation</A><BR>
<A HREF="/software/hurd/gnumach-download.html">Source&nbsp;Code</A><BR>
&nbsp;<BR>
<A HREF="/software/hurd/mig.html"><STRONG>MiG</STRONG></A><BR>
&nbsp;<BR>
<A HREF="/software/hurd/mig-download.html">Source&nbsp;Code</A><BR>
&nbsp;<BR>
<A HREF="/software/hurd/related-projects.html"><STRONG>Related&nbsp;Projects</STRONG></A>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<HR>
<P>
ENDOFINC

    # Top text
    output_xhtml_element ("H3", $title) if $title !~ /^ /s;
}

sub output_xhtml_end {

    print <<'ENDOFINC';
</TD>
</TR>
</TABLE>

<HR>

[
  <A HREF="/software/hurd/faq.en.html">English</A>
| <A HREF="/software/hurd/faq.fr.html">French</A>
| <A HREF="/software/hurd/faq.de.html">German</A>
| <A HREF="/software/hurd/faq.ja.html">Japanese</A>
| <A HREF="/software/hurd/faq.es.html">Spanish</A>
| <A HREF="/software/hurd/faq.it.html">Italian</A>
]

<HR>

<P>
Return to <A HREF="/home.html">GNU's home page</A>.
<P>

Please send FSF &amp; GNU inquiries &amp; questions to

<A HREF="mailto:gnu@gnu.org"><EM>gnu@gnu.org</EM></A>.
There are also <A HREF="/home.html#ContactInfo">other ways to
contact</A> the FSF.
<P>

Please send comments on these web pages to

<A HREF="mailto:web-hurd@gnu.org"><EM>web-hurd@gnu.org</EM></A>,
send other questions to
<A HREF="mailto:gnu@gnu.org"><EM>gnu@gnu.org</EM></A>.
<P>
Copyright (C) 2001 Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA  02111,  USA
<P>
Each section is copyright its respective author(s).  Permission is
granted to copy, distribute and/or modify this document under the
terms of the <A HREF="/licenses/fdl.html">GNU Free Documentation
License</A>, Version 1.1 or any later version published by the Free
Software Foundation; with no Invariant Sections, with no Front-Cover
Texts and with no Back-Cover Texts.
<P>
Updated:
<!-- timestamp start -->
$Date: 2004/10/11 08:14:14 $ $Author: ams $
<!-- timestamp end -->
<HR>
</BODY>
</HTML>
ENDOFINC
}

sub output_xhtml_para {
    
    if ($item && ! /^item/s) {
	print "</li>\n\n</ul>\n\n";
	$item	= 0;
    }

    if (/^item-start:/s) {
	if ($item) {
	    print "</li>\n\n";
	} else {
	    print "<ul>\n\n";
	}
	print "<li>";
	$item	= 1;
	s/^(.*?:)[*-]/$1 /s;
	output_xhtml_element ("p", $_);
    }
    elsif (/^normal:/s || /^item-normal:/s) {
	output_xhtml_element ("p", $_);
    }
    elsif (/^verbatim:/s || /^item-verbatim:/s) {
	output_xhtml_element ("pre", $_);
    }
    else { return 0; }
    return 1;
}

sub output_xhtml {

    $prefix	= "";
    output_xhtml_start ($title);
    
    # Body
    my $first_section	= 1;
    $item		= 0;
    foreach (@content) {
	if (! output_xhtml_para ()) {
	    if (/^section (\d+):/s) {
		output_xhtml_toc () if $first_section;
		$first_section	= 0;
		output_xhtml_element ("H3", $_, "s$1", "$1.");
	    }
	    elsif (/^question/s) {
		/^question (\d+)\.(\d+):/s;
		output_xhtml_element ("H4", $_, "q$1-$2", "$1.$2.");
	    }
	    elsif (/^bottom/s) {
		print "<hr>\n\n";
	    } else {
		print STDERR "Internal error: unknown mark up \`$_'\n";
		output_xhtml_element ("unknown", $_);
	    }
	}
    }
    $_		= "normal:";
    output_xhtml_para ();

    output_xhtml_end ();
}

########################################################################
# XHTML fancy output

sub output_xhtml_fancy_sections {

    my $element	= $_[0];
    my $current	= $_[1];
    my $current_linked	= $_[2];
    
    # List Of Sections
    if ($element eq "p") {
	print "<p>";
	output_xhtml_element ("strong", "los:Sections");
	print "</p>\n\n<blockquote>\n\n";
    } else {
	print "<p><a href=\"index.html\"><small>";
	output_xhtml_element ("strong", "los:Sections");
	print "</a></small></p>\n\n<ul>\n\n";
    }
    foreach (@content) {
	if (/^section (\d+):([\s\S]*)$/s) {
	    print "<li>" if $element ne "p";
	    my $href = "s$1.html";
	    my $elem = $element;
	    if (defined $current && $_ eq $current) {
		print "<$element>";
		$elem	= "strong";
		undef $href if ! defined $current_linked;
	    }
	    output_xhtml_element ($elem, $_, $href, "$1.");
	    print "</$element>" if defined $current && $_ eq $current;
	    print "</li>" if $element ne "p";
	}
    }
    print "</blockquote>\n\n"	if $element eq "p";
    print "</ul>\n\n"		if $element ne "p";
}

sub output_xhtml_fancy {

    $dir	= $_[0];
    die "Non-existent directory \`$dir'\n" if (! -d $dir || ! -r $dir);

    # Top page
    {
	open STDOUT, "> $dir/index.html"
	    or die "Cannot write to $dir/index.html";
	output_xhtml_start ($title);

	# Top text
	$item	= 0;
	foreach (@content) {
	    last if (/^section/s);
	    output_xhtml_para ();
	}
	$_ = "";
	output_xhtml_para ();
	output_xhtml_fancy_sections ("p");
	$item			= 0;
	my $it_is_bottom	= 0;
	foreach (@content) {
	    output_xhtml_para () if $it_is_bottom;
	    $it_is_bottom	= 1 if /^bottom/s;
	}
	output_xhtml_end ();
	close STDOUT;
    }

    # Sections
    {
	foreach my $section (@content) {
	    if ($section =~ /^section (\d+):([\s\S]*)/s) {
		open STDOUT, "> $dir/s$1.html"
		    or die "Cannot write to \`$dir/s$1.html'";
		output_xhtml_start ("$1. $2");
		output_xhtml_fancy_sections ("small", $section);
		print "<hr><p>";
		output_xhtml_element ("strong", "q:Questions");
		print "</p>\n\n<blockquote>\n\n";
		my $started	= 0;
		foreach (@content) {
		    last if $started && /^section/s;
		    $started = 1 if ! $started && $_ eq $section;
		    output_xhtml_element
			("p", $_, "q$1-$2.html", "$1.$2.")
			if $started && /^question (\d+)\.(\d+):([\s\S]*)/s;
		}
		print "</blockquote>\n\n<hr>\n\n";
		output_xhtml_fancy_sections ("small", $section);
		output_xhtml_end ();
		close STDOUT;
	    }
	}
    }

    # Questions
    {
	my $section		= ":"; # no section
	for my $i (0 .. $#content) {
	    if ($content[$i] =~ /^section/s) {
		$section	= $content[$i];
	    } elsif ($content[$i] =~ /^question (\d+).(\d+):([\s\S]*)$/s) {
		open STDOUT, "> $dir/q$1-$2.html"
		    or die "Cannot write to \`$dir/q$1-$2.html'";
		my $sectionnum	= $1;
		my $questionnum	= $2;
		my $title	= $3;
		my $nav		= "";
		output_xhtml_start (" Q$1.$2. $3");
		# Navigation
		{
		    $nav .= "<div class=\"nav\" align=\"center\">";
		    # Is there "next"?
		    my $j	= $i+1;
		    while ($j <= $#content &&
			   $content[$j] !~ /^question (\d+)\.(\d+)/s) {
			$j++;
		    }
		    if ($j <= $#content) {
			$content[$j] =~ /^question (\d+)\.(\d+)/s;
			$nav .= "[<a href=\"q$1-$2.html\">next</a>] ";
		    }
		    # "prev"?
		    $j		= $i-1;
		    while ($j >= 0 &&
			   $content[$j] !~ /^question (\d+)\.(\d+)/s) {
			$j--;
		    }
		    if ($j >= 0) {
			$content[$j] =~ /^question (\d+)\.(\d+):/s;
			$nav .= "[<a href=\"q$1-$2.html\">prev</a>] ";
		    }
		    $nav .= "[<a href=\"s$sectionnum.html\">".
			"this section</a>] ";
		    $nav .= "[<a href=\"index.html\">all sections</a>]";
		    $nav .= "</div>\n\n";
		}
		print "$nav<hr>\n\n";
		# Header
		output_xhtml_element ("H4",
				      "x:Q$sectionnum.$questionnum. $title");
		# Body
		{
		    my $j	= $i+1;
		    $item	= 0;
		    while ($j <= $#content
			   && $content[$j] !~ /^question/s
			   && $content[$j] !~ /^section/s
			   && $content[$j] !~ /^bottom/s) {
			$_	= $content[$j];
			output_xhtml_para ();
			$j++;
		    }
		    print "</ul>\n\n" if $item;
		}
		# Bottom navigation
		print "<hr>$nav";
		output_xhtml_end ();
		close STDOUT;
	    }
	}
    }
}
