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