1 1.1 mrg #!/usr/bin/perl 2 1.1 mrg # 3 1.1 mrg # Original version were part of Gerd Knorr's v4l scripts. 4 1.1 mrg # 5 1.1 mrg # Several improvements by (c) 2005-2007 Mauro Carvalho Chehab 6 1.1 mrg # 7 1.1 mrg # Largely re-written (C) 2007 Trent Piepho <xyzzy (at] speakeasy.org> 8 1.1 mrg # Stolen for DRM usage by airlied 9 1.1 mrg # 10 1.1 mrg # Theory of Operation 11 1.1 mrg # 12 1.1 mrg # This acts as a sort of mini version of cpp, which will process 13 1.1 mrg # #if/#elif/#ifdef/etc directives to strip out code used to support 14 1.1 mrg # multiple kernel versions or otherwise not wanted to be sent upstream to 15 1.1 mrg # git. 16 1.1 mrg # 17 1.1 mrg # Conditional compilation directives fall into two catagories, 18 1.1 mrg # "processed" and "other". The "other" directives are ignored and simply 19 1.1 mrg # output as they come in without changes (see 'keep' exception). The 20 1.1 mrg # "processed" variaty are evaluated and only the lines in the 'true' part 21 1.1 mrg # are kept, like cpp would do. 22 1.1 mrg # 23 1.1 mrg # If gentree knows the result of an expression, that directive will be 24 1.1 mrg # "processed", otherwise it will be an "other". gentree knows the value 25 1.1 mrg # of LINUX_VERSION_CODE, BTTV_VERSION_CODE, the KERNEL_VERSION(x,y,z) 26 1.1 mrg # macro, numeric constants like 0 and 1, and a few defines like MM_KERNEL 27 1.1 mrg # and STV0297_CS2. 28 1.1 mrg # 29 1.1 mrg # An exception is if the comment "/*KEEP*/" appears after the expression, 30 1.1 mrg # in which case that directive will be considered an "other" and not 31 1.1 mrg # processed, other than to remove the keep comment. 32 1.1 mrg # 33 1.1 mrg # Known bugs: 34 1.1 mrg # don't specify the root directory e.g. '/' or even '////' 35 1.1 mrg # directives continued with a back-slash will always be ignored 36 1.1 mrg # you can't modify a source tree in-place, i.e. source dir == dest dir 37 1.1 mrg 38 1.1 mrg use strict; 39 1.1 mrg use File::Find; 40 1.1 mrg use Fcntl ':mode'; 41 1.1 mrg 42 1.1 mrg my $VERSION = shift; 43 1.1 mrg my $SRC = shift; 44 1.1 mrg my $DESTDIR = shift; 45 1.1 mrg 46 1.1 mrg if (!defined($DESTDIR)) { 47 1.1 mrg print "Usage:\ngentree.pl\t<version> <source dir> <dest dir>\n\n"; 48 1.1 mrg exit; 49 1.1 mrg } 50 1.1 mrg 51 1.1 mrg my $BTTVCODE = KERNEL_VERSION(0,9,17); 52 1.1 mrg my ($LINUXCODE, $extra) = kernel_version($VERSION); 53 1.1 mrg my $DEBUG = 0; 54 1.1 mrg 55 1.1 mrg my %defs = ( 56 1.1 mrg 'LINUX_VERSION_CODE' => $LINUXCODE, 57 1.1 mrg 'MM_KERNEL' => ($extra =~ /-mm/)?1:0, 58 1.1 mrg 'DRM_ODD_MM_COMPAT' => 0, 59 1.1 mrg 'I915_HAVE_FENCE' => 1, 60 1.1 mrg 'I915_HAVE_BUFFER' => 1, 61 1.1 mrg 'VIA_HAVE_DMABLIT' => 1, 62 1.1 mrg 'VIA_HAVE_CORE_MM' => 1, 63 1.1 mrg 'VIA_HAVE_FENCE' => 1, 64 1.1 mrg 'VIA_HAVE_BUFFER' => 1, 65 1.1 mrg 'SIS_HAVE_CORE_MM' => 1, 66 1.1 mrg 'DRM_FULL_MM_COMPAT' => 1, 67 1.1 mrg '__linux__' => 1, 68 1.1 mrg ); 69 1.1 mrg 70 1.1 mrg ################################################################# 71 1.1 mrg # helpers 72 1.1 mrg 73 1.1 mrg sub kernel_version($) { 74 1.1 mrg $_[0] =~ m/(\d+)\.(\d+)\.(\d+)(.*)/; 75 1.1 mrg return ($1*65536 + $2*256 + $3, $4); 76 1.1 mrg } 77 1.1 mrg 78 1.1 mrg # used in eval() 79 1.1 mrg sub KERNEL_VERSION($$$) { return $_[0]*65536 + $_[1]*256 + $_[2]; } 80 1.1 mrg 81 1.1 mrg sub evalexp($) { 82 1.1 mrg local $_ = shift; 83 1.1 mrg s|/\*.*?\*/||go; # delete /* */ comments 84 1.1 mrg s|//.*$||o; # delete // comments 85 1.1 mrg s/\bdefined\s*\(/(/go; # defined(foo) to (foo) 86 1.1 mrg while (/\b([_A-Za-z]\w*)\b/go) { 87 1.1 mrg if (exists $defs{$1}) { 88 1.1 mrg my $id = $1; my $pos = $-[0]; 89 1.1 mrg s/$id/$defs{$id}/; 90 1.1 mrg pos = $-[0]; 91 1.1 mrg } elsif ($1 ne 'KERNEL_VERSION') { 92 1.1 mrg return(undef); 93 1.1 mrg } 94 1.1 mrg } 95 1.1 mrg return(eval($_) ? 1 : 0); 96 1.1 mrg } 97 1.1 mrg 98 1.1 mrg ################################################################# 99 1.1 mrg # filter out version-specific code 100 1.1 mrg 101 1.1 mrg sub filter_source ($$) { 102 1.1 mrg my ($in,$out) = @_; 103 1.1 mrg my $line; 104 1.1 mrg my $level=0; 105 1.1 mrg my %if = (); 106 1.1 mrg my %state = (); 107 1.1 mrg 108 1.1 mrg my @dbgargs = \($level, %state, %if, $line); 109 1.1 mrg sub dbgline($\@) { 110 1.1 mrg my $level = ${$_[1][0]}; 111 1.1 mrg printf STDERR ("/* BP %4d $_[0] state=$_[1][1]->{$level} if=$_[1][2]->{$level} level=$level (${$_[1][3]}) */\n", $.) if $DEBUG; 112 1.1 mrg } 113 1.1 mrg 114 1.1 mrg open IN, '<', $in or die "Error opening $in: $!\n"; 115 1.1 mrg open OUT, '>', $out or die "Error opening $out: $!\n"; 116 1.1 mrg 117 1.1 mrg print STDERR "File: $in, for kernel $VERSION($LINUXCODE)/\n" if $DEBUG; 118 1.1 mrg 119 1.1 mrg while ($line = <IN>) { 120 1.1 mrg chomp $line; 121 1.1 mrg next if ($line =~ m/^#include \"compat.h\"/o); 122 1.1 mrg # next if ($line =~ m/[\$]Id:/); 123 1.1 mrg 124 1.1 mrg # For "#if 0 /*KEEP*/;" the ; should be dropped too 125 1.1 mrg if ($line =~ m@^\s*#\s*if(n?def)?\s.*?(\s*/\*\s*(?i)keep\s*\*/;?)@) { 126 1.1 mrg $state{$level} = "ifother"; 127 1.1 mrg $if{$level} = 1; 128 1.1 mrg dbgline "#if$1 (keep)", @dbgargs; 129 1.1 mrg $line =~ s/\Q$2\E//; 130 1.1 mrg $level++; 131 1.1 mrg } 132 1.1 mrg # handle all ifdef/ifndef lines 133 1.1 mrg elsif ($line =~ /^\s*#\s*if(n?)def\s*(\w+)/o) { 134 1.1 mrg if (exists $defs{$2}) { 135 1.1 mrg $state{$level} = 'if'; 136 1.1 mrg $if{$level} = ($1 eq 'n') ? !$defs{$2} : $defs{$2}; 137 1.1 mrg dbgline "#if$1def $2", @dbgargs; 138 1.1 mrg $level++; 139 1.1 mrg next; 140 1.1 mrg } 141 1.1 mrg $state{$level} = "ifother"; 142 1.1 mrg $if{$level} = 1; 143 1.1 mrg dbgline "#if$1def (other)", @dbgargs; 144 1.1 mrg $level++; 145 1.1 mrg } 146 1.1 mrg # handle all ifs 147 1.1 mrg elsif ($line =~ /^\s*#\s*if\s+(.*)$/o) { 148 1.1 mrg my $res = evalexp($1); 149 1.1 mrg if (defined $res) { 150 1.1 mrg $state{$level} = 'if'; 151 1.1 mrg $if{$level} = $res; 152 1.1 mrg dbgline '#if '.($res?'(yes)':'(no)'), @dbgargs; 153 1.1 mrg $level++; 154 1.1 mrg next; 155 1.1 mrg } else { 156 1.1 mrg $state{$level} = 'ifother'; 157 1.1 mrg $if{$level} = 1; 158 1.1 mrg dbgline '#if (other)', @dbgargs; 159 1.1 mrg $level++; 160 1.1 mrg } 161 1.1 mrg } 162 1.1 mrg # handle all elifs 163 1.1 mrg elsif ($line =~ /^\s*#\s*elif\s+(.*)$/o) { 164 1.1 mrg my $exp = $1; 165 1.1 mrg $level--; 166 1.1 mrg $level < 0 and die "more elifs than ifs"; 167 1.1 mrg $state{$level} =~ /if/ or die "unmatched elif"; 168 1.1 mrg 169 1.1 mrg if ($state{$level} eq 'if' && !$if{$level}) { 170 1.1 mrg my $res = evalexp($exp); 171 1.1 mrg defined $res or die 'moving from if to ifother'; 172 1.1 mrg $state{$level} = 'if'; 173 1.1 mrg $if{$level} = $res; 174 1.1 mrg dbgline '#elif1 '.($res?'(yes)':'(no)'), @dbgargs; 175 1.1 mrg $level++; 176 1.1 mrg next; 177 1.1 mrg } elsif ($state{$level} ne 'ifother') { 178 1.1 mrg $if{$level} = 0; 179 1.1 mrg $state{$level} = 'elif'; 180 1.1 mrg dbgline '#elif0', @dbgargs; 181 1.1 mrg $level++; 182 1.1 mrg next; 183 1.1 mrg } 184 1.1 mrg $level++; 185 1.1 mrg } 186 1.1 mrg elsif ($line =~ /^\s*#\s*else/o) { 187 1.1 mrg $level--; 188 1.1 mrg $level < 0 and die "more elses than ifs"; 189 1.1 mrg $state{$level} =~ /if/ or die "unmatched else"; 190 1.1 mrg $if{$level} = !$if{$level} if ($state{$level} eq 'if'); 191 1.1 mrg $state{$level} =~ s/^if/else/o; # if -> else, ifother -> elseother, elif -> elif 192 1.1 mrg dbgline '#else', @dbgargs; 193 1.1 mrg $level++; 194 1.1 mrg next if $state{$level-1} !~ /other$/o; 195 1.1 mrg } 196 1.1 mrg elsif ($line =~ /^\s*#\s*endif/o) { 197 1.1 mrg $level--; 198 1.1 mrg $level < 0 and die "more endifs than ifs"; 199 1.1 mrg dbgline '#endif', @dbgargs; 200 1.1 mrg next if $state{$level} !~ /other$/o; 201 1.1 mrg } 202 1.1 mrg 203 1.1 mrg my $print = 1; 204 1.1 mrg for (my $i=0;$i<$level;$i++) { 205 1.1 mrg next if $state{$i} =~ /other$/o; # keep code in ifother/elseother blocks 206 1.1 mrg if (!$if{$i}) { 207 1.1 mrg $print = 0; 208 1.1 mrg dbgline 'DEL', @{[\$i, \%state, \%if, \$line]}; 209 1.1 mrg last; 210 1.1 mrg } 211 1.1 mrg } 212 1.1 mrg print OUT "$line\n" if $print; 213 1.1 mrg } 214 1.1 mrg close IN; 215 1.1 mrg close OUT; 216 1.1 mrg } 217 1.1 mrg 218 1.1 mrg ################################################################# 219 1.1 mrg 220 1.1 mrg sub parse_dir { 221 1.1 mrg my $file = $File::Find::name; 222 1.1 mrg 223 1.1 mrg return if ($file =~ /CVS/); 224 1.1 mrg return if ($file =~ /~$/); 225 1.1 mrg 226 1.1 mrg my $f2 = $file; 227 1.1 mrg $f2 =~ s/^\Q$SRC\E/$DESTDIR/; 228 1.1 mrg 229 1.1 mrg my $mode = (stat($file))[2]; 230 1.1 mrg if ($mode & S_IFDIR) { 231 1.1 mrg print("mkdir -p '$f2'\n"); 232 1.1 mrg system("mkdir -p '$f2'"); # should check for error 233 1.1 mrg return; 234 1.1 mrg } 235 1.1 mrg print "from $file to $f2\n"; 236 1.1 mrg 237 1.1 mrg if ($file =~ m/.*\.[ch]$/) { 238 1.1 mrg filter_source($file, $f2); 239 1.1 mrg } else { 240 1.1 mrg system("cp $file $f2"); 241 1.1 mrg } 242 1.1 mrg } 243 1.1 mrg 244 1.1 mrg 245 1.1 mrg # main 246 1.1 mrg 247 1.1 mrg printf "kernel is %s (0x%x)\n",$VERSION,$LINUXCODE; 248 1.1 mrg 249 1.1 mrg # remove any trailing slashes from dir names. don't pass in just '/' 250 1.1 mrg $SRC =~ s|/*$||; $DESTDIR =~ s|/*$||; 251 1.1 mrg 252 1.1 mrg print "finding files at $SRC\n"; 253 1.1 mrg 254 1.1 mrg find({wanted => \&parse_dir, no_chdir => 1}, $SRC); 255