292 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			Perl
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			292 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			Perl
		
	
	
		
			Executable File
		
	
	
	
	
| #!/usr/bin/perl -w
 | |
| 
 | |
| 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;
 | |
| 	$text =~ s/USAGE_NOT\w+\(.*?"\s*\)//sxg;
 | |
| 	$text =~ s/USAGE_\w+\(\s*?(.*?)"\s*\)/$1"/sxg;
 | |
| 	$text =~ s/"\s*"//sg;
 | |
| 	my @line = split("\n", $text);
 | |
| 	$text = join('',
 | |
| 		map { 
 | |
| 			s/^\s*"//;
 | |
| 			s/"\s*$//;
 | |
| 			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;
 | |
| 
 | |
| 	# make options bold
 | |
| 	my $trivial = $usage->{trivial};
 | |
| 	$trivial =~ s/(?<!\w)(-\w+)/B<$1>/sxg;
 | |
| 	my @f0 = 
 | |
| 		map { $_ !~ /^\s/ && s/(?<!\w)(-\w+)/B<$1>/g; $_ }
 | |
| 		split("\n", $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"
 | |
| 		: "";
 | |
| 
 | |
| 	return
 | |
| 		"=item B<$name>".
 | |
| 		"\n\n"  .
 | |
| 		"$name $trivial".
 | |
| 		"\n\n"  .
 | |
| 		$full   .
 | |
| 		"\n\n"  .
 | |
| 		$notes  .
 | |
| 		$example.
 | |
| 		"-------------------------------".
 | |
| 		"\n\n"
 | |
| 	;
 | |
| }
 | |
| 
 | |
| # FIXME | generate SGML for an applet
 | |
| sub sgml_for_usage {
 | |
| 	my $name  = shift;
 | |
| 	my $usage = shift;
 | |
| 	return
 | |
| 		"<fixme>\n".
 | |
| 		"  $name\n".
 | |
| 		"</fixme>\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",
 | |
| 	"sgml|s",
 | |
| 	"pod|p",
 | |
| 	"verbose|v",
 | |
| );
 | |
| 
 | |
| if (defined $opt{help}) {
 | |
| 	print
 | |
| 		"$0 [OPTION]... [FILE]...\n",
 | |
| 		"\t--help\n",
 | |
| 		"\t--sgml\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;
 | |
| if (defined $opt{sgml}) {
 | |
| 	$generator = \&sgml_for_usage;
 | |
| }
 | |
| 
 | |
| foreach my $applet (sort keys %docs) {
 | |
| 	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>, and
 | |
| F<docs/busybox.sgml>.  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 was based on a script by Erik Andersen <andersen@lineo.com>
 | |
| which was in turn based on a script by Mark Whitley <markw@lineo.com>
 | |
| 
 | |
| =head1 OPTIONS
 | |
| 
 | |
| =over 4
 | |
| 
 | |
| =item B<--help>
 | |
| 
 | |
| This displays the help message.
 | |
| 
 | |
| =item B<--pod>
 | |
| 
 | |
| Generate POD (this is the default)
 | |
| 
 | |
| =item B<--sgml>
 | |
| 
 | |
| Generate SGML
 | |
| 
 | |
| =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@ax9.org>
 | |
| 
 | |
| =cut
 | |
| 
 | |
| # $Id: autodocifier.pl,v 1.23 2001/10/31 04:29:18 beppu Exp $
 |