Kyle Kinkade Kyle Kinkade - 3 months ago 18
Perl Question

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

Answer

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;