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