2 eval 'exec /usr/bin/perl -S $0 ${1+"$@"}'
3 if $running_under_some_shell;
8 use File
::Path
qw(mkpath);
11 # Make sure read permissions for all are set:
12 if (defined umask && (umask() & 0444)) {
13 umask (umask() & ~0444);
17 use vars
qw($opt_D $opt_d $opt_r $opt_l $opt_h $opt_a $opt_Q $opt_e);
18 die "-r and -a options are mutually exclusive\n" if ($opt_r and $opt_a);
19 my @inc_dirs = inc_dirs() if $opt_a;
23 my $Dest_dir = $opt_d || $Config{installsitearch};
24 die "Destination directory $Dest_dir doesn't exist or isn't a directory\n"
37 @isatype{@isatype} = (1) x
@isatype;
42 @ARGV = ('-') unless @ARGV;
44 build_preamble_if_necessary
();
53 my ($t, $tab, %curargs, $new, $eval_index, $dir, $name, $args, $outfile);
54 my ($incl, $incl_type, $next);
55 while (defined (my $file = next_file
())) {
56 if (-l
$file and -d
$file) {
57 link_if_possible
($file) if ($opt_l);
61 # Recover from header files with unbalanced cpp directives
65 # $eval_index goes into ``#line'' directives, to help locate syntax errors:
72 ($outfile = $file) =~ s/\.h$/.ph/ || next;
73 print "$file -> $outfile\n" unless $opt_Q;
74 if ($file =~ m
|^(.*)/|) {
76 mkpath
"$Dest_dir/$dir";
79 if ($opt_a) { # automagic mode: locate header file in @inc_dirs
86 open(IN
,"$file") || (($Exit = 1),(warn "Can't open $file: $!\n"),next);
87 open(OUT
,">$Dest_dir/$outfile") || die "Can't create $outfile: $!\n";
91 "require '_h2ph_pre.ph';\n\n",
92 "no warnings 'redefine';\n\n";
94 while (defined (local $_ = next_line
($file))) {
96 if (s/^define\s+(\w+)//) {
100 s/\(\w+\s*\(\*\)\s*\(\w*\)\)\s*(-?\d+)/$1/; # (int (*)(foo_t))0
101 if (s/^\(([\w,\s]*)\)//) {
106 foreach my $arg (split(/,\s*/,$args)) {
107 $arg =~ s/^\s*([^\s].*[^\s])\s*$/$1/;
110 $args =~ s/\b(\w)/\$$1/g;
111 $args = "my($args) = \@_;\n$t ";
115 $new =~ s/(["\\])/\\$1/g; #"]);
117 $new = reindent
($new);
118 $args = reindent
($args);
120 $new =~ s/(['\\])/\\$1/g; #']);
123 "eval \"\\n#line $eval_index $outfile\\n\" . 'sub $name $proto\{\n$t ${args}eval q($new);\n$t}' unless defined(\&$name);\n";
127 "eval 'sub $name $proto\{\n$t ${args}eval q($new);\n$t}' unless defined(\&$name);\n";
130 print OUT
"unless(defined(\&$name)) {\n sub $name $proto\{\n\t${args}eval q($new);\n }\n}\n";
136 $new = 1 if $new eq '';
137 $new = reindent
($new);
138 $args = reindent
($args);
140 $new =~ s/(['\\])/\\$1/g; #']);
143 print OUT
$t,"eval \"\\n#line $eval_index $outfile\\n\" . 'sub $name () {",$new,";}' unless defined(\&$name);\n";
146 print OUT
$t,"eval 'sub $name () {",$new,";}' unless defined(\&$name);\n";
149 # Shunt around such directives as `#define FOO FOO':
150 next if " \&$name" eq $new;
152 print OUT
$t,"unless(defined(\&$name)) {\n sub $name () {\t",$new,";}\n}\n";
155 } elsif (/^(include|import|include_next)\s*[<\"](.*)[>\"]/) {
158 if (($incl_type eq 'include_next') ||
159 ($opt_e && exists($bad_file{$incl}))) {
160 $incl =~ s/\.h$/.ph/;
164 $t = "\t" x
($tab / 8) . ' ' x
($tab % 8);
165 print OUT
($t, "my(\@REM);\n");
166 if ($incl_type eq 'include_next') {
168 "my(\%INCD) = map { \$INC{\$_} => 1 } ",
169 "(grep { \$_ eq \"$incl\" } ",
172 "\@REM = map { \"\$_/$incl\" } ",
173 "(grep { not exists(\$INCD{\"\$_/$incl\"})",
174 " and -f \"\$_/$incl\" } \@INC);\n");
177 "\@REM = map { \"\$_/$incl\" } ",
178 "(grep {-r \"\$_/$incl\" } \@INC);\n");
181 "require \"\$REM[0]\" if \@REM;\n");
183 $t = "\t" x
($tab / 8) . ' ' x
($tab % 8);
187 "warn(\$\@) if \$\@;\n");
189 $incl =~ s/\.h$/.ph/;
190 print OUT
$t,"require '$incl';\n";
192 } elsif (/^ifdef\s+(\w+)/) {
193 print OUT
$t,"if(defined(&$1)) {\n";
195 $t = "\t" x
($tab / 8) . ' ' x
($tab % 8);
196 } elsif (/^ifndef\s+(\w+)/) {
197 print OUT
$t,"unless(defined(&$1)) {\n";
199 $t = "\t" x
($tab / 8) . ' ' x
($tab % 8);
200 } elsif (s/^if\s+//) {
205 print OUT
$t,"if($new) {\n";
207 $t = "\t" x
($tab / 8) . ' ' x
($tab % 8);
208 } elsif (s/^elif\s+//) {
214 $t = "\t" x
($tab / 8) . ' ' x
($tab % 8);
215 print OUT
$t,"}\n elsif($new) {\n";
217 $t = "\t" x
($tab / 8) . ' ' x
($tab % 8);
220 $t = "\t" x
($tab / 8) . ' ' x
($tab % 8);
221 print OUT
$t,"} else {\n";
223 $t = "\t" x
($tab / 8) . ' ' x
($tab % 8);
226 $t = "\t" x
($tab / 8) . ' ' x
($tab % 8);
228 } elsif(/^undef\s+(\w+)/) {
229 print OUT
$t, "undef(&$1) if defined(&$1);\n";
230 } elsif(/^error\s+(".*")/) {
231 print OUT
$t, "die($1);\n";
232 } elsif(/^error\s+(.*)/) {
233 print OUT
$t, "die(\"", quotemeta($1), "\");\n";
234 } elsif(/^warning\s+(.*)/) {
235 print OUT
$t, "warn(\"", quotemeta($1), "\");\n";
236 } elsif(/^ident\s+(.*)/) {
237 print OUT
$t, "# $1\n";
239 } elsif (/^\s*(typedef\s*)?enum\s*(\s+[a-zA-Z_]\w*\s*)?/) { # { for vi
240 until(/\{[^}]*\}.*;/ || /;/) {
241 last unless defined ($next = next_line
($file));
243 # drop "#define FOO FOO" in enums
244 $next =~ s/^\s*#\s*define\s+(\w+)\s+\1\s*$//;
245 # #defines in enums (aliases)
246 $next =~ s/^\s*#\s*define\s+(\w+)\s+(\w+)\s*$/$1 = $2,/;
248 print OUT
"# $next\n" if $opt_D;
250 s/#\s*if.*?#\s*endif//g; # drop #ifdefs
253 next unless /^\s?(typedef\s?)?enum\s?([a-zA-Z_]\w*)?\s?\{(.*)\}\s?([a-zA-Z_]\w*)?\s?;/;
254 (my $enum_subs = $3) =~ s/\s//g;
255 my @enum_subs = split(/,/, $enum_subs);
257 foreach my $enum (@enum_subs) {
258 my ($enum_name, $enum_value) = $enum =~ /^([a-zA-Z_]\w*)(=.+)?$/;
260 $enum_value =~ s/^=//;
261 $enum_val = (length($enum_value) ?
$enum_value : $enum_val + 1);
264 "eval(\"\\n#line $eval_index $outfile\\n",
265 "sub $enum_name () \{ $enum_val; \}\") ",
266 "unless defined(\&$enum_name);\n");
270 "eval(\"sub $enum_name () \{ $enum_val; \}\") ",
271 "unless defined(\&$enum_name);\n");
274 } elsif (/^(?:__extension__\s+)?(?:extern|static)\s+(?:__)?inline(?:__)?\s+/
275 and !/;\s*$/ and !/{\s*}\s*$/)
277 # This is a hack to parse the inline functions in the glibc headers.
278 # Warning: massive kludge ahead. We suppose inline functions
279 # are mainly constructed like macros.
281 last unless defined ($next = next_line
($file));
283 undef $_, last if $next =~ /__THROW\s*;/
284 or $next =~ /^(__extension__|extern|static)\b/;
286 print OUT
"# $next\n" if $opt_D;
287 last if $next =~ /^}|^{.*}\s*$/;
289 next if not defined; # because it's only a prototype
290 s/\b(__extension__|extern|static|(?:__)?inline(?:__)?)\b//g;
291 # violently drop #ifdefs
292 s/#\s*if.*?#\s*endif//g
293 and print OUT
"# some #ifdef were dropped here -- fill in the blanks\n";
294 if (s/^(?:\w|\s|\*)*\s(\w+)\s*//) {
297 warn "name not found"; next; # shouldn't occur...
300 if (s/^\(([^()]*)\)\s*(\w+\s*)*//) {
301 for my $arg (split /,/, $1) {
302 if ($arg =~ /(\w+)\s*$/) {
310 ?
"my(" . (join ',', map "\$$_", @args) . ") = \@_;\n$t "
313 my $proto = @args ?
'' : '() ';
315 s/\breturn\b//g; # "return" doesn't occur in macros usually...
317 # try to find and perlify local C variables
318 our @local_variables = (); # needs to be a our(): (?{...}) bug workaround
321 my $typelist = join '|', keys %isatype;
323 (?:(?:__)?const(?:__)?\s+)?
324 (?:(?:un)?signed\s+)?
328 (?{ push @local_variables, $1 })
332 (?:(?:__)?const(?:__)?\s+)?
333 (?:(?:un)?signed\s+)?
337 (?
{ push @local_variables, $1 })
341 $new =~ s/&$_\b/\$$_/g for @local_variables;
342 $new =~ s/(["\\])/\\$1/g; #"]);
343 # now that's almost like a macro (we hope)
347 $Is_converted{$file} = 1;
348 if ($opt_e && exists($bad_file{$file})) {
349 unlink($Dest_dir . '/' . $outfile);
353 queue_includes_from
($file) if $opt_a;
357 if ($opt_e && (scalar(keys %bad_file) > 0)) {
358 warn "Was unable to convert the following files:\n";
359 warn "\t" . join("\n\t",sort(keys %bad_file)) . "\n";
365 $new = '"(assembly code)"' and return if /\b__asm__\b/; # freak out.
368 $joined_args = join('|', keys(%curargs));
371 s/^\&\&// && do { $new .= " &&"; next;}; # handle && operator
372 s/^\&([\(a-z\)]+)/$1/i; # hack for things that take the address of
373 s/^(\s+)// && do {$new .= ' '; next;};
374 s/^0X([0-9A-F]+)[UL]*//i
377 if (length $hex > 8 && !$Config{use64bitint
}) {
378 # Croak if nv_preserves_uv_bits < 64 ?
379 $new .= hex(substr($hex, -8)) +
380 2**32 * hex(substr($hex, 0, -8));
381 # The above will produce "errorneus" code
382 # if the hex constant was e.g. inside UINT64_C
383 # macro, but then again, h2ph is an approximation.
385 $new .= lc("0x$hex");
388 s/^(-?\d+\.\d+E[-+]?\d+)[FL]?//i && do {$new .= $1; next;};
389 s/^(\d+)\s*[LU]*//i && do {$new .= $1; next;};
390 s/^("(\\"|[^"])*")// && do {$new .= $1; next;};
391 s/^'((\\"|[^"])*)'// && do {
393 $new .= "ord('\$$1')";
399 # replace "sizeof(foo)" with "{foo}"
400 # also, remove * (C dereference operator) to avoid perl syntax
401 # problems. Where the %sizeof array comes from is anyone's
402 # guess (c2ph?), but this at least avoids fatal syntax errors.
403 # Behavior is undefined if sizeof() delimiters are unbalanced.
404 # This code was modified to able to handle constructs like this:
405 # sizeof(*(p)), which appear in the HP-UX 10.01 header files.
406 s/^sizeof\s*\(// && do {
408 my $lvl = 1; # already saw one open paren
409 # tack { on the front, and skip it in the loop
412 # find balanced closing paren
413 while ($index <= length($_) && $lvl > 0) {
414 $lvl++ if substr($_, $index, 1) eq "(";
415 $lvl-- if substr($_, $index, 1) eq ")";
418 # tack } on the end, replacing )
419 substr($_, $index - 1, 1) = "}";
420 # remove pesky * operators within the sizeof argument
421 substr($_, 0, $index - 1) =~ s/\*//g;
425 /\(([\w\s]+)[\*\s]*\)\s*[\w\(]/ && do {
427 foreach (split /\s+/, $1) { # Make sure all the words are types,
428 unless($isatype{$_} or $_ eq 'struct' or $_ eq 'union'){
434 s/\([\w\s]+[\*\s]*\)// && next; # then eliminate them.
437 # struct/union member, including arrays:
438 s/^([_A-Z]\w*(\[[^\]]+\])?((\.|->)[_A-Z]\w*(\[[^\]]+\])?)+)//i && do {
440 $id =~ s/(\.|(->))([^\.\-]*)/->\{$3\}/g;
441 $id =~ s/\b([^\$])($joined_args)/$1\$$2/g if length($joined_args);
442 while($id =~ /\[\s*([^\$\&\d\]]+)\]/) {
445 if(exists($curargs{$index})) {
450 $id =~ s/\[\s*([^\$\&\d\]]+)\]/[$index]/;
454 s/^([_a-zA-Z]\w*)// && do {
456 if ($id eq 'struct' || $id eq 'union') {
460 } elsif ($id =~ /^((un)?signed)|(long)|(short)$/) {
461 while (s/^\s+(\w+)//) { $id .= ' ' . $1; }
466 $new .= '->' if /^[\[\{]/;
467 } elsif ($id eq 'defined') {
470 s/^\s*\((\w),/("$1",/ if $id =~ /^_IO[WR]*$/i; # cheat
472 } elsif ($isatype{$id}) {
473 if ($new =~ /{\s*$/) {
475 } elsif ($new =~ /\(\s*$/ && /^[\s*]*\)/) {
479 $new .= q
(').$id.q(');
482 if ($inif && $new !~ /defined\s*\($/) {
483 $new .= '(defined(&' . $id . ') ? &' . $id . ' : 0)';
492 s/^(.)// && do { if ($1 ne '#') { $new .= $1; } next;};
501 my $pre_sub_tri_graphs = 1;
503 READ
: while (not eof IN
) {
506 next unless length $in;
509 if ($pre_sub_tri_graphs) {
510 # Preprocess all tri-graphs
511 # including things stuck in quoted string constants.
512 $in =~ s/\?\?=/#/g; # | ??=| #|
513 $in =~ s/\?\?\!/|/g; # | ??!| ||
514 $in =~ s/\?\?'/^/g; # | ??'| ^|
515 $in =~ s/\?\?\(/[/g; # | ??(| [|
516 $in =~ s/\?\?\)/]/g; # | ??)| ]|
517 $in =~ s/\?\?\-/~/g; # | ??-| ~|
518 $in =~ s/\?\?\//\\/g; # | ??/| \
|
519 $in =~ s/\?\?</{/g; # | ??<| {|
520 $in =~ s/\?\?>/}/g; # | ??>| }|
522 if ($in =~ /^\#ifdef __LANGUAGE_PASCAL__/) {
523 # Tru64 disassembler.h evilness: mixed C and Pascal.
530 if ($in =~ /^extern inline / && # Inlined assembler.
531 $^O
eq 'linux' && $file =~ m!(?:^|/)asm/[^/]+\.h$!) {
538 if ($in =~ s/\\$//) { # \-newline
541 } elsif ($in =~ s/^([^"'\\\/]+)//) { # Passthrough
543 } elsif ($in =~ s/^(\\.)//) { # \...
545 } elsif ($in =~ /^'/) { # '...
546 if ($in =~ s/^('(\\.|[^'\\])*')//) {
551 } elsif ($in =~ /^"/) { # "...
552 if ($in =~ s/^("(\\.|[^"\\])*")//) {
557 } elsif ($in =~ s/^\/\/.*//) { # //...
559 } elsif ($in =~ m/^\/\
*/) { # /*...
560 # C comment removal adapted from perlfaq6:
561 if ($in =~ s/^\/\*[^*]*\*+([^\/*][^*]*\
*+)*\
///) {
563 } else { # Incomplete /* */
566 } elsif ($in =~ s/^(\/)//) { # /...
568 } elsif ($in =~ s/^([^\'\"\\\/]+)//) {
570 } elsif ($^O
eq 'linux' &&
571 $file =~ m!(?:^|/)linux/byteorder/pdp_endian\.h$! &&
572 $in =~ s!\'T KNOW!!) {
573 $out =~ s!I DON$!I_DO_NOT_KNOW!;
576 warn "Cannot parse $file:\n$in\n";
577 $bad_file{$file} = 1;
582 die "Cannot parse:\n$in\n";
587 last READ
if $out =~ /\S/;
594 # Handle recursive subdirectories without getting a grotesquely big stack.
595 # Could this be implemented using File::Find?
603 if ($file eq '-' or -f
$file or -l
$file) {
609 print STDERR
"Skipping directory `$file'\n";
614 print STDERR
"Skipping `$file': not a file or directory\n";
622 # Put all the files in $directory into @ARGV for processing.
625 my ($directory) = @_;
627 $directory =~ s
:/$::;
629 opendir DIR
, $directory;
630 foreach (readdir DIR
) {
631 next if ($_ eq '.' or $_ eq '..');
633 # expand_glob() is going to be called until $ARGV[0] isn't a
634 # directory; so push directories, and unshift everything else.
635 if (-d
"$directory/$_") { push @ARGV, "$directory/$_" }
636 else { unshift @ARGV, "$directory/$_" }
642 # Given $file, a symbolic link to a directory in the C include directory,
643 # make an equivalent symbolic link in $Dest_dir, if we can figure out how.
644 # Otherwise, just duplicate the file or directory.
648 my $target = eval 'readlink($dirlink)';
650 if ($target =~ m
:^\
.\
./: or $target =~ m:^/:) {
651 # The target of a parent or absolute link could leave the $Dest_dir
652 # hierarchy, so let's put all of the contents of $dirlink (actually,
653 # the contents of $target) into @ARGV; as a side effect down the
654 # line, $dirlink will get created as an _actual_ directory.
655 expand_glob
($dirlink);
657 if (-l
"$Dest_dir/$dirlink") {
658 unlink "$Dest_dir/$dirlink" or
659 print STDERR
"Could not remove link $Dest_dir/$dirlink: $!\n";
662 if (eval 'symlink($target, "$Dest_dir/$dirlink")') {
663 print "Linking $target -> $Dest_dir/$dirlink\n";
665 # Make sure that the link _links_ to something:
666 if (! -e
"$Dest_dir/$target") {
667 mkpath
("$Dest_dir/$target", 0755) or
668 print STDERR
"Could not create $Dest_dir/$target/\n";
671 print STDERR
"Could not symlink $target -> $Dest_dir/$dirlink: $!\n";
677 # Push all #included files in $file onto our stack, except for STDIN
678 # and files we've already processed.
679 sub queue_includes_from
684 return if ($file eq "-");
686 open HEADER
, $file or return;
687 while (defined($line = <HEADER
>)) {
688 while (/\\$/) { # Handle continuation lines
693 if ($line =~ /^#\s*include\s+<(.*?)>/) {
694 push(@ARGV, $1) unless $Is_converted{$1};
701 # Determine include directories; $Config{usrinc} should be enough for (all
702 # non-GCC?) C compilers, but gcc uses an additional include directory.
705 my $from_gcc = `LC_ALL=C $Config{cc} -v 2>&1`;
706 if( !( $from_gcc =~ s
:^Reading specs from
(.*?
)/specs\b.*:$1/include
:s
) )
708 $from_gcc = `LC_ALL=C $Config{cc} -print-search-dirs 2>&1`;
709 if ( !($from_gcc =~ s/^install:\s*([^\s]+[^\s\/])([\s\/]*).*$/$1\/include
/s
) )
714 length($from_gcc) ?
($from_gcc, $Config{usrinc
}) : ($Config{usrinc
});
718 # Create "_h2ph_pre.ph", if it doesn't exist or was built by a different
720 sub build_preamble_if_necessary
722 # Increment $VERSION every time this function is modified:
724 my $preamble = "$Dest_dir/_h2ph_pre.ph";
726 # Can we skip building the preamble file?
728 # Extract version number from first line of preamble:
729 open PREAMBLE
, $preamble or die "Cannot open $preamble: $!";
730 my $line = <PREAMBLE
>;
731 $line =~ /(\b\d+\b)/;
732 close PREAMBLE
or die "Cannot close $preamble: $!";
734 # Don't build preamble if a compatible preamble exists:
735 return if $1 == $VERSION;
738 my (%define) = _extract_cc_defines
();
740 open PREAMBLE
, ">$preamble" or die "Cannot open $preamble: $!";
741 print PREAMBLE
"# This file was created by h2ph version $VERSION\n";
743 foreach (sort keys %define) {
745 print PREAMBLE
"# $_=$define{$_}\n";
748 if ($define{$_} =~ /^(\d+)U?L{0,2}$/i) {
750 "unless (defined &$_) { sub $_() { $1 } }\n\n";
751 } elsif ($define{$_} =~ /^\w+$/) {
753 "unless (defined &$_) { sub $_() { &$define{$_} } }\n\n";
756 "unless (defined &$_) { sub $_() { \"",
757 quotemeta($define{$_}), "\" } }\n\n";
760 close PREAMBLE
or die "Cannot close $preamble: $!";
764 # %Config contains information on macros that are pre-defined by the
765 # system's compiler. We need this information to make the .ph files
766 # function with perl as the .h files do with cc.
767 sub _extract_cc_defines
770 my $allsymbols = join " ",
771 @Config{'ccsymbols', 'cppsymbols', 'cppccsymbols'};
773 # Split compiler pre-definitions into `key=value' pairs:
774 foreach (split /\s+/, $allsymbols) {
775 /(.+?)=(.+)/ and $define{$1} = $2;
778 print STDERR
"$_: $1 -> $2\n";
788 ##############################################################################
793 h2ph - convert .h C header files to .ph Perl header files
797 B<h2ph [-d destination directory] [-r | -a] [-l] [headerfiles]>
802 converts any C header files specified to the corresponding Perl header file
804 It is most easily run while in /usr/include:
806 cd /usr/include; h2ph * sys/*
810 cd /usr/include; h2ph * sys/* arpa/* netinet/*
814 cd /usr/include; h2ph -r -l .
816 The output files are placed in the hierarchy rooted at Perl's
817 architecture dependent library directory. You can specify a different
818 hierarchy with a B<-d> switch.
820 If run with no arguments, filters standard input to standard output.
826 =item -d destination_dir
828 Put the resulting B<.ph> files beneath B<destination_dir>, instead of
829 beneath the default Perl library location (C<$Config{'installsitsearch'}>).
833 Run recursively; if any of B<headerfiles> are directories, then run I<h2ph>
834 on all files in those directories (and their subdirectories, etc.). B<-r>
835 and B<-a> are mutually exclusive.
839 Run automagically; convert B<headerfiles>, as well as any B<.h> files
840 which they include. This option will search for B<.h> files in all
841 directories which your C compiler ordinarily uses. B<-a> and B<-r> are
846 Symbolic links will be replicated in the destination directory. If B<-l>
847 is not specified, then links are skipped over.
851 Put ``hints'' in the .ph files which will help in locating problems with
852 I<h2ph>. In those cases when you B<require> a B<.ph> file containing syntax
853 errors, instead of the cryptic
855 [ some error condition ] at (eval mmm) line nnn
857 you will see the slightly more helpful
859 [ some error condition ] at filename.ph line nnn
861 However, the B<.ph> files almost double in size when built using B<-h>.
865 Include the code from the B<.h> file as a comment in the B<.ph> file.
866 This is primarily used for debugging I<h2ph>.
870 ``Quiet'' mode; don't print out the names of the files being converted.
876 No environment variables are used.
895 The usual warnings if it can't read or write the files involved.
899 Doesn't construct the %sizeof array for you.
901 It doesn't handle all C constructs, but it does attempt to isolate
902 definitions inside evals so that you can get at the definitions
903 that it can translate.
905 It's only intended as a rough tool.
906 You may need to dicker with the files produced.
908 You have to run this program by hand; it's not run as part of the Perl
911 Doesn't handle complicated expressions built piecemeal, a la:
921 Doesn't necessarily locate all of your C compiler's internally-defined