Subject: Program to check for balanced #{if|else|endif}s

From: [email-masked] (Alan Stebbens)
Date: 1 May 91 23:47:36 GMT

The following is a perl program to list, with optional indentions 
and line numbers, the `cpp' conditionals: #ifdef, #elif, #else, #endif.
I wrote this because I was unsuccessfully trying to find a missing 
#ifdef in some newly patched software.

Enjoy.

Alan Stebbens        <[email-masked]>             (805) 893-3221
     Center for Computational Sciences and Engineering (CCSE)
          University of California, Santa Barbara (UCSB)
           3111 Engineering I, Santa Barbara, CA 93106

============================= cut here ===================================
#!/bin/perl
# ifdefs [-n] [-i INDENT] [-l]
require 'getopts.pl';

&Getopts('i:nl') || die "Usage: ifdefs [-i indent] [-l] [-n] [files...]\n";

$INDENT = $opt_i ? $opt_i : 3;
$indent = 0;
@block = ();
@state = (0);
# States: 0 - nothing; 1 = #if ; 2 = #elsif ; 3 = #else 
select(STDOUT); $| = 1;
while (<>) {
    if (/^#\s*(if|ifn?def|elif|elsif|elseif|else|endif)/) {
	$key = $1;
	s/[ \t]+/ /g; 
	$nextindent = $indent;
	if ($key eq 'if' || $key =~ /ifn?def/) {
	    $state[$indent] = 1;
	    $block[$indent] = "$key $.";
	    $state[++$nextindent] = 0;
	} elsif ($key eq 'elseif' || $key eq 'elsif' || $key eq 'elif') {
	    $indent--;
	    &Error if !$indent || $state[$indent] < 1 || $state[$indent] > 2;
	    $block[$indent] = "$key $.";
	    $state[$indent] = 2;
	} elsif ($key eq 'else') {
	    &Error if !$indent;
	    $indent--;
	    &Error if $state[$indent] < 1 || $state[$indent] > 2;
	    $state[$indent] = 3;
	    $block[$indent] = "$key $.";
	} elsif ($key eq 'endif') {
    	    &Error if !$indent || $state[$indent];
	    $indent--;
	    &Error if !$state[$indent];
	    $state[$indent] = 0;
	    $block[$indent] = '';
	    $nextindent--;
	}
    } else {
	next unless $opt_l;
    }
    printf "%4d:",$. if $opt_n;
    printf "%s%s",(' 'x($indent * $INDENT)),$_;
    $indent = $nextindent;
}

sub Error {
    if (!$indent) {
	printf "ERROR: Unmatched \#%s:\n%4d: %s",$key,$.,$_;
    } else {
	printf "ERROR: Out of place \#%s:\n%4d: %s",$key,$.,$_;
	($keyw,$keyl) = split(' ',$block[$indent]);
	printf "Previous \#%s at line %d not terminated\n",$keyw,+$keyl;
    }
    next;
}
============================= cut here ===================================
--

Alan Stebbens