~ubuntu-branches/ubuntu/breezy/gettext/breezy

« back to all changes in this revision

Viewing changes to gettext-runtime/man/help2man

  • Committer: Bazaar Package Importer
  • Author(s): Santiago Vila
  • Date: 2004-03-14 17:40:02 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20040314174002-p1ad5ldve1hqzhye
Tags: 0.14.1-2
* Added libexpat1-dev to Build-Depends, for glade support.
* Added libc0.1-dev to Build-Depends, for GNU/kFreeBSD.
* Removed special-casing of knetbsd-gnu in debian/rules.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/perl -w
 
2
 
 
3
# Generate a short man page from --help and --version output.
 
4
# Copyright � 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
 
5
 
 
6
# This program is free software; you can redistribute it and/or modify
 
7
# it under the terms of the GNU General Public License as published by
 
8
# the Free Software Foundation; either version 2, or (at your option)
 
9
# any later version.
 
10
 
 
11
# This program is distributed in the hope that it will be useful,
 
12
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
# GNU General Public License for more details.
 
15
 
 
16
# You should have received a copy of the GNU General Public License
 
17
# along with this program; if not, write to the Free Software Foundation,
 
18
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
19
 
 
20
# Written by Brendan O'Dea <bod@compusol.com.au>
 
21
# Available from ftp://ftp.gnu.org/gnu/help2man/
 
22
 
 
23
use 5.004;
 
24
use strict;
 
25
use Getopt::Long;
 
26
use Text::Tabs qw(expand);
 
27
use POSIX qw(strftime setlocale LC_TIME);
 
28
 
 
29
my $this_program = 'help2man';
 
30
my $this_version = '1.24';
 
31
my $version_info = <<EOT;
 
32
GNU $this_program $this_version
 
33
 
 
34
Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
 
35
This is free software; see the source for copying conditions.  There is NO
 
36
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
37
 
 
38
Written by Brendan O'Dea <bod\@compusol.com.au>
 
39
EOT
 
40
 
 
41
my $help_info = <<EOT;
 
42
`$this_program' generates a man page out of `--help' and `--version' output.
 
43
 
 
44
Usage: $this_program [OPTION]... EXECUTABLE
 
45
 
 
46
 -n, --name=STRING       use `STRING' as the description for the NAME paragraph
 
47
 -s, --section=SECTION   use `SECTION' as the section for the man page
 
48
 -i, --include=FILE      include material from `FILE'
 
49
 -I, --opt-include=FILE  include material from `FILE' if it exists
 
50
 -o, --output=FILE       send output to `FILE'
 
51
 -N, --no-info           suppress pointer to Texinfo manual
 
52
     --help              print this help, then exit
 
53
     --version           print version number, then exit
 
54
 
 
55
EXECUTABLE should accept `--help' and `--version' options.
 
56
 
 
57
Report bugs to <bug-help2man\@gnu.org>.
 
58
EOT
 
59
 
 
60
my $section = 1;
 
61
my ($opt_name, @opt_include, $opt_output, $opt_no_info);
 
62
my %opt_def = (
 
63
    'n|name=s'          => \$opt_name,
 
64
    's|section=s'       => \$section,
 
65
    'i|include=s'       => sub { push @opt_include, [ pop, 1 ] },
 
66
    'I|opt-include=s'   => sub { push @opt_include, [ pop, 0 ] },
 
67
    'o|output=s'        => \$opt_output,
 
68
    'N|no-info'         => \$opt_no_info,
 
69
);
 
70
 
 
71
# Parse options.
 
72
Getopt::Long::config('bundling');
 
73
GetOptions (%opt_def,
 
74
    help    => sub { print $help_info; exit },
 
75
    version => sub { print $version_info; exit },
 
76
) or die $help_info;
 
77
 
 
78
die $help_info unless @ARGV == 1;
 
79
 
 
80
my %include = ();
 
81
my %append = ();
 
82
my @include = (); # retain order given in include file
 
83
 
 
84
# Provide replacement `quote-regex' operator for pre-5.005.
 
85
BEGIN { eval q(sub qr { '' =~ $_[0]; $_[0] }) if $] < 5.005 }
 
