Article 8665 of comp.lang.perl:
Xref: feenix.metronet.com comp.lang.perl:8665
Path: feenix.metronet.com!news.utdallas.edu!hermes.chpc.utexas.edu!cs.utexas.edu!uunet!EU.net!Germany.EU.net!Informatik.Uni-Dortmund.DE!fbi-news!pfeifer
From: pfeifer@woodstock.informatik.uni-dortmund.de (Ulrich Pfeifer)
Newsgroups: comp.lang.perl
Subject: fixinc: toll to fix include statements in C and C++ sources
Date: 06 Dec 1993 15:45:05 GMT
Organization: Universitaet Dortmund, Lehrstuhl Informatik VI
Lines: 297
Distribution: world
Message-ID: <PFEIFER.93Dec6164506@woodstock.informatik.uni-dortmund.de>
Reply-To: Ulrich Pfeifer <pfeifer@ls6.informatik.uni-dortmund.de>
NNTP-Posting-Host: woodstock.informatik.uni-dortmund.de

Hello!

Since comp.lang.perl is not (yet) active this is posted here.

I had to reorganize a larger C++ system this weekend especially
splitting some global include directories. But just splitting the
directories is not the whole task. After that each source file (*.c
*.h) has to be examined to fix the include statements. Inspired by the
"fixin" script in the nutshell book i wrote "fixing" to do the
job. The script accepts the same command line than a C or C++ compiler
plus one more option "-nl" to exclude usage of local (relative)
include pathes. I used find.pl until i realized that it would be
better to get the plainfiles i a dir in front of any subdir. So i
copied it in the script and hacked "finddir". The script has a
wrapman man page with it.

Enjoy

Ulrich
------------------------------------------------------------------------
#!/usr/local/bin/perl
'di';
'ig00';
#                              -*- Mode: Perl -*-
# fixinc.pl --
# ITIID           : $ITI$ $Header $__Header$
# Author          : Ulrich Pfeifer
# Created On      : Fri Dec  3 07:55:59 1993
# Last Modified By: Ulrich Pfeifer
# Last Modified On: Fri Dec  3 17:10:43 1993
# Update Count    : 103
# Status          : Unknown, Use with caution!
#

$nolocals = '';
@incdir = ( "." );
# Process switches.

while ($ARGV[0] =~ /^-/) {
    $_ = shift;
    if (/^-nl/) {
	$nolocals++;
    }
    elsif (/^-I(.*)/) {
	push(@incdir, $1);
    }
    else {
	warn "Unrecognized switch: $_\n";
    }
}

shift @incdir if $nolocals;

#require 'find.pl';
#@incdir = ();                   # remove !
foreach $incdir (@incdir) {
    $localinc = $incdir =~ /^\./ unless $nolocals;
    print STDERR "Processing ";
    print STDERR "local " if $localinc;
    print STDERR "incdir \"$incdir\"\n";
    $qincdir = $incdir;
    $qincdir =~ s#\+#\\+#g;
    &find($incdir) if -d $incdir;
}

FILE:
foreach $infile (@ARGV) {
    print STDERR "Processing file \"$infile\"\n" if $opt_v;

    open (IN, "$infile") || die "Could not open \"$infile\": $!\n";
    $changed='';
    rename($infile, "$infile.bak")
        || ((warn "Can't modify $infile"), next FILE);
    open(OUT,">$infile")
        || die "Can't create new $infile: $!\n";
    ($dev,$ino,$mode) = stat IN;
    # $mode = 0755 unless $dev;
    chmod $mode, $infile;
    select(OUT);

    while (<IN>) {
        if (/^\#include\s*[\"<]([^\">.]+\/)?([^\">]+)[\">](.*)$/) {
            $dir  = $1;
            $file = $2;
            $comm = $3;
            chop; s:/\* fixinc.*::;
            #print STDERR "$_ dir=$dir file=$file $comm\n";
            #print STDERR "inccmd{$dir$file}=",$inccmd{"$dir$file"},"\n" if $dir;
            #print STDERR "inccmd{$file}=$inccmd{$file}\n";

            if ($dir) {
                if ($inccmd{"$dir$file"}) {
                    $file = "$dir$file";
                }
            }
            if ($inccmd{$file}) {
                if (/$inccmd{$file}/) {
                    print "$_\n";
                } else {
                    print "#include $inccmd{$file}\t/* fixinc: was $_ */\n";
                    $changed++;
                }
            } else {
                print "$_\t/*  fixinc: file not found */\n";
                $changed++;
            }
        } else {
            print;
        }
    }
    if (!$changed) {
        unlink($infile);
        rename("$infile.bak", $infile)
        || (warn "Can't reset $infile");
        print STDERR "File \"$infile\" seems ok\n";
    } else {
        print STDERR "File \"$infile\" changed\n";
    }
} continue {
    close(OUT);
    close(IN);
}



