[git commit master] Update documentation generator so that it sucks less

Denys Vlasenko vda.linux at googlemail.com
Thu Oct 1 23:10:32 UTC 2009


commit: http://git.busybox.net/busybox/commit/?id=acabf8fcb86302e55e01f0a20d5ff9914791416a
branch: http://git.busybox.net/busybox/commit/?id=refs/heads/master

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 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 d9a2367..b0ef056 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 9830379..a966f6e 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 17135dd..e67f017 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 1e038b3..d4fd12f 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 0000000..058e0c8
--- /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 <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
+
+*/
diff --git a/docs/autodocifier.pl b/docs/autodocifier.pl
deleted file mode 100755
index e3ba5c9..0000000
--- 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/(?<!\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}) {
-	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<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 <andersen at codepoet.org> which was in turn based on a
-script by Mark Whitley <markw at codepoet.org>
-
-=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 <b at ax9.org>
-
-=cut
-
diff --git a/docs/busybox_header.pod b/docs/busybox_header.pod
index 9f2ffc4..2a99636 100644
--- a/docs/busybox_header.pod
+++ b/docs/busybox_header.pod
@@ -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
 
-- 
1.6.3.3



More information about the busybox-cvs mailing list