Commit | Line | Data |
---|---|---|
92bda632 TC |
1 | #!perl -w |
2 | use strict; | |
fe415ad2 | 3 | use ExtUtils::Manifest 'maniread'; |
92bda632 TC |
4 | |
5 | my $outname = shift || '-'; | |
6 | ||
92bda632 TC |
7 | my @funcs = make_func_list(); |
8 | my %funcs = map { $_ => 1 } @funcs; | |
9 | ||
10 | # look for files to parse | |
11 | ||
fe415ad2 | 12 | my $mani = maniread; |
81409c5e | 13 | my @files = sort grep /\.(c|im|h)$/, keys %$mani; |
92bda632 TC |
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; | |
6cfee9d1 TC |
26 | my $order; |
27 | my %order; | |
92bda632 TC |
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 ]; | |
5ca7e2ab | 40 | $from{$func} = "File $file"; |
92bda632 TC |
41 | if ($category) { |
42 | $funccats{$func} = $category; | |
43 | push @{$cats{$category}}, $func; | |
44 | } | |
45 | if ($synopsis) { | |
46 | $funcsyns{$func} = $synopsis; | |
47 | } | |
6cfee9d1 TC |
48 | defined $order or $order = 50; |
49 | $order{$func} = $order; | |
92bda632 TC |
50 | } |
51 | undef $func; | |
52 | undef $category; | |
6cfee9d1 | 53 | undef $order; |
92bda632 TC |
54 | $synopsis = ''; |
55 | } | |
56 | elsif ($func) { | |
57 | if (/^=category (.*)/) { | |
58 | $category = $1; | |
59 | } | |
60 | elsif (/^=synopsis (.*)/) { | |
8d14daab TC |
61 | unless (length $synopsis) { |
62 | push @funcdocs, "\n"; | |
63 | } | |
92bda632 | 64 | $synopsis .= "$1\n"; |
8d14daab | 65 | push @funcdocs, " $1\n"; |
92bda632 | 66 | } |
6cfee9d1 TC |
67 | elsif (/^=order (.*)$/) { |
68 | $order = $1; | |
69 | $order =~ /^\d+$/ | |
70 | or die "=order must specify a number for $func in $file\n"; | |
71 | } | |
92bda632 TC |
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 | ||
091760c5 TC |
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 | ||
92bda632 TC |
90 | print OUT <<'EOS'; |
91 | Do not edit this file, it is generated automatically by apidocs.perl | |
92 | from Imager's source files. | |
93 | ||
5ca7e2ab TC |
94 | Each function description has a comment listing the source file where |
95 | you can find the documentation. | |
92bda632 TC |
96 | |
97 | =head1 NAME | |
98 | ||
6cfee9d1 | 99 | Imager::APIRef - Imager's C API - reference. |
92bda632 TC |
100 | |
101 | =head1 SYNOPSIS | |
102 | ||
103 | i_color color; | |
6cfee9d1 | 104 | color.rgba.r = 255; color.rgba.g = 0; color.rgba.b = 255; |
92bda632 TC |
105 | |
106 | EOS | |
107 | ||
108 | for my $cat (sort { lc $a cmp lc $b } keys %cats) { | |
109 | print OUT "\n # $cat\n"; | |
81409c5e TC |
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) { | |
92bda632 TC |
115 | my $syn = $funcsyns{$func}; |
116 | $syn =~ s/^/ /gm; | |
117 | print OUT $syn; | |
118 | } | |
119 | } | |
120 | ||
121 | print OUT <<'EOS'; | |
122 | ||
92bda632 TC |
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"; | |
6cfee9d1 TC |
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) { | |
92bda632 TC |
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 | ||
50c75381 | 143 | # see if we have an uncategorised section |
92bda632 TC |
144 | if (grep $alldocs{$_}, keys %undoc) { |
145 | print OUT "=head2 Uncategorized functions\n\n=over\n\n"; | |
6cfee9d1 TC |
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}; | |
92bda632 TC |
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 | ||
5b480b14 | 177 | Tony Cook <tonyc@cpan.org> |
92bda632 TC |
178 | |
179 | =head1 SEE ALSO | |
180 | ||
b96f5e9e | 181 | Imager, Imager::API, Imager::ExtUtils, Imager::Inline |
92bda632 TC |
182 | |
183 | =cut | |
184 | EOS | |
185 | ||
186 | close OUT; | |
187 | ||
188 | ||
189 | sub make_func_list { | |
abffffed | 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); |
92bda632 TC |
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; | |
eac41a26 | 196 | if ($in_struct && !/SKIP/ && /\(\*f_(i[om]?_\w+)/) { |
6d5c85a2 TC |
197 | my $name = $1; |
198 | $name =~ s/_imp$//; | |
199 | push @funcs, $name; | |
92bda632 TC |
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 | } | |
6cfee9d1 TC |
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 |