sub find {
    chop($cwd = `pwd`);
    foreach $topdir (@_) {
	(($topdev,$topino,$topmode,$topnlink) = stat($topdir))
	  || (warn("Can't stat $topdir: $!\n"), next);
	if (-d _) {
	    if (chdir($topdir)) {
		($dir,$_) = ($topdir,'.');
		$name = $topdir;
		&wanted;
		$topdir =~ s,/$,, ;
		&finddir($topdir,$topnlink);
	    }
	    else {
		warn "Can't cd to $topdir: $!\n";
	    }
	}
	else {
	    unless (($dir,$_) = $topdir =~ m#^(.*/)(.*)$#) {
		($dir,$_) = ('.', $topdir);
	    }
	    $name = $topdir;
	    chdir $dir && &wanted;
	}
	chdir $cwd;
    }
}

sub finddir {
    local($dir,$nlink) = @_;
    local($dev,$ino,$mode,$subcount);
    local($name);

    # Get the list of files in the current directory.

    opendir(DIR,'.') || (warn "Can't open $dir: $!\n", return);
    local(@filenames) = readdir(DIR);
    closedir(DIR);

    if ($nlink == 2) {        # This dir has no subdirectories.
	for (@filenames) {
	    next if $_ eq '.';
	    next if $_ eq '..';
	    $name = "$dir/$_";
	    $nlink = 0;
	    &wanted;
	}
    }
    else {                    # This dir has subdirectories.
	$subcount = $nlink - 2;
	for (@filenames) {
	    next if $_ eq '.';
	    next if $_ eq '..';
	    $nlink = $prune = 0;
	    $name = "$dir/$_";
	    &wanted;
	}
	for (@filenames) {
	    next if $_ eq '.';
	    next if $_ eq '..';
	    $nlink = $prune = 0;
	    $name = "$dir/$_";
	    if ($subcount > 0) {    # Seen all the subdirs?

		# Get link count and check for directoriness.

		($dev,$ino,$mode,$nlink) = lstat($_) unless $nlink;

		if (-d _) {

		    # It really is a directory, so do it recursively.

		    if (!$prune && chdir $_) {
			&finddir($name,$nlink);
			chdir '..';
		    }
		    --$subcount;
		}
	    }
	}
    }
}

sub wanted {
    return unless /hh?$/;
    $relpath = $name;
    $relpath =~ s#$qincdir/##;
    #print STDERR "$name: $_ $relpath\n" if /time/;

    if ($localinc) {
        $inccmd{$_} = "\"$relpath\"" unless $inccmd{$_};
    } else {
        $inccmd{$_} =  "<$relpath>"  unless $inccmd{$_};
    }
    if ($localinc) {
        $inccmd{$relpath} = "\"$relpath\"" unless $inccmd{$relpath};
    } else {
        $inccmd{$relpath} =  "<$relpath>"  unless $inccmd{$relpath};
    }
}
###############################################################

    # These next few lines are legal in both Perl and nroff.

.00;                       # finish .ig

'di           \" finish diversion--previous line must be blank
.nr nl 0-1    \" fake up transition to first page again
.nr % 0         \" start at page 1
'; __END__ ##### From here on it's a standard manual page #####
.TH FIXINC 1 "December 3, 1993"
.AT 3
.SH NAME
fixinc \- fix #include statements in C and C++ sources
.SH SYNOPSIS
.B fixinc [-Idir] [-nl] [files]
.SH DESCRIPTION
.I Fixinc
examins recursively the directories in the includepath given on the
command line and remembers the files seen.
.I Fixinc
can be called with the same arguments as the compiler. All unknown
options are ignored. Only
.I \-I
Options are recognized.

In a second step the remaining (non option) arguments are interpreted
as files (Source or include) to fix. The Program searches for include
statements and tries to find the given files in his remembered
list. First the full path is tried then the basename only. If the
path, the includefile was found, is relative (i.e. Starting with a
dot) the statement is interpreted as local file and a statement like

    #include "foo.h"

is generated. Otherwise

    #include <foo.h>

is inserted in the file. If
.I \-nl
is given on the command line no local statements are generated.  The
original statement survives in a c style comment.

If
.I Fixinc
encounters an include statement it cannot resolve it is marked by a
comment.

For all changed files a backup version "*.bak" is generated.

.SH ENVIRONMENT
No environment variables are used.
.SH FILES
None.
.SH AUTHOR
Ulrich Pfeifer
.SH EXAMPLE
fixinc -ggdb -Wall -pipe -I../include \\
.br
    -I/usr/local/gnulang-93c/lib/g++-include \\
.br
    -I/usr/local/gnulang-93c/lib/gcc-lib/sun4/2.4.3/include\\
.br
    -I/usr/local/ls6/nosferatu/include -sun4 -c *.cc

------------------------------------------------------------------------
--
Ulrich  UNIVERSITAET-DORTMUND     telefax:  49 231 755 2386        /////
Pfeifer Lehrstuhl Informatik VI   voice:    49 231 755 3032  ____UNI DO
        D-44221 Dortmund          postbox:  50 05 00         \\*\\////
@RR     e-mail : pfeifer@ls6.informatik.uni-dortmund.de       \\\\\//