From aks@anywhere.ucsb.edu Fri May 3 10:51:57 1991 From: aks@anywhere.ucsb.edu (Alan Stebbens) Newsgroups: comp.lang.perl Subject: Program to list (and comprehend) nested includes Summary: Program to list nested `cpp' includes Keywords: Program lists nested #includes Date: 1 May 91 23:57:43 GMT Organization: CCSE, Univ. of CA, Santa Barbara When trying to port software to the IBM RS3000 running AIX 3.1, it often occurs that I have to isolate a missing or malformed rerenced to some "standard" macro or define. Also, there are many include files in the /usr/include hierarchy which are ultimately recursive by re-invoking, for example, /usr/include/standards.h. It becomes very difficult to understand the dependencies of these include files when such recursion occurs is several places or is very deep. The following program, "includes", is my "quick 'n dirty" solution to this problem: it will list, and optionally indent and line-number, the standard `cpp' include directives. Oh yeah, a caveat: I had originally intended the program to be able to dynamically interpret #define's and #undef's, but never followed up with the code to do the job. Thus, the internal documentation and "usage:" show a -D and -U option usage, but don't really do anything with it. Perhaps, some other time, I'll make it work as intended. Or, someone else will. Enjoy. Alan Stebbens (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 # includes [[-[vincu]...] [-Idir] [-Dname] [-Uname]]... files # # Given a list of files, determine the #include dependency list # given '-c', use CPP to determine the _dynamic_ dependency list, # otherwise, the static include file dependency list is produced. # # If the `-D' or `-U' options are given, `-c' is assumed. # # $IndentStr = ' ' x 4; @IncludeDirs = ('.'); @Defines = (); $Verbose = 0; $Pathnames = 0; $LineNums = 0; $Indent = 0; $SortUniq = 0; &Usage unless $#ARGV >= $[; while ($_ = shift) { # scan arguments if (!/^-/) { unshift(@ARGV,$_); last; } while (s/^-(.)/-/) { $Compile++ if $1 eq 'c'; $Indent++ if $1 eq 'i'; $LineNums++ if $1 eq 'n'; $Pathnames++ if $1 eq 'p'; $SortUniq++ if $1 eq 's'; $Verbose++ if $1 eq 'v'; if ($1 =~ /[IDU]/) { $opt = $1; s/^-(.*)/-$opt$1/; # put option back in push(@IncludeDirs,$_) if $opt eq 'I'; push(@Defines,$_) if $opt =~ /DU/; last; } &Usage unless $1 =~ /[cinpsv]/; } } &Usage if $SortUniq && ($LineNums || $Indent); $Compile++ if $#Defines >= $[; # any defines? compile it $Pathnames = $LineNums = $Indent = 1 if $Verbose; @Files = @ARGV; while ($File = shift(@Files)) { printf "%s:\n",$File; if ($SortUniq) { select(STDOUT); $| = 1; open(SORT,"|sort -u +1 -2") || die "Can't open pipe to `sort -u' filter because $!\n"; select(SORT); $| = 1; } &ShowIncludes($File,0); if ($SortUniq) { close(SORT); select(STDOUT); } } exit; %Included = (); sub ShowIncludes { local($name,$level) = @_; local(*FILE); local($_,$.); local($pathname,$lq,$incname,$rq); local($indent) = $Indent ? $IndentStr x $level : ''; if (open(FILE,$name)) { $Included{$name}++; while () { next unless /^#include/; chop; if (/^#include\s*(")([^"]*)(")/ || /^#include\s*(<)([^>]*)(>)/) { ($lq,$incname,$rq) = ($1,$2,$3); print $indent; printf "%3d:",$. if $LineNums; printf "#include %s%s%s",$lq,$incname,$rq; if ($file = &FindFile($incname,($lq eq '"'))) { printf "\t(%s)",$file if $Pathnames; print "\n"; &ShowIncludes($file,$level+1) unless $Included{$file}; } else { printf ": can't find $incname\n"; } } else { print ": bad syntax.\n"; } } close FILE; } else { print ": can't open $name because $!\n"; } } sub FindFile { local($file,$localflag) = @_; local($path); if ($localflag) { foreach $dir (@IncludeDirs) { ($path = $dir . '/' . $file) =~ s/^-I//; return $path if -f $path; } } foreach $dir ('/usr/local/include', '/usr/include') { return $path if -f ($path = $dir . '/' . $file); } ''; } sub Usage { select(STDERR); print STDERR <<"EOF"; usage: includes [-cinspv] [-Ipath]... [-[D|U]name]... files Prints the '#include' statements referenced by the named files, automatically following nested #includes; statically recursive #includes are detected. -c Compile (interpret) #ifdef's and expressions -i Indent nested #includes -n Print the line numbers of the #include statements -p Print the absolute path names for each include file -s Run the #includes through a `sort -u' filter -v Verbose mode; implies `-inp' options -Ipath Add `path' to the include search path. -Dname Define `name'; implies the `-c' option. -Uname Undefine `name'; implies the `-c' option. Sorting is mutually exclusive with indents and line numbering. EOF exit 1; } ============================= cut here =================================== -- Alan Stebbens From aks@anywhere.ucsb.edu Fri May 3 10:52:08 1991 From: aks@anywhere.ucsb.edu (Alan Stebbens) Newsgroups: comp.lang.perl Subject: Program to check for balanced #{if|else|endif}s Summary: List, with optional line numbers and indention, `cpp' conditionals Keywords: CPP #ifdef #else #endif listing Date: 1 May 91 23:47:36 GMT Organization: CCSE, Univ. of CA, Santa Barbara 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 (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