11638Srgrimes# Make prototypes from .c files
21638Srgrimes# Id
31638Srgrimes
41638Srgrimesuse Getopt::Std;
51638Srgrimesuse File::Compare;
61638Srgrimes
71638Srgrimesuse JSON;
81638Srgrimes
91638Srgrimesmy $comment = 0;
101638Srgrimesmy $doxygen = 0;
111638Srgrimesmy $funcdoc = 0;
121638Srgrimesmy $if_0 = 0;
131638Srgrimesmy $brace = 0;
141638Srgrimesmy $line = "";
151638Srgrimesmy $debug = 0;
161638Srgrimesmy $oproto = 1;
171638Srgrimesmy $private_func_re = "^_";
181638Srgrimesmy %depfunction;
191638Srgrimesmy %exported;
201638Srgrimesmy %deprecated;
211638Srgrimesmy $apple = 0;
221638Srgrimesmy %documentation;
231638Srgrimes
241638Srgrimesgetopts('x:m:o:p:dqE:R:P:') || die "foo";
251638Srgrimesif($opt_a) {
261638Srgrimes    $apple = 1;
271638Srgrimes}
281638Srgrimes
291638Srgrimesif($opt_a) {
301638Srgrimes    $apple = 1;
311638Srgrimes}
321638Srgrimes
3350476Speterif($opt_d) {
341638Srgrimes    $debug = 1;
35206155Sume}
361638Srgrimes
3779538Sruif($opt_q) {
381638Srgrimes    $oproto = 0;
391638Srgrimes}
401638Srgrimes
411638Srgrimesif($opt_R) {
421638Srgrimes    $private_func_re = $opt_R;
4368962Sru}
441638Srgrimesmy %flags = (
451638Srgrimes	  'multiline-proto' => 1,
461638Srgrimes	  'header' => 1,
471638Srgrimes	  'function-blocking' => 0,
481638Srgrimes	  'gnuc-attribute' => 1,
491638Srgrimes	  'cxx' => 1
501638Srgrimes	  );
511638Srgrimesif($opt_m) {
521638Srgrimes    foreach $i (split(/,/, $opt_m)) {
531638Srgrimes	if($i eq "roken") {
541638Srgrimes	    $flags{"multiline-proto"} = 0;
551638Srgrimes	    $flags{"header"} = 0;
5665048Ssheldonh	    $flags{"function-blocking"} = 0;
5779727Sschweikh	    $flags{"gnuc-attribute"} = 0;
581638Srgrimes	    $flags{"cxx"} = 0;
591638Srgrimes	} else {
60131530Sru	    if(substr($i, 0, 3) eq "no-") {
611638Srgrimes		$flags{substr($i, 3)} = 0;
621638Srgrimes	    } else {
631638Srgrimes		$flags{$i} = 1;
641638Srgrimes	    }
651638Srgrimes	}
661638Srgrimes    }
671638Srgrimes}
68206155Sume
69233648Seadlerif($opt_x) {
70206155Sume    my $EXP;
71206155Sume    local $/;
72206155Sume    open(EXP, '<', $opt_x) || die "open ${opt_x}";
73206155Sume    my $obj = JSON->new->utf8->decode(<EXP>);
74206155Sume    close $EXP;
75206155Sume
76206155Sume    foreach my $x (keys %$obj) {
77206155Sume	if (defined $obj->{$x}->{"export"}) {
78206155Sume	    $exported{$x} = $obj->{$x};
79206155Sume	}
8012083Swpaul	if (defined $obj->{$x}->{"deprecated"}) {
8112083Swpaul	    $deprecated{$x} = $obj->{$x}->{"deprecated"};
8212083Swpaul	}
8312083Swpaul    }
8412083Swpaul}
8512083Swpaul
8665048Ssheldonhwhile(<>) {
8765048Ssheldonh    print $brace, " ", $_ if($debug);
8812083Swpaul
891638Srgrimes    # Handle C comments
901638Srgrimes    s@/\*.*\*/@@;
911638Srgrimes    s@//.*/@@;
921638Srgrimes    if ( s@/\*\*(.*)@@) { $comment = 1; $doxygen = 1; $funcdoc = $1;
9368962Sru    } elsif ( s@/\*.*@@) { $comment = 1;
941638Srgrimes    } elsif ($comment && s@.*\*/@@) { $comment = 0; $doxygen = 0;
951638Srgrimes    } elsif ($doxygen) { $funcdoc .= $_; next;
961638Srgrimes    } elsif ($comment) { next; }
971638Srgrimes
981638Srgrimes    if(/^\#if 0/) {
99206155Sume	$if_0 = 1;
100206155Sume    }
1011638Srgrimes    if($if_0 && /^\#endif/) {
1021638Srgrimes	$if_0 = 0;
1031638Srgrimes    }
1041638Srgrimes    if($if_0) { next }
1051638Srgrimes    if(/^\s*\#/) {
106140561Sru	next;
107140561Sru    }
108    if(/^\s*$/) {
109	$line = "";
110	next;
111    }
112    if(/\{/){
113	if (!/\}/) {
114	    $brace++;
115	}
116	$_ = $line;
117	while(s/\*\//\ca/){
118	    s/\/\*(.|\n)*\ca//;
119	}
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;
129		}
130		if(m/(.*)\s(\w+DEPRECATED_FUNCTION)\s?(\(.*\))(.*)/) {
131		    $depfunction{$2} = 1;
132		    $attr .= " $2$3";
133		    $_ = "$1 $4";
134		}
135		if(m/(.*)\s(\w+DEPRECATED)(.*)/) {
136		    $attr .= " $2";
137		    $_ = "$1 $3";
138		}
139		if(m/(.*)\s(HEIMDAL_\w+_ATTRIBUTE)\s?(\(.*\))?(.*)/) {
140		    $attr .= " $2$3";
141		    $_ = "$1 $4";
142		}
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;
157		}
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;
164		}
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 = ")";
176		}
177		# only add newline if more than one parameter
178                if($flags{"multiline-proto"} && /,/){
179		    s/\</ $LP\n\t/;
180		}else{
181		    s/\</ $LP/;
182		}
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/;
187		}
188		if($attr ne "") {
189		    $_ .= "\n    $attr";
190		}
191		if ($funcdoc) {
192		    $documentation{$f} = $funcdoc;
193		}
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})";
202		}
203		if (exists $deprecated{$f}) {
204		    $_ = $_ . "  GSSAPI_DEPRECATED_FUNCTION(\"$deprecated{$f}\")";
205		    $depfunction{GSSAPI_DEPRECATED_FUNCTION} = 1;
206		}
207		$_ = $_ . ";";
208		$funcs{$f} = $_;
209	    }
210	}
211	$line = "";
212    }
213    if(/\}/){
214	$brace--;
215    }
216    if(/^\}/){
217	$brace = 0;
218    }
219    if($brace == 0) {
220	$line = $line . " " . $_;
221    }
222}
223
224die "reached end of code and still in doxygen comment" if ($doxygen);
225die "reached end of code and still in comment" if ($comment);
226
227sub foo {
228    local ($arg) = @_;
229    $_ = $arg;
230    s/.*\/([^\/]*)/$1/;
231    s/.*\\([^\\]*)/$1/;
232    s/[^a-zA-Z0-9]/_/g;
233    "__" . $_ . "__";
234}
235
236if($opt_o) {
237    open(OUT, ">${opt_o}.new");
238    $block = &foo($opt_o);
239} else {
240    $block = "__public_h__";
241}
242
243if($opt_p) {
244    open(PRIV, ">${opt_p}.new");
245    $private = &foo($opt_p);
246} else {
247    $private = "__private_h__";
248}
249
250$public_h = "";
251$private_h = "";
252
253$public_h_header .= "/* This is a generated file */
254#ifndef $block
255#define $block
256#ifndef DOXY
257
258";
259if ($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
270
271";
272} else {
273    $public_h_header .= "#include <stdarg.h>
274
275";
276}
277$public_h_trailer = "";
278
279$private_h_header = "/* This is a generated file */
280#ifndef $private
281#define $private
282
283";
284if($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
295
296";
297} else {
298    $private_h_header .= "#include <stdarg.h>
299
300";
301}
302$private_h_trailer = "";
303
304
305foreach(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 = "";
312    }
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";
318#	}
319	$private_h .= $funcs{$_} . "\n" ;
320	$private_h .= $endblock . "\n";
321	if($funcs{$_} =~ /__attribute__/) {
322	    $private_attribute_seen = 1;
323	}
324    } else {
325	if($documentation{$_}) {
326	    $public_h .= "/**\n";
327	    $public_h .= "$documentation{$_}";
328	    $public_h .= " */\n\n";
329	}
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";
336	    }
337	}
338	$public_h .= $beginblock . $funcs{$_} . "\n" . $endblock;
339	if($funcs{$_} =~ /__attribute__/) {
340	    $public_attribute_seen = 1;
341	}
342	if($flags{"function-blocking"}) {
343	    $public_h .= "#endif\n";
344	}
345	$public_h .= "\n";
346    }
347}
348
349if($flags{"gnuc-attribute"}) {
350    if ($public_attribute_seen) {
351	$public_h_header .= "#if !defined(__GNUC__) && !defined(__attribute__)
352#define __attribute__(x)
353#endif
354
355";
356    }
357
358    if ($private_attribute_seen) {
359	$private_h_header .= "#if !defined(__GNUC__) && !defined(__attribute__)
360#define __attribute__(x)
361#endif
362
363";
364    }
365}
366
367my $depstr = "";
368my $undepstr = "";
369foreach (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 /* $_ */
387
388
389";
390    $public_h_trailer .= "#undef $_
391
392";
393    $private_h_trailer .= "#undef $_
394#define $_(X)
395
396";
397}
398
399$public_h_header .= $depstr;
400$private_h_header .= $depstr;
401
402
403if($flags{"cxx"}) {
404    $public_h_header .= "#ifdef __cplusplus
405extern \"C\" {
406#endif
407
408";
409    $public_h_trailer = "#ifdef __cplusplus
410}
411#endif
412
413" . $public_h_trailer;
414
415}
416if ($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
430";
431
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
445
446";
447}
448
449$public_h_trailer .= $undepstr;
450$private_h_trailer .= $undepstr;
451
452if ($public_h ne "" && $flags{"header"}) {
453    $public_h = $public_h_header . $public_h .
454	$public_h_trailer . "#endif /* DOXY */\n#endif /* $block */\n";
455}
456if ($private_h ne "" && $flags{"header"}) {
457    $private_h = $private_h_header . $private_h .
458	$private_h_trailer . "#endif /* $private */\n";
459}
460
461if($opt_o) {
462    print OUT $public_h;
463}
464if($opt_p) {
465    print PRIV $private_h;
466}
467
468close OUT;
469close PRIV;
470
471if ($opt_o) {
472
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");
478    }
479}
480
481if ($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");
487    }
488}
489