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