xref: /openbsd-src/regress/lib/libcrypto/man/check_complete.pl (revision ff0e7be1ebbcc809ea8ad2b6dafe215824da9e46)
1#!/usr/bin/perl
2#
3# Copyright (c) 2021 Ingo Schwarze <schwarze@openbsd.org>
4#
5# Permission to use, copy, modify, and distribute this software for any
6# purpose with or without fee is hereby granted, provided that the above
7# copyright notice and this permission notice appear in all copies.
8#
9# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
17use strict;
18use warnings;
19
20my %internal = (
21    asn1 => [qw(
22	ASN1_ENCODING
23	ASN1_STRING_FLAG_BITS_LEFT ASN1_STRING_FLAG_CONT
24	ASN1_STRING_FLAG_MSTRING ASN1_STRING_FLAG_NDEF
25	CHARTYPE_FIRST_ESC_2253 CHARTYPE_LAST_ESC_2253 CHARTYPE_PRINTABLESTRING
26    )],
27    bn => [qw(
28	BN_BITS BN_BITS4 BN_BYTES
29	BN_DEC_CONV BN_DEC_FMT1 BN_DEC_FMT2 BN_DEC_NUM BN_LLONG BN_LONG
30	BN_MASK2 BN_MASK2h BN_MASK2h1 BN_MASK2l
31	BN_TBIT BN_ULLONG
32    )],
33    objects => [qw(
34	OBJ_bsearch OBJ_bsearch_ OBJ_bsearch_ex OBJ_bsearch_ex_
35	USE_OBJ_MAC
36    )],
37    x509_vfy => [qw(
38	X509_VERIFY_PARAM_ID
39    )]
40);
41
42my %obsolete = (
43    asn1 => [qw(
44	ASN1_dup ASN1_d2i_bio ASN1_d2i_bio_of ASN1_d2i_fp ASN1_d2i_fp_of
45	ASN1_i2d_bio ASN1_i2d_bio_of ASN1_i2d_bio_of_const
46	ASN1_i2d_fp ASN1_i2d_fp_of ASN1_i2d_fp_of_const
47	ASN1_LONG_UNDEF
48	ub_title
49	V_ASN1_PRIMATIVE_TAG
50	X509_algor_st
51    )],
52    bio => [qw(
53	BIO_C_GET_PROXY_PARAM BIO_C_GET_SOCKS
54	BIO_C_SET_PROXY_PARAM BIO_C_SET_SOCKS
55	BIO_get_no_connect_return BIO_get_proxies
56	BIO_get_proxy_header BIO_get_url
57	BIO_set_filter_bio BIO_set_no_connect_return BIO_set_proxies
58	BIO_set_proxy_cb BIO_set_proxy_header BIO_set_url
59    )],
60    bn => [qw(
61	BN_HEX_FMT1 BN_HEX_FMT2 BN_MASK
62	BN_options BN_prime_checks
63    )],
64    objects => [qw(
65	_DECLARE_OBJ_BSEARCH_CMP_FN
66	DECLARE_OBJ_BSEARCH_CMP_FN DECLARE_OBJ_BSEARCH_GLOBAL_CMP_FN
67	IMPLEMENT_OBJ_BSEARCH_CMP_FN IMPLEMENT_OBJ_BSEARCH_GLOBAL_CMP_FN
68    )],
69);
70
71my %postponed = (
72    asn1 => [qw(
73	ASN1_ITEM_EXP ASN1_ITEM_ptr ASN1_ITEM_ref ASN1_ITEM_rptr
74	ASN1_TEMPLATE ASN1_TLC
75	CHECKED_D2I_OF CHECKED_I2D_OF CHECKED_NEW_OF
76	CHECKED_PPTR_OF CHECKED_PTR_OF
77	DECLARE_ASN1_ALLOC_FUNCTIONS DECLARE_ASN1_ALLOC_FUNCTIONS_name
78	DECLARE_ASN1_ENCODE_FUNCTIONS DECLARE_ASN1_ENCODE_FUNCTIONS_const
79	DECLARE_ASN1_FUNCTIONS DECLARE_ASN1_FUNCTIONS_const
80	DECLARE_ASN1_FUNCTIONS_fname DECLARE_ASN1_FUNCTIONS_name
81	DECLARE_ASN1_ITEM
82	DECLARE_ASN1_NDEF_FUNCTION
83	DECLARE_ASN1_PRINT_FUNCTION DECLARE_ASN1_PRINT_FUNCTION_fname
84	DECLARE_ASN1_SET_OF
85	D2I_OF
86	IMPLEMENT_ASN1_SET_OF
87	I2D_OF I2D_OF_const
88	TYPEDEF_D2I_OF TYPEDEF_D2I2D_OF TYPEDEF_I2D_OF
89    )],
90    x509 => [qw(
91	d2i_PBEPARAM d2i_PBE2PARAM d2i_PBKDF2PARAM
92	i2d_PBEPARAM i2d_PBE2PARAM i2d_PBKDF2PARAM
93	NETSCAPE_SPKAC NETSCAPE_SPKI
94	PBEPARAM PBEPARAM_free PBEPARAM_new
95	PBE2PARAM PBE2PARAM_free PBE2PARAM_new
96	PBKDF2PARAM PBKDF2PARAM_free PBKDF2PARAM_new
97	PKCS5_pbe_set PKCS5_pbe_set0_algor
98	PKCS5_pbe2_set PKCS5_pbe2_set_iv
99	PKCS5_pbkdf2_set
100    )]
101);
102
103my $MANW = 'man -M /usr/share/man -w';
104my $srcdir = '/usr/src/lib/libcrypto/man';
105my $hfile = '/usr/include/openssl';
106
107my $in_cplusplus = 0;
108my $in_comment = 0;
109my $in_define = 0;
110my $in_function = 0;
111my $in_struct = 0;
112my $in_typedef_struct = 0;
113my %expect_undoc = ();
114my %found_undoc = ();
115my $verbose = 0;
116
117if (defined $ARGV[0] && $ARGV[0] eq '-v') {
118	$verbose = 1;
119	shift @ARGV;
120}
121$#ARGV == 0 or die "usage: $0 [-v] headername";
122$hfile .= "/$ARGV[0].h";
123open my $in_fh, '<', $hfile or die "$hfile: $!";
124
125$expect_undoc{$_} = 1 foreach @{$internal{$ARGV[0]}};
126$expect_undoc{$_} = 1 foreach @{$obsolete{$ARGV[0]}};
127$expect_undoc{$_} = 1 foreach @{$postponed{$ARGV[0]}};
128
129while (<$in_fh>) {
130try_again:
131	chomp;
132	my $line = $_;
133
134	# C language comments.
135
136	if ($in_comment) {
137		unless (s/.*?\*\///) {
138			print "-- $line\n" if $verbose;
139			next;
140		}
141		$in_comment = 0;
142	}
143	while (/\/\*/) {
144		s/\s*\/\*.*?\*\/// and next;
145		s/\s*\/\*.*// and $in_comment = 1;
146	}
147
148	# End C++ stuff.
149
150	if ($in_cplusplus) {
151		/^#endif$/ and $in_cplusplus = 0;
152		print "-- $line\n" if $verbose;
153		next;
154	}
155
156	# End declarations of structs.
157
158	if ($in_struct) {
159		if (/^\s*union\s+{$/) {
160			print "-s $line\n" if $verbose;
161			$in_struct++;
162			next;
163		}
164		unless (s/^\s*\}//) {
165			print "-s $line\n" if $verbose;
166			next;
167		}
168		if (--$in_struct && /^\s+\w+;$/) {
169			print "-s $line\n" if $verbose;
170			next;
171		}
172		unless ($in_typedef_struct) {
173			/^\s*;$/ or die "at end of struct: $_";
174			print "-s $line\n" if $verbose;
175			next;
176		}
177		$in_typedef_struct = 0;
178		my ($id) = /^\s*(\w+);$/
179		    or die "at end of typedef struct: $_";
180		unless (system "$MANW -k 'Vt~^$id\$' > /dev/null 2>&1") {
181			print "Vt $line\n" if $verbose;
182			next;
183		}
184		if ($expect_undoc{$id}) {
185			print "V- $line\n" if $verbose;
186			$found_undoc{$id} = 1;
187			next;
188		}
189		if ($verbose) {
190			print "XX $line\n";
191		} else {
192			warn "not found: typedef struct $id";
193		}
194		next;
195	}
196
197	# End macro definitions.
198
199	if ($in_define) {
200		/\\$/ or $in_define = 0;
201		print "-d $line\n" if $verbose;
202		next;
203	}
204
205	# End function declarations.
206
207	if ($in_function) {
208		/^\s/ or die "function arguments not indented: $_";
209		/\);$/ and $in_function = 0;
210		print "-f $line\n" if $verbose;
211		next;
212	}
213
214	# Begin C++ stuff.
215
216	if (/^#ifdef\s+__cplusplus$/) {
217		$in_cplusplus = 1;
218		print "-- $line\n" if $verbose;
219		next;
220	}
221
222	# Uninteresting lines.
223
224	if (/^\s*$/ ||
225	    /^DECLARE_STACK_OF\(\w+\)$/ ||
226	    /^TYPEDEF_D2I2D_OF\(\w+\);$/ ||
227	    /^#define __bounded__\(\w+, \w+, \w+\)$/ ||
228	    /^#define HEADER_\w+_H$/ ||
229	    /^#endif$/ ||
230	    /^#else$/ ||
231	    /^extern\s+const\s+ASN1_ITEM\s+\w+_it;$/ ||
232	    /^#\s*include\s/ ||
233	    /^#ifn?def\s/ ||
234	    /^#if !?defined/ ||
235	    /^#undef\s+BN_LLONG$/) {
236		print "-- $line\n" if $verbose;
237		next;
238	}
239
240	# Begin declarations of structs.
241
242	if (/^(typedef )?(?:struct|enum)(?: \w+)? \{$/) {
243		$in_struct = 1;
244		$1 and $in_typedef_struct = 1;
245		print "-s $line\n" if $verbose;
246		next;
247	}
248
249	# Handle macros.
250
251	if (my ($id) = /^#\s*define\s+(\w+)\s+\S/) {
252		/\\$/ and $in_define = 1;
253		if ($id eq 'BN_ULONG' &&
254		    not system "$MANW -k 'Vt~^$id\$' > /dev/null 2>&1") {
255			print "Vt $line\n" if $verbose;
256			next;
257		}
258		unless (system "$MANW -k 'Dv~^$id\$' > /dev/null 2>&1") {
259			print "Dv $line\n" if $verbose;
260			next;
261		}
262		unless (system "$MANW $id > /dev/null 2>&1") {
263			print "Fn $line\n" if $verbose;
264			next;
265		}
266		unless (system qw/grep -qR/, '^\.\\\\" .*\<' . $id . '\>',
267		    "$srcdir/") {
268			print "D- $line\n" if $verbose;
269			next;
270		}
271		if ($id =~ /^ASN1_PCTX_FLAGS_\w+$/) {
272			print "D- $line\n" if $verbose;
273			next;
274		}
275		if ($id =~ /^(?:ASN1|BIO|BN|X509(?:V3)?)_[FR]_\w+$/) {
276			print "D- $line\n" if $verbose;
277			next;
278		}
279		if ($id =~ /^X509_V_ERR_\w+$/) {
280			print "D- $line\n" if $verbose;
281			next;
282		}
283		if ($id =~ /^(?:SN|LN|NID|OBJ)_\w+$/) {
284			print "D- $line\n" if $verbose;
285			next;
286		}
287		if ($expect_undoc{$id}) {
288			print "D- $line\n" if $verbose;
289			$found_undoc{$id} = 1;
290			next;
291		}
292		if ($verbose) {
293			print "XX $line\n";
294		} else {
295			warn "not found: #define $id";
296		}
297		next;
298	}
299	if (my ($id) = /^#\s*define\s+(\w+)\(/) {
300		/\\$/ and $in_define = 1;
301		unless (system "$MANW $id > /dev/null 2>&1") {
302			print "Fn $line\n" if $verbose;
303			next;
304		}
305		unless (system qw/grep -qR/, '^\.\\\\" .*\<' . $id . '\>',
306		    "$srcdir/") {
307			print "F- $line\n" if $verbose;
308			next;
309		}
310		if ($expect_undoc{$id}) {
311			print "F- $line\n" if $verbose;
312			$found_undoc{$id} = 1;
313			next;
314		}
315		if ($verbose) {
316			print "XX $line\n";
317		} else {
318			warn "not found: #define $id()";
319		}
320		next;
321	}
322	if (my ($id) = /^#\s*define\s+(\w+)$/) {
323		if ($expect_undoc{$id}) {
324			print "-- $line\n" if $verbose;
325			$found_undoc{$id} = 1;
326			next;
327		}
328		if ($verbose) {
329			print "XX $line\n";
330		} else {
331			warn "not found: #define $id";
332		}
333		next;
334	}
335
336	# Handle global variables.
337
338	if (my ($id) = /^extern\s+int\s+(\w+);$/) {
339		unless (system "$MANW -k 'Va~^$id\$' > /dev/null 2>&1") {
340			print "Va $line\n" if $verbose;
341			next;
342		}
343		if ($verbose) {
344			print "XX $line\n";
345		} else {
346			warn "not found: extern int $id";
347		}
348		next;
349	}
350
351	# Handle variable type declarations.
352
353	if (my ($id) = /^struct\s+(\w+);$/) {
354		unless (system "$MANW -k 'Vt~^$id\$' > /dev/null 2>&1") {
355			print "Vt $line\n" if $verbose;
356			next;
357		}
358		if ($expect_undoc{$id}) {
359			print "V- $line\n" if $verbose;
360			$found_undoc{$id} = 1;
361			next;
362		}
363		if ($verbose) {
364			print "XX $line\n";
365		} else {
366			warn "not found: struct $id";
367		}
368		next;
369	}
370
371	if (my ($id) = /^typedef\s+(?:const\s+)?(?:struct\s+)?\S+\s+(\w+);$/) {
372		unless (system "$MANW -k 'Vt~^$id\$' > /dev/null 2>&1") {
373			print "Vt $line\n" if $verbose;
374			next;
375		}
376		if ($expect_undoc{$id}) {
377			print "V- $line\n" if $verbose;
378			$found_undoc{$id} = 1;
379			next;
380		}
381		if ($verbose) {
382			print "XX $line\n";
383		} else {
384			warn "not found: typedef $id";
385		}
386		next;
387	}
388
389	if (my ($id) =/^typedef\s+\w+(?:\s+\*)?\s+\(\*(\w+)\)\(/) {
390		/\);$/ or $in_function = 1;
391		unless (system "$MANW $id > /dev/null 2>&1") {
392			print "Fn $line\n" if $verbose;
393			next;
394		}
395		if ($verbose) {
396			print "XX $line\n";
397		} else {
398			warn "not found: function type (*$id)()";
399		}
400		next;
401	}
402
403	# Handle function declarations.
404
405	if (/^\w+(?:\(\w+\))?(?:\s+\w+)*\s+(?:\(?\*\s*)?(\w+)\(/) {
406		my $id = $1;
407		/\);$/ or $in_function = 1;
408		unless (system "$MANW $id > /dev/null 2>&1") {
409			print "Fn $line\n" if $verbose;
410			next;
411		}
412		# These functions are still provided by OpenSSL
413		# and still used by the Python test suite,
414		# but intentionally undocumented because nothing
415		# else uses them according to tb@, Dec 3, 2021.
416		if ($id =~ /NETSCAPE_(?:CERT_SEQUENCE|SPKAC|SPKI)/) {
417			print "F- $line\n" if $verbose;
418			next;
419		}
420		unless (system qw/grep -qR/, '^\.\\\\" .*\<' . $id . '\>',
421		    "$srcdir/") {
422			print "F- $line\n" if $verbose;
423			next;
424		}
425		if ($expect_undoc{$id}) {
426			print "F- $line\n" if $verbose;
427			$found_undoc{$id} = 1;
428			next;
429		}
430		if ($id =~ /^ASN1_PCTX_\w+$/) {
431			print "F- $line\n" if $verbose;
432			next;
433		}
434		if ($verbose) {
435			print "XX $line\n";
436		} else {
437			warn "not found: function $id()";
438		}
439		next;
440	}
441	if (/^int$/) {
442		$_ .= ' ' . <$in_fh>;
443		goto try_again;
444	}
445	if (/ \*$/) {
446		$_ .= <$in_fh>;
447		goto try_again;
448	}
449	die "parse error: $_";
450}
451close $in_fh;
452foreach (keys %expect_undoc) {
453	warn "expected as undocumented but not found: $_"
454	    unless $found_undoc{$_};
455}
456exit 0;
457