some combinations of status line and screen refresh don't give a
[people/mcb30/busybox.git] / docs / autodocifier.pl
1 #!/usr/bin/perl -w
2
3 use strict;
4 use Getopt::Long;
5
6 # collect lines continued with a '\' into an array
7 sub continuation {
8         my $fh = shift;
9         my @line;
10
11         while (<$fh>) {
12                 my $s = $_;
13                 $s =~ s/\\\s*$//;
14                 #$s =~ s/#.*$//;
15                 push @line, $s;
16                 last unless (/\\\s*$/);
17         }
18         return @line;
19 }
20
21 # regex && eval away unwanted strings from documentation
22 sub beautify {
23         my $text = shift;
24         $text =~ s/USAGE_NOT\w+\(.*?"\s*\)//sxg;
25         $text =~ s/USAGE_\w+\(\s*?(.*?)"\s*\)/$1"/sxg;
26         $text =~ s/"\s*"//sg;
27         my @line = split("\n", $text);
28         $text = join('',
29                 map {
30                         s/^\s*"//;
31                         s/"\s*$//;
32                         s/%/%%/g;
33                         s/\$/\\\$/g;
34                         eval qq[ sprintf(qq{$_}) ]
35                 } @line
36         );
37         return $text;
38 }
39
40 # generate POD for an applet
41 sub pod_for_usage {
42         my $name  = shift;
43         my $usage = shift;
44
45         # Sigh.  Fixup the known odd-name applets.
46         $name =~ s/dpkg_deb/dpkg-deb/g;
47         $name =~ s/fsck_minix/fsck.minix/g;
48         $name =~ s/mkfs_minix/mkfs.minix/g;
49         $name =~ s/run_parts/run-parts/g;
50         $name =~ s/start_stop_daemon/start-stop-daemon/g;
51
52         # make options bold
53         my $trivial = $usage->{trivial};
54         $trivial =~ s/(?<!\w)(-\w+)/B<$1>/sxg;
55         my @f0 =
56                 map { $_ !~ /^\s/ && s/(?<!\w)(-\w+)/B<$1>/g; $_ }
57                 split("\n", $usage->{full});
58
59         # add "\n" prior to certain lines to make indented
60         # lines look right
61         my @f1;
62         my $len = @f0;
63         for (my $i = 0; $i < $len; $i++) {
64                 push @f1, $f0[$i];
65                 if (($i+1) != $len && $f0[$i] !~ /^\s/ && $f0[$i+1] =~ /^\s/) {
66                         next if ($f0[$i] =~ /^$/);
67                         push(@f1, "") unless ($f0[$i+1] =~ /^\s*$/s);
68                 }
69         }
70         my $full = join("\n", @f1);
71
72         # prepare notes if they exist
73         my $notes = (defined $usage->{notes})
74                 ? "$usage->{notes}\n\n"
75                 : "";
76
77         # prepare examples if they exist
78         my $example = (defined $usage->{example})
79                 ?
80                         "Example:\n\n" .
81                         join ("\n",
82                         map  { "\t$_" }
83                         split("\n", $usage->{example})) . "\n\n"
84                 : "";
85
86         return
87                 "=item B<$name>".
88                 "\n\n$name $trivial\n\n".
89                 "$full\n\n"   .
90                 "$notes"  .
91                 "$example" .
92                 "-------------------------------".
93                 "\n\n"
94         ;
95 }
96
97 # the keys are applet names, and
98 # the values will contain hashrefs of the form:
99 #
100 # {
101 #     trivial => "...",
102 #     full    => "...",
103 #     notes   => "...",
104 #     example => "...",
105 # }
106 my %docs;
107
108
109 # get command-line options
110
111 my %opt;
112
113 GetOptions(
114         \%opt,
115         "help|h",
116         "pod|p",
117         "verbose|v",
118 );
119
120 if (defined $opt{help}) {
121         print
122                 "$0 [OPTION]... [FILE]...\n",
123                 "\t--help\n",
124                 "\t--pod\n",
125                 "\t--verbose\n",
126         ;
127         exit 1;
128 }
129
130
131 # collect documenation into %docs
132
133 foreach (@ARGV) {
134         open(USAGE, $_) || die("$0: $_: $!");
135         my $fh = *USAGE;
136         my ($applet, $type, @line);
137         while (<$fh>) {
138                 if (/^#define (\w+)_(\w+)_usage/) {
139                         $applet = $1;
140                         $type   = $2;
141                         @line   = continuation($fh);
142                         my $doc = $docs{$applet} ||= { };
143                         my $text      = join("\n", @line);
144                         $doc->{$type} = beautify($text);
145                 }
146         }
147 }
148
149
150 # generate structured documentation
151
152 my $generator = \&pod_for_usage;
153 foreach my $applet (sort keys %docs) {
154         print $generator->($applet, $docs{$applet});
155 }
156
157 exit 0;
158
159 __END__
160
161 =head1 NAME
162
163 autodocifier.pl - generate docs for busybox based on usage.h
164
165 =head1 SYNOPSIS
166
167 autodocifier.pl [OPTION]... [FILE]...
168
169 Example:
170
171     ( cat docs/busybox_header.pod; \
172       docs/autodocifier.pl usage.h; \
173       cat docs/busybox_footer.pod ) > docs/busybox.pod
174
175 =head1 DESCRIPTION
176
177 The purpose of this script is to automagically generate
178 documentation for busybox using its usage.h as the original source
179 for content.  It used to be that same content has to be duplicated
180 in 3 places in slightly different formats -- F<usage.h>,
181 F<docs/busybox.pod>.  This was tedious and error-prone, so it was
182 decided that F<usage.h> would contain all the text in a
183 machine-readable form, and scripts could be used to transform this
184 text into other forms if necessary.
185
186 F<autodocifier.pl> is one such script.  It is based on a script by
187 Erik Andersen <andersen@codepoet.org> which was in turn based on a
188 script by Mark Whitley <markw@codepoet.org>
189
190 =head1 OPTIONS
191
192 =over 4
193
194 =item B<--help>
195
196 This displays the help message.
197
198 =item B<--pod>
199
200 Generate POD (this is the default)
201
202 =item B<--verbose>
203
204 Be verbose (not implemented)
205
206 =back
207
208 =head1 FORMAT
209
210 The following is an example of some data this script might parse.
211
212     #define length_trivial_usage \
213             "STRING"
214     #define length_full_usage \
215             "Prints out the length of the specified STRING."
216     #define length_example_usage \
217             "$ length Hello\n" \
218             "5\n"
219
220 Each entry is a cpp macro that defines a string.  The macros are
221 named systematically in the form:
222
223     $name_$type_usage
224
225 $name is the name of the applet.  $type can be "trivial", "full", "notes",
226 or "example".  Every documentation macro must end with "_usage".
227
228 The definition of the types is as follows:
229
230 =over 4
231
232 =item B<trivial>
233
234 This should be a brief, one-line description of parameters that
235 the command expects.  This will be displayed when B<-h> is issued to
236 a command.  I<REQUIRED>
237
238 =item B<full>
239
240 This should contain descriptions of each option.  This will also
241 be displayed along with the trivial help if CONFIG_FEATURE_TRIVIAL_HELP
242 is disabled.  I<REQUIRED>
243
244 =item B<notes>
245
246 This is documentation that is intended to go in the POD or SGML, but
247 not be printed when a B<-h> is given to a command.  To see an example
248 of notes being used, see init_notes_usage in F<usage.h>.  I<OPTIONAL>
249
250 =item B<example>
251
252 This should be an example of how the command is actually used.
253 This will not be printed when a B<-h> is given to a command -- it
254 will only be included in the POD or SGML documentation.  I<OPTIONAL>
255
256 =back
257
258 =head1 FILES
259
260 F<usage.h>
261
262 =head1 COPYRIGHT
263
264 Copyright (c) 2001 John BEPPU.  All rights reserved.  This program is
265 free software; you can redistribute it and/or modify it under the same
266 terms as Perl itself.
267
268 =head1 AUTHOR
269
270 John BEPPU <b@ax9.org>
271
272 =cut
273
274 # $Id: autodocifier.pl,v 1.26 2004/04/06 15:26:25 andersen Exp $