Teach gendoc to parse a simple syntax for inline documentation.
Sponsored by: DARPA, NAI Labs git-svn-id: svn+ssh://svn.openpam.org/svn/openpam/trunk@62 185d5e19-27fe-0310-9dcf-9bff6b9f3609
This commit is contained in:
parent
6b7c9e3837
commit
c47feff831
320
misc/gendoc.pl
320
misc/gendoc.pl
|
@ -38,19 +38,56 @@
|
|||
use strict;
|
||||
use Fcntl;
|
||||
use POSIX qw(strftime);
|
||||
use vars qw($COPYRIGHT $TODAY %FUNCTIONS);
|
||||
use vars qw($COPYRIGHT $TODAY %FUNCTIONS %PAMERR);
|
||||
|
||||
sub gendoc($) {
|
||||
%PAMERR = (
|
||||
PAM_SUCCESS => "Success",
|
||||
PAM_OPEN_ERR => "Failed to load module",
|
||||
PAM_SYMBOL_ERR => "Invalid symbol",
|
||||
PAM_SERVICE_ERR => "Error in service module",
|
||||
PAM_SYSTEM_ERR => "System error",
|
||||
PAM_BUF_ERR => "Memory buffer error",
|
||||
PAM_CONV_ERR => "Conversation failure",
|
||||
PAM_PERM_DENIED => "Permission denied",
|
||||
PAM_MAXTRIES => "Maximum number of tries exceeded",
|
||||
PAM_AUTH_ERR => "Authentication error",
|
||||
PAM_NEW_AUTHTOK_REQD => "New authentication token required",
|
||||
PAM_CRED_INSUFFICIENT => "Insufficient credentials",
|
||||
PAM_AUTHINFO_UNAVAIL => "Authentication information is unavailable",
|
||||
PAM_USER_UNKNOWN => "Unknown user",
|
||||
PAM_CRED_UNAVAIL => "Failed to retrieve user credentials",
|
||||
PAM_CRED_EXPIRED => "User credentials have expired",
|
||||
PAM_CRED_ERR => "Failed to set user credentials",
|
||||
PAM_ACCT_EXPIRED => "User accound has expired",
|
||||
PAM_AUTHTOK_EXPIRED => "Password has expired",
|
||||
PAM_SESSION_ERR => "Session failure",
|
||||
PAM_AUTHTOK_ERR => "Authentication token failure",
|
||||
PAM_AUTHTOK_RECOVERY_ERR => "Failed to recover old authentication token",
|
||||
PAM_AUTHTOK_LOCK_BUSY => "Authentication token lock busy",
|
||||
PAM_AUTHTOK_DISABLE_AGING => "Authentication token aging disabled",
|
||||
PAM_NO_MODULE_DATA => "Module data not found",
|
||||
PAM_IGNORE => "Ignore this module",
|
||||
PAM_ABORT => "General failure",
|
||||
PAM_TRY_AGAIN => "Try again",
|
||||
PAM_MODULE_UNKNOWN => "Unknown module type",
|
||||
PAM_DOMAIN_UNKNOWN => "Unknown authentication domain",
|
||||
);
|
||||
|
||||
sub parse_source($) {
|
||||
my $fn = shift;
|
||||
|
||||
local *FILE;
|
||||
my $source;
|
||||
my $mdoc;
|
||||
my $func;
|
||||
my $descr;
|
||||
my $type;
|
||||
my $args;
|
||||
my $name;
|
||||
my $argnames;
|
||||
my $man;
|
||||
my $inlist;
|
||||
my $inliteral;
|
||||
my %xref;
|
||||
my @errors;
|
||||
|
||||
if ($fn !~ m,\.c$,) {
|
||||
warn("$fn: not C source, ignoring\n");
|
||||
|
@ -62,13 +99,13 @@ sub gendoc($) {
|
|||
$source = join('', <FILE>);
|
||||
close(FILE);
|
||||
|
||||
if ($source =~ m,^(/\*-\n.*?)\s*\*/,s) {
|
||||
$mdoc = $1;
|
||||
$mdoc =~ s,^.\*,.\\\",gm;
|
||||
$mdoc .= "\n.\\\"\n";
|
||||
$COPYRIGHT = $mdoc;
|
||||
} else {
|
||||
$mdoc = ".\\\" \$" . "Id" . "\$\n";
|
||||
return if ($source =~ m/^ \* NOPARSE\s*$/m);
|
||||
|
||||
if (!defined($COPYRIGHT) && $source =~ m,^(/\*-\n.*?)\s*\*/,s) {
|
||||
$COPYRIGHT = $1;
|
||||
$COPYRIGHT =~ s,^.\*,.\\\",gm;
|
||||
$COPYRIGHT =~ s,(\$Id).*?\$,$1\$,;
|
||||
$COPYRIGHT .= "\n.\\\"";
|
||||
}
|
||||
$func = $fn;
|
||||
$func =~ s,^(?:.*/)?([^/]+)\.c$,$1,;
|
||||
|
@ -85,34 +122,224 @@ sub gendoc($) {
|
|||
$args =~ s/,\s+/, /gs;
|
||||
$args = "\"$args\"";
|
||||
|
||||
$FUNCTIONS{$func} = [ $type, $args ];
|
||||
%xref = (
|
||||
"pam 3" => 1
|
||||
);
|
||||
|
||||
$mdoc .= ".Dd $TODAY
|
||||
.Dt " . uc($func) . " 3
|
||||
if ($type eq "int") {
|
||||
foreach (split("\n", $source)) {
|
||||
next unless (m/^ \*\s+(!?PAM_[A-Z_]+|=[a-z_]+)\s*$/);
|
||||
push(@errors, $1);
|
||||
}
|
||||
$xref{"pam_strerror 3"} = 1;
|
||||
}
|
||||
|
||||
$argnames = $args;
|
||||
$argnames =~ s/\"[^\"]+\*?\b(\w+)\"/\"$1\"/g;
|
||||
$argnames =~ s/([\|\[\]\(\)\.\*\+\?])/\\$1/g;
|
||||
$argnames =~ s/\" \"/|/g;
|
||||
$argnames =~ s/^\"(.*)\"$/($1)/;
|
||||
foreach (split("\n", $source)) {
|
||||
s/\s*$//;
|
||||
if (!defined($man)) {
|
||||
if (m/^\/\*\*$/) {
|
||||
$man = "";
|
||||
}
|
||||
next;
|
||||
}
|
||||
last if (m/^ \*\/$/);
|
||||
s/^ \* ?//;
|
||||
s/\\(.)/$1/gs;
|
||||
if (m/^$/) {
|
||||
if ($man ne "" && $man !~ m/\.Pp\n$/s) {
|
||||
if ($inliteral) {
|
||||
$man .= "\0\n";
|
||||
} elsif ($inlist) {
|
||||
$man .= ".El\n";
|
||||
$inlist = 0;
|
||||
} else {
|
||||
$man .= ".Pp\n";
|
||||
}
|
||||
}
|
||||
next;
|
||||
}
|
||||
if (m/^>(\w+)(?:\s+(\d))?$/) {
|
||||
++$xref{$2 ? "$1 $2" : "$1 3"};
|
||||
next;
|
||||
}
|
||||
if (s/^\s+(=?\w+):\s*/.It $1/) {
|
||||
if ($inliteral) {
|
||||
$man .= ".Ed\n";
|
||||
$inliteral = 0;
|
||||
}
|
||||
if (!$inlist) {
|
||||
$man =~ s/\.Pp\n$//s;
|
||||
$man .= ".Bl -tag -width 18n\n";
|
||||
$inlist = 1;
|
||||
}
|
||||
s/^\.It =([A-Z][A-Z_]+)$/.It Dv $1/gs;
|
||||
$man .= "$_\n";
|
||||
next;
|
||||
} elsif ($inlist && m/^\S/) {
|
||||
$man .= ".El\n";
|
||||
$inlist = 0;
|
||||
} elsif ($inliteral && m/^\S/) {
|
||||
$man .= ".Ed\n";
|
||||
$inlist = 0;
|
||||
} elsif ($inliteral) {
|
||||
$man .= "$_\n";
|
||||
next;
|
||||
} elsif ($inlist) {
|
||||
s/^\s+//;
|
||||
} elsif (m/^\s+/) {
|
||||
$man .= ".Bd -literal\n";
|
||||
$inliteral = 1;
|
||||
$man .= "$_\n";
|
||||
next;
|
||||
}
|
||||
s/\s*=$func\b\s*/\n.Nm\n/gs;
|
||||
s/\s*=$argnames\b\s*/\n.Va $1\n/gs;
|
||||
s/\s*=(struct \w+(?: \*)?)\b\s*/\n.Vt $1\n/gs;
|
||||
if (s/\s*=([a-z_]+)\b\s*/\n.Xr $1 3\n/gs) {
|
||||
++$xref{"$1 3"};
|
||||
}
|
||||
s/\s*\"(?=\w)/\n.Do\n/gs;
|
||||
s/\"(?!\w)\s*/\n.Dc\n/gs;
|
||||
s/\s*=([A-Z][A-Z_]+)\b\s*(?![\.,:;])/\n.Dv $1\n/gs;
|
||||
s/\s*=([A-Z][A-Z_]+)\b([\.,:;]+)\s*/\n.Dv $1 $2\n/gs;
|
||||
s/\s*{([A-Z][a-z] .*?)}\s*/\n.$1\n/gs;
|
||||
$man .= "$_\n";
|
||||
}
|
||||
if (defined($man)) {
|
||||
$man =~ s/(\n\.[A-Z][a-z] [\w ]+)\n([\.,:;-]\S*)\s*/$1 $2\n/gs;
|
||||
$man =~ s/\s*$/\n/gm;
|
||||
$man =~ s/\n+/\n/gs;
|
||||
$man =~ s/\0//gs;
|
||||
chomp($man);
|
||||
} else {
|
||||
$man = "No description available.";
|
||||
}
|
||||
|
||||
$FUNCTIONS{$func} = {
|
||||
'name' => $func,
|
||||
'descr' => $descr,
|
||||
'type' => $type,
|
||||
'args' => $args,
|
||||
'man' => $man,
|
||||
'xref' => \%xref,
|
||||
'errors' => \@errors,
|
||||
};
|
||||
if ($source =~ m/^ \* NODOC\s*$/m) {
|
||||
$FUNCTIONS{$func}->{'nodoc'} = 1;
|
||||
$FUNCTIONS{$func}->{'nolist'} = 1;
|
||||
}
|
||||
if ($source =~ m/^ \* NOLIST\s*$/m) {
|
||||
$FUNCTIONS{$func}->{'nolist'} = 1;
|
||||
}
|
||||
}
|
||||
|
||||
sub expand_errors($);
|
||||
sub expand_errors($) {
|
||||
my $func = shift; # Ref to function hash
|
||||
|
||||
my %errors;
|
||||
|
||||
if (defined($func->{'recursed'})) {
|
||||
warn("$func->{'name'}(): loop in error spec\n");
|
||||
return qw();
|
||||
}
|
||||
$func->{'recursed'} = 1;
|
||||
|
||||
foreach (@{$func->{'errors'}}) {
|
||||
if (m/^(PAM_[A-Z_]+)$/) {
|
||||
if (!defined($PAMERR{$1})) {
|
||||
warn("$func->{'name'}(): unrecognized error: $1\n");
|
||||
next;
|
||||
}
|
||||
$errors{$1} = 1;
|
||||
} elsif (m/^!(PAM_[A-Z_]+)$/) {
|
||||
# treat negations separately
|
||||
} elsif (m/^=([a-z_]+)$/) {
|
||||
if (!defined($FUNCTIONS{$1})) {
|
||||
warn("$func->{'name'}(): reference to unknown $1()\n");
|
||||
next;
|
||||
}
|
||||
foreach (expand_errors($FUNCTIONS{$1})) {
|
||||
$errors{$_} = 1;
|
||||
}
|
||||
} else {
|
||||
warn("$func->{'name'}(): invalid error specification: $_\n");
|
||||
}
|
||||
}
|
||||
foreach (@{$func->{'errors'}}) {
|
||||
if (m/^!(PAM_[A-Z_]+)$/) {
|
||||
delete($errors{$1});
|
||||
}
|
||||
}
|
||||
delete($func->{'recursed'});
|
||||
return (sort(keys(%errors)));
|
||||
}
|
||||
|
||||
sub gendoc($) {
|
||||
my $func = shift; # Ref to function hash
|
||||
|
||||
local *FILE;
|
||||
my $mdoc;
|
||||
my $fn;
|
||||
|
||||
return if defined($func->{'nodoc'});
|
||||
|
||||
$mdoc = "$COPYRIGHT
|
||||
.Dd $TODAY
|
||||
.Dt " . uc($func->{'name'}) . " 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm $func
|
||||
.Nd $descr
|
||||
.Nm $func->{'name'}
|
||||
.Nd $func->{'descr'}
|
||||
.Sh LIBRARY
|
||||
.Lb libpam
|
||||
.Sh SYNOPSIS
|
||||
.In security/pam_appl.h
|
||||
.Ft $type
|
||||
.Fn $func $args
|
||||
";
|
||||
if ($func->{'name'} =~ m/_sm_/) {
|
||||
$mdoc .= ".In security/pam_modules.h\n"
|
||||
}
|
||||
$mdoc .= ".Ft $func->{'type'}
|
||||
.Fn $func->{'name'} $func->{'args'}
|
||||
.Sh DESCRIPTION
|
||||
$func->{'man'}
|
||||
";
|
||||
if ($func->{'type'} eq "int") {
|
||||
$mdoc .= ".Sh RETURN VALUES
|
||||
The
|
||||
.Nm
|
||||
function is not yet documented.
|
||||
.Sh RETURN VALUES
|
||||
The
|
||||
.Fn
|
||||
function returns one of the following values:
|
||||
.Bl -tag -width PAM_AUTHTOK_DISABLE_AGING
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr pam_strerror 3 ,
|
||||
.Xr pam 3
|
||||
.Sh STANDARDS
|
||||
.Bl -tag -width 18n
|
||||
";
|
||||
my @errors = expand_errors($func);
|
||||
warn("$func->{'name'}(): no error specification\n")
|
||||
unless(@errors);
|
||||
foreach (@errors) {
|
||||
$mdoc .= ".It Bq Er $_\n$PAMERR{$_}.\n";
|
||||
}
|
||||
$mdoc .= ".El\n";
|
||||
} else {
|
||||
if ($func->{'type'} =~ m/\*$/) {
|
||||
$mdoc .= ".Sh RETURN VALUES
|
||||
The
|
||||
.Nm
|
||||
function returns
|
||||
.Dv NULL
|
||||
on failure.
|
||||
";
|
||||
}
|
||||
}
|
||||
$mdoc .= ".Sh SEE ALSO\n";
|
||||
my @xref = sort(keys(%{$func->{'xref'}}));
|
||||
while (@xref) {
|
||||
$mdoc .= ".Xr " . shift(@xref) . (@xref ? " ,\n" : "\n");
|
||||
}
|
||||
$mdoc .= ".Sh STANDARDS
|
||||
.Rs
|
||||
.%T \"X/Open Single Sign-On Service (XSSO) - Pluggable Authentication Modules\"
|
||||
.%D \"June 1997\"
|
||||
|
@ -127,7 +354,7 @@ Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
|
|||
as part of the DARPA CHATS research program.
|
||||
";
|
||||
|
||||
$fn = "$func.3";
|
||||
$fn = "$func->{'name'}.3";
|
||||
sysopen(FILE, $fn, O_RDWR|O_CREAT|O_TRUNC)
|
||||
or die("$fn: open(): $!\n");
|
||||
print(FILE $mdoc);
|
||||
|
@ -136,15 +363,18 @@ as part of the DARPA CHATS research program.
|
|||
|
||||
sub gensummary() {
|
||||
|
||||
print "$COPYRIGHT";
|
||||
print ".Dd $TODAY
|
||||
my $func;
|
||||
|
||||
print "$COPYRIGHT
|
||||
.Dd $TODAY
|
||||
.Dt PAM 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
";
|
||||
my @funcs = sort(keys(%FUNCTIONS));
|
||||
while (@funcs) {
|
||||
print ".Nm " . shift(@funcs) . (@funcs ? " ,\n" : "\n");
|
||||
while ($func = shift(@funcs)) {
|
||||
next if (defined($FUNCTIONS{$func}->{'nolist'}));
|
||||
print ".Nm $func". (@funcs ? " ,\n" : "\n");
|
||||
}
|
||||
print ".Nd Pluggable Authentication Modules Library
|
||||
.Sh LIBRARY
|
||||
|
@ -152,15 +382,26 @@ sub gensummary() {
|
|||
.Sh SYNOPSIS
|
||||
.In security/pam_appl.h
|
||||
";
|
||||
foreach my $func (sort(keys(%FUNCTIONS))) {
|
||||
print ".Ft $FUNCTIONS{$func}->[0]\n";
|
||||
print ".Fn $func $FUNCTIONS{$func}->[1]\n";
|
||||
foreach $func (sort(keys(%FUNCTIONS))) {
|
||||
next if (defined($FUNCTIONS{$func}->{'nolist'}));
|
||||
print ".Ft $FUNCTIONS{$func}->{'type'}\n";
|
||||
print ".Fn $func $FUNCTIONS{$func}->{'args'}\n";
|
||||
}
|
||||
print ".Sh DESCRIPTION
|
||||
.Sh RETURN VALUES
|
||||
The following return codes are defined in the
|
||||
.In security/pam_constants.h
|
||||
header:
|
||||
.Bl -tag -width 18n
|
||||
";
|
||||
foreach (sort(keys(%PAMERR))) {
|
||||
print ".It Bq Er $_\n$PAMERR{$_}.\n";
|
||||
}
|
||||
print ".El
|
||||
.Sh SEE ALSO
|
||||
";
|
||||
foreach my $func (sort(keys(%FUNCTIONS))) {
|
||||
foreach $func (sort(keys(%FUNCTIONS))) {
|
||||
next if (defined($FUNCTIONS{$func}->{'nolist'}));
|
||||
print ".Xr $func 3 ,\n";
|
||||
}
|
||||
print ".Xr pam.conf 5
|
||||
|
@ -183,7 +424,10 @@ MAIN:{
|
|||
$TODAY = strftime("%B %e, %Y", localtime(time()));
|
||||
$TODAY =~ s,\s+, ,g;
|
||||
foreach my $fn (@ARGV) {
|
||||
gendoc($fn);
|
||||
parse_source($fn);
|
||||
}
|
||||
foreach my $func (values(%FUNCTIONS)) {
|
||||
gendoc($func);
|
||||
}
|
||||
gensummary();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue