# Make prototypes from .c files # $Id$ use Getopt::Std; use File::Compare; use JSON::PP my $comment = 0; my $doxygen = 0; my $funcdoc = 0; my $if_0 = 0; my $brace = 0; my $line = ""; my $debug = 0; my $oproto = 1; my $private_func_re = "^_"; my %depfunction; my %exported; my %deprecated; my $apple = 0; my %documentation; getopts('x:m:o:p:dqE:R:P:') || die "foo"; if($opt_a) { $apple = 1; } if($opt_a) { $apple = 1; } if($opt_d) { $debug = 1; } if($opt_q) { $oproto = 0; } if($opt_R) { $private_func_re = $opt_R; } my %flags = ( 'multiline-proto' => 1, 'header' => 1, 'function-blocking' => 0, 'gnuc-attribute' => 1, 'cxx' => 1 ); if($opt_m) { foreach $i (split(/,/, $opt_m)) { if($i eq "roken") { $flags{"multiline-proto"} = 0; $flags{"header"} = 0; $flags{"function-blocking"} = 0; $flags{"gnuc-attribute"} = 0; $flags{"cxx"} = 0; } else { if(substr($i, 0, 3) eq "no-") { $flags{substr($i, 3)} = 0; } else { $flags{$i} = 1; } } } } if($opt_x) { my $EXP; local $/; open(EXP, '<', $opt_x) || die "open ${opt_x}"; my $obj = JSON::PP->new->utf8->decode(); close $EXP; foreach my $x (keys %$obj) { if (defined $obj->{$x}->{"export"}) { $exported{$x} = $obj->{$x}; } if (defined $obj->{$x}->{"deprecated"}) { $deprecated{$x} = $obj->{$x}->{"deprecated"}; } } } while(<>) { print $brace, " ", $_ if($debug); # Handle C comments s@/\*.*\*/@@; s@//.*/@@; if ( s@/\*\*(.*)@@) { $comment = 1; $doxygen = 1; $funcdoc = $1; } elsif ( s@/\*.*@@) { $comment = 1; } elsif ($comment && s@.*\*/@@) { $comment = 0; $doxygen = 0; } elsif ($doxygen) { $funcdoc .= $_; next; } elsif ($comment) { next; } # Handle CPP #define's $define = 1 if /^\s*\#\s*define/; if ($define) { $define = 0 if ! /\\$/; next; } if(/^\#if 0/) { $if_0 = 1; } if($if_0 && /^\#endif/) { $if_0 = 0; } if($if_0) { next } if(/^\s*\#/) { next; } if(/^\s*$/) { $line = ""; next; } if(/\{/){ if (!/\}/) { $brace++; } $_ = $line; while(s/\*\//\ca/){ s/\/\*(.|\n)*\ca//; } s/^\s*//; s/\s*$//; s/\s+/ /g; if($_ =~ /\)$/){ if(!/^static/ && !/^PRIVATE/){ $attr = ""; if(m/(.*)(__attribute__\s?\(.*\))/) { $attr .= " $2"; $_ = $1; } if(m/(.*)\s(\w+DEPRECATED_FUNCTION)\s?(\(.*\))(.*)/) { $depfunction{$2} = 1; $attr .= " $2$3"; $_ = "$1 $4"; } if(m/(.*)\s(\w+DEPRECATED)(.*)/) { $attr .= " $2"; $_ = "$1 $3"; } if(m/(.*)\s(HEIMDAL_\w+_ATTRIBUTE)\s?(\(.*\))?(.*)/) { $attr .= " $2$3"; $_ = "$1 $4"; } # remove outer () s/\s*\(//; # remove , within () while(s/\(([^()]*),(.*)\)/($1\$$2)/g){} s/\<\s*void\s*\>/<>/; # remove parameter names if($opt_P eq "remove") { s/(\s*)([a-zA-Z0-9_]+)([,>])/$3/g; s/\s+\*/*/g; s/\(\*(\s*)([a-zA-Z0-9_]+)\)/(*)/g; } elsif($opt_P eq "comment") { s/([a-zA-Z0-9_]+)([,>])/\/\*$1\*\/$2/g; s/\(\*([a-zA-Z0-9_]+)\)/(*\/\*$1\*\/)/g; } s/\<\>//; # add newlines before parameters if($flags{"multiline-proto"}) { s/,\s*/,\n\t/g; } else { s/,\s*/, /g; } # fix removed , s/\$/,/g; # match function name /([a-zA-Z0-9_]+)\s*\/$RP/; # insert newline before function name if($flags{"multiline-proto"}) { s/(.*)\s([a-zA-Z0-9_]+ \Q$LP\E)/$1\n$2/; } if($attr ne "") { $_ .= "\n $attr"; } if ($funcdoc) { $documentation{$f} = $funcdoc; } $funcdoc = undef; if ($apple && exists $exported{$f}) { $ios = $exported{$f}{ios}; $ios = "NA" if (!defined $ios); $mac = $exported{$f}{macos}; $mac = "NA" if (!defined $mac); die "$f neither" if ($mac eq "NA" and $ios eq "NA"); $_ = $_ . " __OSX_AVAILABLE_STARTING(__MAC_${mac}, __IPHONE_${ios})"; } if (exists $deprecated{$f}) { $_ = $_ . " GSSAPI_DEPRECATED_FUNCTION(\"$deprecated{$f}\")"; $depfunction{GSSAPI_DEPRECATED_FUNCTION} = 1; } $_ = $_ . ";"; $funcs{$f} = $_; } } $line = ""; } if(/\}/){ $brace--; } if(/^\}/){ $brace = 0; } if($brace == 0) { $line = $line . " " . $_; } } die "reached end of code and still in doxygen comment" if ($doxygen); die "reached end of code and still in comment" if ($comment); sub foo { local ($arg) = @_; $_ = $arg; s/.*\/([^\/]*)/$1/; s/.*\\([^\\]*)/$1/; s/[^a-zA-Z0-9]/_/g; "__" . $_ . "__"; } if($opt_o) { open(OUT, ">${opt_o}.new"); $block = &foo($opt_o); } else { $block = "__public_h__"; } if($opt_p) { open(PRIV, ">${opt_p}.new"); $private = &foo($opt_p); } else { $private = "__private_h__"; } $public_h = ""; $private_h = ""; $public_h_header .= "/* This is a generated file */ #ifndef $block #define $block #ifndef DOXY "; if ($oproto) { $public_h_header .= "#ifdef __STDC__ #include #ifndef __P #define __P(x) x #endif #else #ifndef __P #define __P(x) () #endif #endif "; } else { $public_h_header .= "#include "; } $public_h_trailer = ""; $private_h_header = "/* This is a generated file */ #ifndef $private #define $private "; if($oproto) { $private_h_header .= "#ifdef __STDC__ #include #ifndef __P #define __P(x) x #endif #else #ifndef __P #define __P(x) () #endif #endif "; } else { $private_h_header .= "#include "; } $private_h_trailer = ""; foreach(sort keys %funcs){ if(/^(DllMain|main)$/) { next } if ($funcs{$_} =~ /\^/) { $beginblock = "#ifdef __BLOCKS__\n"; $endblock = "#endif /* __BLOCKS__ */\n"; } else { $beginblock = $endblock = ""; } # if we have an export table and doesn't have content, or matches private RE if((scalar(keys(%exported)) ne 0 && !exists $exported{$_} ) || /$private_func_re/) { $private_h .= $beginblock; # if ($apple and not /$private_func_re/) { # $private_h .= "#define $_ __ApplePrivate_${_}\n"; # } $private_h .= $funcs{$_} . "\n" ; $private_h .= $endblock . "\n"; if($funcs{$_} =~ /__attribute__/) { $private_attribute_seen = 1; } } else { if($documentation{$_}) { $public_h .= "/**\n"; $public_h .= "$documentation{$_}"; $public_h .= " */\n\n"; } if($flags{"function-blocking"}) { $fupper = uc $_; if($exported{$_} =~ /proto/) { $public_h .= "#if !defined(HAVE_$fupper) || defined(NEED_${fupper}_PROTO)\n"; } else { $public_h .= "#ifndef HAVE_$fupper\n"; } } $public_h .= $beginblock . $funcs{$_} . "\n" . $endblock; if($funcs{$_} =~ /__attribute__/) { $public_attribute_seen = 1; } if($flags{"function-blocking"}) { $public_h .= "#endif\n"; } $public_h .= "\n"; } } if($flags{"gnuc-attribute"}) { if ($public_attribute_seen) { $public_h_header .= "#if !defined(__GNUC__) && !defined(__attribute__) #define __attribute__(x) #endif "; } if ($private_attribute_seen) { $private_h_header .= "#if !defined(__GNUC__) && !defined(__attribute__) #define __attribute__(x) #endif "; } } my $depstr = ""; my $undepstr = ""; foreach (keys %depfunction) { $depstr .= "#ifndef $_ #ifndef __has_extension #define __has_extension(x) 0 #define ${_}has_extension 1 #endif #if __has_extension(attribute_deprecated_with_message) #define $_(x) __attribute__((__deprecated__(x))) #elif defined(__GNUC__) && ((__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1 ))) #define $_(X) __attribute__((__deprecated__)) #else #define $_(X) #endif #ifdef ${_}has_extension #undef __has_extension #undef ${_}has_extension #endif #endif /* $_ */ "; $public_h_trailer .= "#undef $_ "; $private_h_trailer .= "#undef $_ #define $_(X) "; } $public_h_header .= $depstr; $private_h_header .= $depstr; if($flags{"cxx"}) { $public_h_header .= "#ifdef __cplusplus extern \"C\" { #endif "; $public_h_trailer = "#ifdef __cplusplus } #endif " . $public_h_trailer; } if ($opt_E) { $public_h_header .= "#ifndef $opt_E #ifndef ${opt_E}_FUNCTION #if defined(_WIN32) #define ${opt_E}_FUNCTION __declspec(dllimport) #else #define ${opt_E}_FUNCTION #endif #endif #ifndef ${opt_E}_NORETURN_FUNCTION #if defined(_WIN32) #define ${opt_E}_NORETURN_FUNCTION __declspec(dllimport noreturn) #else #define ${opt_E}_NORETURN_FUNCTION #endif #endif #ifndef ${opt_E}_CALL #if defined(_WIN32) #define ${opt_E}_CALL __stdcall #else #define ${opt_E}_CALL #endif #endif #ifndef ${opt_E}_VARIABLE #if defined(_WIN32) #define ${opt_E}_VARIABLE __declspec(dllimport) #else #define ${opt_E}_VARIABLE #endif #endif #endif "; $private_h_header .= "#ifndef $opt_E #ifndef ${opt_E}_FUNCTION #if defined(_WIN32) #define ${opt_E}_FUNCTION __declspec(dllimport) #else #define ${opt_E}_FUNCTION #endif #endif #ifndef ${opt_E}_NORETURN_FUNCTION #if defined(_WIN32) #define ${opt_E}_NORETURN_FUNCTION __declspec(dllimport noreturn) #else #define ${opt_E}_NORETURN_FUNCTION #endif #endif #ifndef ${opt_E}_CALL #if defined(_WIN32) #define ${opt_E}_CALL __stdcall #else #define ${opt_E}_CALL #endif #endif #ifndef ${opt_E}_VARIABLE #if defined(_WIN32) #define ${opt_E}_VARIABLE __declspec(dllimport) #else #define ${opt_E}_VARIABLE #endif #endif #endif "; } $public_h_trailer .= $undepstr; $private_h_trailer .= $undepstr; if ($public_h ne "" && $flags{"header"}) { $public_h = $public_h_header . $public_h . $public_h_trailer . "#endif /* DOXY */\n#endif /* $block */\n"; } if ($private_h ne "" && $flags{"header"}) { $private_h = $private_h_header . $private_h . $private_h_trailer . "#endif /* $private */\n"; } if($opt_o) { print OUT $public_h; } if($opt_p) { print PRIV $private_h; } close OUT; close PRIV; if ($opt_o) { if (compare("${opt_o}.new", ${opt_o}) != 0) { printf("updating ${opt_o}\n"); rename("${opt_o}.new", ${opt_o}); } else { unlink("${opt_o}.new"); } } if ($opt_p) { if (compare("${opt_p}.new", ${opt_p}) != 0) { printf("updating ${opt_p}\n"); rename("${opt_p}.new", ${opt_p}); } else { unlink("${opt_p}.new"); } }