[Date Prev][Date Next][Thread Prev][Thread Next] [Search] [Date Index] [Thread Index]

Re: [MacPerl] Generic Search Script



>From Ero Brown
--------------
>>I would appreciate suggestions for improvements.


>From Paul J. Schinder
---------------------
> Just a few comments after a not very careful reading.  "my" is always
> recommended over "local" these days, for reasons having to do with how they
> work (local is actually a "save/restore" of a global variable, whereas my
> is lexical, which is more local than local().  Go figure).  You're simply
> wasting a variable in GetHostOS; you can simply "return $^O;".  It looks
> like you're reinventing a wheel or two here.  You should become familiar
> with the Getopt:: modules.  You should not, these days, use any of the *.pl
> files distributed with Perl, since they are legacy code.  You might as well
> use File::Find directly, which gives you more control.

In version reposted below I have simply replaced all "local"
references with "my".

Paul makes a number of good points, currently looking into:
   - simply "return $^O;" instead of function GetHostOS.
   - the Getopt:: modules.
   - ridding use of *.pl files distributed with Perl.
   - use File::Find directly.


>From Raffael Cavallaro:
-----------------------
> Hmm, when I syntax check this script, it flags several errors:
>
> # syntax error, near "works!"
> File ...; Line 87
> # syntax error, near "$expression "
> File ...; Line 129
> # ... had compilation errors.

Had some line wrapping errors, I appologize, hope the following
works better for you.


#========================================================================
#========================================================================
#
# Search.pl
#
# Author: Ero Brown <ero@fiber.net>
#
# Version: 1.4
#
# Changed from version 1.3:
#      - corrected tab, line-length, and wrapping issues
#      - replaced use of "local" with "my"
#
#========================================================================
#========================================================================

#!/usr/local/bin/perl

### required package needed for this script
require 'find.pl';


#========================================================================

### define true and false.
$TRUE = 1;
$FALSE = 0;


#========================================================================

### Forward declare all sub-routines used
sub Usage;
sub GetHostOS;
sub GetDirSeperatorChar;
sub ReadArguments;
sub DoAFile;
sub wanted;


#========================================================================
# Function: Usage
# Purpose:  this details the usage of this script -- we can call this
#           function when a invalid usage error occurs.
#========================================================================
sub Usage {
   die <<END_USAGE;
usage: $0 [-r] [-p] [-c] [-i] [-m] [-f <expression>] -e <expression>
<folder(s) &| file(s) . . .>

   -r   recursively process encountered sub-directories
   -c   only list a total count of matching occurrances
   -i   make pattern matching case insensitive
   -f   file expression representing a file filter
   -e   the expression representing what you are searching for
   -m   mpw style output
   -p   print progress and summary information

   *Parameters can be given in any order.

   *Fully resolved pathnames are required, partial pathnames will
    cause this script to barf.

   Version 1.3
END_USAGE
}


#========================================================================
# Function: GetHostOS
# Purpose:  Determine what OS we are running on -- $^O is a Perl variable
#           that contains to name of the OS that Perl was compiled on.
#========================================================================
sub GetHostOS
{
   my ($tOSString) = $^O;
   ## print "Running this script on a computer running $tOSString...\n\n";
   return($tOSString)
}


#========================================================================
# Function: GetDirSeperatorChar
# Purpose:  Each platform (OS) uses a unique character to seperate
#           directory names within a full path specification string.
#           Here we set a variable to contain the correct directory
#           seperator character to be correct for the OS that we are
#           currently running this script on.
#========================================================================
sub GetDirSeperatorChar
{
  # my ($tOSString) = @_;
   my ($tDir);
   if ($tOSString =~ /mac/i) {  #it's a Macintosh!
      $tDir = ':';
   }
   elsif ($tOSString =~ /nix/i) {  #it's probably some flavor of Unix
      $tDir = '/';
   }
   else {  #it could be other things, but assume a Wintel PC
      $tDir = '/';  #!?! -- only the unix flavor works!
   }
   return ($tDir)
}


