mirror of
https://github.com/moparisthebest/wget
synced 2024-07-03 16:38:41 -04:00
325 lines
7.1 KiB
Perl
Executable File
325 lines
7.1 KiB
Perl
Executable File
#!/usr/bin/perl
|
|
|
|
# Copyright (C) 2008, 2009 Free Software Foundation, Inc.
|
|
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
use strict;
|
|
use warnings;
|
|
use constant true => 1;
|
|
use constant false => 0;
|
|
|
|
use FindBin qw($Bin);
|
|
use File::Spec ();
|
|
|
|
my $main_c_file = File::Spec->catfile($Bin, File::Spec->updir, 'src', 'main.c');
|
|
my $init_c_file = File::Spec->catfile($Bin, File::Spec->updir, 'src', 'init.c');
|
|
my $tex_file = File::Spec->catfile($Bin, File::Spec->updir, 'doc', 'wget.texi');
|
|
my $main_content = read_file($main_c_file);
|
|
my $init_content = read_file($init_c_file);
|
|
my $tex_content = read_file($tex_file);
|
|
|
|
my @args = ([
|
|
$main_content,
|
|
qr/static \s+? struct \s+? cmdline_option \s+? option_data\[\] \s+? = \s+? \{ (.*?) \}\;/sx,
|
|
[ qw(long_name short_name type data argtype) ],
|
|
], [
|
|
$init_content,
|
|
qr/commands\[\] \s+? = \s+? \{ (.*?) \}\;/sx,
|
|
[ qw(name place action) ],
|
|
]);
|
|
|
|
{
|
|
my @data;
|
|
|
|
foreach my $arg (@args) {
|
|
my ($source, $regex, $names) = @$arg;
|
|
my @chunks = extract_chunks($source, $regex);
|
|
push @data, extract_entries(\@chunks, $names);
|
|
}
|
|
|
|
output_results(@data);
|
|
}
|
|
|
|
sub read_file
|
|
{
|
|
my ($file) = @_;
|
|
|
|
open(my $fh, '<', $file) or die "Cannot open $file: $!";
|
|
|
|
return do { local $/; <$fh> };
|
|
}
|
|
|
|
sub extract_chunks
|
|
{
|
|
my ($source, $regex) = @_;
|
|
|
|
my ($raw_data) = $source =~ $regex;
|
|
|
|
return map { /\S/ && !/^\#/ ? $_ : () } split /(?<=\})/, $raw_data;
|
|
}
|
|
|
|
sub extract_entries
|
|
{
|
|
my ($chunks, $names) = @_;
|
|
|
|
my (@entries, %index, $i);
|
|
|
|
foreach my $chunk (@$chunks) {
|
|
my ($args) = $chunk =~ /\{ \s+? (.*?) \s+? \}/sx;
|
|
next unless defined $args;
|
|
|
|
my @args = map {
|
|
tr/'"//d; $_
|
|
} map {
|
|
/\((.*?)\)/ ? $1 : $_
|
|
} split /\,\s+/, $args;
|
|
|
|
my $entry = { map { $_ => shift @args } @$names };
|
|
|
|
($entry->{line}) = $chunk =~ /^ \s+? (\{.*)/mx;
|
|
if ($chunk =~ /deprecated/i) {
|
|
$entries[-1]->{deprecated} = true;
|
|
}
|
|
|
|
my $index_name = exists $entry->{data}
|
|
? $entry->{data}
|
|
: $entry->{name};
|
|
|
|
$index{$index_name} = $i++;
|
|
|
|
push @entries, $entry;
|
|
}
|
|
|
|
push @entries, \%index;
|
|
|
|
return \@entries;
|
|
}
|
|
|
|
sub output_results
|
|
{
|
|
my ($opts, $cmds) = @_;
|
|
|
|
my %index = (
|
|
opts => pop @$opts,
|
|
cmds => pop @$cmds,
|
|
);
|
|
|
|
emit_no_corresponding_cmds($opts);
|
|
print "\n";
|
|
emit_no_matching_long_cmds($opts);
|
|
print "\n";
|
|
emit_no_corresponding_opts($opts, $cmds);
|
|
print "\n";
|
|
emit_deprecated_opts($opts);
|
|
print "\n";
|
|
emit_deprecated_cmds($cmds);
|
|
print "\n";
|
|
|
|
emit_undocumented_opts($tex_content, $main_content, $opts);
|
|
print "\n";
|
|
emit_undocumented_cmds($tex_content, $opts, $cmds, \%index);
|
|
print "\n";
|
|
}
|
|
|
|
sub emit_no_corresponding_cmds
|
|
{
|
|
my ($opts) = @_;
|
|
|
|
my @options;
|
|
foreach my $opt (@$opts) {
|
|
unless ($opt->{type} =~ /^(?:OPT_BOOLEAN|OPT_VALUE)$/
|
|
&& $opt->{argtype} == -1)
|
|
{
|
|
push @options, $opt->{line};
|
|
}
|
|
}
|
|
|
|
local $" = "\n";
|
|
print <<EOT;
|
|
No corresponding commands
|
|
=========================
|
|
@options
|
|
EOT
|
|
}
|
|
|
|
sub emit_no_matching_long_cmds
|
|
{
|
|
my ($opts) = @_;
|
|
|
|
my @options;
|
|
foreach my $opt (@$opts) {
|
|
my $long_name = $opt->{long_name};
|
|
$long_name =~ tr/-//d;
|
|
unless ($long_name eq $opt->{data}) {
|
|
push @options, $opt->{line};
|
|
}
|
|
}
|
|
|
|
local $" = "\n";
|
|
print <<EOT;
|
|
Non-matching commands
|
|
=====================
|
|
@options
|
|
EOT
|
|
}
|
|
|
|
sub emit_no_corresponding_opts
|
|
{
|
|
my ($opts, $cmds) = @_;
|
|
|
|
my @commands;
|
|
foreach my $cmd (@$cmds) {
|
|
my $found = false;
|
|
foreach my $opt (@$opts) {
|
|
my $long_name = $opt->{long_name};
|
|
$long_name =~ tr/-//d;
|
|
if ($cmd->{name} eq $opt->{data}
|
|
|| $cmd->{name} eq $long_name) {
|
|
$found = true;
|
|
last;
|
|
}
|
|
}
|
|
unless ($found) {
|
|
push @commands, $cmd->{line};
|
|
}
|
|
}
|
|
|
|
local $" = "\n";
|
|
print <<EOT;
|
|
No corresponding options
|
|
========================
|
|
@commands
|
|
EOT
|
|
}
|
|
|
|
sub emit_deprecated_opts
|
|
{
|
|
my ($opts) = @_;
|
|
|
|
my @options;
|
|
foreach my $opt (@$opts) {
|
|
if ($opt->{deprecated}) {
|
|
push @options, $opt->{line};
|
|
}
|
|
}
|
|
|
|
local $" = "\n";
|
|
print <<EOT;
|
|
Deprecated options
|
|
==================
|
|
@options
|
|
EOT
|
|
}
|
|
|
|
sub emit_deprecated_cmds
|
|
{
|
|
my ($cmds) = @_;
|
|
|
|
my @commands;
|
|
foreach my $cmd (@$cmds) {
|
|
if ($cmd->{deprecated}) {
|
|
push @commands, $cmd->{line};
|
|
}
|
|
}
|
|
|
|
local $" = "\n";
|
|
print <<EOT;
|
|
Deprecated commands
|
|
===================
|
|
@commands
|
|
EOT
|
|
}
|
|
|
|
sub find_documentation
|
|
{
|
|
my ($push, $opt) = (shift, shift);
|
|
my $info = [];
|
|
|
|
my $opt_name = $opt->{'long_name'};
|
|
for my $doc (@_) {
|
|
next if $opt->{'deprecated'};
|
|
if ($doc->{$opt_name}
|
|
|| ($opt_name !~ /^no/ && $doc->{"no-$opt_name"})) {
|
|
push @$info, 1;
|
|
} else {
|
|
push @$info, 0;
|
|
}
|
|
}
|
|
push @$push, [$opt_name, @$info] if grep {$_ eq 0} @$info;
|
|
}
|
|
|
|
sub emit_undocumented_opts
|
|
{
|
|
my ($tex, $main, $opts) = @_;
|
|
|
|
my (%tex_items, %main_items);
|
|
while ($tex =~ /^\@item\w*? \s+? --([\w\-]+)/gmx) {
|
|
$tex_items{$1} = true;
|
|
}
|
|
($main) = $main =~ /(\nprint_help.*\n}\n)/s;
|
|
while ($main =~ /--([-a-z0-9]+)/g) {
|
|
$main_items{$1} = true;
|
|
}
|
|
my @options;
|
|
foreach my $opt (@$opts) {
|
|
find_documentation (\@options, $opt, \%tex_items, \%main_items);
|
|
}
|
|
|
|
local $" = "\n";
|
|
print <<EOT;
|
|
Undocumented options Not In:
|
|
==================== ==================
|
|
EOT
|
|
for my $opt (@options) {
|
|
printf("%-29s ", $opt->[0]);
|
|
print 'texinfo ' unless $opt->[1];
|
|
print 'nor ' unless $opt->[1] or $opt->[2];
|
|
print '--help ' unless $opt->[2];
|
|
print "\n";
|
|
}
|
|
}
|
|
|
|
sub emit_undocumented_cmds
|
|
{
|
|
my ($tex, $opts, $cmds, $index) = @_;
|
|
|
|
my %items;
|
|
while ($tex =~ /^\@item\w*? \s+? ([\w\_]+) \s+? = \s+? \S+?/gmx) {
|
|
my $cmd = $1;
|
|
$cmd =~ tr/_//d;
|
|
$items{$cmd} = true;
|
|
}
|
|
my @commands;
|
|
foreach my $cmd (@$cmds) {
|
|
my $cmd_name = do {
|
|
local $_ = exists $index->{opts}->{$cmd->{name}}
|
|
? $opts->[$index->{opts}->{$cmd->{name}}]->{long_name}
|
|
: $cmd->{name};
|
|
tr/-/_/;
|
|
$_;
|
|
};
|
|
if (not $items{$cmd->{name}} || $cmd->{deprecated}) {
|
|
push @commands, $cmd_name;
|
|
}
|
|
}
|
|
|
|
local $" = "\n";
|
|
print <<EOT;
|
|
Undocumented commands
|
|
=====================
|
|
@commands
|
|
EOT
|
|
}
|