File Coverage

apidocs.perl
Criterion Covered Total %
statement 113 116 97.4
branch 37 52 71.1
condition 16 17 94.1
subroutine 3 3 100.0
pod n/a
total 169 188 89.8


line stmt bran cond sub pod time code
1             #!perl -w
2 1     1   4115 use strict;
  1         2  
  1         38  
3 1     1   550 use ExtUtils::Manifest 'maniread';
  1         13272  
  1         2589  
4              
5 1   50     115714 my $outname = shift || '-';
6              
7 1         8 my @funcs = make_func_list();
8 1         5 my %funcs = map { $_ => 1 } @funcs;
  160         190  
9              
10             # look for files to parse
11              
12 1         12 my $mani = maniread;
13 1         5296 my @files = sort grep /\.(c|im|h)$/, keys %$mani;
14              
15             # scan each file for =item \b
16 1         26 my $func;
17             my $start;
18 1         0 my %alldocs;
19 1         0 my @funcdocs;
20 1         0 my %from;
21 1         0 my $category;
22 1         0 my %funccats;
23 1         0 my %cats;
24 1         2 my $synopsis = '';
25 1         1 my %funcsyns;
26             my $order;
27 1         0 my %order;
28 1         3 for my $file (@files) {
29 104 50       2827 open SRC, "< $file"
30             or die "Cannot open $file for documentation: $!\n";
31 104         1408 while () {
32 68032 100 100     141737 if (/^=item (\w+)\b/ && $funcs{$1}) {
    100 100        
    100          
33 156         210 $func = $1;
34 156         159 $start = $.;
35 156         756 @funcdocs = $_;
36             }
37             elsif ($func && /^=(cut|head)/) {
38 156 50       204 if ($funcs{$func}) { # only save the API functions
39 156         530 $alldocs{$func} = [ @funcdocs ];
40 156         247 $from{$func} = "File $file";
41 156 100       152 if ($category) {
42 147         160 $funccats{$func} = $category;
43 147         97 push @{$cats{$category}}, $func;
  147         252  
44             }
45 156 100       152 if ($synopsis) {
46 69         72 $funcsyns{$func} = $synopsis;
47             }
48 156 100       168 defined $order or $order = 50;
49 156         160 $order{$func} = $order;
50             }
51 156         112 undef $func;
52 156         87 undef $category;
53 156         99 undef $order;
54 156         438 $synopsis = '';
55             }
56             elsif ($func) {
57 1654 100       2120 if (/^=category (.*)/) {
    100          
    100          
58 147         412 $category = $1;
59             }
60             elsif (/^=synopsis (.*)/) {
61 90 100       96 unless (length $synopsis) {
62 69         65 push @funcdocs, "\n";
63             }
64 90         160 $synopsis .= "$1\n";
65 90         313 push @funcdocs, " $1\n";
66             }
67             elsif (/^=order (.*)$/) {
68 16         18 $order = $1;
69 16 50       67 $order =~ /^\d+$/
70             or die "=order must specify a number for $func in $file\n";
71             }
72             else {
73 1401         1799 push @funcdocs, $_;
74             }
75             }
76             }
77             $func and
78 104 50       108 die "Documentation for $func not followed by =cut or =head in $file\n";
79            
80 104         834 close SRC;
81             }
82              
83 1 50       138 open OUT, "> $outname"
84             or die "Cannot open $outname: $!";
85              
86             # I keep this file in git and as part of the dist, make sure newlines
87             # don't mess me up
88 1         8 binmode OUT;
89              
90 1         7 print OUT <<'EOS';
91             Do not edit this file, it is generated automatically by apidocs.perl
92             from Imager's source files.
93              
94             Each function description has a comment listing the source file where
95             you can find the documentation.
96              
97             =head1 NAME
98              
99             Imager::APIRef - Imager's C API - reference.
100              
101             =head1 SYNOPSIS
102              
103             i_color color;
104             color.rgba.r = 255; color.rgba.g = 0; color.rgba.b = 255;
105             double x[] = { ... };
106             double y[] = { ... };
107             i_polygon_t poly;
108             poly.count = sizeof(x) / sizeof(*x);
109             poly.x = x;
110             poly.y = y;
111              
112             EOS
113              
114 1         21 for my $cat (sort { lc $a cmp lc $b } keys %cats) {
  46         72  
115 17         20 print OUT "\n # $cat\n";
116 17         14 my @funcs = @{$cats{$cat}};
  17         73  
117 17         17 my %orig;
118 17         104 @orig{@funcs} = 0 .. $#funcs;
119 17 50       29 @funcs = sort { $order{$a} <=> $order{$b} || $orig{$a} <=> $orig{$b} } @funcs;
  249         398  
120 17         61 for my $func (grep $funcsyns{$_}, @funcs) {
121 66         66 my $syn = $funcsyns{$func};
122 66         141 $syn =~ s/^/ /gm;
123 66         82 print OUT $syn;
124             }
125             }
126              
127 1         2 print OUT <<'EOS';
128              
129             =head1 DESCRIPTION
130              
131             EOS
132              
133 1         109 my %undoc = %funcs;
134              
135 1         17 for my $cat (sort { lc $a cmp lc $b } keys %cats) {
  46         65  
136 17         21 print OUT "=head2 $cat\n\n=over\n\n";
137             my @ordered_funcs = sort {
138 366 50       530 $order{$a} <=> $order{$b}
139             || lc $a cmp lc $b
140 17         16 } @{$cats{$cat}};
  17         32  
141 17         36 for my $func (@ordered_funcs) {
142 147         182 print OUT @{$alldocs{$func}}, "\n";
  147         538  
143 147         192 print OUT "=for comment\nFrom: $from{$func}\n\n";
144 147         153 delete $undoc{$func};
145             }
146 17         33 print OUT "\n=back\n\n";
147             }
148              
149             # see if we have an uncategorised section
150 1 50       12 if (grep $alldocs{$_}, keys %undoc) {
151 1         2 print OUT "=head2 Uncategorized functions\n\n=over\n\n";
152             #print join(",", grep !exists $order{$_}, @funcs), "\n";
153 1 0 100     103 for my $func (sort { $order{$a} <=> $order{$b} || $a cmp $b }
  21         27  
154             grep $undoc{$_} && $alldocs{$_}, @funcs) {
155 9         8 print OUT @{$alldocs{$func}}, "\n";
  9         17  
156 9         11 print OUT "=for comment\nFrom: $from{$func}\n\n";
157 9         8 delete $undoc{$func};
158             }
159 1         2 print OUT "\n\n=back\n\n";
160             }
161              
162 1 50       3 if (keys %undoc) {
163 1         2 print OUT <<'EOS';
164              
165             =head1 UNDOCUMENTED
166              
167             The following API functions are undocumented so far, hopefully this
168             will change:
169              
170             =over
171              
172             EOS
173              
174 1         6 print OUT "=item *\n\nB<$_>\n\n" for sort keys %undoc;
175              
176 1         1 print OUT "\n\n=back\n\n";
177             }
178              
179 1         2 print OUT <<'EOS';
180              
181             =head1 AUTHOR
182              
183             Tony Cook
184              
185             =head1 SEE ALSO
186              
187             Imager, Imager::API, Imager::ExtUtils, Imager::Inline
188              
189             =cut
190             EOS
191              
192 1         0 close OUT;
193              
194              
195             sub make_func_list {
196 1     1   8 my @funcs =
197             qw(i_img i_color i_fcolor i_fill_t mm_log mm_log i_color_model_t
198             im_context_t i_img_dim i_img_dim_u im_slot_t
199             i_polygon_t i_poly_fill_mode_t i_mutex_t
200             i_img_has_alpha i_DF i_DFc i_DFp i_DFcp i_psamp_bits i_gsamp_bits
201             i_psamp i_psampf);
202 1 50       48 open FUNCS, "< imexttypes.h"
203             or die "Cannot open imexttypes.h: $!\n";
204 1         3 my $in_struct;
205 1         51 while () {
206 281 100       250 /^typedef struct/ && ++$in_struct;
207 281 100 100     771 if ($in_struct && !/SKIP/ && /\(\*f_(i[om]?_\w+)/) {
      100        
208 137         135 my $name = $1;
209 137         94 $name =~ s/_imp$//;
210 137         123 push @funcs, $name;
211             }
212 281 100       507 if (/^\} im_ext_funcs;$/) {
213 1 50       3 $in_struct
214             or die "Found end of functions structure but not the start";
215              
216 1         15 close FUNCS;
217 1         27 return @funcs;
218             }
219             }
220 0 0         if ($in_struct) {
221 0           die "Found start of the functions structure but not the end\n";
222             }
223             else {
224 0           die "Found neither the start nor end of the functions structure\n";
225             }
226             }
227              
228             =head1 NAME
229              
230             apidocs.perl - parse Imager's source for POD documenting the C API
231              
232             =head1 SYNOPSIS
233              
234             perl apidocs.perl lib/Imager/APIRef.pod
235              
236             =head1 DESCRIPTION
237              
238             Parses Imager's C sources, including .c, .h and .im files searching
239             for function documentation.
240              
241             Besides the normal POD markup, the following can be included:
242              
243             =over
244              
245             =item =category I
246              
247             The category the function should be in.
248              
249             =item =synopsis I
250              
251             Sample code using the function to include in the Imager::APIRef SYNOPSIS
252              
253             =item =order I
254              
255             Allows a function to be listed out of order. If this isn't specified
256             it defaults to 50, so a value of 10 will cause the function to be
257             listed at the beginning of its category, or 90 to list at the end.
258              
259             Functions with equal order are otherwise ordered by name.
260              
261             =back
262              
263             =head1 AUTHOR
264              
265             Tony Cook
266              
267             =cut
268