Avoid make dist fail when doxyout/ does not exist
[heimdal.git] / cf / make-proto.pl
blob577876c2d9e008453bb6b0ad60ff9eaf65c73a01
1 # Make prototypes from .c files
2 # $Id$
4 use Getopt::Std;
5 use File::Compare;
7 use JSON;
9 my $comment = 0;
10 my $doxygen = 0;
11 my $funcdoc = 0;
12 my $if_0 = 0;
13 my $brace = 0;
14 my $line = "";
15 my $debug = 0;
16 my $oproto = 1;
17 my $private_func_re = "^_";
18 my %depfunction;
19 my %exported;
20 my %deprecated;
21 my $apple = 0;
22 my %documentation;
24 getopts('x:m:o:p:dqE:R:P:') || die "foo";
25 if($opt_a) {
26 $apple = 1;
29 if($opt_a) {
30 $apple = 1;
33 if($opt_d) {
34 $debug = 1;
37 if($opt_q) {
38 $oproto = 0;
41 if($opt_R) {
42 $private_func_re = $opt_R;
44 my %flags = (
45 'multiline-proto' => 1,
46 'header' => 1,
47 'function-blocking' => 0,
48 'gnuc-attribute' => 1,
49 'cxx' => 1
51 if($opt_m) {
52 foreach $i (split(/,/, $opt_m)) {
53 if($i eq "roken") {
54 $flags{"multiline-proto"} = 0;
55 $flags{"header"} = 0;
56 $flags{"function-blocking"} = 0;
57 $flags{"gnuc-attribute"} = 0;
58 $flags{"cxx"} = 0;
59 } else {
60 if(substr($i, 0, 3) eq "no-") {
61 $flags{substr($i, 3)} = 0;
62 } else {
63 $flags{$i} = 1;
69 if($opt_x) {
70 my $EXP;
71 local $/;
72 open(EXP, '<', $opt_x) || die "open ${opt_x}";
73 my $obj = JSON->new->utf8->decode(<EXP>);
74 close $EXP;
76 foreach my $x (keys %$obj) {
77 if (defined $obj->{$x}->{"export"}) {
78 $exported{$x} = $obj->{$x};
80 if (defined $obj->{$x}->{"deprecated"}) {
81 $deprecated{$x} = $obj->{$x}->{"deprecated"};
86 while(<>) {
87 print $brace, " ", $_ if($debug);
89 # Handle C comments
90 s@/\*.*\*/@@;
91 s@//.*/@@;
92 if ( s@/\*\*(.*)@@) { $comment = 1; $doxygen = 1; $funcdoc = $1;
93 } elsif ( s@/\*.*@@) { $comment = 1;
94 } elsif ($comment && s@.*\*/@@) { $comment = 0; $doxygen = 0;
95 } elsif ($doxygen) { $funcdoc .= $_; next;
96 } elsif ($comment) { next; }
98 if(/^\#if 0/) {
99 $if_0 = 1;
101 if($if_0 && /^\#endif/) {
102 $if_0 = 0;
104 if($if_0) { next }
105 if(/^\s*\#/) {
106 next;
108 if(/^\s*$/) {
109 $line = "";
110 next;
112 if(/\{/){
113 if (!/\}/) {
114 $brace++;
116 $_ = $line;
117 while(s/\*\//\ca/){
118 s/\/\*(.|\n)*\ca//;
120 s/^\s*//;
121 s/\s*$//;
122 s/\s+/ /g;
123 if($_ =~ /\)$/){
124 if(!/^static/ && !/^PRIVATE/){
125 $attr = "";
126 if(m/(.*)(__attribute__\s?\(.*\))/) {
127 $attr .= " $2";
128 $_ = $1;
130 if(m/(.*)\s(\w+DEPRECATED_FUNCTION)\s?(\(.*\))(.*)/) {
131 $depfunction{$2} = 1;
132 $attr .= " $2$3";
133 $_ = "$1 $4";
135 if(m/(.*)\s(\w+DEPRECATED)(.*)/) {
136 $attr .= " $2";
137 $_ = "$1 $3";
139 if(m/(.*)\s(HEIMDAL_\w+_ATTRIBUTE)\s?(\(.*\))?(.*)/) {
140 $attr .= " $2$3";
141 $_ = "$1 $4";
143 # remove outer ()
144 s/\s*\(/</;
145 s/\)\s?$/>/;
146 # remove , within ()
147 while(s/\(([^()]*),(.*)\)/($1\$$2)/g){}
148 s/\<\s*void\s*\>/<>/;
149 # remove parameter names
150 if($opt_P eq "remove") {
151 s/(\s*)([a-zA-Z0-9_]+)([,>])/$3/g;
152 s/\s+\*/*/g;
153 s/\(\*(\s*)([a-zA-Z0-9_]+)\)/(*)/g;
154 } elsif($opt_P eq "comment") {
155 s/([a-zA-Z0-9_]+)([,>])/\/\*$1\*\/$2/g;
156 s/\(\*([a-zA-Z0-9_]+)\)/(*\/\*$1\*\/)/g;
158 s/\<\>/<void>/;
159 # add newlines before parameters
160 if($flags{"multiline-proto"}) {
161 s/,\s*/,\n\t/g;
162 } else {
163 s/,\s*/, /g;
165 # fix removed ,
166 s/\$/,/g;
167 # match function name
168 /([a-zA-Z0-9_]+)\s*\</;
169 $f = $1;
170 if($oproto) {
171 $LP = "__P((";
172 $RP = "))";
173 } else {
174 $LP = "(";
175 $RP = ")";
177 # only add newline if more than one parameter
178 if($flags{"multiline-proto"} && /,/){
179 s/\</ $LP\n\t/;
180 }else{
181 s/\</ $LP/;
183 s/\>/$RP/;
184 # insert newline before function name
185 if($flags{"multiline-proto"}) {
186 s/(.*)\s([a-zA-Z0-9_]+ \Q$LP\E)/$1\n$2/;
188 if($attr ne "") {
189 $_ .= "\n $attr";
191 if ($funcdoc) {
192 $documentation{$f} = $funcdoc;
194 $funcdoc = undef;
195 if ($apple && exists $exported{$f}) {
196 $ios = $exported{$f}{ios};
197 $ios = "NA" if (!defined $ios);
198 $mac = $exported{$f}{macos};
199 $mac = "NA" if (!defined $mac);
200 die "$f neither" if ($mac eq "NA" and $ios eq "NA");
201 $_ = $_ . " __OSX_AVAILABLE_STARTING(__MAC_${mac}, __IPHONE_${ios})";
203 if (exists $deprecated{$f}) {
204 $_ = $_ . " GSSAPI_DEPRECATED_FUNCTION(\"$deprecated{$f}\")";
205 $depfunction{GSSAPI_DEPRECATED_FUNCTION} = 1;
207 $_ = $_ . ";";
208 $funcs{$f} = $_;
211 $line = "";
213 if(/\}/){
214 $brace--;
216 if(/^\}/){
217 $brace = 0;
219 if($brace == 0) {
220 $line = $line . " " . $_;
224 die "reached end of code and still in doxygen comment" if ($doxygen);
225 die "reached end of code and still in comment" if ($comment);
227 sub foo {
228 local ($arg) = @_;
229 $_ = $arg;
230 s/.*\/([^\/]*)/$1/;
231 s/.*\\([^\\]*)/$1/;
232 s/[^a-zA-Z0-9]/_/g;
233 "__" . $_ . "__";
236 if($opt_o) {
237 open(OUT, ">${opt_o}.new");
238 $block = &foo($opt_o);
239 } else {
240 $block = "__public_h__";
243 if($opt_p) {
244 open(PRIV, ">${opt_p}.new");
245 $private = &foo($opt_p);
246 } else {
247 $private = "__private_h__";
250 $public_h = "";
251 $private_h = "";
253 $public_h_header .= "/* This is a generated file */
254 #ifndef $block
255 #define $block
256 #ifndef DOXY
259 if ($oproto) {
260 $public_h_header .= "#ifdef __STDC__
261 #include <stdarg.h>
262 #ifndef __P
263 #define __P(x) x
264 #endif
265 #else
266 #ifndef __P
267 #define __P(x) ()
268 #endif
269 #endif
272 } else {
273 $public_h_header .= "#include <stdarg.h>
277 $public_h_trailer = "";
279 $private_h_header = "/* This is a generated file */
280 #ifndef $private
281 #define $private
284 if($oproto) {
285 $private_h_header .= "#ifdef __STDC__
286 #include <stdarg.h>
287 #ifndef __P
288 #define __P(x) x
289 #endif
290 #else
291 #ifndef __P
292 #define __P(x) ()
293 #endif
294 #endif
297 } else {
298 $private_h_header .= "#include <stdarg.h>
302 $private_h_trailer = "";
305 foreach(sort keys %funcs){
306 if(/^(DllMain|main)$/) { next }
307 if ($funcs{$_} =~ /\^/) {
308 $beginblock = "#ifdef __BLOCKS__\n";
309 $endblock = "#endif /* __BLOCKS__ */\n";
310 } else {
311 $beginblock = $endblock = "";
313 # if we have an export table and doesn't have content, or matches private RE
314 if((scalar(keys(%exported)) ne 0 && !exists $exported{$_} ) || /$private_func_re/) {
315 $private_h .= $beginblock;
316 # if ($apple and not /$private_func_re/) {
317 # $private_h .= "#define $_ __ApplePrivate_${_}\n";
319 $private_h .= $funcs{$_} . "\n" ;
320 $private_h .= $endblock . "\n";
321 if($funcs{$_} =~ /__attribute__/) {
322 $private_attribute_seen = 1;
324 } else {
325 if($documentation{$_}) {
326 $public_h .= "/**\n";
327 $public_h .= "$documentation{$_}";
328 $public_h .= " */\n\n";
330 if($flags{"function-blocking"}) {
331 $fupper = uc $_;
332 if($exported{$_} =~ /proto/) {
333 $public_h .= "#if !defined(HAVE_$fupper) || defined(NEED_${fupper}_PROTO)\n";
334 } else {
335 $public_h .= "#ifndef HAVE_$fupper\n";
338 $public_h .= $beginblock . $funcs{$_} . "\n" . $endblock;
339 if($funcs{$_} =~ /__attribute__/) {
340 $public_attribute_seen = 1;
342 if($flags{"function-blocking"}) {
343 $public_h .= "#endif\n";
345 $public_h .= "\n";
349 if($flags{"gnuc-attribute"}) {
350 if ($public_attribute_seen) {
351 $public_h_header .= "#if !defined(__GNUC__) && !defined(__attribute__)
352 #define __attribute__(x)
353 #endif
358 if ($private_attribute_seen) {
359 $private_h_header .= "#if !defined(__GNUC__) && !defined(__attribute__)
360 #define __attribute__(x)
361 #endif
367 my $depstr = "";
368 my $undepstr = "";
369 foreach (keys %depfunction) {
370 $depstr .= "#ifndef $_
371 #ifndef __has_extension
372 #define __has_extension(x) 0
373 #define ${_}has_extension 1
374 #endif
375 #if __has_extension(attribute_deprecated_with_message)
376 #define $_(x) __attribute__((__deprecated__(x)))
377 #elif defined(__GNUC__) && ((__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1 )))
378 #define $_(X) __attribute__((__deprecated__))
379 #else
380 #define $_(X)
381 #endif
382 #ifdef ${_}has_extension
383 #undef __has_extension
384 #undef ${_}has_extension
385 #endif
386 #endif /* $_ */
390 $public_h_trailer .= "#undef $_
393 $private_h_trailer .= "#undef $_
394 #define $_(X)
399 $public_h_header .= $depstr;
400 $private_h_header .= $depstr;
403 if($flags{"cxx"}) {
404 $public_h_header .= "#ifdef __cplusplus
405 extern \"C\" {
406 #endif
409 $public_h_trailer = "#ifdef __cplusplus
411 #endif
413 " . $public_h_trailer;
416 if ($opt_E) {
417 $public_h_header .= "#ifndef $opt_E
418 #ifndef ${opt_E}_FUNCTION
419 #if defined(_WIN32)
420 #define ${opt_E}_FUNCTION __declspec(dllimport)
421 #define ${opt_E}_CALL __stdcall
422 #define ${opt_E}_VARIABLE __declspec(dllimport)
423 #else
424 #define ${opt_E}_FUNCTION
425 #define ${opt_E}_CALL
426 #define ${opt_E}_VARIABLE
427 #endif
428 #endif
429 #endif
432 $private_h_header .= "#ifndef $opt_E
433 #ifndef ${opt_E}_FUNCTION
434 #if defined(_WIN32)
435 #define ${opt_E}_FUNCTION __declspec(dllimport)
436 #define ${opt_E}_CALL __stdcall
437 #define ${opt_E}_VARIABLE __declspec(dllimport)
438 #else
439 #define ${opt_E}_FUNCTION
440 #define ${opt_E}_CALL
441 #define ${opt_E}_VARIABLE
442 #endif
443 #endif
444 #endif
449 $public_h_trailer .= $undepstr;
450 $private_h_trailer .= $undepstr;
452 if ($public_h ne "" && $flags{"header"}) {
453 $public_h = $public_h_header . $public_h .
454 $public_h_trailer . "#endif /* DOXY */\n#endif /* $block */\n";
456 if ($private_h ne "" && $flags{"header"}) {
457 $private_h = $private_h_header . $private_h .
458 $private_h_trailer . "#endif /* $private */\n";
461 if($opt_o) {
462 print OUT $public_h;
464 if($opt_p) {
465 print PRIV $private_h;
468 close OUT;
469 close PRIV;
471 if ($opt_o) {
473 if (compare("${opt_o}.new", ${opt_o}) != 0) {
474 printf("updating ${opt_o}\n");
475 rename("${opt_o}.new", ${opt_o});
476 } else {
477 unlink("${opt_o}.new");
481 if ($opt_p) {
482 if (compare("${opt_p}.new", ${opt_p}) != 0) {
483 printf("updating ${opt_p}\n");
484 rename("${opt_p}.new", ${opt_p});
485 } else {
486 unlink("${opt_p}.new");