1#!/usr/bin/perl -w 2# 3# Regenerate (overwriting only if changed): 4# 5# embed.h 6# embedvar.h 7# proto.h 8# 9# from information stored in 10# 11# embed.fnc 12# intrpvar.h 13# perlvars.h 14# regen/opcodes 15# 16# Accepts the standard regen_lib -q and -v args. 17# 18# This script is normally invoked from regen.pl. 19 20require 5.004; # keep this compatible, an old perl is all we may have before 21 # we build the new one 22 23use strict; 24 25BEGIN { 26 # Get function prototypes 27 require './regen/regen_lib.pl'; 28 require './regen/embed_lib.pl'; 29} 30 31my $unflagged_pointers; 32 33# 34# See database of global and static function prototypes in embed.fnc 35# This is used to generate prototype headers under various configurations, 36# export symbols lists for different platforms, and macros to provide an 37# implicit interpreter context argument. 38# 39 40my $error_count = 0; 41sub die_at_end ($) { # Keeps going for now, but makes sure the regen doesn't 42 # succeed. 43 warn shift; 44 $error_count++; 45} 46 47sub full_name ($$) { # Returns the function name with potentially the 48 # prefixes 'S_' or 'Perl_' 49 my ($func, $flags) = @_; 50 51 return "Perl_$func" if $flags =~ /p/; 52 return "S_$func" if $flags =~ /[SIi]/; 53 return $func; 54} 55 56sub open_print_header { 57 my ($file, $quote) = @_; 58 59 return open_new($file, '>', 60 { file => $file, style => '*', by => 'regen/embed.pl', 61 from => ['data in embed.fnc', 'regen/embed.pl', 62 'regen/opcodes', 'intrpvar.h', 'perlvars.h'], 63 final => "\nEdit those files and run 'make regen_headers' to effect changes.\n", 64 copyright => [1993 .. 2009], quote => $quote }); 65} 66 67my ($embed, $core, $ext, $api) = setup_embed(); 68 69# generate proto.h 70{ 71 my $pr = open_print_header("proto.h"); 72 print $pr "START_EXTERN_C\n"; 73 my $ret; 74 75 foreach (@$embed) { 76 if (@$_ == 1) { 77 print $pr "$_->[0]\n"; 78 next; 79 } 80 81 my ($flags,$retval,$plain_func,@args) = @$_; 82 if ($flags =~ / ( [^AabCDdEefFGhIiMmNnOoPpRrSsTUuWXx] ) /x) { 83 die_at_end "flag $1 is not legal (for function $plain_func)"; 84 } 85 my @nonnull; 86 my $args_assert_line = ( $flags !~ /G/ ); 87 my $has_depth = ( $flags =~ /W/ ); 88 my $has_context = ( $flags !~ /T/ ); 89 my $never_returns = ( $flags =~ /r/ ); 90 my $binarycompat = ( $flags =~ /b/ ); 91 my $commented_out = ( $flags =~ /m/ ); 92 my $is_malloc = ( $flags =~ /a/ ); 93 my $can_ignore = ( $flags !~ /R/ ) && ( $flags !~ /P/ ) && !$is_malloc; 94 my @names_of_nn; 95 my $func; 96 97 if (! $can_ignore && $retval eq 'void') { 98 warn "It is nonsensical to require the return value of a void function ($plain_func) to be checked"; 99 } 100 101 die_at_end "$plain_func: S and p flags are mutually exclusive" 102 if $flags =~ /S/ && $flags =~ /p/; 103 die_at_end "$plain_func: m and $1 flags are mutually exclusive" 104 if $flags =~ /m/ && $flags =~ /([pS])/; 105 106 die_at_end "$plain_func: u flag only usable with m" if $flags =~ /u/ 107 && $flags !~ /m/; 108 109 my $static_inline = 0; 110 if ($flags =~ /([SIi])/) { 111 my $type; 112 if ($never_returns) { 113 $type = { 114 'S' => 'PERL_STATIC_NO_RET', 115 'i' => 'PERL_STATIC_INLINE_NO_RET', 116 'I' => 'PERL_STATIC_FORCE_INLINE_NO_RET' 117 }->{$1}; 118 } 119 else { 120 $type = { 121 'S' => 'STATIC', 122 'i' => 'PERL_STATIC_INLINE', 123 'I' => 'PERL_STATIC_FORCE_INLINE' 124 }->{$1}; 125 } 126 $retval = "$type $retval"; 127 die_at_end "Don't declare static function '$plain_func' pure" if $flags =~ /P/; 128 $static_inline = $type =~ /^PERL_STATIC(?:_FORCE)?_INLINE/; 129 } 130 else { 131 if ($never_returns) { 132 $retval = "PERL_CALLCONV_NO_RET $retval"; 133 } 134 else { 135 $retval = "PERL_CALLCONV $retval"; 136 } 137 } 138 139 $func = full_name($plain_func, $flags); 140 141 die_at_end "For '$plain_func', M flag requires p flag" 142 if $flags =~ /M/ && $flags !~ /p/; 143 die_at_end "For '$plain_func', C flag requires one of [pIimb] flags" 144 if $flags =~ /C/ 145 && ($flags !~ /[Iibmp]/ 146 147 # Notwithstanding the 148 # above, if the name 149 # won't clash with a 150 # user name, it's ok. 151 && $plain_func !~ /^[Pp]erl/); 152 153 die_at_end "For '$plain_func', X flag requires one of [Iip] flags" 154 if $flags =~ /X/ && $flags !~ /[Iip]/; 155 die_at_end "For '$plain_func', X and m flags are mutually exclusive" 156 if $flags =~ /X/ && $flags =~ /m/; 157 die_at_end "For '$plain_func', [Ii] with [ACX] requires p flag" 158 if $flags =~ /[Ii]/ && $flags =~ /[ACX]/ && $flags !~ /p/; 159 die_at_end "For '$plain_func', b and m flags are mutually exclusive" 160 . " (try M flag)" if $flags =~ /b/ && $flags =~ /m/; 161 die_at_end "For '$plain_func', b flag without M flag requires D flag" 162 if $flags =~ /b/ && $flags !~ /M/ && $flags !~ /D/; 163 die_at_end "For '$plain_func', I and i flags are mutually exclusive" 164 if $flags =~ /I/ && $flags =~ /i/; 165 166 $ret = ""; 167 $ret .= "$retval\t$func("; 168 if ( $has_context ) { 169 $ret .= @args ? "pTHX_ " : "pTHX"; 170 } 171 if (@args) { 172 die_at_end "n flag is contradicted by having arguments" 173 if $flags =~ /n/; 174 my $n; 175 for my $arg ( @args ) { 176 ++$n; 177 if ( $args_assert_line 178 && $arg =~ /\*/ 179 && $arg !~ /\b(NN|NULLOK)\b/ ) 180 { 181 warn "$func: $arg needs NN or NULLOK\n"; 182 ++$unflagged_pointers; 183 } 184 my $nn = ( $arg =~ s/\s*\bNN\b\s+// ); 185 push( @nonnull, $n ) if $nn; 186 187 my $nullok = ( $arg =~ s/\s*\bNULLOK\b\s+// ); # strip NULLOK with no effect 188 189 # Make sure each arg has at least a type and a var name. 190 # An arg of "int" is valid C, but want it to be "int foo". 191 my $temp_arg = $arg; 192 $temp_arg =~ s/\*//g; 193 $temp_arg =~ s/\s*\bstruct\b\s*/ /g; 194 if ( ($temp_arg ne "...") 195 && ($temp_arg !~ /\w+\s+(\w+)(?:\[\d+\])?\s*$/) ) { 196 die_at_end "$func: $arg ($n) doesn't have a name\n"; 197 } 198 if (defined $1 && $nn && !($commented_out && !$binarycompat)) { 199 push @names_of_nn, $1; 200 } 201 } 202 $ret .= join ", ", @args; 203 } 204 else { 205 $ret .= "void" if !$has_context; 206 } 207 $ret .= " _pDEPTH" if $has_depth; 208 $ret .= ")"; 209 my @attrs; 210 if ( $flags =~ /r/ ) { 211 push @attrs, "__attribute__noreturn__"; 212 } 213 if ( $flags =~ /D/ ) { 214 push @attrs, "__attribute__deprecated__"; 215 } 216 if ( $is_malloc ) { 217 push @attrs, "__attribute__malloc__"; 218 } 219 if ( !$can_ignore ) { 220 push @attrs, "__attribute__warn_unused_result__"; 221 } 222 if ( $flags =~ /P/ ) { 223 push @attrs, "__attribute__pure__"; 224 } 225 if ( $flags =~ /I/ ) { 226 push @attrs, "__attribute__always_inline__"; 227 } 228 if( $flags =~ /f/ ) { 229 my $prefix = $has_context ? 'pTHX_' : ''; 230 my ($args, $pat); 231 if ($args[-1] eq '...') { 232 $args = scalar @args; 233 $pat = $args - 1; 234 $args = $prefix . $args; 235 } 236 else { 237 # don't check args, and guess which arg is the pattern 238 # (one of 'fmt', 'pat', 'f'), 239 $args = 0; 240 my @fmts = grep $args[$_] =~ /\b(f|pat|fmt)$/, 0..$#args; 241 if (@fmts != 1) { 242 die "embed.pl: '$plain_func': can't determine pattern arg\n"; 243 } 244 $pat = $fmts[0] + 1; 245 } 246 my $macro = grep($_ == $pat, @nonnull) 247 ? '__attribute__format__' 248 : '__attribute__format__null_ok__'; 249 if ($plain_func =~ /strftime/) { 250 push @attrs, sprintf "%s(__strftime__,%s1,0)", $macro, $prefix; 251 } 252 else { 253 push @attrs, sprintf "%s(__printf__,%s%d,%s)", $macro, 254 $prefix, $pat, $args; 255 } 256 } 257 elsif ((grep { $_ eq '...' } @args) && $flags !~ /F/) { 258 die_at_end "$plain_func: Function with '...' arguments must have" 259 . " f or F flag"; 260 } 261 if ( @attrs ) { 262 $ret .= "\n"; 263 $ret .= join( "\n", map { "\t\t\t$_" } @attrs ); 264 } 265 $ret .= ";"; 266 $ret = "/* $ret */" if $commented_out; 267 268 $ret .= "\n#define PERL_ARGS_ASSERT_\U$plain_func\E" 269 if $args_assert_line || @names_of_nn; 270 $ret .= "\t\\\n\t" . join '; ', map "assert($_)", @names_of_nn 271 if @names_of_nn; 272 273 $ret = "#ifndef PERL_NO_INLINE_FUNCTIONS\n$ret\n#endif" if $static_inline; 274 $ret = "#ifndef NO_MATHOMS\n$ret\n#endif" if $binarycompat; 275 $ret .= @attrs ? "\n\n" : "\n"; 276 277 print $pr $ret; 278 } 279 280 print $pr <<'EOF'; 281#ifdef PERL_CORE 282# include "pp_proto.h" 283#endif 284END_EXTERN_C 285EOF 286 287 read_only_bottom_close_and_rename($pr) if ! $error_count; 288} 289 290die_at_end "$unflagged_pointers pointer arguments to clean up\n" if $unflagged_pointers; 291 292sub readvars { 293 my ($file, $pre) = @_; 294 local (*FILE, $_); 295 my %seen; 296 open(FILE, '<', $file) 297 or die "embed.pl: Can't open $file: $!\n"; 298 while (<FILE>) { 299 s/[ \t]*#.*//; # Delete comments. 300 if (/PERLVARA?I?C?\($pre,\s*(\w+)/) { 301 die_at_end "duplicate symbol $1 while processing $file line $.\n" 302 if $seen{$1}++; 303 } 304 } 305 close(FILE); 306 return sort keys %seen; 307} 308 309my @intrp = readvars 'intrpvar.h','I'; 310my @globvar = readvars 'perlvars.h','G'; 311 312sub hide { 313 my ($from, $to, $indent) = @_; 314 $indent = '' unless defined $indent; 315 my $t = int(length("$indent$from") / 8); 316 "#${indent}define $from" . "\t" x ($t < 3 ? 3 - $t : 1) . "$to\n"; 317} 318 319sub multon ($$$) { 320 my ($sym,$pre,$ptr) = @_; 321 hide("PL_$sym", "($ptr$pre$sym)"); 322} 323 324my $em = open_print_header('embed.h'); 325 326print $em <<'END'; 327/* (Doing namespace management portably in C is really gross.) */ 328 329/* By defining PERL_NO_SHORT_NAMES (not done by default) the short forms 330 * (like warn instead of Perl_warn) for the API are not defined. 331 * Not defining the short forms is a good thing for cleaner embedding. 332 * BEWARE that a bunch of macros don't have long names, so either must be 333 * added or don't use them if you define this symbol */ 334 335#ifndef PERL_NO_SHORT_NAMES 336 337/* Hide global symbols */ 338 339END 340 341my @az = ('a'..'z'); 342 343sub embed_h { 344 my ($guard, $funcs) = @_; 345 print $em "$guard\n" if $guard; 346 347 my $lines; 348 foreach (@$funcs) { 349 if (@$_ == 1) { 350 my $cond = $_->[0]; 351 # Indent the conditionals if we are wrapped in an #if/#endif pair. 352 $cond =~ s/#(.*)/# $1/ if $guard; 353 $lines .= "$cond\n"; 354 next; 355 } 356 my $ret = ""; 357 my ($flags,$retval,$func,@args) = @$_; 358 unless ($flags =~ /[omM]/) { 359 my $args = scalar @args; 360 if ($flags =~ /T/) { 361 my $full_name = full_name($func, $flags); 362 next if $full_name eq $func; # Don't output a no-op. 363 $ret = hide($func, $full_name); 364 } 365 elsif ($args and $args[$args-1] =~ /\.\.\./) { 366 if ($flags =~ /p/) { 367 # we're out of luck for varargs functions under CPP 368 # So we can only do these macros for non-MULTIPLICITY perls: 369 $ret = "#ifndef MULTIPLICITY\n" 370 . hide($func, full_name($func, $flags)) . "#endif\n"; 371 } 372 } 373 else { 374 my $alist = join(",", @az[0..$args-1]); 375 $ret = "#define $func($alist)"; 376 my $t = int(length($ret) / 8); 377 $ret .= "\t" x ($t < 4 ? 4 - $t : 1); 378 $ret .= full_name($func, $flags) . "(aTHX"; 379 $ret .= "_ " if $alist; 380 $ret .= $alist; 381 if ($flags =~ /W/) { 382 if ($alist) { 383 $ret .= " _aDEPTH"; 384 } else { 385 die "Can't use W without other args (currently)"; 386 } 387 } 388 $ret .= ")\n"; 389 } 390 $ret = "#ifndef NO_MATHOMS\n$ret#endif\n" if $flags =~ /b/; 391 } 392 $lines .= $ret; 393 } 394 # Prune empty #if/#endif pairs. 395 while ($lines =~ s/#\s*if[^\n]+\n#\s*endif\n//) { 396 } 397 # Merge adjacent blocks. 398 while ($lines =~ s/(#ifndef MULTIPLICITY 399[^\n]+ 400)#endif 401#ifndef MULTIPLICITY 402/$1/) { 403 } 404 405 print $em $lines; 406 print $em "#endif\n" if $guard; 407} 408 409embed_h('', $api); 410embed_h('#if defined(PERL_CORE) || defined(PERL_EXT)', $ext); 411embed_h('#ifdef PERL_CORE', $core); 412 413print $em <<'END'; 414 415#endif /* #ifndef PERL_NO_SHORT_NAMES */ 416 417/* Compatibility stubs. Compile extensions with -DPERL_NOCOMPAT to 418 disable them. 419 */ 420 421#if !defined(PERL_CORE) 422# define sv_setptrobj(rv,ptr,name) sv_setref_iv(rv,name,PTR2IV(ptr)) 423# define sv_setptrref(rv,ptr) sv_setref_iv(rv,NULL,PTR2IV(ptr)) 424#endif 425 426#if !defined(PERL_CORE) && !defined(PERL_NOCOMPAT) 427 428/* Compatibility for various misnamed functions. All functions 429 in the API that begin with "perl_" (not "Perl_") take an explicit 430 interpreter context pointer. 431 The following are not like that, but since they had a "perl_" 432 prefix in previous versions, we provide compatibility macros. 433 */ 434# define perl_atexit(a,b) call_atexit(a,b) 435END 436 437foreach (@$embed) { 438 my ($flags, $retval, $func, @args) = @$_; 439 next unless $func; 440 next unless $flags =~ /O/; 441 442 my $alist = join ",", @az[0..$#args]; 443 my $ret = "# define perl_$func($alist)"; 444 my $t = (length $ret) >> 3; 445 $ret .= "\t" x ($t < 5 ? 5 - $t : 1); 446 print $em "$ret$func($alist)\n"; 447} 448 449my @nocontext; 450{ 451 my (%has_va, %has_nocontext); 452 foreach (@$embed) { 453 next unless @$_ > 1; 454 ++$has_va{$_->[2]} if $_->[-1] =~ /\.\.\./; 455 ++$has_nocontext{$1} if $_->[2] =~ /(.*)_nocontext/; 456 } 457 458 @nocontext = sort grep { 459 $has_nocontext{$_} 460 && !/printf/ # Not clear to me why these are skipped but they are. 461 } keys %has_va; 462} 463 464print $em <<'END'; 465 466/* varargs functions can't be handled with CPP macros. :-( 467 This provides a set of compatibility functions that don't take 468 an extra argument but grab the context pointer using the macro 469 dTHX. 470 */ 471#if defined(MULTIPLICITY) && !defined(PERL_NO_SHORT_NAMES) 472END 473 474foreach (@nocontext) { 475 print $em hide($_, "Perl_${_}_nocontext", " "); 476} 477 478print $em <<'END'; 479#endif 480 481#endif /* !defined(PERL_CORE) && !defined(PERL_NOCOMPAT) */ 482 483#if !defined(MULTIPLICITY) 484/* undefined symbols, point them back at the usual ones */ 485END 486 487foreach (@nocontext) { 488 print $em hide("Perl_${_}_nocontext", "Perl_$_", " "); 489} 490 491print $em <<'END'; 492#endif 493END 494 495read_only_bottom_close_and_rename($em) if ! $error_count; 496 497$em = open_print_header('embedvar.h'); 498 499print $em <<'END'; 500#if defined(MULTIPLICITY) 501# define vTHX aTHX 502END 503 504my $sym; 505 506for $sym (@intrp) { 507 if ($sym eq 'sawampersand') { 508 print $em "#ifndef PL_sawampersand\n"; 509 } 510 print $em multon($sym,'I','vTHX->'); 511 if ($sym eq 'sawampersand') { 512 print $em "#endif\n"; 513 } 514} 515 516print $em <<'END'; 517 518#endif /* MULTIPLICITY */ 519END 520 521read_only_bottom_close_and_rename($em) if ! $error_count; 522 523die "$error_count errors found" if $error_count; 524 525# ex: set ts=8 sts=4 sw=4 noet: 526