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; |
bd8052a6 | 13 | my @files = 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 (.*)/) { | |
61 | $synopsis .= "$1\n"; | |
62 | } | |
6cfee9d1 TC |
63 | elsif (/^=order (.*)$/) { |
64 | $order = $1; | |
65 | $order =~ /^\d+$/ | |
66 | or die "=order must specify a number for $func in $file\n"; | |
67 | } | |
92bda632 TC |
68 | else { |
69 | push @funcdocs, $_; | |
70 | } | |
71 | } | |
72 | } | |
73 | $func and | |
74 | die "Documentation for $func not followed by =cut or =head in $file\n"; | |
75 | ||
76 | close SRC; | |
77 | } | |
78 | ||
79 | open OUT, "> $outname" | |
80 | or die "Cannot open $outname: $!"; | |
81 | ||
091760c5 TC |
82 | # I keep this file in git and as part of the dist, make sure newlines |
83 | # don't mess me up | |
84 | binmode OUT; | |
85 | ||
92bda632 TC |
86 | print OUT <<'EOS'; |
87 | Do not edit this file, it is generated automatically by apidocs.perl | |
88 | from Imager's source files. | |
89 | ||
5ca7e2ab TC |
90 | Each function description has a comment listing the source file where |
91 | you can find the documentation. | |
92bda632 TC |
92 | |
93 | =head1 NAME | |
94 | ||
6cfee9d1 | 95 | Imager::APIRef - Imager's C API - reference. |
92bda632 TC |
96 | |
97 | =head1 SYNOPSIS | |
98 | ||
99 | i_color color; | |
6cfee9d1 | 100 | color.rgba.r = 255; color.rgba.g = 0; color.rgba.b = 255; |
92bda632 TC |
101 | |
102 | EOS | |
103 | ||
104 | for my $cat (sort { lc $a cmp lc $b } keys %cats) { | |
105 | print OUT "\n # $cat\n"; | |
6cfee9d1 | 106 | for my $func (grep $funcsyns{$_}, sort { $order{$a} <=> $order{$b} } @{$cats{$cat}}) { |
92bda632 TC |
107 | my $syn = $funcsyns{$func}; |
108 | $syn =~ s/^/ /gm; | |
109 | print OUT $syn; | |
110 | } | |
111 | } | |
112 | ||
113 | print OUT <<'EOS'; | |
114 | ||
92bda632 TC |
115 | =head1 DESCRIPTION |
116 | ||
117 | EOS | |
118 | ||
119 | my %undoc = %funcs; | |
120 | ||
121 | for my $cat (sort { lc $a cmp lc $b } keys %cats) { | |
122 | print OUT "=head2 $cat\n\n=over\n\n"; | |
6cfee9d1 TC |
123 | my @ordered_funcs = sort { |
124 | $order{$a} <=> $order{$b} | |
125 | || lc $a cmp lc $b | |
126 | } @{$cats{$cat}}; | |
127 | for my $func (@ordered_funcs) { | |
92bda632 TC |
128 | print OUT @{$alldocs{$func}}, "\n"; |
129 | print OUT "=for comment\nFrom: $from{$func}\n\n"; | |
130 | delete $undoc{$func}; | |
131 | } | |
132 | print OUT "\n=back\n\n"; | |
133 | } | |
134 | ||
50c75381 | 135 | # see if we have an uncategorised section |
92bda632 TC |
136 | if (grep $alldocs{$_}, keys %undoc) { |
137 | print OUT "=head2 Uncategorized functions\n\n=over\n\n"; | |
6cfee9d1 TC |
138 | #print join(",", grep !exists $order{$_}, @funcs), "\n"; |
139 | for my $func (sort { $order{$a} <=> $order{$b} || $a cmp $b } | |
140 | grep $undoc{$_} && $alldocs{$_}, @funcs) { | |
141 | print OUT @{$alldocs{$func}}, "\n"; | |
142 | print OUT "=for comment\nFrom: $from{$func}\n\n"; | |
143 | delete $undoc{$func}; | |
92bda632 TC |
144 | } |
145 | print OUT "\n\n=back\n\n"; | |
146 | } | |
147 | ||
148 | if (keys %undoc) { | |
149 | print OUT <<'EOS'; | |
150 | ||
151 | =head1 UNDOCUMENTED | |
152 | ||
153 | The following API functions are undocumented so far, hopefully this | |
154 | will change: | |
155 | ||
156 | =over | |
157 | ||
158 | EOS | |
159 | ||
160 | print OUT "=item *\n\nB<$_>\n\n" for sort keys %undoc; | |
161 | ||
162 | print OUT "\n\n=back\n\n"; | |
163 | } | |
164 | ||
165 | print OUT <<'EOS'; | |
166 | ||
167 | =head1 AUTHOR | |
168 | ||
5b480b14 | 169 | Tony Cook <tonyc@cpan.org> |
92bda632 TC |
170 | |
171 | =head1 SEE ALSO | |
172 | ||
173 | Imager, Imager::ExtUtils, Imager::Inline | |
174 | ||
175 | =cut | |
176 | EOS | |
177 | ||
178 | close OUT; | |
179 | ||
180 | ||
181 | sub make_func_list { | |
6cfee9d1 | 182 | my @funcs = qw(i_img i_color i_fcolor i_fill_t mm_log i_img_color_channels i_img_has_alpha i_img_dim); |
92bda632 TC |
183 | open FUNCS, "< imexttypes.h" |
184 | or die "Cannot open imexttypes.h: $!\n"; | |
185 | my $in_struct; | |
186 | while (<FUNCS>) { | |
187 | /^typedef struct/ && ++$in_struct; | |
188 | if ($in_struct && /\(\*f_(i_\w+)/) { | |
189 | push @funcs, $1; | |
190 | } | |
191 | if (/^\} im_ext_funcs;$/) { | |
192 | $in_struct | |
193 | or die "Found end of functions structure but not the start"; | |
194 | ||
195 | close FUNCS; | |
196 | return @funcs; | |
197 | } | |
198 | } | |
199 | if ($in_struct) { | |
200 | die "Found start of the functions structure but not the end\n"; | |
201 | } | |
202 | else { | |
203 | die "Found neither the start nor end of the functions structure\n"; | |
204 | } | |
205 | } | |
6cfee9d1 TC |
206 | |
207 | =head1 NAME | |
208 | ||
209 | apidocs.perl - parse Imager's source for POD documenting the C API | |
210 | ||
211 | =head1 SYNOPSIS | |
212 | ||
213 | perl apidocs.perl lib/Imager/APIRef.pod | |
214 | ||
215 | =head1 DESCRIPTION | |
216 | ||
217 | Parses Imager's C sources, including .c, .h and .im files searching | |
218 | for function documentation. | |
219 | ||
220 | Besides the normal POD markup, the following can be included: | |
221 | ||
222 | =over | |
223 | ||
224 | =item =category I<category-name> | |
225 | ||
226 | The category the function should be in. | |
227 | ||
228 | =item =synopsis I<sample-code> | |
229 | ||
230 | Sample code using the function to include in the Imager::APIRef SYNOPSIS | |
231 | ||
232 | =item =order I<integer> | |
233 | ||
234 | Allows a function to be listed out of order. If this isn't specified | |
235 | it defaults to 50, so a value of 10 will cause the function to be | |
236 | listed at the beginning of its category, or 90 to list at the end. | |
237 | ||
238 | Functions with equal order are otherwise ordered by name. | |
239 | ||
240 | =back | |
241 | ||
242 | =head1 AUTHOR | |
243 | ||
244 | Tony Cook <tonyc@cpan.org> | |
245 | ||
246 | =cut | |
247 |