halibut --html puzzles.but chm.but
TRANSLATIONS := $(patsubst po/%.po,%,$(wildcard po/*.po))
+LANGUAGES := en $(TRANSLATIONS)
update-po:
# Please tell me there is an easier way to preserve the POT file header.
test -f po/puzzles-doc.pot
po4a-gettextize -f halibut -m puzzles.but --package-name puzzles \
-p po/puzzles-doc.tmp1.pot
+ awk -F: '{ print ""; \
+ print "#: " $$1 ".R"; \
+ print "msgid \"" $$4 "\""; \
+ print "msgstr \"\""; }' \
+ < gamedesc.txt >> po/puzzles-doc.tmp1.pot
+ xgettext -j -cTranslator: --package-name puzzles \
+ -o po/puzzles-doc.tmp1.pot mkmanpages.pl
sed -i '1,/^#$$/d' po/puzzles-doc.tmp1.pot
cat po/puzzles-doc.pot.head po/puzzles-doc.tmp1.pot \
> po/puzzles-doc.tmp2.pot
halibut --text=$@ --input-charset=UTF-8 $<
all: $(addprefix doc/puzzles.txt.,$(TRANSLATIONS))
+doc/man-en-stamp: preprocessed.but
+ mkdir -p doc
+ rm -rf doc/man-en
+ mkdir doc/man-en
+ perl mkmanpages.pl en
+ touch $@
+doc/man-%-stamp: doc/preprocessed.but.%
+ mkdir -p doc
+ rm -rf doc/man-$*
+ mkdir doc/man-$*
+ perl mkmanpages.pl $*
+ touch $@
+man: $(patsubst %,doc/man-%-stamp,$(LANGUAGES))
+
+doc/html-en-stamp: preprocessed.but
+ mkdir -p doc
+ rm -rf doc/html-en
+ mkdir doc/html-en
+ cd doc/html-en && halibut --html ../../preprocessed.but
+ touch $@
+doc/html-%-stamp: doc/preprocessed.but.%
+ mkdir -p doc
+ rm -rf doc/html-$*
+ mkdir doc/html-$*
+ cd doc/html-$* && halibut --html --input-charset=UTF-8 ../preprocessed.but.$*
+ touch $@
+html: $(patsubst %,doc/html-%-stamp,$(LANGUAGES))
+
+.PHONY: man html
+all: man html
+
clean:
rm -f puzzles.hlp puzzles.txt preprocessed.but HACKING *.html *.hh[pck]
+ rm -f puzzles.cnt
rm -rf doc
--- /dev/null
+#!/usr/bin/perl -w
+
+# Generate manual pages for sgt-puzzles by running extracts of puzzles.but
+# through halibut.
+
+use strict;
+use File::Temp;
+use IO::File;
+use Locale::PO;
+use POSIX ();
+
+my $package = 'sgt-puzzles';
+my $language = $ARGV[0] or die 'mkmanpages.pl: no language specified';
+
+# Fake up gettext without compilation or locales
+my $po_map = Locale::PO->load_file_ashash("po/$language.po");
+sub gettext {
+ my $msgid = shift;
+ my $po = $po_map->{Locale::PO->quote($msgid)};
+ return $po ? Locale::PO->dequote($po->msgstr()) : $msgid;
+}
+
+# Header information
+my $package_roff = $package;
+$package_roff =~ s/-/\\-/g;
+my $date;
+# Translator: conventional name for manual section 6
+my $section = gettext('Games');
+my $section_no = "6";
+my $man_dir = "doc/man-$language";
+
+my %commands;
+my %short_descs;
+my $gamedesc = new IO::File('gamedesc.txt', 'r');
+while (<$gamedesc>) {
+ (my $name, undef, undef, my $desc) = split /:/;
+ $commands{$name} = $ENV{BINPREFIX} . $name;
+ $short_descs{$name} = $desc;
+}
+close $gamedesc;
+
+# We should be able to look these up with strftime('%A') but that
+# requires the relevant locale to be installed on the build host
+my @MONTHS = (gettext('January'), gettext('February'), gettext('March'),
+ gettext('April'), gettext('May'), gettext('June'),
+ gettext('July'), gettext('August'), gettext('September'),
+ gettext('October'), gettext('November'), gettext('December'));
+
+# Chapter name, initialised to dummy value to capture header
+my $name = '__HEADER__';
+
+# Contents of each chapter/appendix
+my %contents;
+
+# Gather chapters from the original documentation
+my $source_name =
+ $language eq 'en' ? 'preprocessed.but' : "doc/preprocessed.but.$language";
+my $source = new IO::File($source_name, 'r') or die "$source_name: $!";
+while (<$source>) {
+ # Look for chapter/appendix heading
+ if (/^\\[AC]{([^}]+)}\s*/) {
+ $name = $1;
+ # The odd one out - chapter name doesn't match command name
+ if ($name eq 'rectangles') {
+ $name = 'rect';
+ }
+ }
+ # Look for version ID with date
+ if (/^\\versionid .* (\d{4})(\d{2})\d{2}\./) {
+ $date = "${MONTHS[$2-1]} $1";
+ }
+ $contents{$name} .= $_;
+}
+close $source;
+
+# Remove all normal text from the header
+$contents{__HEADER__} =~ s/^(?!\\(?:cfg|define|title){).*$//gm;
+
+# Remove introduction from "common features" chapter
+$contents{common} =~ s/^.*?(?=\\H\{)//s;
+
+for my $short_name (keys %commands) {
+ my $command = $commands{$short_name};
+ print "Generating $command.6\n";
+
+ my $text_name = $language eq 'en' ? 'puzzles.txt' : "puzzles.txt.$language";
+ my $contents =
+ "\\cfg{man-mindepth}{1}\n" # don't show original chapter headings
+ . "\\cfg{man-identity}{".uc($command)."}{$section_no}{$date}{$command ($package_roff)}{$section}\n\n"
+ . "\\cfg{man-charset}{UTF-8}\n" # output encoding
+ . $contents{__HEADER__}
+ . "\\C{man-$command} $command\n\n" # dummy chapter
+ . "\\H{man-$command-name} " . gettext('NAME') . "\n\n"
+ . "\\c{$command} \\- $short_descs{$short_name}\n\n"
+ . "\\H{man-$command-synopsis} " . gettext('SYNOPSIS') . "\n\n"
+ # Translator: abbreviation for 'number'
+ . "\\cw{$command} [\\cw{--generate }\\e{" . gettext('n') . "}]\n"
+ # Translator: abbreviation for 'width'
+ . "[\\cw{--print }\\e{" . gettext('w') . "}\\cw{x}\\e{"
+ # Translator: abbreviation for 'height'
+ . gettext('h') . "} [\\cw{--with-solutions}]\n"
+ . "[\\cw{--scale }\\e{" . gettext('n') . "}] [\\cw{--colour}]]\n"
+ . "[\\e{" . gettext('game-parameters') . "}|\\e{" . gettext('game-ID')
+ . "}|\\e{" . gettext('random-seed') . "}]\n\n"
+ . "\\cw{$command --version}\n\n"
+ . "\\H{man-$command-desc} " . gettext('DESCRIPTION') . "\n\n"
+ . $contents{$short_name}
+ . $contents{common}
+ . "\\H{man-$command-see-also} " . gettext('SEE ALSO') . "\n\n"
+ # Translator: "Full documentation in <filename>."
+ . sprintf(gettext("Full documentation in %s."),
+ "/usr/share/doc/$package/$text_name.gz")
+ . "\n";
+
+ # Kluge cross-references
+ sub replace_ref {
+ my ($above, $target, $below) = @_;
+ # If the target is an earlier or later section in the current page, say
+ # it's above or below.
+ if ($above =~ m/\\(?:[CHA]|S\d*){$target}/) {
+ # Translator: earlier in the manual page
+ gettext('above');
+ } elsif ($below =~ m/\\(?:[CHA]|S\d*){$target}/) {
+ # Translator: later in the manual page
+ gettext('below');
+ }
+ # Else if the target is a bibliographic entry, include the entry directly.
+ elsif ($below =~ m/\\B\{$target\}\s*(.*?)\s*(?:\\(?:[BCHA]|S\d*|$))/s) {
+ "($1)";
+ }
+ # Else if it appears to refer to another game, convert to a customary
+ # cross-manual-page reference.
+ elsif ($target =~ /(\w+)/ && exists $commands{$1}) {
+ "\\e{$commands{$1}}($section_no)";
+ }
+ # Otherwise (and this shouldn't happen), show the reference target.
+ else {
+ print STDERR "Failed to resolve reference to $target\n";
+ $target;
+ }
+ }
+ $contents =~ s/(?:\bin\s+)?\\[kK]{([^}]+)}/replace_ref($`, $1, $')/eg;
+
+ # Run through halibut. It does not default to using stdin or stdout,
+ # and /dev/std{in,out} apparently don't exist on some systems, so we
+ # can't reliably do this with a pipeline.
+ my ($temp_but, $temp_but_name) = mkstemp "/tmp/sgt-puzzles-but-XXXXXX"
+ or die "$!";
+ my $man_name = "$command.$section_no";
+ print $temp_but $contents or die "$!";
+ close $temp_but;
+ system "halibut --man=$man_dir/$man_name --input-charset=UTF-8 $temp_but_name";
+ unlink $temp_but_name;
+ -s "$man_dir/$man_name" or die "halibut produced an empty $man_name";
+}
+
+exit;