1# Make prototypes from .c files 2# $Id$ 3 4##use Getopt::Std; 5require 'getopts.pl'; 6 7use JSON; 8 9my $comment = 0; 10my $doxygen = 0; 11my $funcdoc = 0; 12my $if_0 = 0; 13my $brace = 0; 14my $line = ""; 15my $debug = 0; 16my $oproto = 1; 17my $private_func_re = "^_"; 18my %depfunction = (); 19my %exported; 20my %deprecated; 21my $apple = 0; 22my %documentation; 23 24Getopts('ax:m:o:p:dqE:R:P:') || die "foo"; 25 26if($opt_a) { 27 $apple = 1; 28} 29 30if($opt_d) { 31 $debug = 1; 32} 33 34if($opt_q) { 35 $oproto = 0; 36} 37 38if($opt_R) { 39 $private_func_re = $opt_R; 40} 41my %flags = ( 42 'multiline-proto' => 1, 43 'header' => 1, 44 'function-blocking' => 0, 45 'gnuc-attribute' => 1, 46 'cxx' => 1 47 ); 48if($opt_m) { 49 foreach $i (split(/,/, $opt_m)) { 50 if($i eq "roken") { 51 $flags{"multiline-proto"} = 0; 52 $flags{"header"} = 0; 53 $flags{"function-blocking"} = 0; 54 $flags{"gnuc-attribute"} = 0; 55 $flags{"cxx"} = 0; 56 } else { 57 if(substr($i, 0, 3) eq "no-") { 58 $flags{substr($i, 3)} = 0; 59 } else { 60 $flags{$i} = 1; 61 } 62 } 63 } 64} 65 66if($opt_x) { 67 my $EXP; 68 local $/; 69 open(EXP, '<', $opt_x) || die "open ${opt_x}"; 70 my $obj = JSON->new->utf8->decode(<EXP>); 71 close $EXP; 72 73 foreach my $x (keys %$obj) { 74 if (defined $obj->{$x}->{"export"}) { 75 $exported{$x} = $obj->{$x}; 76 } 77 if (defined $obj->{$x}->{"deprecated"}) { 78 $deprecated{$x} = $obj->{$x}->{"deprecated"}; 79 } 80 } 81} 82 83my %defineRules = ( 84 'HEIMDAL_DEPRECATED' => 85 "#if defined(__GNUC__) && ((__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1 )))\n". 86 "#define HEIMDAL_DEPRECATED __attribute__((deprecated))\n". 87 "#elif defined(_MSC_VER) && (_MSC_VER>1200)\n". 88 "#define HEIMDAL_DEPRECATED __declspec(deprecated)\n". 89 "#else\n". 90 "#define HEIMDAL_DEPRECATED\n". 91 "#endif", 92 'HEIMDAL_PRINTF_ATTRIBUTE' => 93 "#if defined(__GNUC__) && ((__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1 )))\n". 94 "#define HEIMDAL_PRINTF_ATTRIBUTE(x) __attribute__((format x))\n". 95 "#else\n". 96 "#define HEIMDAL_PRINTF_ATTRIBUTE(x)\n". 97 "#endif", 98 'HEIMDAL_NORETURN_ATTRIBUTE' => 99 "#if defined(__GNUC__) && ((__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1 )))\n". 100 "#define HEIMDAL_NORETURN_ATTRIBUTE __attribute__((noreturn))\n". 101 "#else\n". 102 "#define HEIMDAL_NORETURN_ATTRIBUTE\n". 103 "#endif", 104 'HEIMDAL_UNUSED_ATTRIBUTE' => 105 "#if defined(__GNUC__) && ((__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1 )))\n". 106 "#define HEIMDAL_UNUSED_ATTRIBUTE __attribute__((unused))\n". 107 "#else\n". 108 "#define HEIMDAL_UNUSED_ATTRIBUTE\n". 109 "#endif" 110); 111 112my %usedRules; 113 114while(<>) { 115 print $brace, " ", $_ if($debug); 116 117 # Handle C comments 118 s@/\*.*\*/@@; 119 s@//.*/@@; 120 if ( s@/\*\*(.*)@@) { $comment = 1; $doxygen = 1; $funcdoc = $1; 121 } elsif ( s@/\*.*@@) { $comment = 1; 122 } elsif ($comment && s@.*\*/@@) { $comment = 0; $doxygen = 0; 123 } elsif ($doxygen) { $funcdoc .= $_; next; 124 } elsif ($comment) { next; } 125 126 if(/^\#if 0/) { 127 $if_0 = 1; 128 } 129 if($if_0 && /^\#endif/) { 130 $if_0 = 0; 131 } 132 if($if_0) { next } 133 if(/^\s*\#/) { 134 next; 135 } 136 if(/^\s*$/) { 137 $line = ""; 138 next; 139 } 140 if(/\{/){ 141 if (!/\}/) { 142 $brace++; 143 } 144 $_ = $line; 145 while(s/\*\//\ca/){ 146 s/\/\*(.|\n)*\ca//; 147 } 148 s/^\s*//; 149 s/\s*$//; 150 s/\s+/ /g; 151 if($_ =~ /\)/){ 152 if(!/^static/ && !/^PRIVATE/){ 153 $attr = ""; 154 if(m/(.*)(__attribute__\s?\(.*\))/) { 155 $attr .= " $2"; 156 $_ = $1; 157 } 158 if(m/(.*)\s(\w+DEPRECATED_FUNCTION)\s?(\(.*\))(.*)/) { 159 $depfunction{$2} = 1; 160 $attr .= " $2$3"; 161 $_ = "$1 $4"; 162 } 163 if(m/(.*)\s(\w+DEPRECATED)(.*)/) { 164 $usedRules{$2} = 1; 165 $attr .= " $2"; 166 $_ = "$1 $3"; 167 } 168 if(m/(.*)\s(HEIMDAL_\w+_ATTRIBUTE)\s?(\(.*\))?(.*)/) { 169 $usedRules{$2} = 1; 170 $attr .= " $2$3"; 171 $_ = "$1 $4"; 172 } 173 # remove outer () 174 s/\s*\(/</; 175 s/\)\s?$/>/; 176 # remove , within () 177 while(s/\(([^()]*),(.*)\)/($1\$$2)/g){} 178 s/\<\s*void\s*\>/<>/; 179 # remove parameter names 180 if($opt_P eq "remove") { 181 s/(\s*)([a-zA-Z0-9_]+)([,>])/$3/g; 182 s/\s+\*/*/g; 183 s/\(\*(\s*)([a-zA-Z0-9_]+)\)/(*)/g; 184 } elsif($opt_P eq "comment") { 185 s/([a-zA-Z0-9_]+)([,>])/\/\*$1\*\/$2/g; 186 s/\(\*([a-zA-Z0-9_]+)\)/(*\/\*$1\*\/)/g; 187 } 188 s/\<\>/<void>/; 189 # add newlines before parameters 190 if($flags{"multiline-proto"}) { 191 s/,\s*/,\n\t/g; 192 } else { 193 s/,\s*/, /g; 194 } 195 # fix removed , 196 s/\$/,/g; 197 # match function name 198 /([a-zA-Z0-9_]+)\s*\</; 199 $f = $1; 200 if($oproto) { 201 $LP = "__P(("; 202 $RP = "))"; 203 } else { 204 $LP = "("; 205 $RP = ")"; 206 } 207 # only add newline if more than one parameter 208 if($flags{"multiline-proto"} && /,/){ 209 s/\</ $LP\n\t/; 210 }else{ 211 s/\</ $LP/; 212 } 213 s/\>/$RP/; 214 # insert newline before function name 215 if($flags{"multiline-proto"}) { 216 s/(.*)\s([a-zA-Z0-9_]+ \Q$LP\E)/$1\n$2/; 217 } 218 if($attr ne "") { 219 $_ .= "\n $attr"; 220 } 221 if ($funcdoc) { 222 $documentation{$f} = $funcdoc; 223 } 224 $funcdoc = undef; 225 if ($apple && exists $exported{$f}) { 226 $ios = $exported{$f}{ios}; 227 $ios = "NA" if (!defined $ios); 228 $mac = $exported{$f}{macos}; 229 $mac = "NA" if (!defined $mac); 230 die "$f neither" if ($mac eq "NA" and $ios eq "NA"); 231 232 if (exists $exported{$f}{deprecated}) { 233 $iosDep = $exported{$f}{iosDep}; 234 if ($ios eq "NA") { 235 $iosDep = "NA"; 236 } 237 238 $macDep = $exported{$f}{macosDep}; 239 if ($mac eq "NA") { 240 $macDep = "NA"; 241 } 242 243 $_ = $_ . " __OSX_AVAILABLE_BUT_DEPRECATED_MSG(__MAC_${mac}, __MAC_${macDep}, __IPHONE_${ios}, __IPHONE_${iosDep}, \"$exported{$f}{deprecated}\")"; 244 } else { 245 $_ = $_ . " __OSX_AVAILABLE_STARTING(__MAC_${mac}, __IPHONE_${ios})"; 246 } 247 } 248 print "found function $f\n" if($debug); 249 if (exists $deprecated{$f} && !$apple && exists $exported{$f}) { 250 $_ = $_ . " GSSAPI_DEPRECATED_FUNCTION(\"$deprecated{$f}\")"; 251 $depfunction{GSSAPI_DEPRECATED_FUNCTION} = 1; 252 } 253 $_ = $_ . ";"; 254 $funcs{$f} = $_; 255 } 256 } 257 $line = ""; 258 } 259 if(/\}/){ 260 $brace--; 261 } 262 if(/^\}/){ 263 $brace = 0; 264 } 265 if($brace == 0) { 266 $line = $line . " " . $_; 267 } 268} 269 270die "reached end of code and still in doxygen comment" if ($doxygen); 271die "reached end of code and still in comment" if ($comment); 272 273sub foo { 274 local ($arg) = @_; 275 $_ = $arg; 276 s/.*\/([^\/]*)/$1/; 277 s/.*\\([^\\]*)/$1/; 278 s/[^a-zA-Z0-9]/_/g; 279 "__" . $_ . "__"; 280} 281 282if($opt_o) { 283 open(OUT, ">$opt_o"); 284 $block = &foo($opt_o); 285} else { 286 $block = "__public_h__"; 287} 288 289if($opt_p) { 290 open(PRIV, ">$opt_p"); 291 $private = &foo($opt_p); 292} else { 293 $private = "__private_h__"; 294} 295 296$public_h = ""; 297$private_h = ""; 298 299$public_h_header .= "/* This is a generated file */ 300#ifndef $block 301#define $block 302 303"; 304if ($oproto) { 305 $public_h_header .= "#ifdef __STDC__ 306#include <stdarg.h> 307#ifndef __P 308#define __P(x) x 309#endif 310#else 311#ifndef __P 312#define __P(x) () 313#endif 314#endif 315 316"; 317} else { 318 $public_h_header .= "#include <stdarg.h> 319 320"; 321} 322$public_h_trailer = ""; 323 324$private_h_header = "/* This is a generated file */ 325#ifndef $private 326#define $private 327 328"; 329if($oproto) { 330 $private_h_header .= "#ifdef __STDC__ 331#include <stdarg.h> 332#ifndef __P 333#define __P(x) x 334#endif 335#else 336#ifndef __P 337#define __P(x) () 338#endif 339#endif 340 341"; 342} else { 343 $private_h_header .= "#include <stdarg.h> 344 345"; 346} 347$private_h_trailer = ""; 348 349foreach(sort keys %usedRules) { 350 next if not exists $defineRules{$_}; 351 352 my $var = "#ifndef $_ 353$defineRules{$_} 354#endif 355 356"; 357 358 $private_h_header .= $var; 359 $public_h_header .= $var; 360} 361 362foreach(sort keys %funcs){ 363 if(/^(DllMain|main)$/) { next } 364 if ($funcs{$_} =~ /\^/) { 365 $beginblock = "#ifdef __BLOCKS__\n"; 366 $endblock = "#endif /* __BLOCKS__ */\n"; 367 } else { 368 $beginblock = $endblock = ""; 369 } 370 # if we have an export table and doesn't have content, or matches private RE 371 if(((scalar keys %exported) ne 0 && !exists $exported{$_} ) || /$private_func_re/) { 372 $private_h .= $beginblock; 373# if ($apple and not /$private_func_re/) { 374# $private_h .= "#define $_ __ApplePrivate_${_}\n"; 375# } 376 $private_h .= $funcs{$_} . "\n" ; 377 $private_h .= $endblock . "\n"; 378 if($funcs{$_} =~ /__attribute__/) { 379 $private_attribute_seen = 1; 380 } 381 } else { 382 if($documentation{$_}) { 383 $public_h .= "/**\n"; 384 $public_h .= "$documentation{$_}"; 385 $public_h .= " */\n\n"; 386 } 387 if($flags{"function-blocking"}) { 388 $fupper = uc $_; 389 if($exported{$_} =~ /proto/) { 390 $public_h .= "#if !defined(HAVE_$fupper) || defined(NEED_${fupper}_PROTO)\n"; 391 } else { 392 $public_h .= "#ifndef HAVE_$fupper\n"; 393 } 394 } 395 $public_h .= $beginblock . $funcs{$_} . "\n" . $endblock; 396 if($funcs{$_} =~ /__attribute__/) { 397 $public_attribute_seen = 1; 398 } 399 if($flags{"function-blocking"}) { 400 $public_h .= "#endif\n"; 401 } 402 $public_h .= "\n"; 403 } 404} 405 406if($flags{"gnuc-attribute"}) { 407 if ($public_attribute_seen) { 408 $public_h_header .= "#if !defined(__GNUC__) && !defined(__attribute__) 409#define __attribute__(x) 410#endif 411 412"; 413 } 414 415 if ($private_attribute_seen) { 416 $private_h_header .= "#if !defined(__GNUC__) && !defined(__attribute__) 417#define __attribute__(x) 418#endif 419 420"; 421 } 422} 423 424my $depstr = ""; 425my $undepstr = ""; 426foreach (keys %depfunction) { 427 $depstr .= "#ifndef $_ 428#ifndef __has_extension 429#define __has_extension(x) 0 430#define ${_}has_extension 1 431#endif 432#if __has_extension(attribute_deprecated_with_message) 433#define $_(x) __attribute__((__deprecated__(x))) 434#elif defined(__GNUC__) && ((__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1 ))) 435#define $_(X) __attribute__((__deprecated__)) 436#else 437#define $_(X) 438#endif 439#ifdef ${_}has_extension 440#undef __has_extension 441#undef ${_}has_extension 442#endif 443#endif /* $_ */ 444 445 446"; 447 $public_h_trailer .= "#undef $_ 448 449"; 450 $private_h_trailer .= "#undef $_ 451#define $_(X) 452 453"; 454} 455 456$public_h_header .= $depstr; 457$private_h_header .= $depstr; 458 459 460if($flags{"cxx"}) { 461 $public_h_header .= "#ifdef __cplusplus 462extern \"C\" { 463#endif 464 465"; 466 $public_h_trailer = "#ifdef __cplusplus 467} 468#endif 469 470" . $public_h_trailer; 471 472} 473if ($opt_E) { 474 $public_h_header .= "#ifndef $opt_E 475#ifndef ${opt_E}_FUNCTION 476#if defined(_WIN32) 477#define ${opt_E}_FUNCTION __declspec(dllimport) 478#define ${opt_E}_CALL __stdcall 479#define ${opt_E}_VARIABLE __declspec(dllimport) 480#else 481#define ${opt_E}_FUNCTION 482#define ${opt_E}_CALL 483#define ${opt_E}_VARIABLE 484#endif 485#endif 486#endif 487"; 488 489 $private_h_header .= "#ifndef $opt_E 490#ifndef ${opt_E}_FUNCTION 491#if defined(_WIN32) 492#define ${opt_E}_FUNCTION __declspec(dllimport) 493#define ${opt_E}_CALL __stdcall 494#define ${opt_E}_VARIABLE __declspec(dllimport) 495#else 496#define ${opt_E}_FUNCTION 497#define ${opt_E}_CALL 498#define ${opt_E}_VARIABLE 499#endif 500#endif 501#endif 502 503"; 504} 505 506$public_h_trailer .= $undepstr; 507$private_h_trailer .= $undepstr; 508 509if ($public_h ne "" && $flags{"header"}) { 510 $public_h = $public_h_header . $public_h . 511 $public_h_trailer . "#endif /* $block */\n"; 512} 513if ($private_h ne "" && $flags{"header"}) { 514 $private_h = $private_h_header . $private_h . 515 $private_h_trailer . "#endif /* $private */\n"; 516} 517 518if($opt_o) { 519 print OUT $public_h; 520} 521if($opt_p) { 522 print PRIV $private_h; 523} 524 525close OUT; 526close PRIV; 527