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: Reply-To: Ulrich Pfeifer 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 () { 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 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 \\\\\//