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   3402 use strict;
  1         1  
  1         34  
3 1     1   441 use ExtUtils::Manifest 'maniread';
  1         10887  
  1         2277  
4              
5 1   50     107800 my $outname = shift || '-';
6              
7 1         4 my @funcs = make_func_list();
8 1         4 my %funcs = map { $_ => 1 } @funcs;
  160         207  
9              
10             # look for files to parse
11              
12 1         12 my $mani = maniread;
13 1         5126 my @files = sort grep /\.(c|im|h)$/, keys %$mani;
14              
15             # scan each file for =item \b
16 1         20 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         11 my %funcsyns;
26             my $order;
27 1         0 my %order;
28 1         2 for my $file (@files) {
29 104 50       2176 open SRC, "< $file"
30             or die "Cannot open $file for documentation: $!\n";
31 104         1288 while () {
32 68002 100 100     136560 if (/^=item (\w+)\b/ && $funcs{$1}) {
    100 100        
    100          
33 156         166 $func = $1;
34 156         120 $start = $.;
35 156         663 @funcdocs = $_;
36             }
37             elsif ($func && /^=(cut|head)/) {
38 156 50       177 if ($funcs{$func}) { # only save the API functions
39 156         514 $alldocs{$func} = [ @funcdocs ];
40 156         184 $from{$func} = "File $file";
41 156 100       141 if ($category) {
42 147         168 $funccats{$func} = $category;
43 147         99 push @{$cats{$category}}, $func;
  147         206  
44             }
45 156 100       153 if ($synopsis) {
46 69         75 $funcsyns{$func} = $synopsis;
47             }
48 156 100       154 defined $order or $order = 50;
49 156         154 $order{$func} = $order;
50             }
51 156         98 undef $func;
52 156         96 undef $category;
53 156         93 undef $order;
54 156         386 $synopsis = '';
55             }
56             elsif ($func) {
57 1649 100       2071 if (/^=category (.*)/) {
    100          
    100          
58 147         395 $category = $1;
59             }
60             elsif (/^=synopsis (.*)/) {
61 90 100       95 unless (length $synopsis) {
62 69         52 push @funcdocs, "\n";
63             }
64 90         150 $synopsis .= "$1\n";
65 90         308 push @funcdocs, " $1\n";
66             }
67             elsif (/^=order (.*)$/) {
68 16         17 $order = $1;
69 16 50       75 $order =~ /^\d+$/
70             or die "=order must specify a number for $func in $file\n";
71             }
72             else {
73 1396         1811 push @funcdocs, $_;
74             }
75             }
76             }
77             $func and
78 104 50       114 die "Documentation for $func not followed by =cut or =head in $file\n";
79            
80 104         578 close SRC;
81             }
82              
83 1 50       152 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         5 binmode OUT;
89              
90 1         4 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         15 for my $cat (sort { lc $a cmp lc $b } keys %cats) {
  46         42  
115 17         16 print OUT "\n # $cat\n";
116 17         9 my @funcs = @{$cats{$cat}};
  17         69  
117 17         11 my %orig;
118 17         92 @orig{@funcs} = 0 .. $#funcs;
119 17 50       20 @funcs = sort { $order{$a} <=> $order{$b} || $orig{$a} <=> $orig{$b} } @funcs;
  249         309  
120 17         54 for my $func (grep $funcsyns{$_}, @funcs) {
121 66         79 my $syn = $funcsyns{$func};
122 66         130 $syn =~ s/^/ /gm;
123 66         69 print OUT $syn;
124             }
125             }
126              
127 1         3 print OUT <<'EOS';
128              
129             =head1 DESCRIPTION
130              
131             EOS
132              
133 1         47 my %undoc = %funcs;
134              
135 1         8 for my $cat (sort { lc $a cmp lc $b } keys %cats) {
  46         38  
136 17         15 print OUT "=head2 $cat\n\n=over\n\n";
137             my @ordered_funcs = sort {
138 366 50       460 $order{$a} <=> $order{$b}
139             || lc $a cmp lc $b
140 17         10 } @{$cats{$cat}};
  17         23  
141 17         13 for my $func (@ordered_funcs) {
142 147         82 print OUT @{$alldocs{$func}}, "\n";
  147         485  
143 147         153 print OUT "=for comment\nFrom: $from{$func}\n\n";
144 147         127 delete $undoc{$func};
145             }
146 17         25 print OUT "\n=back\n\n";
147             }
148              
149             # see if we have an uncategorised section
150 1 50       29 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     85 for my $func (sort { $order{$a} <=> $order{$b} || $a cmp $b }
  21         25  
154             grep $undoc{$_} && $alldocs{$_}, @funcs) {
155 9         9 print OUT @{$alldocs{$func}}, "\n";
  9         15  
156 9         9 print OUT "=for comment\nFrom: $from{$func}\n\n";
157 9         7 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         1 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         2 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   9 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       69 open FUNCS, "< imexttypes.h"
203             or die "Cannot open imexttypes.h: $!\n";
204 1         2 my $in_struct;
205 1         54 while () {
206 281 100       247 /^typedef struct/ && ++$in_struct;
207 281 100 100     708 if ($in_struct && !/SKIP/ && /\(\*f_(i[om]?_\w+)/) {
      100        
208 137         139 my $name = $1;
209 137         99 $name =~ s/_imp$//;
210 137         119 push @funcs, $name;
211             }
212 281 100       537 if (/^\} im_ext_funcs;$/) {
213 1 50       2 $in_struct
214             or die "Found end of functions structure but not the start";
215              
216 1         16 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