| #!/usr/bin/perl |
| |
| use strict; |
| use IO::File; |
| use Getopt::Std; |
| our %opts = (W => 2); |
| |
| getopts('ohwW:', \%opts) || usage(); |
| |
| usage() if ($opts{'h'}); |
| |
| usage() if ($#ARGV != 1); |
| |
| # should be the feature-details.h file |
| my $inputfile = shift @ARGV; |
| my $outputfile = shift @ARGV; |
| |
| my %features; |
| my %top; |
| my %files; |
| my $reqfile; |
| |
| gather_data($inputfile); |
| if ($opts{'w'}) { |
| print_wiki_mode($outputfile); |
| } else { |
| print_org_mode($outputfile); |
| } |
| |
| sub gather_data { |
| my ($inputfile) = @_; |
| |
| open(I, $inputfile); |
| while(<I>) { |
| if (/(required|provided|wanted) by (.*) \*/) { |
| $reqfile = $2; |
| } elsif (/define NETSNMP_FEATURE_PROVIDE_(.*) 1/) { |
| my $lc = lc($1); |
| die "no reqfile currently set; bug!" if (!defined($reqfile)); |
| |
| add($lc); |
| |
| push @{$files{$reqfile}{'provides'}}, $lc; |
| push @{$features{$lc}{'providedby'}}, $reqfile; |
| |
| } elsif (/define NETSNMP_FEATURE_REQUIRE_(.*) 1/) { |
| my $lc = lc($1); |
| die "no reqfile currently set; bug!" if (!defined($reqfile)); |
| |
| add($lc); |
| |
| push @{$files{$reqfile}{'requires'}}, $lc; |
| push @{$features{$lc}{'requiredby'}}, $reqfile; |
| |
| } elsif (/define NETSNMP_FEATURE_WANT_(.*) 1/) { |
| my $lc = lc($1); |
| die "no reqfile currently set; bug!" if (!defined($reqfile)); |
| |
| add($lc); |
| |
| push @{$files{$reqfile}{'wants'}}, $lc; |
| push @{$features{$lc}{'wantedby'}}, $reqfile; |
| } elsif (/define NETSNMP_FEATURE_(.*)_CHILD_OF_(.*) 1/) { |
| my $child = lc($1); |
| my $parent = lc($2); |
| |
| add_child($child, $parent); |
| } |
| } |
| } |
| |
| sub add { |
| my ($name) = @_; |
| if (!exists($features{$name})) { |
| # new feature entirely, mark it as a top node |
| $top{$name} = 1; |
| } |
| } |
| |
| sub add_child { |
| my ($child, $parent) = @_; |
| |
| add($parent); |
| |
| if (exists($top{$child})) { |
| # it's no longer a top node if it's a child of something else |
| delete $top{$child}; |
| } |
| $features{$parent}{'children'}{$child}++; |
| |
| $features{$child}{'providedby'}, $reqfile; |
| } |
| |
| ###################################################################### |
| # org-mode output |
| # |
| sub print_org_mode { |
| my ($outputfile) = @_; |
| |
| my $fh = new IO::File; |
| |
| if (!$fh->open("> $outputfile")) { |
| die "error!\n"; |
| } |
| |
| foreach my $node (sort keys(%top)) { |
| print_org_node($fh, $node, "*"); |
| } |
| } |
| |
| sub print_org_node { |
| my ($fh, $node, $prefix) = @_; |
| |
| my $spaces = $prefix; |
| $spaces =~ s/./ /g; |
| |
| print $fh "$prefix $node\n"; |
| if (exists($features{$node}{'providedby'})) { |
| print $fh "$spaces + provided in file: " . |
| join(", ", org_link_files(@{$features{$node}{'providedby'}})) . "\n"; |
| } |
| if (exists($features{$node}{'requiredby'})) { |
| print $fh "$spaces + required in file: " . |
| join(", ", org_link_files(@{$features{$node}{'requiredby'}})) . "\n"; |
| } |
| if (exists($features{$node}{'wantedby'})) { |
| print $fh "$spaces + wanted in file: " . |
| join(", ", org_link_files(@{$features{$node}{'wantedby'}})) . "\n"; |
| } |
| if (exists($features{$node}{'children'})) { |
| foreach my $child (sort keys(%{$features{$node}{'children'}})) { |
| print_org_node($fh, $child, $prefix . "*"); |
| } |
| } |
| } |
| |
| sub org_link_files { |
| my @files = @_; |
| map { $_ = "[[file:$_][$_]]"; } @files; |
| return @files; |
| } |
| |
| ###################################################################### |
| # wiki output |
| # |
| sub print_wiki_mode { |
| my ($outputfile) = @_; |
| |
| my $fh = new IO::File; |
| my $depth = 0; |
| |
| if (!$fh->open("> $outputfile")) { |
| die "error!\n"; |
| } |
| |
| print $fh "'''The contents of this page is auto-generated from local/minimalist/feature-makedocs; do not edit by hand (changes will be lost)'''\n\n"; |
| print $fh "Details of the feature marking system and how it is used can be found at [[Feature Marking and Selection]]\n\n"; |
| |
| foreach my $node (sort keys(%top)) { |
| print_wiki_node($fh, $node, $depth+1); |
| } |
| } |
| |
| sub print_wiki_node { |
| my ($fh, $node, $depth) = @_; |
| |
| my $dataheader; |
| my $depthincrease = 1; |
| |
| if ($depth > $opts{'W'}) { |
| print $fh "*" x ($depth - $opts{'W'} + 1) . " $node\n"; |
| $dataheader = "*" x ($depth - $opts{'W'} + 2); |
| $depthincrease++; |
| } else { |
| print $fh "=" x $depth . " $node " . "=" x $depth . "\n"; |
| $dataheader = "*"; |
| } |
| |
| if (exists($features{$node}{'providedby'})) { |
| print $fh "$dataheader provided in file: " . |
| join(", ", wiki_link_files(@{$features{$node}{'providedby'}})) ."\n"; |
| } |
| if (exists($features{$node}{'requiredby'})) { |
| print $fh "$dataheader required in file: " . |
| join(", ", wiki_link_files(@{$features{$node}{'requiredby'}})) ."\n"; |
| } |
| if (exists($features{$node}{'wantedby'})) { |
| print $fh "$dataheader wanted in file: " . |
| join(", ", wiki_link_files(@{$features{$node}{'wantedby'}})) . "\n"; |
| } |
| if (exists($features{$node}{'children'})) { |
| if ($depth >= $opts{'W'}) { |
| print $fh "$dataheader Children:\n"; |
| } |
| foreach my $child (sort keys(%{$features{$node}{'children'}})) { |
| print_wiki_node($fh, $child, $depth + $depthincrease); |
| } |
| } |
| } |
| |
| sub wiki_link_files { |
| my @files = @_; |
| map { $_ = "[http://net-snmp.svn.sourceforge.net/viewvc/net-snmp/trunk/net-snmp/$_?view=markup $_]"; } @files; |
| return @files; |
| } |
| |
| ###################################################################### |
| # help output |
| # |
| sub usage { |
| print "Usage: $0 [FLAGS] INPUTFILE OUTPUTFILE\n\n"; |
| print "FLAGS:\n"; |
| print "\t-h\thelp\n"; |
| print "\t-o\tOutput style: Org-Mode [default]\n"; |
| print "\t-w\tOutput style: wiki\n"; |
| print "\t-W DEPTH\tWiki header to bullet list depth (default 2)\n"; |
| print "\nINPUT/OUTPUT\n"; |
| print "\tINPUTFILE:\tlocation of the include/net-snmp/feature-details.h file\n"; |
| print "\tOUTPUTFILE:\tthe file to write the results to\n"; |
| exit; |
| } |