Several additions and bug fixes.
[wine] / tools / winapi_check / winapi_documentation.pm
1 package winapi_documentation;
2
3 use strict;
4
5 use config qw($current_dir $wine_dir);
6 use nativeapi qw($nativeapi);
7
8 my %comment_width;
9 my %comment_indent;
10 my %comment_spacing;
11
12 sub check_documentation {
13     local $_;
14
15     my $options = shift;
16     my $output = shift;
17     my $win16api = shift;
18     my $win32api = shift;
19     my $modules = shift;
20     my $function = shift;
21
22     my $file = $function->file;
23     my $external_name16 = $function->external_name16;
24     my $external_name32 = $function->external_name32;
25     my $internal_name = $function->internal_name;
26     my $module16 = $function->module16;
27     my $module32 = $function->module32;
28     my $ordinal16 = $function->ordinal16;
29     my $ordinal32 = $function->ordinal32;
30     my $documentation = $function->documentation;
31     my $documentation_line = $function->documentation_line;
32     my @argument_documentations = @{$function->argument_documentations};
33
34     my $documentation_error = 0;
35     my $documentation_warning = 0;
36     if($options->documentation_name || 
37        $options->documentation_ordinal ||
38        $options->documentation_pedantic) 
39     {
40         my @winapis = ($win16api, $win32api);
41         my @modules = ($module16, $module32);
42         my @external_names = ($external_name16, $external_name32);
43         my @ordinals = ($ordinal16, $ordinal32);
44         while(
45               defined(my $winapi = shift @winapis) &&
46               defined(my $external_name = shift @external_names) &&
47               defined(my $module = shift @modules) &&
48               defined(my $ordinal = shift @ordinals))
49         {
50             if($winapi->is_function_stub_in_module($module, $internal_name)) { next; }
51
52             my @external_name = split(/\s*\&\s*/, $external_name);
53             my @modules = split(/\s*\&\s*/, $module);
54             my @ordinals = split(/\s*\&\s*/, $ordinal);
55
56             my $pedantic_failed = 0;
57             while(defined(my $external_name = shift @external_name) && 
58                   defined(my $module = shift @modules) && 
59                   defined(my $ordinal = shift @ordinals)) 
60             {
61                 my $found_name = 0;
62                 my $found_ordinal = 0;
63                 foreach (split(/\n/, $documentation)) {
64                     if(/^(\s*)\*(\s*)(\@|\S+)(\s*)([\(\[])(\w+)\.(\@|\d+)([\)\]])/) {
65                         my $external_name2 = $3;
66                         my $module2 = $6;
67                         my $ordinal2 = $7;
68
69                         if(length($1) != 1 || length($2) < 1 || 
70                            length($4) < 1 || $5 ne "(" || $8 ne ")")
71                         {
72                             $pedantic_failed = 1;
73                         }
74
75                         if($external_name eq $external_name2) {
76                             $found_name = 1;
77                             if("\U$module\E" eq $module2 &&
78                                $ordinal eq $ordinal2)
79                             {
80                                 $found_ordinal = 1;
81                             }
82                         }
83                     }
84                 }
85                 if(($options->documentation_name && !$found_name) || 
86                    ($options->documentation_ordinal && !$found_ordinal))
87                 {
88                     $documentation_error = 1;
89                     $output->write("documentation: expected $external_name (\U$module\E.$ordinal): \\\n$documentation\n");
90                 }
91                 
92             }
93             if($options->documentation_pedantic && $pedantic_failed) {
94                 $documentation_warning = 1;
95                 $output->write("documentation: pedantic failed: \\\n$documentation\n");
96             }
97         }
98     }
99
100     if(!$documentation_error && $options->documentation_wrong) {
101         foreach (split(/\n/, $documentation)) {
102             if(/^\s*\*\s*(\S+)\s*[\(\[]\s*(\w+)\s*\.\s*([^\s\)\]]*)\s*[\)\]].*?$/) {
103                 my $external_name = $1;
104                 my $module = $2;
105                 my $ordinal = $3;
106
107                 my $found = 0;
108                 foreach my $entry2 (winapi::get_all_module_internal_ordinal($internal_name)) {
109                     (my $external_name2, my $module2, my $ordinal2) = @$entry2;
110
111                     if($external_name eq $external_name2 &&
112                        lc($module) eq $module2 &&
113                        $ordinal eq $ordinal2 &&
114                        ($external_name2 eq "@" ||
115                         ($win16api->is_module($module2) && !$win16api->is_function_stub_in_module($module2, $external_name2)) ||
116                         ($win32api->is_module($module2) && !$win32api->is_function_stub_in_module($module2, $external_name2))) &&
117                         $modules->is_allowed_module_in_file($module2, "$current_dir/$file"))
118                     {
119                         $found = 1;
120                     }
121                 }
122                 if(!$found) {
123                     $output->write("documentation: $external_name (\U$module\E.$ordinal) wrong\n");
124                 }
125             }
126         }
127     }
128
129     if($options->documentation_comment_indent) {
130         foreach (split(/\n/, $documentation)) {
131             if(/^\s*\*(\s*)\S+(\s*)[\(\[]\s*\w+\s*\.\s*[^\s\)\]]*\s*[\)\]].*?$/) {
132                 my $indent = $1;
133                 my $spacing = $2;
134                 
135                 $indent =~ s/\t/        /g;
136                 $indent = length($indent);
137                 
138                 $spacing =~ s/\t/        /g;
139                 $spacing = length($spacing);
140                 
141                 $comment_indent{$indent}++;
142                 if($indent >= 20) {
143                     $output->write("documentation: comment indent is $indent\n");
144                 }
145                 $comment_spacing{$spacing}++;
146             }
147         }
148     }
149
150     if($options->documentation_comment_width) {
151         if($documentation =~ /(^\/\*\*+)/) {
152             my $width = length($1);
153
154             $comment_width{$width}++;
155             if($width <= 65 || $width >= 81) {
156                 $output->write("comment is $width columns wide\n");
157             }
158         }
159     }
160
161     if($options->documentation_arguments) {
162         my $n = 0;
163         for my $argument_documentation (@argument_documentations) {
164             $n++;
165             if($argument_documentation ne "") {
166                 if($argument_documentation !~ /^\/\*\s+\[(?:in|out|in\/out|\?\?\?)\].*?\*\/$/s) {
167                     $output->write("argument $n documentation: \\\n$argument_documentation\n");
168                 }
169             }
170         }
171     }
172 }
173
174 sub report_documentation {
175     my $options = shift;
176     my $output = shift;
177
178     if($options->documentation_comment_indent) {
179         foreach my $indent (sort(keys(%comment_indent))) {
180             my $count = $comment_indent{$indent};
181             $output->write("*.c: $count functions have comment that is indented $indent\n");
182         }
183     }
184
185     if($options->documentation_comment_width) {
186         foreach my $width (sort(keys(%comment_width))) {
187             my $count = $comment_width{$width};
188             $output->write("*.c: $count functions have comments of width $width\n");
189         }
190     }
191 }
192
193 1;