autodocifier.pl 6.2 KB

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