SPUG: FW: function source grepping tool
Patterson, David S (David)
davidpa at lucent.com
Tue Jun 13 21:48:05 CDT 2000
> -----Original Message-----
> From: Patterson, David S (David)
> Sent: Tuesday, June 13, 2000 7:41 PM
> To: Dubuc, Paul M (Paul)
> Subject: RE: function source grepping tool
>
> Ok, I spent about an hour on this. Modified a search/replace utility I
> had to isolate blocks of code (complete functions, in your case) and then
> search for items within those blocks.
>
> Here is the utility:
>
> <<findblock.txt>>
> I did not clean up the help page to reflect all the tweaking I did to the
> original utility program 'findtext'.
>
> Here's how you would use it:
>
> 1) To list all the files, and functions within the files containing the
> string MY_QUEST, run the program in the file's directory (or a directory
> above it) as follows
>
> findblock -s '*.c' -D '^\w+ *\(.+?^{.+?^}' 'MY_QUEST'
>
> 2) To just list the function names, pipe the output through grep, as
> follows:
>
> findblock -s '*.c' -D '^\w+ *\(.+?^{.+?^}' 'MY_QUEST' | grep '^<'
>
> The -D option would have to be modified in the case of C++ code to allow
> for colons in the function name.
>
> findblock -s '*.cpp' -D '^[\w:]+ *\(.+?^{.+?^}' 'case' | grep '^<'
> ((I think, --didn't test this one))
>
> Note that the -R (replace) option does not work as described in the help
> text (due to the modifications for this problem).
> It does work, however, in the original utility. Let me know if you are
> interested in having a copy of it.
>
> Best regards,
>
> Dave Patterson
>
>
> -----Original Message-----
> From: Dubuc, Paul M (Paul)
> Sent: Monday, June 12, 2000 12:31 PM
> To: Patterson, David S (David)
> Subject: Re: function source grepping tool
>
> Yes the functions are all ANSI C/C++.
>
> Paul
>
> "Patterson, David S (David)" wrote:
>
> > I have a tool I wrote a long time ago that allows full perl regexp
> searches
> > or search/replaces through files in an entire directory tree. I've
> often
> > had situations where I wanted to extend it in such a way that the seach
> > pattern for locating the block of interest was separate from the search
> > pattern I used to do the search/replace of text. I wrote this tool
> (called
> > findtext) in perl 4. Perl 4 is missing a lot of the sophistication in
> the
> > regular expression syntax that perl 5 has. It might be interesting to
> > upgrade if (if necessary) to do this job.
> >
> > Question: are your functions of the following form?
> >
> > type
> > function_name (param list...
> > ...)
> > {
> > function body
> > ...
> > }
> >
> > If not, how are they formatted?
> >
> >
> > > -----Original Message-----
> > > From: Dubuc, Paul M (Paul)
> > > Sent: Monday, June 12, 2000 10:12 AM
> > > To: Patterson, David S (David)
> > > Subject: Re: function source grepping tool
> > >
> > > I've been distracted from the problem by work demands, but I haven't
> > > really
> > > seen a good solution. I would be glad to read yours. Thanks.
> > >
> > > Paul
> > >
> > > "Patterson, David S (David)" wrote:
> > >
> > > > Did you find a solution to this? I had several ideas about this
> (and
> > > > probably one good one). Let me know if you're still interested....
> > > >
> > > > Best regards,
> > > >
> > > > > ---
> > > > "To do great important tasks, two things are
> necessary,
> > > a
> > > > plan and not enough time..."
> > > >
> > > > > David Patterson
> > > > > Software Engineer
> > > > > Lucent Technologies *
> > > > > 6464 185th Ave NE
> > > > > Redmond, WA 98052-6736
> > > > > 425-558-8008 x 2172
> > > > > 888-501-4835 Pgr
> > > > > davidpa at lucent.com
> > > > >
> > >
> > > --
> > > Paul M. Dubuc (614) 860-7836 (voice & fax)
> > > Lucent Technologies dubuc at lucent.com
> > > Rm. 3s319 http://waterworks.cb.lucent.com/pmd/
> > > 6200 E. Broad St.
> > > Columbus, OH 43213-1569
> > >
>
> --
> Paul M. Dubuc (614) 860-7836 (voice & fax)
> Lucent Technologies dubuc at lucent.com
> Rm. 3s319 http://waterworks.cb.lucent.com/pmd/
> 6200 E. Broad St.
> Columbus, OH 43213-1569
>
-------------- next part --------------
#!/opt/exp/bin/perl
## findtext by Dave Patterson 12 May 94
## Ver 2.1 02 Sep 94
## Ver 2.2 15 Jun 95 -- Added -s, -L switches
## Ver 2.3 14 Aug 95 -- Refined DOS vs whole word search styles
## Ver 3.0 14 Sep 98 -- Repair -P bugs
##
## NAME
## findtext - displays filename and lines containing matches to
## RegExpr in text files in current or deeper subdirectories.
## Optionally replaces matches with a replacement text string.
##
## SYNTAX
## findtext [-s "FileExpr"] [-i] [[-S] "TextSearchExpr"] [-I]
## [-R "TextReplExpr"] [-P "TextReplSwitches"]
## [-acEefIiLsvWw] [-l n] [-D "InputRecSep"] [-r [-C|-b]]
## [-?]
##
## DESCRIPTION
## findtext will search text files for a match to the Regular
## Expression in the current and deeper subdirectories. Output
## consists of a relative path/filename followed by lines con-
## taining matches to the regular expression prepended with
## "<".
##
## findtext only searches text files and skips any file that
## appears to have binary or non-text contents. findtext
## searches for any string match by default, but whole words or
## arbitrarily complex regular expressions can be searched for
## using the -w, -W, -e, or -E options.
##
## In DOS-style search expressions, /? + */ are treated as
## /.? .+ .*/, other nonalphanumerics are treated as literals,
## and expressions are assumed to be right & left-justified.
##
## findtext optionally replaces matched strings with a replace-
## ment text string. Options include auto-confirmation and/or
## auto-backup of changed files.
##
##
## OPTIONS
## -a Alphabetize (sort) file listing before searching.
##
## -b backup modified files. (Can't be used with -f)
##
## -c set file search pattern to "*.[Cch]"
##
## -C confirm replacments. Program prompts "Confirm: ([y]/n/f/a)"
## where:
## y - confirm change,
## n - do not make change,
## f - confirm change for remainder of current file,
## a - confirm all further changes.
##
## -d dry run replacements (display but don't actually write to
## file proposed changes)
##
## -D Specify alternate input record delimiter (separator).
## Default is \n (line by line).
##
## -e file search pattern is an extended regular expression
## (SED- or PERL-style. Default is DOS-style).
##
## -E text search pattern is an extended regular expression
## (SED- or PERL-style. Default is DOS-style).
##
## -f force processing of backup files. Normally backup and
## RCS files (*,n & *,v) are not processed.
## (Can't be used with -b)
##
## -i ignore case during file search.
##
## -I ignore case during text search.
##
## -l levels of directories to process. Don't descend deeper
## than this number (default: no limit)
##
## -L follow (descend into) soft-linked directories.
## (warning: infinite loops are possible in this mode)
##
## -o Override read-only flag on file (try to, anyway).
##
## -P "Expr" text replace switches (any of {geio}). Causes the following
## evaluation: s/{-S "Expr"}/{-R "Expr"/{-P "Expr"}. Assumes that
## s/TextSearchExpr/TextReplExpr/TextReplSwitches constitutes a fully
## specified perl extended regular expression. Any valid perl search
## expression is allowed. Runs slower than when using the built-in
## search/replace feature, but gives you more options. See the
## perl manual for syntax.
##
## -q Quiet mode; only list file names with text matches.
## Skips the diff listing.
##
## -s "Expr" file search pattern.
##
## -S "Expr" text search pattern. ("Expr" alone implies -S)
##
## -R "RepStr" replacement string for text matching text search pattern.
##
## -v verbose mode shows search matches and replaced lines, if appl.
##
## -w Search for whole word matches for file name pattern.
## (Note: do not use ^ or $ anchors in pattern with this switch).
##
## -W Search for whole word matches for text search pattern.
## (Note: do not use ^ or $ anchors in pattern with this switch).
##
## -? show syntax (also -h or -H)
##
## CAVEATS
## Quotes around RegExpr, RepStr are required if not a simple
## alphanumeric text string.
##
## EXAMPLES
## findtext -s zoo -S dogs # Find all files containing whose names
## contain the string "zoo" and search for
## the string "dogs".
##
## findtext -S dogs -E # Find all files containing string "dogs".
##
## # Find files ending in ".c" and then find the word dogs and
## # replace with word cats:
##
## findtext -s "*.c" -S dogs -R cats -W
##
## SEE ALSO
## Findfile (1), renfiles (1)
##
# Default values:
$NLEVELS = 9999; # Max levels
# Process command line args:
if (@ARGV)
{
foreach $ARG (@ARGV)
{
if ($DD == 2)
{
$DD = 1;
$IRD = $ARG;
}
elsif ($L == 2)
{
$L = 1;
$NLEVELS = $ARG;
}
elsif ($PP == 2)
{
$PP = 1;
$SWITCHES = $ARG;
}
elsif ($S == 2)
{
$S = 1;
$REGEXP = $ARG;
}
elsif ($SS == 2)
{
$SS = 1;
$SREGEXP = $ARG;
}
elsif ($RR == 2)
{
$RR = 1;
$SREPL = $ARG;
}
elsif ($ARG eq "-a") ## alphabetize (sort) file list
{
$A = 1;
}
elsif ($ARG eq "-b") ## backup changed files
{
$B = 1;
}
elsif ($ARG eq "-c") ## set file search string to "*.[Cch]"
{
$C = 1;
}
elsif ($ARG eq "-d") ## dry run changes
{
$D = 1;
}
elsif ($ARG eq "-D") ## alternate input record delimiter
{
$DD = 2;
}
elsif ($ARG eq "-C") ## confirm replacements
{
$CC = 1;
}
elsif ($ARG eq "-e") ## file search pattern is ERE
{
$E = 1;
}
elsif ($ARG eq "-E") ## text search pattern is ERE
{
$EE = 1;
}
elsif ($ARG eq "-f") ## force processing of backup files
{
$F = 1;
}
elsif ($ARG eq "-i") ## case insensitive file search
{
$I = "i";
}
elsif ($ARG eq "-I") ## case insensitive text search
{
$II = "i";
}
elsif ($ARG eq "-l") ## limit depth
{
$L = 2;
}
elsif ($ARG eq "-L") ## follow sym-links
{
$LL = 1;
}
elsif ($ARG eq "-o") ## override read-only flag
{
$O = 1;
}
elsif ($ARG eq "-P") ## text search string is a fully specified perl ERE.
{ ## Next arg contains search/replace switches.
$PP = 2;
}
elsif ($ARG eq "-q") ## Quiet mode. No diff listings.
{
$Q = 1;
}
elsif ($ARG eq "-R") ## text replacement string
{
$RR = 2;
}
elsif ($ARG eq "-s") ## file search string
{
$S = 2;
}
elsif ($ARG eq "-S") ## text search string
{
$SS = 2;
}
elsif ($ARG eq "-v") ## verbose (same as -d -f switches in findfile)
{
$V = 1;
}
elsif ($ARG eq "-w") ## search for whole words matching file pattern
{
$W = 1;
}
elsif ($ARG eq "-W") ## search for whole words matching text pattern
{
$WW = 1;
}
elsif ($ARG =~ /^\-/)
{
$H = 1;
}
else
{
$SREGEXP = $ARG;
}
}
}
if ($H || $NLEVELS < 1 || $RR < 0 || $SS < 0 || $L < 0 ||
($B || $CC) && ! $RR || $B && $F)
{
system ("cat $0 | grep \"^##\" | more");
exit (-1);
}
# Set up for file search string:
if ($C)
{
$REGEXP = '.+\.[Cch]';
$E = 1;
$W = 1;
}
elsif (! $REGEXP) # Default case is to process all text files:
{
$REGEXP = '.+';
$E = 1;
}
if ($E) # ere style
{
$RE = $REGEXP;
if ($W)
{
# Make expression valid for whole words only:
$RE = "(^|[\\W_])" . $RE . "(\$|[\\W_])";
}
}
else # dos style
{
$RE = $REGEXP;
$DOT = ".";
# Place a \ in front of all non-alpha chars:
$RE =~ s/(\W)/\\$1/g;
# Convert DOS wildcards to ERE wildcards:
$RE =~ s/\\([*?+])/$DOT$1/g;
$RE = "^" . $RE . "\$";
}
study $RE;
if ($V)
{
print "File ERE = /$RE/$I\n";
}
# Set up for text search string:
if (! $SREGEXP) # Default case is to show all text in files:
{
$SREGEXP = '^';
$EE = 1;
}
if ($EE || $PP) # ere style
{
$SRE = $SREGEXP;
}
else # dos style
{
$SRE = $SREGEXP;
$DOT = ".";
# Place a \ in front of all non-alpha chars:
$SRE =~ s/(\W)/\\$1/g;
# Convert DOS wildcards to ERE wildcards:
$SRE =~ s/\\([*?+])/$DOT$1/g;
}
if ($WW)
{
# Make expression valid for whole words only:
$SRE = '(^|\W)' . $SRE . '($|\W)';
}
study $SRE;
if ($V)
{
if ($PP)
{
print "Text ERE = s/$SRE/$SREPL/$SWITCHES\n";
}
elsif ($RR)
{
print "Text ERE = s/$SRE/$SREPL/$II\n";
}
else
{
print "Text ERE = s/$SRE/$II\n";
}
}
$PWD = `pwd`;
chop $PWD;
if ($V)
{
print "$PWD/\n";
}
$LEVEL = 0;
&Ckdir (".", $PWD);
exit (0);
sub Ckdir
{
$OLDDIRPATH = $DIRPATH;
local (@DIRLIST, @DIRLIST0, $DIRPATH,
$FN, $PARENTDIR, $CURRENTDIR);
$PARENTDIR = $_[1];
$CURRENTDIR = "${PARENTDIR}/${_[0]}";
if (! chdir ($_[0]))
{
print "Error: Couldn't cd down to $_[0]!!!";
return; # SHOULD never get here, but...
}
$LEVEL++;
opendir (DIR, ".");
if ($A) # alphabetize (sort) file names first
{
@DIRLIST0 = readdir (DIR);
@DIRLIST = sort @DIRLIST0;
}
else
{
@DIRLIST = readdir (DIR);
}
$DIRPATH = "${OLDDIRPATH}${_[0]}/";
closedir (DIR);
foreach $FN (@DIRLIST) # first print files:
{
if (! -d $FN)
{
if ($I ? $FN =~ /$RE/i : $FN =~ /$RE/)
{
# Process file if it is a text file and (file is not a comma version
# or file is a comma version and "force processing" flag is on):
if (-T $FN && ($FN !~ /,\w+$/ || $F)) # Text processing section:
{
$CF = 0;
$MATCH = 0;
$FLISTED = 0;
$FNT = $FN; # All reading is done on file $FNT
if ($RR) # if replace text option, back up file before opening
# it for output:
{
if (! -w $FN)
{
print "$FN not writeable. Skipping;\n\n";
next;
}
if (! $D)
{
$FNT = &Backup_file ($FN, "", 0);
$STATUS = open (FO1, ">$FN");
if ($STATUS != 1)
{
die "Error opening $FN for writing. Exiting;\n\n";
}
}
}
$STATUS = open (FI1, $FNT);
undef $/;
while (<FI1>) # Loops only once with undef $/...
{
@A = ($_ =~ /$IRD/gsm);
$/ = "\n";
foreach $_ (@A)
{
# print "\n[$_]\n";
if (! $II ? /$SRE/o : /$SRE/io)
{
$MATCH++;
if (! $FLISTED)
{
print "${DIRPATH}${FN}\n";
$FLISTED++;
}
if (! $Q)
{
print "< $_\n\n";
}
if ($RR)
{
if ($CC)
{
$ORIG = $_;
}
if ($PP) # Fully specified regexp evaluation:
{
eval "s/$SRE/$SREPL/$SWITCHES";
}
elsif ($EE) # if ERE text search strring:
{
$II ? s/$SRE/$SREPL/gio : s/$SRE/$SREPL/go;
}
else # Dos-like version
{
$II ? s/$SRE/$1$SREPL$2/gio : s/$SRE/$1$SREPL$2/go;
}
if (! $Q)
{
print "> $_";
}
if ($CC && ! $CF)
{
print "Confirm: ([y]/n/f/a) ";
$ANS = <STDIN>; chop $ANS;
if ($ANS =~ /^[Nn]/)
{
print "Line not changed.\n\n";
$_ = $ORIG;
$MATCH--;
}
elsif ($ANS =~ /^[Ff]/) # No further confirms this file.
{
$CF = 1;
}
elsif ($ANS =~ /^[Aa]/) # No further confirms required.
{
$CC = 0;
}
else
{
print "\n";
}
}
}
}
if ($RR && ! $D)
{
print FO1 $_;
}
}
close FI1;
if ($RR && ! $D)
{
close FO1;
if (($MATCH && ! $B) || ! $MATCH)
{
system ("rm -f $FNT"); # kill the backup
}
}
if ($MATCH && ! $Q)
{
print "\n";
}
}
}
}
}
}
foreach $FN (@DIRLIST) # next print directory names:
{
if ((-d $FN) && ! ($FN =~ /^\.\.?$/))
{
if (-x $FN)
{
$AD = "";
}
else
{
$AD = " (Access denied)";
}
if ($V) # case where we always want to print the dir:
{
if (-l $FN)
{
print "${DIRPATH}${FN}@/${AD}\n";
}
else
{
print "${DIRPATH}${FN}/${AD}\n";
}
}
# This is where we decide whether to descend into the current dir:
# We do if: (1) haven't exceeded the max level, and
# (2) directory allows us access, and
# (3) we are allowed to follow symbolic links
if ($LEVEL < $NLEVELS && ! $AD && ($LL || ! (-l $FN)))
{
&Ckdir ("$FN", "$CURRENTDIR");
}
}
}
$LEVEL--;
chdir ("$PARENTDIR");
}
# ############################################################################
#
# Sub Name: Backup_file
#
# Description: Looks for all versions of file name from $FILE_SPEC
# in $BACKUP_LOC. Makes a backup of file as follows:
# Program copies filename to filename,# where # is next highest
# backup number in sequence. File name cannot be
# a wild card.
#
# Arguments: NAME DESCRIPTION
# $FILE_SPEC Fully specified file to backup
# $BACKUP_LOC Directory to place backup copy, e.g:
# "./.backup" - for ./backup directory.
# "" - for same directory.
# $NOTIFY 0 - No backup message
# n - (n != 0) print backup message
# Globals:
#
# Returns: $BACKUP_FILE Name of backup file, -or-
# <aborts> Failure
#
# ############################################################################
sub Backup_file
{
local ($FILE_SPEC, $BACKUP_LOC, $NOTIFY) = @_;
local ($BKP_SPEC); # file name to search for in backup dir.
local (@FILES); # list of existing versions of $FILE_NAME
local ($FILE_NAME); # Name of file (no dir path)
local ($FILE_NAME_RX); # Name of file converted to a perl search string
local ($HIGH_VN); # Highest version not found so far
local ($HIGH_FN); # FN of highest version no found so far
local ($LATEST_BKP_VN); # Computed new version no for backup
local ($LATEST_BKP_FN); # Fully specified new backup file name
local ($THIS_FILE_VN); # Current file version number
if (@_ != 3)
{
die "Error: sub Backup_file argc error!\n";
}
if (-l $FILE_SPEC)
{
# handle softlinks by backing up file link is connected to:
$TMP = `ls -l $FILE_SPEC`;
($FILE_SPEC) = ($TMP =~ /-> (.+)$/);
# print "FILE_SPEC is now [$FILE_SPEC]\n";
}
# Extract the file name from the file spec:
($FILE_NAME) = ($FILE_SPEC =~ /([^\/]+)$/);
# Create a regular expression version of the file name:
$FILE_NAME_RX = $FILE_NAME;
$FILE_NAME_RX =~ s/([\W])/\\$1/g;
if ($BACKUP_LOC)
{
$BKP_SPEC = "$BACKUP_LOC/$FILE_NAME";
}
else
{
$BKP_SPEC = "$FILE_SPEC";
}
$HIGH_VN = -1;
$HIGH_FN = "${FILE_SPEC}_$$";
# Create a list of all files matching the filespec in the
# backup directory:
@FILE = `ls -d $BKP_SPEC* 2>/dev/null`;
foreach (@FILE)
{
$CURFILE = $_;
chop $CURFILE;
# Determine the version number of this file (-1 if none):
($THIS_FILE_VN) = ($CURFILE =~ /$FILE_NAME_RX,(\d+)$/);
$THIS_FILE_VN = (length ($THIS_FILE_VN) ? $THIS_FILE_VN : -1);
if ($THIS_FILE_VN > $HIGH_VN)
{
$HIGH_VN = $THIS_FILE_VN;
$HIGH_FN = $CURFILE;
}
}
$LATEST_BKP_VN = $HIGH_VN + 1;
$LATEST_BKP_FN = "$BKP_SPEC,$LATEST_BKP_VN";
# print "> FILE_SPEC[$FILE_SPEC] HIGH_FN[$HIGH_FN] LATEST_BKP_FN[$LATEST_BKP_FN]\n";
if (-d $FILE_SPEC)
{
$? = "1";
}
else
{
system ("cmp -s $FILE_SPEC $HIGH_FN");
}
if ($? || "$FILE_SPEC" eq "$HIGH_FN")
{
if (-e $FILE_SPEC)
{
if (-d $FILE_SPEC)
{
$RFLAG = "-r"; # If file is a directory, back it up recursively
$DFLAG = "directory ";
}
if ($NOTIFY)
{
print "Backing up $DFLAG$FILE_SPEC to $LATEST_BKP_FN.\n";
}
$ERR1 = system ("cp -p $RFLAG $FILE_SPEC $LATEST_BKP_FN");
}
else # File doesn't exist so just touch backup file.
{
if (-z $HIGH_FN)
{
warn "$FILE_SPEC does not exist. Backup file $LATEST_BKP_FN is empty.\n";
}
}
if ($ERR1)
{
warn "\nPROBLEM: Can't copy $FILE_SPEC to $LATEST_BKP_FN\n";
die "Exiting.\n\n";
}
}
else # Don't back up if last backup file is identical:
{
if ($NOTIFY)
{
print "Identical file $HIGH_FN already exists.\n";
}
$LATEST_BKP_FN = $HIGH_FN;
}
return $LATEST_BKP_FN;
}
More information about the spug-list
mailing list