chiark / gitweb /
sgt-puzzles (20161228.7cae89f-1) unstable; urgency=medium
[sgt-puzzles.git] / debian / patches / 201_make-more-docs.diff
1 Author: Ben Hutchings <ben@decadent.org.uk>
2 Description: Add rules and script to build manual pages and HTML
3
4 Halibut already supports these formats but since the documentation is
5 all combined we need to do a bit more work to extract the right
6 information for each game's manual page.
7
8 --- a/Makefile.doc
9 +++ b/Makefile.doc
10 @@ -14,12 +14,20 @@ puzzles.hhp: puzzles.but chm.but
11         halibut --html puzzles.but chm.but
12  
13  TRANSLATIONS := $(patsubst po/%.po,%,$(wildcard po/*.po))
14 +LANGUAGES := en $(TRANSLATIONS)
15  
16  update-po:
17  # Please tell me there is an easier way to preserve the POT file header.
18         test -f po/puzzles-doc.pot
19         po4a-gettextize -f halibut -m puzzles.but --package-name puzzles \
20                 -p po/puzzles-doc.tmp1.pot
21 +       awk -F: '{ print ""; \
22 +                  print "#: " $$1 ".R"; \
23 +                  print "msgid \"" $$4 "\""; \
24 +                  print "msgstr \"\""; }' \
25 +               < gamedesc.txt >> po/puzzles-doc.tmp1.pot
26 +       xgettext -j -cTranslator: --package-name puzzles \
27 +               -o po/puzzles-doc.tmp1.pot mkmanpages.pl
28         sed -i '1,/^#$$/d' po/puzzles-doc.tmp1.pot
29         cat po/puzzles-doc.pot.head po/puzzles-doc.tmp1.pot \
30                 > po/puzzles-doc.tmp2.pot
31 @@ -44,6 +52,38 @@ doc/puzzles.txt.%: doc/preprocessed.but.
32         halibut --text=$@ --input-charset=UTF-8 $<
33  all: $(addprefix doc/puzzles.txt.,$(TRANSLATIONS))
34  
35 +doc/man-en-stamp: preprocessed.but
36 +       mkdir -p doc
37 +       rm -rf doc/man-en
38 +       mkdir doc/man-en
39 +       perl mkmanpages.pl en
40 +       touch $@
41 +doc/man-%-stamp: doc/preprocessed.but.%
42 +       mkdir -p doc
43 +       rm -rf doc/man-$*
44 +       mkdir doc/man-$*
45 +       perl mkmanpages.pl $*
46 +       touch $@
47 +man: $(patsubst %,doc/man-%-stamp,$(LANGUAGES))
48 +
49 +doc/html-en-stamp: preprocessed.but
50 +       mkdir -p doc
51 +       rm -rf doc/html-en
52 +       mkdir doc/html-en
53 +       cd doc/html-en && halibut --html ../../preprocessed.but
54 +       touch $@
55 +doc/html-%-stamp: doc/preprocessed.but.%
56 +       mkdir -p doc
57 +       rm -rf doc/html-$*
58 +       mkdir doc/html-$*
59 +       cd doc/html-$* && halibut --html --input-charset=UTF-8 ../preprocessed.but.$*
60 +       touch $@
61 +html: $(patsubst %,doc/html-%-stamp,$(LANGUAGES))
62 +
63 +.PHONY: man html
64 +all: man html
65 +
66  clean:
67         rm -f puzzles.hlp puzzles.txt preprocessed.but HACKING *.html *.hh[pck]
68 +       rm -f puzzles.cnt
69         rm -rf doc
70 --- /dev/null
71 +++ b/mkmanpages.pl
72 @@ -0,0 +1,157 @@
73 +#!/usr/bin/perl -w
74 +
75 +# Generate manual pages for sgt-puzzles by running extracts of puzzles.but
76 +# through halibut.
77 +
78 +use strict;
79 +use File::Temp;
80 +use IO::File;
81 +use Locale::PO;
82 +use POSIX ();
83 +
84 +my $package = 'sgt-puzzles';
85 +my $language = $ARGV[0] or die 'mkmanpages.pl: no language specified';
86 +
87 +# Fake up gettext without compilation or locales
88 +my $po_map = Locale::PO->load_file_ashash("po/$language.po");
89 +sub gettext {
90 +    my $msgid = shift;
91 +    my $po = $po_map->{Locale::PO->quote($msgid)};
92 +    return $po ? Locale::PO->dequote($po->msgstr()) : $msgid;
93 +}
94 +
95 +# Header information
96 +my $package_roff = $package;
97 +$package_roff =~ s/-/\\-/g;
98 +my $date;
99 +# Translator: conventional name for manual section 6
100 +my $section = gettext('Games');
101 +my $section_no = "6";
102 +my $man_dir = "doc/man-$language";
103 +
104 +my %commands;
105 +my %short_descs;
106 +my $gamedesc = new IO::File('gamedesc.txt', 'r');
107 +while (<$gamedesc>) {
108 +    (my $name, undef, undef, my $desc) = split /:/;
109 +    $commands{$name} = $ENV{BINPREFIX} . $name;
110 +    $short_descs{$name} = $desc;
111 +}
112 +close $gamedesc;
113 +
114 +# We should be able to look these up with strftime('%A') but that
115 +# requires the relevant locale to be installed on the build host
116 +my @MONTHS = (gettext('January'), gettext('February'), gettext('March'),
117 +             gettext('April'),   gettext('May'),      gettext('June'),
118 +             gettext('July'),    gettext('August'),   gettext('September'),
119 +             gettext('October'), gettext('November'), gettext('December'));
120 +
121 +# Chapter name, initialised to dummy value to capture header
122 +my $name = '__HEADER__';
123 +
124 +# Contents of each chapter/appendix
125 +my %contents;
126 +
127 +# Gather chapters from the original documentation
128 +my $source_name =
129 +    $language eq 'en' ? 'preprocessed.but' : "doc/preprocessed.but.$language";
130 +my $source = new IO::File($source_name, 'r') or die "$source_name: $!";
131 +while (<$source>) {
132 +    # Look for chapter/appendix heading
133 +    if (/^\\[AC]{([^}]+)}\s*/) {
134 +       $name = $1;
135 +       # The odd one out - chapter name doesn't match command name
136 +       if ($name eq 'rectangles') {
137 +           $name = 'rect';
138 +       }
139 +    }
140 +    # Look for version ID with date
141 +    if (/^\\versionid .* (\d{4})(\d{2})\d{2}\./) {
142 +       $date = "${MONTHS[$2-1]} $1";
143 +    }
144 +    $contents{$name} .= $_;
145 +}
146 +close $source;
147 +
148 +# Remove all normal text from the header
149 +$contents{__HEADER__} =~ s/^(?!\\(?:cfg|define|title){).*$//gm;
150 +
151 +# Remove introduction from "common features" chapter
152 +$contents{common} =~ s/^.*?(?=\\H\{)//s;
153 +
154 +for my $short_name (keys %commands) {
155 +    my $command = $commands{$short_name};
156 +    print "Generating $command.6\n";
157 +
158 +    my $text_name = $language eq 'en' ? 'puzzles.txt' : "puzzles.txt.$language";
159 +    my $contents =
160 +      "\\cfg{man-mindepth}{1}\n" # don't show original chapter headings
161 +      . "\\cfg{man-identity}{".uc($command)."}{$section_no}{$date}{$command ($package_roff)}{$section}\n\n"
162 +      . "\\cfg{man-charset}{UTF-8}\n" # output encoding
163 +      . $contents{__HEADER__}
164 +      . "\\C{man-$command} $command\n\n" # dummy chapter
165 +      . "\\H{man-$command-name} " . gettext('NAME') . "\n\n"
166 +      . "\\c{$command} \\- $short_descs{$short_name}\n\n"
167 +      . "\\H{man-$command-synopsis} " . gettext('SYNOPSIS') . "\n\n"
168 +      # Translator: abbreviation for 'number'
169 +      . "\\cw{$command} [\\cw{--generate }\\e{" . gettext('n') . "}]\n"
170 +      # Translator: abbreviation for 'width'
171 +      . "[\\cw{--print }\\e{" . gettext('w') . "}\\cw{x}\\e{"
172 +      # Translator: abbreviation for 'height'
173 +      . gettext('h') . "} [\\cw{--with-solutions}]\n"
174 +      . "[\\cw{--scale }\\e{" . gettext('n') . "}] [\\cw{--colour}]]\n"
175 +      . "[\\e{" . gettext('game-parameters') . "}|\\e{" . gettext('game-ID')
176 +      . "}|\\e{" . gettext('random-seed') . "}]\n\n"
177 +      . "\\cw{$command --version}\n\n"
178 +      . "\\H{man-$command-desc} " . gettext('DESCRIPTION') . "\n\n"
179 +      . $contents{$short_name}
180 +      . $contents{common}
181 +      . "\\H{man-$command-see-also} " . gettext('SEE ALSO') . "\n\n"
182 +      # Translator: "Full documentation in <filename>."
183 +      . sprintf(gettext("Full documentation in %s."),
184 +               "/usr/share/doc/$package/$text_name.gz")
185 +      . "\n";
186 +
187 +    # Kluge cross-references
188 +    sub replace_ref {
189 +       my ($above, $target, $below) = @_;
190 +       # If the target is an earlier or later section in the current page, say
191 +       # it's above or below.
192 +       if ($above =~ m/\\(?:[CHA]|S\d*){$target}/) {
193 +           # Translator: earlier in the manual page
194 +           gettext('above');
195 +       } elsif ($below =~ m/\\(?:[CHA]|S\d*){$target}/) {
196 +           # Translator: later in the manual page
197 +           gettext('below');
198 +       }
199 +       # Else if the target is a bibliographic entry, include the entry directly.
200 +       elsif ($below =~ m/\\B\{$target\}\s*(.*?)\s*(?:\\(?:[BCHA]|S\d*|$))/s) {
201 +           "($1)";
202 +       }
203 +       # Else if it appears to refer to another game, convert to a customary
204 +       # cross-manual-page reference.
205 +       elsif ($target =~ /(\w+)/ && exists $commands{$1}) {
206 +           "\\e{$commands{$1}}($section_no)";
207 +       }
208 +       # Otherwise (and this shouldn't happen), show the reference target.
209 +       else {
210 +           print STDERR "Failed to resolve reference to $target\n";
211 +           $target;
212 +       }
213 +    }
214 +    $contents =~ s/(?:\bin\s+)?\\[kK]{([^}]+)}/replace_ref($`, $1, $')/eg;
215 +
216 +    # Run through halibut.  It does not default to using stdin or stdout,
217 +    # and /dev/std{in,out} apparently don't exist on some systems, so we
218 +    # can't reliably do this with a pipeline.
219 +    my ($temp_but, $temp_but_name) = mkstemp "/tmp/sgt-puzzles-but-XXXXXX"
220 +      or die "$!";
221 +    my $man_name = "$command.$section_no";
222 +    print $temp_but $contents or die "$!";
223 +    close $temp_but;
224 +    system "halibut --man=$man_dir/$man_name --input-charset=UTF-8 $temp_but_name";
225 +    unlink $temp_but_name;
226 +    -s "$man_dir/$man_name" or die "halibut produced an empty $man_name";
227 +}
228 +
229 +exit;