Search code examples
xcodeperlxcode4xcode4.5

Removing occurences of #ifdef/#endif from a file with perl


I have a code file that has some #ifdefs I would like removed in the header file after building a library. My first thought was to do this as a perl script that XCode can run. While I can certainly open the header file and read all content of it into a string in perl, I'm curious as to the best way to do the following

  1. Find any occurrence of #ifdef EXAMPLE

  2. Remove it and anything in between the following #endif

So the example is:

int i;
NSString *someString;
#ifdef EXAMPLE
NSString *exampleString;
#endif
bool done;

and the output would be:

int i;
NSString *someString;
bool done;

Options I'm considering:

  • finding index of every #ifdef EXAMPLE and removing it via substring with the next found #endif
  • Write a regex that can somehow remove these occurences.

Considering I haven't written Perl before (Objective-C is my primary language) I was curious if any XCode or Perl developers had any suggestions on what the best approach would be


Solution

  • I'm not sure why you want to strip out ifdefs, and you can probably use a C pre-processor to do this, but here's how you'd do it in Perl because it means I get to play with the flip-flop operator.

    First thing is to craft a sufficient regex to match the ifdefs. IIRC they can be indented and there can be indentation between the # and the word.

    #ifdef
    #    ifdef
        #ifdef
    

    Not sure if that last one is valid, but I'm going with it anyway.

    my $ifdef_re = qr{^\s*#\s*ifdef\b};
    my $endif_re = qr{^\s*#\s*endif\b};
    

    If it was just removing text between #ifdef and #endif, Perl has the little used flip flop scalar .. operator.

    #!/usr/bin/env perl
    
    use strict;
    use warnings;
    
    my $ifdef_re = qr{^\s*#\s*ifdef\b};
    my $endif_re = qr{^\s*#\s*endif\b};
    
    while(<DATA>) {
        my $in_ifdef = /$ifdef_re/ .. /$endif_re/;
    
        print if !$in_ifdef;
    }
    
    __DATA__
    int i;
    NSString *someString;
    #ifdef EXAMPLE
    NSString *exampleString;
    #endif
    bool done;
    

    But since we need to worry about nested ifdefs, its insufficient. A depth counter takes care of that.

    #!/usr/bin/env perl
    
    use strict;
    use warnings;
    
    my $ifdef_re = qr{^\s*#\s*ifdef\b};
    my $endif_re = qr{^\s*#\s*endif\b};
    
    my $ifdef_count = 0;
    while(<DATA>) {
        $ifdef_count++ if /$ifdef_re/;
    
        print if $ifdef_count <= 0;
    
        $ifdef_count-- if /$endif_re/;
    }
    
    __DATA__
    int i;
    NSString *someString;
    #ifdef EXAMPLE
    NSString *exampleString;
    #    ifdef FOO
    this should not appear
    #    endif
    nor should this
    #endif
    bool done;