xref: /openbsd-src/regress/lib/libcrypto/man/check_complete.pl (revision 3374c67d44f9b75b98444cbf63020f777792342e)
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 BN_MUL_COMBA
31	BN_RECURSION BN_SQR_COMBA 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    bn => [qw(
53	BN_FLG_EXP_CONSTTIME BN_FLG_FREE BN_get_params
54	BN_HEX_FMT1 BN_HEX_FMT2 BN_MASK
55	BN_options BN_prime_checks BN_set_params
56    )],
57    objects => [qw(
58	_DECLARE_OBJ_BSEARCH_CMP_FN
59	DECLARE_OBJ_BSEARCH_CMP_FN DECLARE_OBJ_BSEARCH_GLOBAL_CMP_FN
60	IMPLEMENT_OBJ_BSEARCH_CMP_FN IMPLEMENT_OBJ_BSEARCH_GLOBAL_CMP_FN
61    )],
62);
63
64my %postponed = (
65    asn1 => [qw(
66	ASN1_ITEM_EXP ASN1_ITEM_ptr ASN1_ITEM_ref ASN1_ITEM_rptr
67	ASN1_TEMPLATE ASN1_TLC
68	CHECKED_D2I_OF CHECKED_I2D_OF CHECKED_NEW_OF
69	CHECKED_PPTR_OF CHECKED_PTR_OF
70	DECLARE_ASN1_ALLOC_FUNCTIONS DECLARE_ASN1_ALLOC_FUNCTIONS_name
71	DECLARE_ASN1_ENCODE_FUNCTIONS DECLARE_ASN1_ENCODE_FUNCTIONS_const
72	DECLARE_ASN1_FUNCTIONS DECLARE_ASN1_FUNCTIONS_const
73	DECLARE_ASN1_FUNCTIONS_fname DECLARE_ASN1_FUNCTIONS_name
74	DECLARE_ASN1_ITEM
75	DECLARE_ASN1_NDEF_FUNCTION
76	DECLARE_ASN1_PRINT_FUNCTION DECLARE_ASN1_PRINT_FUNCTION_fname
77	DECLARE_ASN1_SET_OF
78	D2I_OF
79	IMPLEMENT_ASN1_SET_OF
80	I2D_OF I2D_OF_const
81	TYPEDEF_D2I_OF TYPEDEF_D2I2D_OF TYPEDEF_I2D_OF
82    )],
83    x509 => [qw(
84	d2i_PBEPARAM d2i_PBE2PARAM d2i_PBKDF2PARAM
85	i2d_PBEPARAM i2d_PBE2PARAM i2d_PBKDF2PARAM
86	NETSCAPE_SPKAC NETSCAPE_SPKI
87	PBEPARAM PBEPARAM_free PBEPARAM_new
88	PBE2PARAM PBE2PARAM_free PBE2PARAM_new
89	PBKDF2PARAM PBKDF2PARAM_free PBKDF2PARAM_new
90	PKCS5_pbe_set PKCS5_pbe_set0_algor
91	PKCS5_pbe2_set PKCS5_pbe2_set_iv
92	PKCS5_pbkdf2_set
93    )]
94);
95
96my $MANW = 'man -M /usr/share/man -w';
97my $srcdir = '/usr/src/lib/libcrypto/man';
98my $hfile = '/usr/include/openssl';
99
100my $in_cplusplus = 0;
101my $in_comment = 0;
102my $in_define = 0;
103my $in_function = 0;
104my $in_struct = 0;
105my $in_typedef_struct = 0;
106my %expect_undoc = ();
107my %found_undoc = ();
108my $verbose = 0;
109
110if (defined $ARGV[0] && $ARGV[0] eq '-v') {
111	$verbose = 1;
112	shift @ARGV;
113}
114$#ARGV == 0 or die "usage: $0 [-v] headername";
115$hfile .= "/$ARGV[0].h";
116open my $in_fh, '<', $hfile or die "$hfile: $!";
117
118$expect_undoc{$_} = 1 foreach @{$internal{$ARGV[0]}};
119$expect_undoc{$_} = 1 foreach @{$obsolete{$ARGV[0]}};
120$expect_undoc{$_} = 1 foreach @{$postponed{$ARGV[0]}};
121
122while (<$in_fh>) {
123try_again:
124	chomp;
125	my $line = $_;
126
127	# C language comments.
128
129	if ($in_comment) {
130		unless (s/.*?\*\///) {
131			print "-- $line\n" if $verbose;
132			next;
133		}
134		$in_comment = 0;
135	}
136	while (/\/\*/) {
137		s/\s*\/\*.*?\*\/// and next;
138		s/\s*\/\*.*// and $in_comment = 1;
139	}
140
141	# End C++ stuff.
142
143	if ($in_cplusplus) {
144		/^#endif$/ and $in_cplusplus = 0;
145		print "-- $line\n" if $verbose;
146		next;
147	}
148
149	# End declarations of structs.
150
151	if ($in_struct) {
152		if (/^\s*union\s+{$/) {
153			print "-s $line\n" if $verbose;
154			$in_struct++;
155			next;
156		}
157		unless (s/^\s*\}//) {
158			print "-s $line\n" if $verbose;
159			next;
160		}
161		if (--$in_struct && /^\s+\w+;$/) {
162			print "-s $line\n" if $verbose;
163			next;
164		}
165		unless ($in_typedef_struct) {
166			/^\s*;$/ or die "at end of struct: $_";
167			print "-s $line\n" if $verbose;
168			next;
169		}
170		$in_typedef_struct = 0;
171		my ($id) = /^\s*(\w+);$/
172		    or die "at end of typedef struct: $_";
173		unless (system "$MANW -k 'Vt~^$id\$' > /dev/null 2>&1") {
174			print "Vt $line\n" if $verbose;
175			next;
176		}
177		if ($expect_undoc{$id}) {
178			print "V- $line\n" if $verbose;
179			$found_undoc{$id} = 1;
180			next;
181		}
182		if ($verbose) {
183			print "XX $line\n";
184		} else {
185			warn "not found: typedef struct $id";
186		}
187		next;
188	}
189
190	# End macro definitions.
191
192	if ($in_define) {
193		/\\$/ or $in_define = 0;
194		print "-d $line\n" if $verbose;
195		next;
196	}
197
198	# End function declarations.
199
200	if ($in_function) {
201		/^\s/ or die "function arguments not indented: $_";
202		/\);$/ and $in_function = 0;
203		print "-f $line\n" if $verbose;
204		next;
205	}
206
207	# Begin C++ stuff.
208
209	if (/^#ifdef\s+__cplusplus$/) {
210		$in_cplusplus = 1;
211		print "-- $line\n" if $verbose;
212		next;
213	}
214
215	# Uninteresting lines.
216
217	if (/^\s*$/ ||
218	    /^DECLARE_STACK_OF\(\w+\)$/ ||
219	    /^TYPEDEF_D2I2D_OF\(\w+\);$/ ||
220	    /^#define HEADER_\w+_H$/ ||
221	    /^#endif$/ ||
222	    /^#else$/ ||
223	    /^extern\s+const\s+ASN1_ITEM\s+\w+_it;$/ ||
224	    /^#include\s/ ||
225	    /^#ifn?def\s/ ||
226	    /^#if !?defined/ ||
227	    /^#undef\s+BN_LLONG$/) {
228		print "-- $line\n" if $verbose;
229		next;
230	}
231
232	# Begin declarations of structs.
233
234	if (/^(typedef )?(?:struct|enum)(?: \w+)? \{$/) {
235		$in_struct = 1;
236		$1 and $in_typedef_struct = 1;
237		print "-s $line\n" if $verbose;
238		next;
239	}
240
241	# Handle macros.
242
243	if (my ($id) = /^#\s*define\s+(\w+)\s+\S/) {
244		/\\$/ and $in_define = 1;
245		if ($id eq 'BN_ULONG' &&
246		    not system "$MANW -k 'Vt~^$id\$' > /dev/null 2>&1") {
247			print "Vt $line\n" if $verbose;
248			next;
249		}
250		unless (system "$MANW -k 'Dv~^$id\$' > /dev/null 2>&1") {
251			print "Dv $line\n" if $verbose;
252			next;
253		}
254		unless (system "$MANW $id > /dev/null 2>&1") {
255			print "Fn $line\n" if $verbose;
256			next;
257		}
258		unless (system qw/grep -qR/, '^\.\\\\" .*\<' . $id . '\>',
259		    "$srcdir/") {
260			print "D- $line\n" if $verbose;
261			next;
262		}
263		if ($id =~ /^ASN1_PCTX_FLAGS_\w+$/) {
264			print "D- $line\n" if $verbose;
265			next;
266		}
267		if ($id =~ /^(?:ASN1|BN|X509(?:V3)?)_[FR]_\w+$/) {
268			print "D- $line\n" if $verbose;
269			next;
270		}
271		if ($id =~ /^X509_V_ERR_\w+$/) {
272			print "D- $line\n" if $verbose;
273			next;
274		}
275		if ($id =~ /^(?:SN|LN|NID|OBJ)_\w+$/) {
276			print "D- $line\n" if $verbose;
277			next;
278		}
279		if ($expect_undoc{$id}) {
280			print "D- $line\n" if $verbose;
281			$found_undoc{$id} = 1;
282			next;
283		}
284		if ($verbose) {
285			print "XX $line\n";
286		} else {
287			warn "not found: #define $id";
288		}
289		next;
290	}
291	if (my ($id) = /^#\s*define\s+(\w+)\(/) {
292		/\\$/ and $in_define = 1;
293		unless (system "$MANW $id > /dev/null 2>&1") {
294			print "Fn $line\n" if $verbose;
295			next;
296		}
297		unless (system qw/grep -qR/, '^\.\\\\" .*\<' . $id . '\>',
298		    "$srcdir/") {
299			print "F- $line\n" if $verbose;
300			next;
301		}
302		if ($expect_undoc{$id}) {
303			print "F- $line\n" if $verbose;
304			$found_undoc{$id} = 1;
305			next;
306		}
307		if ($verbose) {
308			print "XX $line\n";
309		} else {
310			warn "not found: #define $id()";
311		}
312		next;
313	}
314	if (my ($id) = /^#\s*define\s+(\w+)$/) {
315		if ($expect_undoc{$id}) {
316			print "-- $line\n" if $verbose;
317			$found_undoc{$id} = 1;
318			next;
319		}
320		if ($verbose) {
321			print "XX $line\n";
322		} else {
323			warn "not found: #define $id";
324		}
325		next;
326	}
327
328	# Handle global variables.
329
330	if (my ($id) = /^extern\s+int\s+(\w+);$/) {
331		unless (system "$MANW -k 'Va~^$id\$' > /dev/null 2>&1") {
332			print "Va $line\n" if $verbose;
333			next;
334		}
335		if ($verbose) {
336			print "XX $line\n";
337		} else {
338			warn "not found: extern int $id";
339		}
340		next;
341	}
342
343	# Handle variable type declarations.
344
345	if (my ($id) = /^struct\s+(\w+);$/) {
346		unless (system "$MANW -k 'Vt~^$id\$' > /dev/null 2>&1") {
347			print "Vt $line\n" if $verbose;
348			next;
349		}
350		if ($expect_undoc{$id}) {
351			print "V- $line\n" if $verbose;
352			$found_undoc{$id} = 1;
353			next;
354		}
355		if ($verbose) {
356			print "XX $line\n";
357		} else {
358			warn "not found: struct $id";
359		}
360		next;
361	}
362
363	if (my ($id) = /^typedef\s+(?:const\s+)?(?:struct\s+)?\S+\s+(\w+);$/) {
364		unless (system "$MANW -k 'Vt~^$id\$' > /dev/null 2>&1") {
365			print "Vt $line\n" if $verbose;
366			next;
367		}
368		if ($expect_undoc{$id}) {
369			print "V- $line\n" if $verbose;
370			$found_undoc{$id} = 1;
371			next;
372		}
373		if ($verbose) {
374			print "XX $line\n";
375		} else {
376			warn "not found: typedef $id";
377		}
378		next;
379	}
380
381	if (my ($id) =/^typedef\s+\w+(?:\s+\*)?\s+\(\*(\w+)\)\(/) {
382		/\);$/ or $in_function = 1;
383		unless (system "$MANW $id > /dev/null 2>&1") {
384			print "Fn $line\n" if $verbose;
385			next;
386		}
387		if ($verbose) {
388			print "XX $line\n";
389		} else {
390			warn "not found: function type (*$id)()";
391		}
392		next;
393	}
394
395	# Handle function declarations.
396
397	if (/^\w+(?:\(\w+\))?(?:\s+\w+)*\s+(?:\(?\*\s*)?(\w+)\(/) {
398		my $id = $1;
399		/\);$/ or $in_function = 1;
400		unless (system "$MANW $id > /dev/null 2>&1") {
401			print "Fn $line\n" if $verbose;
402			next;
403		}
404		# These functions are still provided by OpenSSL
405		# and still used by the Python test suite,
406		# but intentionally undocumented because nothing
407		# else uses them according to tb@, Dec 3, 2021.
408		if ($id =~ /NETSCAPE_(?:CERT_SEQUENCE|SPKAC|SPKI)/) {
409			print "F- $line\n" if $verbose;
410			next;
411		}
412		unless (system qw/grep -qR/, '^\.\\\\" .*\<' . $id . '\>',
413		    "$srcdir/") {
414			print "F- $line\n" if $verbose;
415			next;
416		}
417		if ($expect_undoc{$id}) {
418			print "F- $line\n" if $verbose;
419			$found_undoc{$id} = 1;
420			next;
421		}
422		if ($id =~ /^ASN1_PCTX_\w+$/) {
423			print "F- $line\n" if $verbose;
424			next;
425		}
426		if ($verbose) {
427			print "XX $line\n";
428		} else {
429			warn "not found: function $id()";
430		}
431		next;
432	}
433	if (/^int$/) {
434		$_ .= ' ' . <$in_fh>;
435		goto try_again;
436	}
437	if (/ \*$/) {
438		$_ .= <$in_fh>;
439		goto try_again;
440	}
441	die "parse error: $_";
442}
443close $in_fh;
444foreach (keys %expect_undoc) {
445	warn "expected as undocumented but not found: $_"
446	    unless $found_undoc{$_};
447}
448exit 0;
449