86
 
 
87
# Process include file (if given).  Format is:
 
88
#
 
89
#   [section name]
 
90
#   verbatim text
 
91
#
 
92
# or
 
93
#
 
94
#   /pattern/
 
95
#   verbatim text
 
96
#
 
97
 
 
98
while (@opt_include)
 
99
{
 
100
    my ($inc, $required) = @{shift @opt_include};
 
101
 
 
102
    next unless -f $inc or $required;
 
103
    die "$this_program: can't open `$inc' ($!)\n"
 
104
        unless open INC, $inc;
 
105
 
 
106
    my $key;
 
107
    my $hash = \%include;
 
108
 
 
109
    while (<INC>)
 
110
    {
 
111
        # [section]
 
112
        if (/^\[([^]]+)\]/)
 
113
        {
 
114
            $key = uc $1;
 
115
            $key =~ s/^\s+//;
 
116
            $key =~ s/\s+$//;
 
117
            $hash = \%include;
 
118
            push @include, $key unless $include{$key};
 
119
            next;
 
120
        }
 
121
 
 
122
        # /pattern/
 
123
        if (m!^/(.*)/([ims]*)!)
 
124
        {
 
125
            my $pat = $2 ? "(?$2)$1" : $1;
 
126
 
 
127
            # Check pattern.
 
128
            eval { $key = qr($pat) };
 
129
            if ($@)
 
130
            {
 
131
                $@ =~ s/ at .*? line \d.*//;
 
132
                die "$inc:$.:$@";
 
133
            }
 
134
 
 
135
            $hash = \%append;
 
136
            next;
 
137
        }
 
138
 
 
139
        # Check for options before the first section--anything else is
 
140
        # silently ignored, allowing the first for comments and
 
141
        # revision info.
 
142
        unless ($key)
 
143
        {
 
144
            # handle options
 
145
            if (/^-/)
 
146
            {
 
147
                local @ARGV = split;
 
148
                GetOptions %opt_def;
 
149
            }
 
150
 
 
151
            next;
 
152
        }
 
153
 
 
154
        $hash->{$key} ||= '';
 
155
        $hash->{$key} .= $_;
 
156
    }
 
157
 
 
158
    close INC;
 
159
 
 
160
    die "$this_program: no valid information found in `$inc'\n"
 
161
        unless $key;
 
162
}
 
163
 
 
164
# Compress trailing blank lines.
 
165
for my $hash (\(%include, %append))
 
166
{
 
167
    for (keys %$hash) { $hash->{$_} =~ s/\n+$/\n/ }
 
168
}
 
169
 
 
170
# Turn off localisation of executable's ouput.
 
171
@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
 
172
 
 
173
# Turn off localisation of date (for strftime).
 
174
setlocale LC_TIME, 'C';
 
175
 
 
176
# Grab help and version info from executable.
 
177
my ($help_text, $version_text) = map {
 
178
    join '', map { s/ +$//; expand $_ } `$ARGV[0] --$_ 2>/dev/null`
 
179
        or die "$this_program: can't get `--$_' info from $ARGV[0]\n"
 
180
} qw(help version);
 
181
 
 
182
my $date = strftime "%B %Y", localtime;
 
183
(my $program = $ARGV[0]) =~ s!.*/!!;
 
184
my $package = $program;
 
185
my $version;
 
186
 
 
187
if ($opt_output)
 
188
{
 
189
    unlink $opt_output
 
190
        or die "$this_program: can't unlink $opt_output ($!)\n"
 
191
        if -e $opt_output;
 
192
 
 
193
    open STDOUT, ">$opt_output"
 
194
        or die "$this_program: can't create $opt_output ($!)\n";
 
195
}
 
196
 
 
197
# The first line of the --version information is assumed to be in one
 
198
# of the following formats:
 
199
#
 
200
#   <version>
 
201
#   <program> <version>
 
202
#   {GNU,Free} <program> <version>
 
203
#   <program> ({GNU,Free} <package>) <version>
 
204
#   <program> - {GNU,Free} <package> <version>
 
205
#
 
206
# and seperated from any copyright/author details by a blank line.
 
207
 
 
208
($_, $version_text) = split /\n+/, $version_text, 2;
 
209
 
 
210
if (/^(\S+) +\(((?:GNU|Free) +[^)]+)\) +(.*)/ or
 
211
    /^(\S+) +- *((?:GNU|Free) +\S+) +(.*)/)
 
