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:
Dag-Erling Smørgrav 2002-02-18 19:08:28 +00:00
parent 6b7c9e3837
commit c47feff831
1 changed files with 287 additions and 43 deletions

View File

@ -38,37 +38,74 @@
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");
return;
}
sysopen(FILE, $fn, O_RDONLY)
or die("$fn: open(): $!\n");
$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 ];
$mdoc .= ".Dd $TODAY
.Dt " . uc($func) . " 3
%xref = (
"pam 3" => 1
);
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,24 +354,27 @@ Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
as part of the DARPA CHATS research program.
";
$fn = "$func.3";
sysopen(FILE, $fn, O_RDWR|O_CREAT|O_TRUNC)
$fn = "$func->{'name'}.3";
sysopen(FILE, $fn, O_RDWR|O_CREAT|O_TRUNC)
or die("$fn: open(): $!\n");
print(FILE $mdoc);
close(FILE);
print(FILE $mdoc);
close(FILE);
}
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();
}