Update documentation generator so that it sucks less
No binary (build failed)
—
(log yok)
| @@ -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 | |
| @@ -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 | |
| @@ -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); | |
| @@ -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[] = "" | |
| @@ -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 <unistd.h> |
| + | #include <stdint.h> |
| + | #include <string.h> |
| + | #include <stdio.h> |
| + | |
| + | /* 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> |
| + | |
| + | 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 |
| + | |
| + | */ |
| @@ -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/(?<!\w)(-\w+)/B<$1>/sxg; |
| - | } |
| - | my @f0 = |
| - | map { $_ !~ /^\s/ && s/(?<!\w)(-\w+)/B<$1>/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}) { |
| - | |
| - | "$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<usage.h>, |
| - | F<docs/busybox.pod>. This was tedious and error-prone, so it was |
| - | decided that F<usage.h> 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<autodocifier.pl> is one such script. It is based on a script by |
| - | Erik Andersen <[email protected]> which was in turn based on a |
| - | script by Mark Whitley <[email protected]> |
| - | |
| - | =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<trivial> |
| - | |
| - | 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<REQUIRED> |
| - | |
| - | =item B<full> |
| - | |
| - | 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<REQUIRED> |
| - | |
| - | =item B<notes> |
| - | |
| - | 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<usage.h>. I<OPTIONAL> |
| - | |
| - | =item B<example> |
| - | |
| - | 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<OPTIONAL> |
| - | |
| - | =back |
| - | |
| - | =head1 FILES |
| - | |
| - | F<usage.h> |
| - | |
| - | =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 <[email protected]> |
| - | |
| - | =cut |
| - | |
| @@ -8,7 +8,7 @@ BusyBox - The Swiss Army Knife of Embedded Linux | |
| busybox <applet> [arguments...] # or | |
| - | <applet> [arguments...] # if symlinked |
| + | <applet> [arguments...] # if symlinked |
| =head1 DESCRIPTION | |