#! /usr/bin/perl -w

use warnings;
use strict;

# add comments to preprocessor #endif statements
# usage:
#  cppb < file.cc
#  cppb -2 < file.h

# version: 2023-May-30 (14:40)


my $ml = 3;  # PARAMETER: min line diff to add comment

my $cq = 1; # PARAMETER: whether/what to add after #endif
# 0 --> nothing
# 1 --> condition (like NAME==VAL, def BLA)
# 2 --> full expr (like #if NAME==VAL, #ifdef BLA)

my $ind = 0;  # (initial value of) indentation
if ( $ARGV[0] )  { $ind = $ARGV[0]; }
# give -2 (minus $indinc) as arg to avoid header wrappers (#ifdef HAVE_SINCOS_H__)
# being taken into account

my $indinc = 2; # PARAMETER: increment for indentation, set to 0 to disable indentation
my $indstr = ' ' x $ind;

my $hppc = 1; # whether commented out cpp-lines should be included
# this will fail for unbalanced #if/#else/#endif in comments


my @strst = (); # string stack
my @nst = ();  # line number stack
my $lct = 0;   # line counter

sub ind_incr
{
#    printf STDERR " INCR";
    $ind += $indinc;
    $indstr = ' ' x $ind;
}

sub ind_decr
{
#    printf STDERR " DECR";
    $ind -= $indinc;
    $indstr = ' ' x $ind;
}

while ( <STDIN> )
{
    ++$lct;
    chomp;
    my $line = $_;

    my $ppcq = 0;
    if ( $hppc )
    {
        if ( $line =~ /^\/\/(\#.*)$/ )
        {
            $line = $1;
            $ppcq = 1;
        }
    }

    if ( $line =~ /^\# *(if([a-z]*[ \t]+.*))/ )
    {
        my $cond;
        if ( $cq==0 )  { $cond = ""; }
        else
        {
            if ( $cq==1 )  { $cond = "$2"; }  # text after #if
            else           { $cond = "\#$1"; }  # full text
        }

        $line = "#" . "$indstr" . "$1";

        $cond =~ s/ *\/\/.*$//;  # strip C++ comments
        $cond =~ s/ *\/\*.*$//;  # strip C comments

        push @strst, $cond;
        push @nst, $lct;

        &ind_incr();
        goto  finish;
    }

    if ( $line =~ /^\# *((endif|else))[ \t]*(.*)?/ )
    {
        &ind_decr();

        if ( $#strst < 0 )
        {
            print STDERR " ??? unbalanced #if/#endif ??? \n";
            die "XXX: string stack empty while processing #endif/#else: $#strst !\n";
        }

        my $st = pop @strst;
        my $n = pop @nst;
        $line = "\#" . "$indstr" . "$1";

        if ( ($lct-$n) >= $ml ) # enough lines away from clause opening
        {
            $line = $line. " // " . $st;
        }

        if ( $1 =~ "else" ) # pushback if it was an #else
        {
            push @strst, $st;
            push @nst, $n;

            &ind_incr();
        }

        goto  finish;
    }

    if ( $line =~ /^\# *(.*)/ )
    {
        $line = "\#" . "$indstr" . "$1";
        goto  finish;
    }

finish:
    if ( $ppcq )
    {
        $line = '//' . $line;
    }

    print "$line\n";
}

if ( $#strst != -1 )
{
    print STDERR '??? unbalanced #if/#endif ???' . "\n";
    print STDERR 'we still have:' . "\n";
    my $t = $#strst;
    while ( $t >= 0 )
    {
        print STDERR "(#if)  $strst[$t]" . "  \@line # $nst[$t] " . "\n";
        $t--;
    }
    $t = $#strst + 1;
    die "XXX: string stack not empty at exit: $t element(s) left !\n";
}
