From acabf8fcb86302e55e01f0a20d5ff9914791416a Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 2 Oct 2009 01:10:32 +0200 Subject: [PATCH] Update documentation generator so that it sucks less Signed-off-by: Denys Vlasenko --- Makefile.custom | 18 +-- applets/Kbuild | 9 +- applets/applet_tables.c | 21 +-- applets/usage.c | 14 +- applets/usage_pod.c | 97 +++++++++++++ docs/autodocifier.pl | 307 ---------------------------------------- docs/busybox_header.pod | 2 +- 7 files changed, 132 insertions(+), 336 deletions(-) create mode 100644 applets/usage_pod.c delete mode 100755 docs/autodocifier.pl diff --git a/Makefile.custom b/Makefile.custom index d9a2367ab..b0ef05627 100644 --- a/Makefile.custom +++ b/Makefile.custom @@ -111,15 +111,19 @@ doc: docs/busybox.pod docs/BusyBox.txt docs/BusyBox.1 docs/BusyBox.html silent_cmd_doc = disp_doc = $($(quiet)cmd_doc) +# sed adds newlines after "Options:" etc, +# this is needed in order to get good BusyBox.{1,txt,html} docs/busybox.pod: $(srctree)/docs/busybox_header.pod \ $(srctree)/include/usage.h \ $(srctree)/docs/busybox_footer.pod \ - $(srctree)/docs/autodocifier.pl + applets/usage_pod $(disp_doc) $(Q)-mkdir -p docs - $(Q)-( cat $(srctree)/docs/busybox_header.pod ; \ - $(srctree)/docs/autodocifier.pl $(srctree)/include/usage.h ; \ - cat $(srctree)/docs/busybox_footer.pod ; ) > docs/busybox.pod + $(Q)-( \ + cat $(srctree)/docs/busybox_header.pod; \ + applets/usage_pod | sed 's/^[A-Za-z][A-Za-z ]*[a-z]:$$/&\n/'; \ + cat $(srctree)/docs/busybox_footer.pod; \ + ) > docs/busybox.pod docs/BusyBox.txt: docs/busybox.pod $(disp_doc) @@ -129,8 +133,7 @@ docs/BusyBox.txt: docs/busybox.pod docs/BusyBox.1: docs/busybox.pod $(disp_doc) $(Q)-mkdir -p docs - $(Q)-pod2man --center=BusyBox --release="version $(VERSION)" \ - $< > $@ + $(Q)-pod2man --center=BusyBox --release="version $(VERSION)" $< > $@ docs/BusyBox.html: docs/busybox.net/BusyBox.html $(disp_doc) @@ -140,8 +143,7 @@ docs/BusyBox.html: docs/busybox.net/BusyBox.html docs/busybox.net/BusyBox.html: docs/busybox.pod $(Q)-mkdir -p docs/busybox.net - $(Q)-pod2html --noindex $< > \ - docs/busybox.net/BusyBox.html + $(Q)-pod2html --noindex $< > $@ $(Q)-rm -f pod2htm* # documentation, cross-reference diff --git a/applets/Kbuild b/applets/Kbuild index 983037987..a966f6e5b 100644 --- a/applets/Kbuild +++ b/applets/Kbuild @@ -8,7 +8,7 @@ obj-y := obj-y += applets.o hostprogs-y:= -hostprogs-y += usage applet_tables +hostprogs-y += usage usage_pod applet_tables always:= $(hostprogs-y) @@ -22,13 +22,14 @@ else srctree_slash = $(srctree)/ endif - -HOSTCFLAGS_usage.o = -I$(srctree_slash)include +HOSTCFLAGS_usage.o = -I$(srctree_slash)include -Iinclude +HOSTCFLAGS_usage_pod.o = -I$(srctree_slash)include -Iinclude applets/applets.o: include/usage_compressed.h include/applet_tables.h -applets/usage: .config $(srctree_slash)applets/usage_compressed applets/applet_tables: .config +applets/usage: .config +applets/usage_pod: .config include/applet_tables.h quiet_cmd_gen_usage_compressed = GEN include/usage_compressed.h cmd_gen_usage_compressed = $(srctree_slash)applets/usage_compressed include/usage_compressed.h applets diff --git a/applets/applet_tables.c b/applets/applet_tables.c index 17135ddc1..e67f017e7 100644 --- a/applets/applet_tables.c +++ b/applets/applet_tables.c @@ -70,29 +70,32 @@ int main(int argc, char **argv) /* Keep in sync with include/busybox.h! */ - puts("/* This is a generated file, don't edit */\n"); + printf("/* This is a generated file, don't edit */\n\n"); printf("#define NUM_APPLETS %u\n", NUM_APPLETS); if (NUM_APPLETS == 1) { printf("#define SINGLE_APPLET_STR \"%s\"\n", applets[0].name); printf("#define SINGLE_APPLET_MAIN %s_main\n", applets[0].name); } + printf("\n"); - puts("\nconst char applet_names[] ALIGN1 = \"\""); + printf("const char applet_names[] ALIGN1 = \"\"\n"); for (i = 0; i < NUM_APPLETS; i++) { printf("\"%s\" \"\\0\"\n", applets[i].name); if (MAX_APPLET_NAME_LEN < strlen(applets[i].name)) MAX_APPLET_NAME_LEN = strlen(applets[i].name); } - puts(";"); + printf(";\n\n"); - puts("\nint (*const applet_main[])(int argc, char **argv) = {"); + printf("#ifndef SKIP_applet_main\n"); + printf("int (*const applet_main[])(int argc, char **argv) = {\n"); for (i = 0; i < NUM_APPLETS; i++) { printf("%s_main,\n", applets[i].main); } - puts("};"); + printf("};\n"); + printf("#endif\n\n"); - puts("const uint16_t applet_nameofs[] ALIGN2 = {"); + printf("const uint16_t applet_nameofs[] ALIGN2 = {\n"); for (i = 0; i < NUM_APPLETS; i++) { printf("0x%04x,\n", offset[i] @@ -105,10 +108,10 @@ int main(int argc, char **argv) #endif ); } - puts("};"); + printf("};\n\n"); #if ENABLE_FEATURE_INSTALLER - puts("const uint8_t applet_install_loc[] ALIGN1 = {"); + printf("const uint8_t applet_install_loc[] ALIGN1 = {\n"); i = 0; while (i < NUM_APPLETS) { int v = applets[i].install_loc; /* 3 bits */ @@ -117,7 +120,7 @@ int main(int argc, char **argv) printf("0x%02x,\n", v); i++; } - puts("};\n"); + printf("};\n\n"); #endif printf("#define MAX_APPLET_NAME_LEN %u\n", MAX_APPLET_NAME_LEN); diff --git a/applets/usage.c b/applets/usage.c index 1e038b367..d4fd12f9b 100644 --- a/applets/usage.c +++ b/applets/usage.c @@ -8,17 +8,17 @@ /* Just #include "autoconf.h" doesn't work for builds in separate * object directory */ -#include "../include/autoconf.h" +#include "autoconf.h" /* Since we can't use platform.h, have to do this again by hand: */ #if ENABLE_NOMMU -#define BB_MMU 0 -#define USE_FOR_NOMMU(...) __VA_ARGS__ -#define USE_FOR_MMU(...) +# define BB_MMU 0 +# define USE_FOR_NOMMU(...) __VA_ARGS__ +# define USE_FOR_MMU(...) #else -#define BB_MMU 1 -#define USE_FOR_NOMMU(...) -#define USE_FOR_MMU(...) __VA_ARGS__ +# define BB_MMU 1 +# define USE_FOR_NOMMU(...) +# define USE_FOR_MMU(...) __VA_ARGS__ #endif static const char usage_messages[] = "" diff --git a/applets/usage_pod.c b/applets/usage_pod.c new file mode 100644 index 000000000..058e0c842 --- /dev/null +++ b/applets/usage_pod.c @@ -0,0 +1,97 @@ +/* vi: set sw=4 ts=4: */ +/* + * Copyright (C) 2009 Denys Vlasenko. + * + * Licensed under GPLv2, see file LICENSE in this tarball for details. + */ +#include +#include +#include +#include + +/* Just #include "autoconf.h" doesn't work for builds in separate + * object directory */ +#include "autoconf.h" + +#define SKIP_applet_main +#define ALIGN1 /* nothing, just to placate applet_tables.h */ +#define ALIGN2 /* nothing, just to placate applet_tables.h */ +#include "applet_tables.h" + +/* Since we can't use platform.h, have to do this again by hand: */ +#if ENABLE_NOMMU +# define BB_MMU 0 +# define USE_FOR_NOMMU(...) __VA_ARGS__ +# define USE_FOR_MMU(...) +#else +# define BB_MMU 1 +# define USE_FOR_NOMMU(...) +# define USE_FOR_MMU(...) __VA_ARGS__ +#endif + +static const char usage_messages[] = "" +#define MAKE_USAGE +#include "usage.h" +#include "applets.h" +; + +int main(void) +{ + const char *names; + const char *usage; + int col, len2; + + col = 0; + names = applet_names; + while (*names) { + len2 = strlen(names) + 2; + if (col >= 76 - len2) { + printf(",\n"); + col = 0; + } + if (col == 0) { + col = 6; + printf("\t"); + } else { + printf(", "); + } + printf(names); + col += len2; + names += len2 - 1; + } + printf("\n\n"); + + printf("=head1 COMMAND DESCRIPTIONS\n\n"); + printf("=over 4\n\n"); + + names = applet_names; + usage = usage_messages; + while (*names && usage) { + if (*names >= 'a' && *names <= 'z' + && *usage != NOUSAGE_STR[0] + ) { + printf("=item B<%s>\n\n", names); + printf("%s %s\n\n", names, usage); + } + names += strlen(names) + 1; + usage += strlen(usage) + 1; + } + return 0; +} + +/* TODO: we used to make options bold with B<> and output an example too: + +=item B + +cat [B<-u>] [FILE]... + +Concatenate FILE(s) and print them to stdout + +Options: + -u Use unbuffered i/o (ignored) + +Example: + $ cat /proc/uptime + 110716.72 17.67 + +*/ diff --git a/docs/autodocifier.pl b/docs/autodocifier.pl deleted file mode 100755 index e3ba5c94b..000000000 --- a/docs/autodocifier.pl +++ /dev/null @@ -1,307 +0,0 @@ -#!/usr/bin/perl -w -# vi: set sw=4 ts=4: - -use strict; -use Getopt::Long; - -# collect lines continued with a '\' into an array -sub continuation { - my $fh = shift; - my @line; - - while (<$fh>) { - my $s = $_; - $s =~ s/\\\s*$//; - #$s =~ s/#.*$//; - push @line, $s; - last unless (/\\\s*$/); - } - return @line; -} - -# regex && eval away unwanted strings from documentation -sub beautify { - my $text = shift; - for (;;) { - my $text2 = $text; - $text =~ s/IF_NOT_\w+\(.*?"\s*\)//sxg; - $text =~ s/IF_\w+\(\s*?(.*?)"\s*\)/$1"/sxg; - $text =~ s/USAGE_\w+\(\s*?(.*?)"\s*\)/$1"/sxg; - last if ( $text2 eq $text ); - } - $text =~ s/"\s*"//sg; - my @line = split("\n", $text); - $text = join('', - map { - s/^\s*"//; - s/"\s*$//; - s/%/%%/g; - s/\$/\\\$/g; - s/\@/\\\@/g; - eval qq[ sprintf(qq{$_}) ] - } @line - ); - return $text; -} - -# generate POD for an applet -sub pod_for_usage { - my $name = shift; - my $usage = shift; - - # Sigh. Fixup the known odd-name applets. -# Perhaps we can use some of APPLET_ODDNAME from include/applets.h ? - $name =~ s/dpkg_deb/dpkg-deb/g; - $name =~ s/fsck_minix/fsck.minix/g; - $name =~ s/mkfs_minix/mkfs.minix/g; - $name =~ s/run_parts/run-parts/g; - $name =~ s/start_stop_daemon/start-stop-daemon/g; - $name =~ s/ether_wake/ether-wake/g; - - # make options bold - my $trivial = $usage->{trivial}; - if (!defined $usage->{trivial}) { - $trivial = ""; - } else { - $trivial =~ s/(?/sxg; - } - my @f0 = - map { $_ !~ /^\s/ && s/(?/g; $_ } - split("\n", (defined $usage->{full} ? $usage->{full} : "")); - - # add "\n" prior to certain lines to make indented - # lines look right - my @f1; - my $len = @f0; - for (my $i = 0; $i < $len; $i++) { - push @f1, $f0[$i]; - if (($i+1) != $len && $f0[$i] !~ /^\s/ && $f0[$i+1] =~ /^\s/) { - next if ($f0[$i] =~ /^$/); - push(@f1, "") unless ($f0[$i+1] =~ /^\s*$/s); - } - } - my $full = join("\n", @f1); - - # prepare notes if they exist - my $notes = (defined $usage->{notes}) - ? "$usage->{notes}\n\n" - : ""; - - # prepare examples if they exist - my $example = (defined $usage->{example}) - ? - "Example:\n\n" . - join ("\n", - map { "\t$_" } - split("\n", $usage->{example})) . "\n\n" - : ""; - - # Pad the name so that the applet name gets a line - # by itself in BusyBox.txt - my $spaces = 10 - length($name); - if ($spaces > 0) { - $name .= " " x $spaces; - } - - return - "=item B<$name>". - "\n\n$name $trivial\n\n". - "$full\n\n" . - "$notes" . - "$example" . - "\n\n" - ; -} - -# the keys are applet names, and -# the values will contain hashrefs of the form: -# -# { -# trivial => "...", -# full => "...", -# notes => "...", -# example => "...", -# } -my %docs; - - -# get command-line options - -my %opt; - -GetOptions( - \%opt, - "help|h", - "pod|p", - "verbose|v", -); - -if (defined $opt{help}) { - print - "$0 [OPTION]... [FILE]...\n", - "\t--help\n", - "\t--pod\n", - "\t--verbose\n", - ; - exit 1; -} - - -# collect documenation into %docs - -foreach (@ARGV) { - open(USAGE, $_) || die("$0: $_: $!"); - my $fh = *USAGE; - my ($applet, $type, @line); - while (<$fh>) { - if (/^#define (\w+)_(\w+)_usage/) { - $applet = $1; - $type = $2; - @line = continuation($fh); - my $doc = $docs{$applet} ||= { }; - my $text = join("\n", @line); - $doc->{$type} = beautify($text); - } - } -} - - -# generate structured documentation - -my $generator = \&pod_for_usage; - -my @names = sort keys %docs; -my $line = "\t[, [[, "; -for (my $i = 0; $i < $#names; $i++) { - if (length ($line.$names[$i]) >= 65) { - print "$line\n\t"; - $line = ""; - } - $line .= "$names[$i], "; -} -print $line . $names[-1]; - -print "\n\n=head1 COMMAND DESCRIPTIONS\n"; -print "\n=over 4\n\n"; - -foreach my $applet (@names) { - print $generator->($applet, $docs{$applet}); -} - -exit 0; - -__END__ - -=head1 NAME - -autodocifier.pl - generate docs for busybox based on usage.h - -=head1 SYNOPSIS - -autodocifier.pl [OPTION]... [FILE]... - -Example: - - ( cat docs/busybox_header.pod; \ - docs/autodocifier.pl usage.h; \ - cat docs/busybox_footer.pod ) > docs/busybox.pod - -=head1 DESCRIPTION - -The purpose of this script is to automagically generate -documentation for busybox using its usage.h as the original source -for content. It used to be that same content has to be duplicated -in 3 places in slightly different formats -- F, -F. This was tedious and error-prone, so it was -decided that F would contain all the text in a -machine-readable form, and scripts could be used to transform this -text into other forms if necessary. - -F is one such script. It is based on a script by -Erik Andersen which was in turn based on a -script by Mark Whitley - -=head1 OPTIONS - -=over 4 - -=item B<--help> - -This displays the help message. - -=item B<--pod> - -Generate POD (this is the default) - -=item B<--verbose> - -Be verbose (not implemented) - -=back - -=head1 FORMAT - -The following is an example of some data this script might parse. - - #define length_trivial_usage \ - "STRING" - #define length_full_usage \ - "Prints out the length of the specified STRING." - #define length_example_usage \ - "$ length Hello\n" \ - "5\n" - -Each entry is a cpp macro that defines a string. The macros are -named systematically in the form: - - $name_$type_usage - -$name is the name of the applet. $type can be "trivial", "full", "notes", -or "example". Every documentation macro must end with "_usage". - -The definition of the types is as follows: - -=over 4 - -=item B - -This should be a brief, one-line description of parameters that -the command expects. This will be displayed when B<-h> is issued to -a command. I - -=item B - -This should contain descriptions of each option. This will also -be displayed along with the trivial help if CONFIG_FEATURE_TRIVIAL_HELP -is disabled. I - -=item B - -This is documentation that is intended to go in the POD or SGML, but -not be printed when a B<-h> is given to a command. To see an example -of notes being used, see init_notes_usage in F. I - -=item B - -This should be an example of how the command is actually used. -This will not be printed when a B<-h> is given to a command -- it -will only be included in the POD or SGML documentation. I - -=back - -=head1 FILES - -F - -=head1 COPYRIGHT - -Copyright (c) 2001 John BEPPU. All rights reserved. This program is -free software; you can redistribute it and/or modify it under the same -terms as Perl itself. - -=head1 AUTHOR - -John BEPPU - -=cut - diff --git a/docs/busybox_header.pod b/docs/busybox_header.pod index 9f2ffc48d..2a99636b1 100644 --- a/docs/busybox_header.pod +++ b/docs/busybox_header.pod @@ -8,7 +8,7 @@ BusyBox - The Swiss Army Knife of Embedded Linux busybox [arguments...] # or - [arguments...] # if symlinked + [arguments...] # if symlinked =head1 DESCRIPTION -- 2.25.1