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   5652 use strict;
  1         3  
  1         48  
3 1     1   691 use ExtUtils::Manifest 'maniread';
  1         19113  
  1         3780  
4              
5 1   50     185312 my $outname = shift || '-';
6              
7 1         5 my @funcs = make_func_list();
8 1         5 my %funcs = map { $_ => 1 } @funcs;
  160         186  
9              
10             # look for files to parse
11              
12 1         12 my $mani = maniread;
13 1         5150 my @files = sort grep /\.(c|im|h)$/, keys %$mani;
14              
15             # scan each file for =item \b
16 1         25 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         5 my %funcsyns;
26             my $order;
27 1         0 my %order;
28 1         3 for my $file (@files) {
29 104 50       3162 open SRC, "< $file"
30             or die "Cannot open $file for documentation: $!\n";
31 104         1646 while () {
32 68003 100 100     231499 if (/^=item (\w+)\b/ && $funcs{$1}) {
    100 100        
    100          
33 156         301 $func = $1;
34 156         249 $start = $.;
35 156         1266 @funcdocs = $_;
36             }
37             elsif ($func && /^=(cut|head)/) {
38 156 50       387 if ($funcs{$func}) { # only save the API functions
39 156         862 $alldocs{$func} = [ @funcdocs ];
40 156         374 $from{$func} = "File $file";
41 156 100       276 if ($category) {
42 147         300 $funccats{$func} = $category;
43 147         167 push @{$cats{$category}}, $func;
  147         449  
44             }
45 156 100       281 if ($synopsis) {
46 69         124 $funcsyns{$func} = $synopsis;
47             }
48 156 100       323 defined $order or $order = 50;
49 156         287 $order{$func} = $order;
50             }
51 156         216 undef $func;
52 156         171 undef $category;
53 156         196 undef $order;
54 156         743 $synopsis = '';
55             }
56             elsif ($func) {
57 1649 100       3786 if (/^=category (.*)/) {
    100          
    100          
58 147         700 $category = $1;
59             }
60             elsif (/^=synopsis (.*)/) {
61 90 100       158 unless (length $synopsis) {
62 69         96 push @funcdocs, "\n";
63             }
64 90         257 $synopsis .= "$1\n";
65 90         430 push @funcdocs, " $1\n";
66             }
67             elsif (/^=order (.*)$/) {
68 16         36 $order = $1;
69 16 50       127 $order =~ /^\d+$/
70             or die "=order must specify a number for $func in $file\n";
71             }
72             else {
73 1396         3422 push @funcdocs, $_;
74             }
75             }
76             }
77             $func and
78 104 50       213 die "Documentation for $func not followed by =cut or =head in $file\n";
79            
80 104         941 close SRC;
81             }
82              
83 1 50       326 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         6 binmode OUT;
89              
90 1         5 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         16 for my $cat (sort { lc $a cmp lc $b } keys %cats) {
  48         81  
115 17         36 print OUT "\n # $cat\n";
116 17         25 my @funcs = @{$cats{$cat}};
  17         99  
117 17         26 my %orig;
118 17         149 @orig{@funcs} = 0 .. $#funcs;
119 17 50       46 @funcs = sort { $order{$a} <=> $order{$b} || $orig{$a} <=> $orig{$b} } @funcs;
  249         648  
120 17         94 for my $func (grep $funcsyns{$_}, @funcs) {
121 66         113 my $syn = $funcsyns{$func};
122 66         294 $syn =~ s/^/ /gm;
123 66         152 print OUT $syn;
124             }
125             }
126              
127 1         5 print OUT <<'EOS';
128              
129             =head1 DESCRIPTION
130              
131             EOS
132              
133 1         84 my %undoc = %funcs;
134              
135 1         18 for my $cat (sort { lc $a cmp lc $b } keys %cats) {
  48         80  
136 17         32 print OUT "=head2 $cat\n\n=over\n\n";
137             my @ordered_funcs = sort {
138 366 50       892 $order{$a} <=> $order{$b}
139             || lc $a cmp lc $b
140 17         22 } @{$cats{$cat}};
  17         55  
141 17         51 for my $func (@ordered_funcs) {
142 147         195 print OUT @{$alldocs{$func}}, "\n";
  147         824  
143 147         310 print OUT "=for comment\nFrom: $from{$func}\n\n";
144 147         247 delete $undoc{$func};
145             }
146 17         46 print OUT "\n=back\n\n";
147             }
148              
149             # see if we have an uncategorised section
150 1 50       16 if (grep $alldocs{$_}, keys %undoc) {
151 1         4 print OUT "=head2 Uncategorized functions\n\n=over\n\n";
152             #print join(",", grep !exists $order{$_}, @funcs), "\n";
153 1 0 100     176 for my $func (sort { $order{$a} <=> $order{$b} || $a cmp $b }
  21         51  
154             grep $undoc{$_} && $alldocs{$_}, @funcs) {
155 9         12 print OUT @{$alldocs{$func}}, "\n";
  9         30  
156 9         19 print OUT "=for comment\nFrom: $from{$func}\n\n";
157 9         16 delete $undoc{$func};
158             }
159 1         15 print OUT "\n\n=back\n\n";
160             }
161              
162 1 50       5 if (keys %undoc) {
163 1         3 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         9 print OUT "=item *\n\nB<$_>\n\n" for sort keys %undoc;
175              
176 1         4 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       41 open FUNCS, "< imexttypes.h"
203             or die "Cannot open imexttypes.h: $!\n";
204 1         4 my $in_struct;
205 1         33 while () {
206 281 100       255 /^typedef struct/ && ++$in_struct;
207 281 100 100     687 if ($in_struct && !/SKIP/ && /\(\*f_(i[om]?_\w+)/) {
      100        
208 137         134 my $name = $1;
209 137         106 $name =~ s/_imp$//;
210 137         123 push @funcs, $name;
211             }
212 281 100       471 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         13 close FUNCS;
217 1         26 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