From: Ben Hutchings Date: Tue, 17 Jan 2017 23:57:33 +0000 (+0000) Subject: _make-more-docs X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ian/git?a=commitdiff_plain;h=0cde7ecaa25b7da50b2dcd316e36ec9a382bfd76;p=sgt-puzzles.git _make-more-docs Halibut already supports these formats but since the documentation is all combined we need to do a bit more work to extract the right information for each game's manual page. Gbp-Pq: Name 201_make-more-docs.diff --- diff --git a/Makefile.doc b/Makefile.doc index 53e9557..00436a5 100644 --- a/Makefile.doc +++ b/Makefile.doc @@ -14,12 +14,20 @@ puzzles.hhp: puzzles.but chm.but 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 @@ -44,6 +52,38 @@ doc/puzzles.txt.%: doc/preprocessed.but.% 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 diff --git a/mkmanpages.pl b/mkmanpages.pl new file mode 100644 index 0000000..0b56d4c --- /dev/null +++ b/mkmanpages.pl @@ -0,0 +1,157 @@ +#!/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 ." + . 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;