autodocifier.pl 5.7 KB

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