#========================================================================
# Function: ReadArguments
# Purpose:  Parse the arguments array and seperate everything into two
#           distinct arrays, one containing the "-<opt>" command options,
#           and the other containing the list of directories (and possibly
#           files) to be checked; then go through the command options
#           array and set the appropriate command flags . . . we do it
#           this way so we can put commands and regualr arguments in any
#           order on the command line.
#========================================================================
sub ReadArguments
{
   my ($i,$hasArgs);

   #if no arguments are passed in, assume the user needs some help
   if (@ARGV < 1) {
      Usage;
   }

   #these are the two lists (arrays) we're going to seperate our args into
   @ARG_Options = ();
   @ARG_Dirs = ();
   $expression = "";
   $fileFilter = "";

   $hasArgs = $FALSE;
   $i = 0;
   while ($i <= $#ARGV) {
      $option = $ARGV[$i];
      if ($option =~ /-[rcfmpei]/i) {  #if it's a valid command option...
         push(@ARG_Options,$option);  #add to command options list
         if (($option =~ /-e/i) && ($i+1 <= $#ARGV)) {
            $i++;
            $expression = $ARGV[$i];
         }
         if (($option =~ /-f/i) && ($i+1 <= $#ARGV)) {
            $i++;
            $fileFilter = $ARGV[$i];
         }
         $hasArgs = $TRUE;
      }
      else {
         push(@ARG_Dirs,$option);  #add to directories list
      }
      $i++;
   }

   $recurseOpt = $FALSE;
   $progressOpt = $FALSE;
   $expressionOpt = $FALSE;
   $fileFilterOpt = $FALSE;
   $mpwOutputOpt = $FALSE;
   $countOnlyOpt = $FALSE;
   $caseInSensitive = $FALSE;
   $pad = "";

   #now that we have all the command options, go through as set the
   #appropriate flags that tell us how this script should behave.
   if ($hasArgs) {
      while (@ARG_Options) {
         $op = shift(@ARG_Options);
         if ($op =~ /-r/i) {
            $recurseOpt = $TRUE;
         }
         if ($op =~ /-p/i) {
            $progressOpt = $TRUE;
            $pad = "\t";
         }
         if ($op =~ /-e/i) {
            $expressionOpt = $TRUE;
         }
         if ($op =~ /-f/i) {
            $fileFilterOpt = $TRUE;
         }
         if ($op =~ /-m/i) {
            $mpwOutputOpt = $TRUE;
         }
         if ($op =~ /-c/i) {
            $countOnlyOpt = $TRUE;
         }
         if ($op =~ /-i/i) {
            $caseInSensitive = $TRUE;
         }
      }
   }
}


#========================================================================
# Function: DoAFile
# Purpose:  process the file/directory
#           this is where the action is -- look at every file and
#           directory and perform the desired operations.
#========================================================================
sub DoAFile {
   my ($theFileName) = @_;
   my ($shortName, $doSearch);

   if (-f $theFileName) {
      $fileCount++;
      if ($progressOpt) {
         print $pad, "FILE: $theFileName\n";
      }
      $shortName = $theFileName;
      @dirNameParts = split($Dir,$shortName);  #break full pathname apart
      $shortName = $tempName = pop(@dirNameParts);  #filename by itself

      $doSearch = $TRUE;
      if ($fileFilterOpt) {
         $doSearch = $FALSE;
         if ($caseInSensitive) {
            if (eval($shortName =~ /$fileFilter/oi)) {
               $doSearch = $TRUE;
            }
         }
         else {
            if (eval($shortName =~ /$fileFilter/o)) {
               $doSearch = $TRUE;
            }
         }
      }

      if ($doSearch) {
         my ($tempFoundCount) = 0;
         my ($lineCounter) = 1;
         if ($progressOpt) {
            print $pad, "Searching $theFileName...\n";
         }
         $exp = "/".$expression."/".$setting;

         open(THEFILE, $theFileName) || die "Can't open file $theFileName\n";
         while ($lineStr= <THEFILE>) {
            $found = $FALSE;
            if ($caseInSensitive) {
               if (eval($lineStr =~ /$expression/oi)) {
                  $found = $TRUE;
               }
            }
            else {
               if (eval($lineStr =~ /$expression/o)) {
                  $found = $TRUE;
               }
            }
            if ($found) {
               $tempFoundCount++;
               if (!$countOnlyOpt) {
                  if ($mpwOutputOpt) {
                     print $pad, $pad, "File \"", $theFileName, "\"; Line ";
                     print $lineCounter, ":¤ \t# ", $lineStr;
                  }
                  else {
                     print $pad, $pad, $theFileName, " -- line #";
                     print $lineCounter, "\n",  $pad, $pad, $pad, $lineStr;
                  }
               }
            }
            $lineCounter++;
         }
         close(THEFILE);
         if (($progressOpt) && ($tempFoundCount > 0)) {
            print $pad, $pad, $theFileName, " -- had ", $tempFoundCount;
            print " occurrances of the search expression.\n";
         }
         $foundCount += $tempFoundCount;
      }

   }
   # it must be a directory (-d $theFileName)
   else {
      $dirCount++;
      if ($progressOpt) {
         print "DIRECTORY: $theFileName\n";
      }
   }
}


#========================================================================
# Function: wanted
# Purpose:  We need to provide this function for the &find() function in
#           the 'find.pl' package -- this is so we can control (via filter)
#           what kind of files and/or directories get processed.
#========================================================================
sub wanted
{
   #filter so we only process the files/directories we want
   ((-f $_) ||   #do all files
      #only one level deep if the recurse option is not on
      ((-d $_) && (!$recurseOpt) && ($File::Find::prune = 1)) ||
      ((-d $_) && ($recurseOpt)) ) &&   #all subdirectories if recurse is on
      DoAFile($name);   #call our critical function that does the checking
}


#========================================================================
#============================   MAIN   ==================================
#========================================================================

### main part of the program --
### we go through every file and directory passed in on
### the command line and check it for validity.

#what OS are we running on?
$osString = GetHostOS;

#what's the right dir seperator char to use?
$Dir = GetDirSeperatorChar($osString);

#parse the command line for commands and arguments
ReadArguments;

#initialize these counter variables
$fileCount = 0;
$dirCount = 0;
$unknownCount = 0;
$errorCount = 0;
$foundCount = 0;

#if no directories/files are passed in, assume the user needs some help
if (@ARG_Dirs < 1) {
   print "No search Directorie(s) was specified.\n";
   Usage;
}
elsif (!$expressionOpt) {
   print "The required -e expression option was NOT specified.\n";
   Usage;
}
elsif (!$expression) {
   print "The search expression specified was empty.\n";
   Usage;
}
elsif (($fileFilterOpt) && (!$fileFilter)) {
   print "The file filter expression was empty.\n";
   Usage;
}

#process every directory (and/or file) provided on the command line
while (@ARG_Dirs) {
   $arg = shift(@ARG_Dirs);  #get the next directory/file to examine
   if ((-f $arg) || (-d $arg)) {  #check for a valid disk entity
      find($arg);  #'find' calls "wanted"
   }               #which we use as a filter and to call our "DoAFile".
   else {
      $unknownCount++;
      print STDERR "$PROGRAM: could not read $arg: $!\n\n";
   }
}

if (($progressOpt) || ($countOnlyOpt)) {
   print "FOUND $foundCount occurrances of \"$expression\" ";
   print "in the specified files.\n";
}
if ($progressOpt) {
   print "Examined $fileCount files, and $dirCount directories";
}
if (($progressOpt) && ($errorCount > 0)) {
   print "-- $errorCount of which had invalid names";
}
if ($progressOpt) {
   print ".\n";
}
if (($progressOpt) && ($unknownCount > 0)) {
   print "THERE WERE $unknownCount UNKNOWN ENTITIES ENCOUNTERED.\n";
}
exit;

#========================================================================
#========================================================================



***** Want to unsubscribe from this list?
***** Send mail with body "unsubscribe" to mac-perl-request@iis.ee.ethz.ch