1#!perl -w 2use strict; 3 4use Pod::Usage; 5use Getopt::Std; 6$Getopt::Std::STANDARD_HELP_VERSION = 1; 7 8my $trysource = "try.c"; 9my $tryout = "try.i"; 10 11getopts('fF:ekvI:', \my %opt) or pod2usage(); 12 13my($expr, @headers) = @ARGV ? splice @ARGV : "-"; 14 15pod2usage "-f and -F <tool> are exclusive\n" if $opt{f} and $opt{F}; 16 17foreach($trysource, $tryout) { 18 unlink $_ if $opt{e}; 19 die "You already have a $_" if -e $_; 20} 21 22if ($expr eq '-') { 23 warn "reading from stdin...\n"; 24 $expr = do { local $/; <> }; 25} 26 27my($macro, $args) = $expr =~ /^\s*(\w+)((?:\s*\(.*\))?)\s*;?\s*$/s 28 or pod2usage "$expr doesn't look like a macro-name or macro-expression to me"; 29 30if (!(@ARGV = @headers)) { 31 open my $fh, '<', 'MANIFEST' or die "Can't open MANIFEST: $!"; 32 while (<$fh>) { 33 push @ARGV, $1 if m!^([^/]+\.h)\t!; 34 } 35 push @ARGV, 'config.h' if -f 'config.h'; 36} 37 38my $header; 39while (<>) { 40 next unless /^#\s*define\s+$macro\b/; 41 my ($def_args) = /^#\s*define\s+$macro\(([^)]*)\)/; 42 if (defined $def_args && !$args) { 43 my @args = split ',', $def_args; 44 print "# macro: $macro args: @args in $_\n" if $opt{v}; 45 my $argname = "A0"; 46 $args = '(' . join (', ', map {$argname++} 1..@args) . ')'; 47 } 48 $header = $ARGV; 49 last; 50} 51die "$macro not found\n" unless defined $header; 52 53open my $out, '>', $trysource or die "Can't open $trysource: $!"; 54 55my $sentinel = "$macro expands to"; 56 57print $out <<"EOF"; 58#include "EXTERN.h" 59#include "perl.h" 60EOF 61 62print $out qq{#include "$header"\n} 63 unless $header eq 'perl.h' or $header eq 'EXTERN.h'; 64 65print $out <<"EOF"; 66#line 4 "$sentinel" 67$macro$args 68EOF 69 70close $out or die "Can't close $trysource: $!"; 71 72print "doing: make $tryout\n" if $opt{v}; 73system "make $tryout" and die; 74 75# if user wants 'indent' formatting .. 76my $out_fh; 77 78if ($opt{f} || $opt{F}) { 79 # a: indent is a well behaved filter when given 0 arguments, reading from 80 # stdin and writing to stdout 81 # b: all our braces should be balanced, indented back to column 0, in the 82 # headers, hence everything before our #line directive can be ignored 83 # 84 # We can take advantage of this to reduce the work to indent. 85 86 my $indent_command = $opt{f} ? 'indent' : $opt{F}; 87 88 if (defined $opt{I}) { 89 $indent_command .= " $opt{I}"; 90 } 91 open $out_fh, '|-', $indent_command or die $?; 92} else { 93 $out_fh = \*STDOUT; 94} 95 96open my $fh, '<', $tryout or die "Can't open $tryout: $!"; 97 98while (<$fh>) { 99 print $out_fh $_ if /$sentinel/o .. 1; 100} 101 102unless ($opt{k}) { 103 foreach($trysource, $tryout) { 104 die "Can't unlink $_" unless unlink $_; 105 } 106} 107 108__END__ 109 110=head1 NAME 111 112expand-macro.pl - expand C macros using the C preprocessor 113 114=head1 SYNOPSIS 115 116 expand-macro.pl [options] [ < macro-name | macro-expression | - > [headers] ] 117 118 options: 119 -f use 'indent' to format output 120 -F <tool> use <tool> to format output (instead of -f) 121 -e erase try.[ic] instead of failing when they're present (errdetect) 122 -k keep them after generating (for handy inspection) 123 -v verbose 124 -I <indent-opts> passed into indent 125 126=cut 127