1######################################################################## 2# 3# remover is free software; you can redistribute it and/or modify 4# it under the terms of the GNU General Public License as published by 5# the Free Software Foundation; either version 2 of the License, or 6# (at your option) any later version. 7# 8# This program is distributed in the hope that it will be useful, 9# but WITHOUT ANY WARRANTY; without even the implied warranty of 10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11# GNU General Public License for more details. 12# 13# You should have received a copy of the GNU General Public License 14# along with this program; see the file COPYING. If not, write to 15# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 16# 17######################################################################## 18# 19# Project : File Preprocessor - remover module 20# Filename : $RCSfile: remover.pm,v $ 21# Author : $Author: darren $ 22# Maintainer : Darren Miller: darren@cabaret.demon.co.uk 23# File version : $Revision: 1.2 $ 24# Last changed : $Date: 2005/09/01 17:37:20 $ 25# Description : This module removes all code between #ifdef and #if 26# statements for a predifined set of macros. Useful 27# for permanently removing uneeded bits of code. 28# Licence : GNU copyleft 29# 30######################################################################## 31# THIS IS A FILEPP MODULE, YOU NEED FILEPP TO USE IT!!! 32# usage: edit the list of macros below then do: 33# filepp -m remover.pm <files> 34######################################################################## 35 36package Remover; 37 38use strict; 39 40# version number of module 41my $VERSION = '0.1.0'; 42 43# list of macros to be removed 44# enter macro as '1' if it should be initially defined 45# enter macro as '0' if it should be initially undefined 46my %Macros = (); 47 48# "if", "else", "endif" keywords - should match set you are using, 49# defaults to standard filepp/cpp list 50my %Ifwords = ('if', '', 51 'ifdef', '', 52 'ifndef', ''); 53my %Elsewords = ('else', '', 54 'elif', ''); 55my %Endifwords = ('endif', ''); 56 57# turn off keyword processing - will be enabled only when needed 58Filepp::RemoveProcessor("Filepp::ParseKeywords"); 59# turn off all macro processing 60Filepp::RemoveProcessor("Filepp::ReplaceDefines"); 61 62my $keywordchar = Filepp::GetKeywordchar(); 63 64 65# keywords which may or may not be removed 66my %Keywords = ( 67 'define' => \&Define, 68 'elif' => \&Elif, 69 'else' => \&Else, 70 'endif' => \&Endif, 71 'if' => \&If, 72 'ifdef' => \&Ifdef, 73 'ifndef' => \&Ifndef, 74 'remove' => \&Remove, 75 'undef' => \&Undef, 76 ); 77 78 79# counter for number of #if[n][def] loops currently in 80my $iflevel = 0; 81# flag to control when to write output 82my @Writing = (1); # initialise default to 'writing' 83# flag to show if current 'if' block has passed a 'true if' 84my @Ifdone = (0); # initialise first to 'not passed true if' 85 86# flag to say if keyword with removable macros found 87my @RemoveLine = (0); 88my $remove_line = 0; 89 90# function to set macros for removal 91sub Remove 92{ 93 my $macrodefn = shift; 94 my $macro; 95 my $defn; 96 my $i; 97 98 # check there is an argument 99 if($macrodefn !~ /\S/o) { 100 Filepp::Error("remove keyword used without arguments"); 101 } 102 103 # find end of macroword - assume separated by space or tab 104 $i = Filepp::GetNextWordEnd($macrodefn); 105 106 # separate macro and defn (can't use split, doesn't work with '0') 107 $macro = substr($macrodefn, 0, $i); 108 $defn = substr($macrodefn, $i); 109 110 # strip leading whitespace from $defn 111 if($defn) { 112 $defn =~ s/^[ \t]*//; 113 } 114 else { 115 $defn = ""; 116 } 117 $remove_line = 1; 118 $Macros{$macro} = $defn; 119 if($defn) { 120 Filepp::Debug("Remove: $macro added for removal defined=$defn"); 121 Filepp::Define($macrodefn); 122 } 123 else { 124 Filepp::Debug("Remove: $macro added for removal undefined"); 125 Filepp::Undef($macro); 126 } 127} 128 129 130# remove #define for all defines of unwanted macro 131sub Define 132{ 133 my $macrodefn = shift; 134 $macrodefn =~ /^\s*\w+\b/; 135 my $macro = $&; 136 if(exists($Macros{$macro})) { 137 Filepp::Debug("Remove: removing define <$macro>"); 138 $remove_line = 1; 139 } 140 else { Filepp::Define($macrodefn); } 141} 142 143# remove #undef for all undefs of unwanted macro 144sub Undef 145{ 146 my $macro = shift; 147 if(exists($Macros{$macro})) { 148 Filepp::Debug("Remove: removing undef <$macro>"); 149 $remove_line = 1; 150 } 151 else { Filepp::Undef($macro); } 152} 153 154# remove if statements with unwanted conditional in, ignore rest 155sub If 156{ 157 my $expr = shift; 158 my $macro; 159 my $found = 0; 160 foreach $macro (keys(%Macros)) { 161 if($expr=~ /\b$macro\b/) { $found = 1; } 162 } 163 if($found) { 164 Filepp::Debug("Remove: removing if line <$expr>"); 165 $RemoveLine[$iflevel] = 1; 166 $remove_line = 1; 167 return Filepp::If($expr); 168 } 169 else { $RemoveLine[$iflevel] = 0; } 170 return 1; 171} 172 173# elif is not fully supported, prints warning out to for by hand removal 174sub Elif 175{ 176 my $expr = shift; 177 my $macro; 178 foreach $macro (keys(%Macros)) { 179 if($expr=~ /\b$macro\b/) { 180 Filepp::Warning("Remove: #elif removal not fully supported, remove by hand"); 181 } 182 } 183 if($RemoveLine[$iflevel]) { 184 $remove_line = 1; 185 return Filepp::Elif($expr); 186 } 187 return 1; 188} 189 190# remove ifdef statements with unwanted conditional in, ignore rest 191sub Ifdef 192{ 193 my $macro = shift; 194 # separate macro from any trailing garbage 195 $macro = substr($macro, 0, Filepp::GetNextWordEnd($macro)); 196 if(exists($Macros{$macro})) { 197 Filepp::Debug("Remove: removing Ifdef line <$macro>"); 198 $RemoveLine[$iflevel] = 1; 199 $remove_line = 1; 200 return Filepp::Ifdef($macro); 201 } 202 else { $RemoveLine[$iflevel] = 0; } 203 return 1; 204} 205 206 207# remove ifndef statements with unwanted conditional in, ignore rest 208sub Ifndef 209{ 210 my $macro = shift; 211 # separate macro from any trailing garbage 212 $macro = substr($macro, 0, Filepp::GetNextWordEnd($macro)); 213 if(exists($Macros{$macro})) { 214 Filepp::Debug("Remove: removing Ifndef line <$macro>"); 215 $RemoveLine[$iflevel] = 1; 216 $remove_line = 1; 217 return Filepp::Ifndef($macro); 218 } 219 else { $RemoveLine[$iflevel] = 0; } 220 return 1; 221} 222 223sub Else 224{ 225 $remove_line = $RemoveLine[$iflevel]; 226 return 1; 227} 228 229sub Endif 230{ 231 $remove_line = $RemoveLine[$iflevel]; 232 return 1; 233} 234 235############################################################################## 236# Keyword parsing routine 237############################################################################## 238sub ParseKeywords 239{ 240 # input is next line in file 241 my $inline = shift; 242 my $outline = ""; 243 244 my $thisline = $inline; 245 my $keyword; 246 247 # remove whitespace from start of line 248 $thisline = Filepp::CleanStart($thisline); 249 # check if first char on line is a # 250 if($thisline && $thisline =~ /^$keywordchar/) { 251 # remove "#" and any following whitespace 252 $thisline =~ s/^$keywordchar\s*//g; 253 # check for keyword 254 if($thisline && $thisline =~ /^\w+\b/ && exists($Keywords{$&})) { 255 $keyword = $&; 256 # remove newline from line 257 chomp($thisline); 258 # remove leading whitespace and keyword from line 259 my $inline = Filepp::CleanStart(substr($thisline, 260 length($keyword))); 261 262 # check for 'if' style keyword 263 if(exists($Ifwords{$keyword})) { 264 # increment ifblock level and set ifdone to same 265 # value as previous block 266 $iflevel++; 267 $Ifdone[$iflevel] = 0; 268 $Writing[$iflevel] = $Writing[$iflevel - 1]; 269 $RemoveLine[$iflevel] = $RemoveLine[$iflevel - 1]; 270 if(!$Writing[$iflevel]) { $Ifdone[$iflevel] = 1; } 271 } 272 # check for out of place 'else' or 'endif' style keyword 273 elsif($iflevel <= 0 && (exists($Elsewords{$keyword}) || 274 exists($Endifwords{$keyword}) )) { 275 Filepp::Warning($keywordchar.$keyword. 276 " found without preceding ".$keywordchar. 277 "[else]ifword"); 278 } 279 280 # decide if to run 'if' or 'else' keyword 281 if(exists($Ifwords{$keyword}) || exists($Elsewords{$keyword})){ 282 # run keyword to set RemoveLine 283 my $value = $Keywords{$keyword}->($inline); 284 if($RemoveLine[$iflevel] && !$Ifdone[$iflevel]) { 285 # check return value of 'if' 286 if($value) { 287 $Ifdone[$iflevel] = 1; 288 $Writing[$iflevel] = 1; 289 } 290 else { $Writing[$iflevel] = 0; } 291 } 292 elsif($RemoveLine[$iflevel] || $Ifdone[$iflevel]) { 293 $Writing[$iflevel] = 0; 294 } 295 else { $Writing[$iflevel] = 1; } 296 } 297 # check for 'endif' style keyword 298 elsif(exists($Endifwords{$keyword})) { 299 # run endif keyword and decrement iflevel if true 300 if($Keywords{$keyword}->($inline)) { $iflevel--; } 301 } 302 # run all other keywords 303 elsif($Writing[$iflevel] || $RemoveLine[$iflevel] == 0) { 304 $Keywords{$keyword}->($inline); 305 } 306 307 } # keyword if statement 308 } 309 # no keywords in line - write line to file if not #ifdef'ed out 310 if($remove_line || !$Writing[$iflevel]) { 311 # do nothing 312 } 313 else { 314 $outline = $outline.$inline; 315 } 316 317 $remove_line = 0; 318 return $outline; 319} 320Filepp::AddProcessor("Remover::ParseKeywords"); 321 322 323return 1; 324 325######################################################################## 326# End of file 327######################################################################## 328