212
{
 
213
    $program = $1;
 
214
    $package = $2;
 
215
    $version = $3;
 
216
}
 
217
elsif (/^((?:GNU|Free) +)?(\S+) +(.*)/)
 
218
{
 
219
    $program = $2;
 
220
    $package = $1 ? "$1$2" : $2;
 
221
    $version = $3;
 
222
}
 
223
else
 
224
{
 
225
    $version = $_;
 
226
}
 
227
 
 
228
$program =~ s!.*/!!;
 
229
 
 
230
# No info for `info' itself.
 
231
$opt_no_info = 1 if $program eq 'info';
 
232
 
 
233
# --name overrides --include contents.
 
234
$include{NAME} = "$program \\- $opt_name\n" if $opt_name;
 
235
 
 
236
# Default (useless) NAME paragraph.
 
237
$include{NAME} ||= "$program \\- manual page for $program $version\n";
 
238
 
 
239
# Man pages traditionally have the page title in caps.
 
240
my $PROGRAM = uc $program;
 
241
 
 
242
# Extract usage clause(s) [if any] for SYNOPSIS.
 
243
if ($help_text =~ s/^Usage:( +(\S+))(.*)((?:\n(?: {6}\1| *or: +\S).*)*)//m)
 
244
{
 
245
    my @syn = $2 . $3;
 
246
 
 
247
    if ($_ = $4)
 
248
    {
 
249
        s/^\n//;
 
250
        for (split /\n/) { s/^ *(or: +)?//; push @syn, $_ }
 
251
    }
 
252
 
 
253
    my $synopsis = '';
 
254
    for (@syn)
 
255
    {
 
256
        $synopsis .= ".br\n" if $synopsis;
 
257
        s!^\S*/!!;
 
258
        s/^(\S+) *//;
 
259
        $synopsis .= ".B $1\n";
 
260
        s/\s+$//;
 
261
        s/(([][]|\.\.+)+)/\\fR$1\\fI/g;
 
262
        s/^/\\fI/ unless s/^\\fR//;
 
263
        $_ .= '\fR';
 
264
        s/(\\fI)( *)/$2$1/g;
 
265
        s/\\fI\\fR//g;
 
266
        s/^\\fR//;
 
267
        s/\\fI$//;
 
268
        s/^\./\\&./;
 
269
 
 
270
        $synopsis .= "$_\n";
 
271
    }
 
272
 
 
273
    $include{SYNOPSIS} ||= $synopsis;
 
274
}
 
275
 
 
276
# Process text, initial section is DESCRIPTION.
 
277
my $sect = 'DESCRIPTION';
 
278
$_ = "$help_text\n\n$version_text";
 
279
 
 
280
# Normalise paragraph breaks.
 
281
s/^\n+//;
 
282
s/\n*$/\n/;
 
283
s/\n\n+/\n\n/g;
 
284
 
 
285
# Temporarily exchange leading dots, apostrophes and backslashes for
 
286
# tokens.
 
287
s/^\./\x80/mg;
 
288
s/^'/\x81/mg;
 
289
s/\\/\x82/g;
 
290
 
 
291
# Start a new paragraph (if required) for these.
 
292
s/([^\n])\n(Report +bugs|Email +bug +reports +to|Written +by)/$1\n\n$2/g;
 
293
 
 
294
sub convert_option;
 
295
 
 
296
while (length)
 
297
{
 
298
    # Convert some standard paragraph names.
 
299
    if (s/^(Options|Examples): *\n//)
 
300
    {
 
301
        $sect = uc $1;
 
302
        next;
 
303
    }
 
304
 
 
305
    # Copyright section
 
306
    if (/^Copyright +[(\xa9]/)
 
307
    {
 
308
        $sect = 'COPYRIGHT';
 
309
        $include{$sect} ||= '';
 
310
        $include{$sect} .= ".PP\n" if $include{$sect};
 
311
 
 
312
        my $copy;
 
313
        ($copy, $_) = split /\n\n/, $_, 2;
 
314
 
 
315
        for ($copy)
 
316
        {
 
317
            # Add back newline
 
318
            s/\n*$/\n/;
 
319
 
 
320
            # Convert iso9959-1 copyright symbol or (c) to nroff
 
321
            # character.
 
322
            s/^Copyright +(?:\xa9|\([Cc]\))/Copyright \\(co/mg;
 
323
 
 
324
            # Insert line breaks before additional copyright messages
 
325
            # and the disclaimer.
 
326
            s/(.)\n(Copyright |This +is +free +software)/$1\n.br\n$2/g;
 
327
 
 
328
            # Join hyphenated lines.
 
329
            s/([A-Za-z])-\n */$1/g;
 
330
        }
 
331
 
 
332
        $include{$sect} .= $copy;
 
333
        $_ ||= '';
 
334
        next;
 
335
    }
 
336
 
 
337
    # Catch bug report text.
 
338
    if (/^(Report +bugs|Email +bug +reports +to) /)
 
339
    {
 
340
        $sect = 'REPORTING BUGS';
 
341
    }
 
342
 
 
343
    # Author section.
 
344
    elsif (/^Written +by/)
 
345
    {
 
346
        $sect = 'AUTHOR';
 
347
    }
 
348
 
 
349
    # Examples, indicated by an indented leading $, % or > are
 
350
    # rendered in a constant width font.
 
351
    if (/^( +)([\$\%>] )\S/)
 
352
    {
 
353
        my $indent = $1;
 
354
        my $prefix = $2;
 
355
        my $break = '.IP';
 
356
        $include{$sect} ||= '';
 
357
        while (s/^$indent\Q$prefix\E(\S.*)\n*//)
 
358
        {
 
359
            $include{$sect} .= "$break\n\\f(CW$prefix$1\\fR\n";
 
360
            $break = '.br';
 
361
        }
 
362
 
 
363
        next;
 
364
    }
 
365
 
 
366
    my $matched = '';
 
367
    $include{$sect} ||= '';
 
368
 
 
369
    # Sub-sections have a trailing colon and the second line indented.
 
370
    if (s/^(\S.*:) *\n / /)
 
371
    {
 
372
        $matched .= $& if %append;
 
373
        $include{$sect} .= qq(.SS "$1"\n);
 
374
    }
 
375
 
 
376
    my $indent = 0;
 
377
    my $content = '';
 
378
 
 
379
    # Option with description.
 
380
    if (s/^( {1,10}([+-]\S.*?))(?:(  +)|\n( {20,}))(\S.*)\n//)
 
381
    {
 
382
        $matched .= $& if %append;
 
383
        $indent = length ($4 || "$1$3");
 
384
        $content = ".TP\n\x83$2\n\x83$5\n";
 
385
        unless ($4)
 
386
        {
 
387
            # Indent may be different on second line.
 
388
            $indent = length $& if /^ {20,}/;
 
389
        }
 
390
    }
 
391
 
 
392
    # Option without description.
 
393
    elsif (s/^ {1,10}([+-]\S.*)\n//)
 
394
    {
 
395
        $matched .= $& if %append;
 
396
        $content = ".HP\n\x83$1\n";
 
397
        $indent = 80; # not continued
 
398
    }
 
399
 
 
400
    # Indented paragraph with tag.
 
401
    elsif (s/^( +(\S.*?)  +)(\S.*)\n//)
 
402
    {
 
403
        $matched .= $& if %append;
 
404
        $indent = length $1;
 
405
        $content = ".TP\n\x83$2\n\x83$3\n";
 
406
    }
 
407
 
 
408
    # Indented paragraph.
 
409
    elsif (s/^( +)(\S.*)\n//)
 
410
    {
 
411
        $matched .= $& if %append;
 
412
        $indent = length $1;
 
413
        $content = ".IP\n\x83$2\n";
 
414
    }
 
415
 
 
416
    # Left justified paragraph.
 
417
    else
 
418
    {
 
419
        s/(.*)\n//;
 
420
        $matched .= $& if %append;
 
421
        $content = ".PP\n" if $include{$sect};
 
422
        $content .= "$1\n";
 
423
    }
 
424
 
 
425
    # Append continuations.
 
426
    while (s/^ {$indent}(\S.*)\n//)
 
427
    {
 
428
        $matched .= $& if %append;
 
429
        $content .= "\x83$1\n"
 
430
    }
 
431
 
 
432
    # Move to next paragraph.
 
433
    s/^\n+//;
 
434
 
 
435
    for ($content)
 
436
    {
 
437
        # Leading dot and apostrophe protection.
 
438
        s/\x83\./\x80/g;
 
439
        s/\x83'/\x81/g;
 
440
        s/\x83//g;
 
441
 
 
442
        # Convert options.
 
443
        s/(^| )(-[][\w=-]+)/$1 . convert_option $2/mge;
 
444
    }
 
445
 
 
446
    # Check if matched paragraph contains /pat/.
 
447
    if (%append)
 
448
    {
 
449
        for my $pat (keys %append)
 
450
        {
 
451
            if ($matched =~ $pat)
 
452
            {
 
453
                $content .= ".PP\n" unless $append{$pat} =~ /^\./;
 
454
                $content .= $append{$pat};
 
455
            }
 
456
        }
 
457
    }
 
458
 
 
459
    $include{$sect} .= $content;
 
460
}
 
461
 
 
462
# Refer to the real documentation.
 
463
unless ($opt_no_info)
 
464
{
 
465
    $sect = 'SEE ALSO';
 
466
    $include{$sect} ||= '';
 
467
    $include{$sect} .= ".PP\n" if $include{$sect};
 
468
    $include{$sect} .= <<EOT;
 
469
The full documentation for
 
470
.B $program
 
471
is maintained as a Texinfo manual.  If the
 
472
.B info
 
473
and
 
474
.B $program
 
475
programs are properly installed at your site, the command
 
476
.IP
 
477
.B info $program
 
478
.PP
 
479
should give you access to the complete manual.
 
480
EOT
 
481
}
 
482
 
 
483
# Output header.
 
484
print <<EOT;
 
485
.\\" DO NOT MODIFY THIS FILE!  It was generated by $this_program $this_version.
 
486
.TH $PROGRAM "$section" "$date" "$package $version" GNU
 
487
EOT
 
488
 
 
489
# Section ordering.
 
490
my @pre = qw(NAME SYNOPSIS DESCRIPTION OPTIONS EXAMPLES);
 
491
my @post = ('AUTHOR', 'REPORTING BUGS', 'COPYRIGHT', 'SEE ALSO');
 
492
my $filter = join '|', @pre, @post;
 
493
 
 
494
# Output content.
 
495
for (@pre, (grep ! /^($filter)$/o, @include), @post)
 
496
{
 
497
    if ($include{$_})
 
498
    {
 
499
        my $quote = /\W/ ? '"' : '';
 
500
        print ".SH $quote$_$quote\n";
 
501
 
 
502
        for ($include{$_})
 
503
        {
 
504
            # Replace leading dot, apostrophe and backslash tokens.
 
505
            s/\x80/\\&./g;
 
506
            s/\x81/\\&'/g;
 
507
            s/\x82/\\e/g;
 
508
            print;
 
509
        }
 
510
    }
 
511
}
 
512
 
 
513
exit;
 
514
 
 
515
# Convert option dashes to \- to stop nroff from hyphenating 'em, and
 
516
# embolden.  Option arguments get italicised.
 
517
sub convert_option
 
518
{
 
519
    local $_ = '\fB' . shift;
 
520
 
 
521
    s/-/\\-/g;
 
522
    unless (s/\[=(.*)\]$/\\fR[=\\fI$1\\fR]/)
 
523
    {
 
524
        s/=(.)/\\fR=\\fI$1/;
 
525
        s/ (.)/ \\fI$1/;
 
526
        $_ .= '\fR';
 
527
    }
 
528
 
 
529
    $_;
 
530
}