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