source: openpam/trunk/misc/gendoc.pl @ 534

Last change on this file since 534 was 534, checked in by des, 2 years ago

Additional return value hackery.

  • Property svn:keywords set to Id
File size: 17.1 KB
Line 
1#!/usr/bin/perl -w
2#-
3# Copyright (c) 2002-2003 Networks Associates Technology, Inc.
4# Copyright (c) 2004-2011 Dag-Erling Smørgrav
5# All rights reserved.
6#
7# This software was developed for the FreeBSD Project by ThinkSec AS and
8# Network Associates Laboratories, the Security Research Division of
9# Network Associates, Inc.  under DARPA/SPAWAR contract N66001-01-C-8035
10# ("CBOSS"), as part of the DARPA CHATS research program.
11#
12# Redistribution and use in source and binary forms, with or without
13# modification, are permitted provided that the following conditions
14# are met:
15# 1. Redistributions of source code must retain the above copyright
16#    notice, this list of conditions and the following disclaimer.
17# 2. Redistributions in binary form must reproduce the above copyright
18#    notice, this list of conditions and the following disclaimer in the
19#    documentation and/or other materials provided with the distribution.
20# 3. The name of the author may not be used to endorse or promote
21#    products derived from this software without specific prior written
22#    permission.
23#
24# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
25# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
28# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34# SUCH DAMAGE.
35#
36# $Id$
37#
38
39use strict;
40use locale;
41use Fcntl;
42use Getopt::Std;
43use POSIX qw(locale_h strftime);
44use vars qw($COPYRIGHT %AUTHORS $TODAY %FUNCTIONS %PAMERR);
45
46$COPYRIGHT = ".\\\"-
47.\\\" Copyright (c) 2001-2003 Networks Associates Technology, Inc.
48.\\\" Copyright (c) 2004-2011 Dag-Erling Smørgrav
49.\\\" All rights reserved.
50.\\\"
51.\\\" This software was developed for the FreeBSD Project by ThinkSec AS and
52.\\\" Network Associates Laboratories, the Security Research Division of
53.\\\" Network Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
54.\\\" (\"CBOSS\"), as part of the DARPA CHATS research program.
55.\\\"
56.\\\" Redistribution and use in source and binary forms, with or without
57.\\\" modification, are permitted provided that the following conditions
58.\\\" are met:
59.\\\" 1. Redistributions of source code must retain the above copyright
60.\\\"    notice, this list of conditions and the following disclaimer.
61.\\\" 2. Redistributions in binary form must reproduce the above copyright
62.\\\"    notice, this list of conditions and the following disclaimer in the
63.\\\"    documentation and/or other materials provided with the distribution.
64.\\\" 3. The name of the author may not be used to endorse or promote
65.\\\"    products derived from this software without specific prior written
66.\\\"    permission.
67.\\\"
68.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
69.\\\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
70.\\\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
71.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
72.\\\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
73.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
74.\\\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
75.\\\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
76.\\\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
77.\\\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
78.\\\" SUCH DAMAGE.
79.\\\"
80.\\\" \$" . "Id" . "\$
81.\\\"";
82
83%AUTHORS = (
84    THINKSEC => "ThinkSec AS and Network Associates Laboratories, the
85Security Research Division of Network Associates, Inc.\\& under
86DARPA/SPAWAR contract N66001-01-C-8035
87.Pq Dq CBOSS ,
88as part of the DARPA CHATS research program.",
89    DES => ".An Dag-Erling Sm\\(/orgrav Aq des\@FreeBSD.org .",
90);
91
92%PAMERR = (
93    PAM_SUCCESS                 => "Success",
94    PAM_OPEN_ERR                => "Failed to load module",
95    PAM_SYMBOL_ERR              => "Invalid symbol",
96    PAM_SERVICE_ERR             => "Error in service module",
97    PAM_SYSTEM_ERR              => "System error",
98    PAM_BUF_ERR                 => "Memory buffer error",
99    PAM_CONV_ERR                => "Conversation failure",
100    PAM_PERM_DENIED             => "Permission denied",
101    PAM_MAXTRIES                => "Maximum number of tries exceeded",
102    PAM_AUTH_ERR                => "Authentication error",
103    PAM_NEW_AUTHTOK_REQD        => "New authentication token required",
104    PAM_CRED_INSUFFICIENT       => "Insufficient credentials",
105    PAM_AUTHINFO_UNAVAIL        => "Authentication information is unavailable",
106    PAM_USER_UNKNOWN            => "Unknown user",
107    PAM_CRED_UNAVAIL            => "Failed to retrieve user credentials",
108    PAM_CRED_EXPIRED            => "User credentials have expired",
109    PAM_CRED_ERR                => "Failed to set user credentials",
110    PAM_ACCT_EXPIRED            => "User account has expired",
111    PAM_AUTHTOK_EXPIRED         => "Password has expired",
112    PAM_SESSION_ERR             => "Session failure",
113    PAM_AUTHTOK_ERR             => "Authentication token failure",
114    PAM_AUTHTOK_RECOVERY_ERR    => "Failed to recover old authentication token",
115    PAM_AUTHTOK_LOCK_BUSY       => "Authentication token lock busy",
116    PAM_AUTHTOK_DISABLE_AGING   => "Authentication token aging disabled",
117    PAM_NO_MODULE_DATA          => "Module data not found",
118    PAM_IGNORE                  => "Ignore this module",
119    PAM_ABORT                   => "General failure",
120    PAM_TRY_AGAIN               => "Try again",
121    PAM_MODULE_UNKNOWN          => "Unknown module type",
122    PAM_DOMAIN_UNKNOWN          => "Unknown authentication domain",
123);
124
125sub parse_source($) {
126    my $fn = shift;
127
128    local *FILE;
129    my $source;
130    my $func;
131    my $descr;
132    my $type;
133    my $args;
134    my $argnames;
135    my $man;
136    my $inlist;
137    my $intaglist;
138    my $inliteral;
139    my %xref;
140    my @errors;
141    my $author;
142
143    if ($fn !~ m,\.c$,) {
144        warn("$fn: not C source, ignoring\n");
145        return undef;
146    }
147
148    open(FILE, "<", "$fn")
149        or die("$fn: open(): $!\n");
150    $source = join('', <FILE>);
151    close(FILE);
152
153    return undef
154        if ($source =~ m/^ \* NOPARSE\s*$/m);
155
156    $author = 'THINKSEC';
157    if ($source =~ s/^ \* AUTHOR\s+(.*?)\s*$//m) {
158        $author = $1;
159    }
160
161    $func = $fn;
162    $func =~ s,^(?:.*/)?([^/]+)\.c$,$1,;
163    if ($source !~ m,\n \* ([\S ]+)\n \*/\n\n([\S ]+)\n$func\((.*?)\)\n\{,s) {
164        warn("$fn: can't find $func\n");
165        return undef;
166    }
167    ($descr, $type, $args) = ($1, $2, $3);
168    $descr =~ s,^([A-Z][a-z]),lc($1),e;
169    $descr =~ s,[\.\s]*$,,;
170    while ($args =~ s/^((?:[^\(]|\([^\)]*\))*),\s*/$1\" \"/g) {
171        # nothing
172    }
173    $args =~ s/,\s+/, /gs;
174    $args = "\"$args\"";
175
176    %xref = (
177        3 => { 'pam' => 1 },
178    );
179
180    if ($type eq "int") {
181        foreach (split("\n", $source)) {
182            next unless (m/^ \*\s+(!?PAM_[A-Z_]+|=[a-z_]+)\s*$/);
183            push(@errors, $1);
184        }
185        ++$xref{3}->{'pam_strerror'};
186    }
187
188    $argnames = $args;
189    # extract names of regular arguments
190    $argnames =~ s/\"[^\"]+\*?\b(\w+)\"/\"$1\"/g;
191    # extract names of function pointer arguments
192    $argnames =~ s/\"([\w\s\*]+)\(\*?(\w+)\)\([^\)]+\)\"/\"$2\"/g;
193    # escape metacharacters (there shouldn't be any, but...)
194    $argnames =~ s/([\|\[\]\(\)\.\*\+\?])/\\$1/g;
195    # separate argument names with |
196    $argnames =~ s/\" \"/|/g;
197    # and surround with ()
198    $argnames =~ s/^\"(.*)\"$/($1)/;
199    # $argnames is now a regexp that matches argument names
200    $inliteral = $inlist = $intaglist = 0;
201    foreach (split("\n", $source)) {
202        s/\s*$//;
203        if (!defined($man)) {
204            if (m/^\/\*\*$/) {
205                $man = "";
206            }
207            next;
208        }
209        last if (m/^ \*\/$/);
210        s/^ \* ?//;
211        s/\\(.)/$1/gs;
212        if (m/^$/) {
213            # paragraph separator
214            if ($man ne "" && $man !~ m/\.Pp\n$/s) {
215                if ($inliteral) {
216                    $man .= "\0\n";
217                } elsif ($inlist || $intaglist) {
218                    $man .= ".El\n.Pp\n";
219                    $inlist = $intaglist = 0;
220                } else {
221                    $man .= ".Pp\n";
222                }
223            }
224            next;
225        }
226        if (m/^>(\w+)(\s+\d)?$/) {
227            # "see also" cross-reference
228            my ($page, $sect) = ($1, $2 ? int($2) : 3);
229            ++$xref{$sect}->{$page};
230            next;
231        }
232        if (s/^\s+-\s+//) {
233            # item in bullet list
234            if ($inliteral) {
235                $man .= ".Ed\n";
236                $inliteral = 0;
237            }
238            if ($intaglist) {
239                $man .= ".El\n.Pp\n";
240                $intaglist = 0;
241            }
242            if (!$inlist) {
243                $man =~ s/\.Pp\n$//s;
244                $man .= ".Bl -bullet\n";
245                $inlist = 1;
246            }
247            $man .= ".It\n";
248            # fall through
249        } elsif (s/^\s+(\S+):\s*/.It $1/) {
250            # item in tag list
251            if ($inliteral) {
252                $man .= ".Ed\n";
253                $inliteral = 0;
254            }
255            if ($inlist) {
256                $man .= ".El\n.Pp\n";
257                $inlist = 0;
258            }
259            if (!$intaglist) {
260                $man =~ s/\.Pp\n$//s;
261                $man .= ".Bl -tag -width 18n\n";
262                $intaglist = 1;
263            }
264            s/^\.It =([A-Z][A-Z_]+)$/.It Dv $1/gs;
265            $man .= "$_\n";
266            next;
267        } elsif (($inlist || $intaglist) && m/^\S/) {
268            # regular text after list
269            $man .= ".El\n.Pp\n";
270            $inlist = $intaglist = 0;
271        } elsif ($inliteral && m/^\S/) {
272            # regular text after literal section
273            $man .= ".Ed\n";
274            $inliteral = 0;
275        } elsif ($inliteral) {
276            # additional text within literal section
277            $man .= "$_\n";
278            next;
279        } elsif ($inlist || $intaglist) {
280            # additional text within list
281            s/^\s+//;
282        } elsif (m/^\s+/) {
283            # new literal section
284            $man .= ".Bd -literal\n";
285            $inliteral = 1;
286            $man .= "$_\n";
287            next;
288        }
289        s/\s*=$func\b\s*/\n.Nm\n/gs;
290        s/\s*=$argnames\b\s*/\n.Fa $1\n/gs;
291        s/\s*=(struct \w+(?: \*)?)\b\s*/\n.Vt $1\n/gs;
292        s/\s*:([a-z_]+)\b\s*/\n.Va $1\n/gs;
293        s/\s*;([a-z_]+)\b\s*/\n.Dv $1\n/gs;
294        while (s/\s*=([a-z_]+)\b\s*/\n.Xr $1 3\n/s) {
295            ++$xref{3}->{$1};
296        }
297        s/\s*\"(?=\w)/\n.Do\n/gs;
298        s/\"(?!\w)\s*/\n.Dc\n/gs;
299        s/\s*=([A-Z][A-Z_]+)\b\s*(?![\.,:;])/\n.Dv $1\n/gs;
300        s/\s*=([A-Z][A-Z_]+)\b([\.,:;]+)\s*/\n.Dv $1 $2\n/gs;
301        s/\s*{([A-Z][a-z] .*?)}\s*/\n.$1\n/gs;
302        $man .= "$_\n";
303    }
304    if (defined($man)) {
305        if ($inlist || $intaglist) {
306            $man .= ".El\n";
307            $inlist = $intaglist = 0;
308        }
309        if ($inliteral) {
310            $man .= ".Ed\n";
311            $inliteral = 0;
312        }
313        $man =~ s/\%/\\&\%/gs;
314        $man =~ s/(\n\.[A-Z][a-z] [\w ]+)\n([\.,:;-]\S*)\s*/$1 $2\n/gs;
315        $man =~ s/\s*$/\n/gm;
316        $man =~ s/\n+/\n/gs;
317        $man =~ s/\0//gs;
318        $man =~ s/\n\n\./\n\./gs;
319        chomp($man);
320    } else {
321        $man = "No description available.";
322    }
323
324    $FUNCTIONS{$func} = {
325        'source'        => $fn,
326        'name'          => $func,
327        'descr'         => $descr,
328        'type'          => $type,
329        'args'          => $args,
330        'man'           => $man,
331        'xref'          => \%xref,
332        'errors'        => \@errors,
333        'author'        => $author,
334    };
335    if ($source =~ m/^ \* NODOC\s*$/m) {
336        $FUNCTIONS{$func}->{'nodoc'} = 1;
337    }
338    if ($source !~ m/^ \* XSSO \d/m) {
339        $FUNCTIONS{$func}->{'openpam'} = 1;
340    }
341    expand_errors($FUNCTIONS{$func});
342    return $FUNCTIONS{$func};
343}
344
345sub expand_errors($);
346sub expand_errors($) {
347    my $func = shift;           # Ref to function hash
348
349    my %errors;
350    my $ref;
351    my $fn;
352
353    if (defined($func->{'recursed'})) {
354        warn("$func->{'name'}(): loop in error spec\n");
355        return qw();
356    }
357    $func->{'recursed'} = 1;
358
359    foreach (@{$func->{'errors'}}) {
360        if (m/^(PAM_[A-Z_]+)$/) {
361            if (!defined($PAMERR{$1})) {
362                warn("$func->{'name'}(): unrecognized error: $1\n");
363                next;
364            }
365            $errors{$1} = 1;
366        } elsif (m/^!(PAM_[A-Z_]+)$/) {
367            # treat negations separately
368        } elsif (m/^=([a-z_]+)$/) {
369            $ref = $1;
370            if (!defined($FUNCTIONS{$ref})) {
371                $fn = $func->{'source'};
372                $fn =~ s/$func->{'name'}/$ref/;
373                parse_source($fn);
374            }
375            if (!defined($FUNCTIONS{$ref})) {
376                warn("$func->{'name'}(): reference to unknown $ref()\n");
377                next;
378            }
379            foreach (@{$FUNCTIONS{$ref}->{'errors'}}) {
380                $errors{$_} = 1;
381            }
382        } else {
383            warn("$func->{'name'}(): invalid error specification: $_\n");
384        }
385    }
386    foreach (@{$func->{'errors'}}) {
387        if (m/^!(PAM_[A-Z_]+)$/) {
388            delete($errors{$1});
389        }
390    }
391    delete($func->{'recursed'});
392    $func->{'errors'} = [ sort(keys(%errors)) ];
393}
394
395sub dictionary_order($$) {
396    my ($a, $b) = @_;
397
398    $a =~ s/[^[:alpha:]]//g;
399    $b =~ s/[^[:alpha:]]//g;
400    $a cmp $b;
401}
402
403sub genxref($) {
404    my $xref = shift;           # References
405
406    my $mdoc = '';
407    my @refs = ();
408    foreach my $sect (sort(keys(%{$xref}))) {
409        foreach my $page (sort(dictionary_order keys(%{$xref->{$sect}}))) {
410            push(@refs, "$page $sect");
411        }
412    }
413    while ($_ = shift(@refs)) {
414        $mdoc .= ".Xr $_" .
415            (@refs ? " ,\n" : "\n");
416    }
417    return $mdoc;
418}
419
420sub gendoc($) {
421    my $func = shift;           # Ref to function hash
422
423    local *FILE;
424    my $mdoc;
425    my $fn;
426
427    return if defined($func->{'nodoc'});
428
429    $mdoc = "$COPYRIGHT
430.Dd $TODAY
431.Dt " . uc($func->{'name'}) . " 3
432.Os
433.Sh NAME
434.Nm $func->{'name'}
435.Nd $func->{'descr'}
436.Sh LIBRARY
437.Lb libpam
438.Sh SYNOPSIS
439.In sys/types.h
440.In security/pam_appl.h
441";
442    if ($func->{'name'} =~ m/_sm_/) {
443        $mdoc .= ".In security/pam_modules.h\n"
444    }
445    if ($func->{'name'} =~ m/openpam/) {
446        $mdoc .= ".In security/openpam.h\n"
447    }
448    $mdoc .= ".Ft \"$func->{'type'}\"
449.Fn $func->{'name'} $func->{'args'}
450.Sh DESCRIPTION
451$func->{'man'}
452";
453    my @errors = @{$func->{'errors'}};
454    if ($func->{'type'} eq "int" && @errors) {
455        $mdoc .= ".Sh RETURN VALUES
456The
457.Nm
458function returns one of the following values:
459.Bl -tag -width 18n
460";
461        foreach (@errors) {
462            $mdoc .= ".It Bq Er $_\n$PAMERR{$_}.\n";
463        }
464        $mdoc .= ".El\n";
465    } elsif ($func->{'type'} eq "int") {
466        $mdoc .= ".Sh RETURN VALUES
467The
468.Nm
469function returns 0 on success and -1 on failure.
470";
471    } elsif ($func->{'type'} =~ m/\*$/) {
472        $mdoc .= ".Sh RETURN VALUES
473The
474.Nm
475function returns
476.Dv NULL
477on failure.
478";
479    } elsif ($func->{'type'} ne "void") {
480        warn("$func->{'name'}(): no error specification\n");
481    }
482    $mdoc .= ".Sh SEE ALSO\n" . genxref($func->{'xref'});
483    $mdoc .= ".Sh STANDARDS\n";
484    if ($func->{'openpam'}) {
485        $mdoc .= "The
486.Nm
487function is an OpenPAM extension.
488";
489    } else {
490        $mdoc .= ".Rs
491.%T \"X/Open Single Sign-On Service (XSSO) - Pluggable Authentication Modules\"
492.%D \"June 1997\"
493.Re
494";
495    }
496    $mdoc .= ".Sh AUTHORS
497The
498.Nm
499function and this manual page were developed for the
500.Fx
501Project by\n" . $AUTHORS{$func->{'author'} // 'THINKSEC_DARPA'} . "\n";
502    $fn = "$func->{'name'}.3";
503    if (open(FILE, ">", $fn)) {
504        print(FILE $mdoc);
505        close(FILE);
506    } else {
507        warn("$fn: open(): $!\n");
508    }
509}
510
511sub readproto($) {
512    my $fn = shift;             # File name
513
514    local *FILE;
515    my %func;
516
517    open(FILE, "<", "$fn")
518        or die("$fn: open(): $!\n");
519    while (<FILE>) {
520        if (m/^\.Nm ((?:open)?pam_.*?)\s*$/) {
521            $func{'Nm'} = $func{'Nm'} || $1;
522        } elsif (m/^\.Ft (\S.*?)\s*$/) {
523            $func{'Ft'} = $func{'Ft'} || $1;
524        } elsif (m/^\.Fn (\S.*?)\s*$/) {
525            $func{'Fn'} = $func{'Fn'} || $1;
526        }
527    }
528    close(FILE);
529    if ($func{'Nm'}) {
530        $FUNCTIONS{$func{'Nm'}} = \%func;
531    } else {
532        warn("No function found\n");
533    }
534}
535
536sub gensummary($) {
537    my $page = shift;           # Which page to produce
538
539    local *FILE;
540    my $upage;
541    my $func;
542    my %xref;
543
544    open(FILE, ">", "$page.3")
545        or die("$page.3: $!\n");
546
547    $page =~ m/(\w+)$/;
548    $upage = uc($1);
549    print FILE "$COPYRIGHT
550.Dd $TODAY
551.Dt $upage 3
552.Os
553.Sh NAME
554";
555    my @funcs = sort(keys(%FUNCTIONS));
556    while ($func = shift(@funcs)) {
557        print FILE ".Nm $FUNCTIONS{$func}->{'Nm'}";
558        print FILE " ,"
559                if (@funcs);
560        print FILE "\n";
561    }
562    print FILE ".Nd Pluggable Authentication Modules Library
563.Sh LIBRARY
564.Lb libpam
565.Sh SYNOPSIS\n";
566    if ($page eq 'pam') {
567        print FILE ".In security/pam_appl.h\n";
568    } else {
569        print FILE ".In security/openpam.h\n";
570    }
571    foreach $func (sort(keys(%FUNCTIONS))) {
572        print FILE ".Ft $FUNCTIONS{$func}->{'Ft'}\n";
573        print FILE ".Fn $FUNCTIONS{$func}->{'Fn'}\n";
574    }
575    while (<STDIN>) {
576        if (m/^\.Xr (\S+)\s*(\d)\s*$/) {
577            ++$xref{int($2)}->{$1};
578        }
579        print FILE $_;
580    }
581
582    if ($page eq 'pam') {
583        print FILE ".Sh RETURN VALUES
584The following return codes are defined by
585.In security/pam_constants.h :
586.Bl -tag -width 18n
587";
588        foreach (sort(keys(%PAMERR))) {
589            print FILE ".It Bq Er $_\n$PAMERR{$_}.\n";
590        }
591        print FILE ".El\n";
592    }
593    print FILE ".Sh SEE ALSO
594";
595    if ($page eq 'pam') {
596        ++$xref{3}->{'openpam'};
597    }
598    foreach $func (keys(%FUNCTIONS)) {
599        ++$xref{3}->{$func};
600    }
601    print FILE genxref(\%xref);
602    print FILE ".Sh STANDARDS
603.Rs
604.%T \"X/Open Single Sign-On Service (XSSO) - Pluggable Authentication Modules\"
605.%D \"June 1997\"
606.Re
607.Sh AUTHORS
608The OpenPAM library and this manual page were developed for the
609.Fx
610Project by ThinkSec AS and Network Associates Laboratories, the
611Security Research Division of Network Associates, Inc.\\& under
612DARPA/SPAWAR contract N66001-01-C-8035
613.Pq Dq CBOSS ,
614as part of the DARPA CHATS research program.
615";
616    close(FILE);
617}
618
619sub usage() {
620
621    print(STDERR "usage: gendoc [-op] source [...]\n");
622    exit(1);
623}
624
625MAIN:{
626    my %opts;
627
628    usage()
629        unless (@ARGV && getopts("op", \%opts));
630    setlocale(LC_ALL, "en_US.UTF-8");
631    $TODAY = strftime("%B %e, %Y", localtime(time()));
632    $TODAY =~ s,\s+, ,g;
633    if ($opts{'o'} || $opts{'p'}) {
634        foreach my $fn (@ARGV) {
635            readproto($fn);
636        }
637        gensummary('openpam')
638            if ($opts{'o'});
639        gensummary('pam')
640            if ($opts{'p'});
641    } else {
642        foreach my $fn (@ARGV) {
643            my $func = parse_source($fn);
644            gendoc($func)
645                if (defined($func));
646        }
647    }
648    exit(0);
649}
Note: See TracBrowser for help on using the repository browser.