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