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   4071 use strict;
  1         3  
  1         34  
3 1     1   574 use ExtUtils::Manifest 'maniread';
  1         13904  
  1         2748  
4              
5 1   50     129835 my $outname = shift || '-';
6              
7 1         5 my @funcs = make_func_list();
8 1         6 my %funcs = map { $_ => 1 } @funcs;
  160         207  
9              
10             # look for files to parse
11              
12 1         13 my $mani = maniread;
13 1         5647 my @files = sort grep /\.(c|im|h)$/, keys %$mani;
14              
15             # scan each file for =item \b
16 1         21 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         9 my %funcsyns;
26             my $order;
27 1         0 my %order;
28 1         3 for my $file (@files) {
29 104 50       2830 open SRC, "< $file"
30             or die "Cannot open $file for documentation: $!\n";
31 104         2097 while () {
32 67988 100 100     199443 if (/^=item (\w+)\b/ && $funcs{$1}) {
    100 100        
    100          
33 156         231 $func = $1;
34 156         180 $start = $.;
35 156         839 @funcdocs = $_;
36             }
37             elsif ($func && /^=(cut|head)/) {
38 156 50       230 if ($funcs{$func}) { # only save the API functions
39 156         671 $alldocs{$func} = [ @funcdocs ];
40 156         232 $from{$func} = "File $file";
41 156 100       192 if ($category) {
42 147         230 $funccats{$func} = $category;
43 147         129 push @{$cats{$category}}, $func;
  147         282  
44             }
45 156 100       207 if ($synopsis) {
46 69         100 $funcsyns{$func} = $synopsis;
47             }
48 156 100       194 defined $order or $order = 50;
49 156         199 $order{$func} = $order;
50             }
51 156         135 undef $func;
52 156         134 undef $category;
53 156         119 undef $order;
54 156         563 $synopsis = '';
55             }
56             elsif ($func) {
57 1649 100       2415 if (/^=category (.*)/) {
    100          
    100          
58 147         486 $category = $1;
59             }
60             elsif (/^=synopsis (.*)/) {
61 90 100       108 unless (length $synopsis) {
62 69         65 push @funcdocs, "\n";
63             }
64 90         159 $synopsis .= "$1\n";
65 90         295 push @funcdocs, " $1\n";
66             }
67             elsif (/^=order (.*)$/) {
68 16         21 $order = $1;
69 16 50       107 $order =~ /^\d+$/
70             or die "=order must specify a number for $func in $file\n";
71             }
72             else {
73 1396         2261 push @funcdocs, $_;
74             }
75             }
76             }
77             $func and
78 104 50       124 die "Documentation for $func not followed by =cut or =head in $file\n";
79            
80 104         2391 close SRC;
81             }
82              
83 1 50       355 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         6 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         18 for my $cat (sort { lc $a cmp lc $b } keys %cats) {
  45         79  
115 17         34 print OUT "\n # $cat\n";
116 17         20 my @funcs = @{$cats{$cat}};
  17         97  
117 17         22 my %orig;
118 17         153 @orig{@funcs} = 0 .. $#funcs;
119 17 50       64 @funcs = sort { $order{$a} <=> $order{$b} || $orig{$a} <=> $orig{$b} } @funcs;
  249         646  
120 17         90 for my $func (grep $funcsyns{$_}, @funcs) {
121 66         111 my $syn = $funcsyns{$func};
122 66         260 $syn =~ s/^/ /gm;
123 66         149 print OUT $syn;
124             }
125             }
126              
127 1         5 print OUT <<'EOS';
128              
129             =head1 DESCRIPTION
130              
131             EOS
132              
133 1         113 my %undoc = %funcs;
134              
135 1         18 for my $cat (sort { lc $a cmp lc $b } keys %cats) {
  45         78  
136 17         32 print OUT "=head2 $cat\n\n=over\n\n";
137             my @ordered_funcs = sort {
138 366 50       953 $order{$a} <=> $order{$b}
139             || lc $a cmp lc $b
140 17         25 } @{$cats{$cat}};
  17         53  
141 17         40 for my $func (@ordered_funcs) {
142 147         191 print OUT @{$alldocs{$func}}, "\n";
  147         855  
143 147         313 print OUT "=for comment\nFrom: $from{$func}\n\n";
144 147         268 delete $undoc{$func};
145             }
146 17         51 print OUT "\n=back\n\n";
147             }
148              
149             # see if we have an uncategorised section
150 1 50       18 if (grep $alldocs{$_}, keys %undoc) {
151 1         3 print OUT "=head2 Uncategorized functions\n\n=over\n\n";
152             #print join(",", grep !exists $order{$_}, @funcs), "\n";
153 1 0 100     188 for my $func (sort { $order{$a} <=> $order{$b} || $a cmp $b }
  21         50  
154             grep $undoc{$_} && $alldocs{$_}, @funcs) {
155 9         15 print OUT @{$alldocs{$func}}, "\n";
  9         29  
156 9         20 print OUT "=for comment\nFrom: $from{$func}\n\n";
157 9         14 delete $undoc{$func};
158             }
159 1         3 print OUT "\n\n=back\n\n";
160             }
161              
162 1 50       5 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         9 print OUT "=item *\n\nB<$_>\n\n" for sort keys %undoc;
175              
176 1         3 print OUT "\n\n=back\n\n";
177             }
178              
179 1         3 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   12 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       92 open FUNCS, "< imexttypes.h"
203             or die "Cannot open imexttypes.h: $!\n";
204 1         4 my $in_struct;
205 1         74 while () {
206 281 100       260 /^typedef struct/ && ++$in_struct;
207 281 100 100     700 if ($in_struct && !/SKIP/ && /\(\*f_(i[om]?_\w+)/) {
      100        
208 137         128 my $name = $1;
209 137         106 $name =~ s/_imp$//;
210 137         125 push @funcs, $name;
211             }
212 281 100       472 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         21 close FUNCS;
217 1         29 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