autodocifier.pl 6.4 KB

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