#!/usr/bin/perl use Tk; # global variables $version = "grGui version 1.53 030505 cplager\@uiuc.edu"; $noWrap = "none"; # do not change $wrap = "word"; # do not change $charWrap = "char"; # do not change $xon = "/home/cplager/bin/startcommand"; $font = "6x13"; $checkCase = ""; $doDirectories = ""; $verbose = "true"; $doBinary = ""; $doAnd = ""; $doFileAnd = ""; $doWrap = $wrap; $height = 60; $width = 80; $help = "\nUsage: grGui w=word1 (w=word2 n=word3 ...) (file1 file2 ...) (-options) options: -and => does 'and' instead of 'or' -avoid dir/ => doesn't look in directory dir/ -bin => search binary files -case => force case matching -charwrap => window will wrap long lines (character wrap) -dir => expand directories -fn XXX => sets emacs font to 'XXX' -file => only prints files where each word is found at least once -height NN => set height to NN lines (default: $height) -help => this help screen -list file => uses 'file' to provide list of files to check -noback => won't open up backup files ('~' or '.bak') -nolink => won't follow soft-linked directories -nowrap => will NOT rap long lines -nv => non-verbose (won't print directory names) -width NN => set width to NN lines (default $width) -wrap => window will wrap long lines (word wrap) The order of the arguments doesn't matter. If no files are given, the default is to search all files in the current directory. $version\n"; sub clicked { my $var = shift; $position = $var->index('current'); if ($position =~ /(\d+).\d+/) { my $lineNum = $1; my $line = $var->get("$lineNum.0", "$lineNum.0 lineend"); if ($line =~ /^in file (.+):$/i) { my $file = $1; if ($file !~ m|^/|) { $file = "$ENV{PWD}/$file"; } $cmd = "$xon emacs -rv -fn $font $file"; system ($cmd); } } } # parsing arguments while ($arg = shift @ARGV) { if ($arg =~ /w=/) { push @words, $'; next; } if ($arg =~ /n=/) { push @not, $'; next; } if ($arg =~ /^-/) { $option = $'; if ($option =~ /^and/i) { $doAnd = "true"; next; } if ($option =~ /^noback/i) { $noback = "true"; next; } if ($option =~ /^bin/i) { $doBinary = "true"; next; } if ($option =~ /^case/) { $checkCase = "true"; next; } if ($option =~ /^dir/i) { $doDirectories = "true"; next; } if ($option =~ /^list/i) { $filename = shift @ARGV; if (! -e $filename) { warn "Can't open $filename for list of files\n"; next; } open (LISTFILE, $filename) or warn "Can't open $filename for reading\n"; while () { chomp; if (-e $_) { push @files, $_; } } next; } if ($option =~ /^file/i) { $doFileAnd = "true"; next; } elsif ($option =~ /^fn(\w+)/) { $font = $1; if (! $font) { $font = shift @ARGV; } next; } if ($option =~ /^height/i) { $value = shift @ARGV; if ($value =~ /^\d+$/) { $height = $value; } next; } if ($option =~ /^width/i) { $value = shift @ARGV; if ($value =~ /^\d+$/) { $width = $value; } next; } if ($option =~ /^h/i) { print "$help"; exit; } if ($option =~ /^nv/i) { $verbose = ""; next; } if ($option =~ /^nowrap/i) { $doWrap = $noWrap; next; } if ($option =~ /^charwrap/i) { $doWrap = $charWrap; next; } if ($option =~ /^wrap/i) { $doWrap = $wrap; next; } next; } # If we got all the way down here, we must be talking about a file push @files, $arg; } # don't have both lineAnd and fileAnd if ($doAnd) { $doFileAnd = ""; } #$numfiles = @files; #print "files ($numfiles):\n".join("\n", @files)."\n"; if (! @files) { @files = glob ("*"); push @files, glob (".*"); } die "Usage: grGui w=word1 (w=word2) file1 file2\nUse -h for help\n" if (!@words); $startDir = $currentDir = $ENV{'PWD'}; @goodFiles = (); %beenThere = (); foreach $file (@files) { if ($noback) { # check file name next if (($file =~ /\~$/) || ($file =~ /\.bak$/)); } if ($file !~ m|^/|) { $file = "$currentDir/$file"; } if (-d $file) { next if (! $doDirectories); if (($file eq ".") && (1 == @files)) { $file = $startDir; } # we don't want /. or /.. if ( ($file =~ m|/\.$|) || ($file =~ m|/\.\.$|) ) { next; } $file =~ s|//|/|g; chdir $file; $key = `pwd`; if (! $beenThere{$key}) { # we haven't been there yet print "dir $file\n" if ($verbose); $beenThere{$key} = "yep"; @newFiles = glob ("$file/*"); push @files, @newFiles; @newFiles = glob ("$file/.*"); push @files, @newFiles; } } elsif (-e $file) { if ($doBinary || (! -B $file)) { push @goodFiles, $file; } } else { warn "$file doesn't exist\n"; } } chdir $startDir; # setup Tk stuff $main = MainWindow->new (-background => 'white', -title => "grGui: @words"); $text = $main->Scrolled("Text", -background => "white", -tabs => [qw/1.8i 2.9i left/], -spacing3 => 0, -width => $width, -font => $font, -wrap => $doWrap, -height => $height)->pack(); $okButton = $main->Button(-text => "Done", -relief => 'flat', -borderwidth => 2, -width => 4, -takefocus => 1, -highlightthickness => 3, -background => 'white', -foreground => 'black', -activebackground => 'white', -activeforeground => 'red', -command => sub {exit;})-> pack (-side => 'bottom', -anchor => 'center'); # make tags $text->tagConfigure('filename', -foreground => "blue", -underline => 1); $text->tagConfigure('red', -foreground => "red"); $text->tagConfigure('green', -foreground => "darkgreen"); $text->tagConfigure('lineNumber', -foreground => 'white', -background => 'darkgreen'); # set tag binds $text->tagBind('filename', "", \&clicked); $text->tagBind('filename', "", sub {shift->configure(-cursor => 'hand2')} ); $text->tagBind('filename', "", sub {shift->configure(-cursor => 'xterm')} ); $text->tagRaise('lineNumber'); # bind events $main->bind("", sub {exit;}); $main->bind("", sub {exit;}); $main->bind("", sub {$text->yviewMoveto(0.0);}); $main->bind("", sub {$text->yviewMoveto(1.0);}); $main->bind("", sub {$text->yviewScroll(1 => pages);}); $main->bind("", sub {$text->yviewScroll(-1 => pages);}); $main->bind("", sub {$text->yviewScroll(-1 => pages);}); $main->bind("", sub {$text->yviewScroll(1 => pages);}); $main->bind("", sub {$text->yviewScroll(1 => units);}); $main->bind("", sub {$text->yviewScroll(-1 => units);}); $main->bind("", sub {$text->xviewScroll(1 => units);}); $main->bind("", sub {$text->xviewScroll(-1 => units);}); $numFiles = $numWords = $numLines = 0; foreach $file (sort @goodFiles) { ++$numFilesSearched; $file =~ s|//|/|g; $file =~ s|/\./|/|g; if (! open (SOURCE, $file) ) { warn "Can't open $file\n"; next; } if ($doFileAnd) { %wordFound = (); READING: while () { $wordIndex = -1; # kick out the lines with the words we don't want foreach $word (@not) { # if we find any of these words, don't use this line if ((/$word/) || (/$word/i && ! $checkCase)) { # got one, skip this line next READING; } } foreach $word (@words) { ++$wordIndex; if ((/$word/) || (/$word/i && ! $checkCase)) { $wordFound{$word} = "found"; } } } $ok = "true"; foreach $word (@words) { if (! $wordFound{$word} ) { $ok = ""; last; } } if (! $ok) { next; #file } close (SOURCE); open (SOURCE, $file) } # doFileAnd $first = "true"; $line = 0; $options = "i"; READFILE: while () { ++$line; # kick out the lines with the words we don't want foreach $word (@not) { # if we find any of these words, don't use this line if ((/$word/) || (/$word/i && ! $checkCase)) { # got one, skip this line next READFILE; } } if ($doAnd) { foreach $word (@words) { if (! (/$word/) && ! (/$word/i && ! $checkCase) ) { next READFILE; } } } # if doAnd foreach $word (@words) { ++$wordIndex; if ((/$word/) || (/$word/i && ! $checkCase)) { $whichWords[$wordIndex] = 1; ++$numLines; if ($first) { ++$numFiles; if ($file !~ m|^/|) { $file = "$ENV{PWD}/$file"; } $text->insert ('end', "\nIn file "); $text->insert ('end', $file, 'filename'); $text->insert ('end', ":\n"); $first = 0; } $number = sprintf ("%4d", $line); $good = sprintf (" %s", $_); chomp $good; $good =~ s/\t/ /g; $text->insert ('end', $number, 'lineNumber'); $text->insert ('end', "$good\n"); # first let's get a list of all words we should highlight @goodWords = (); foreach $word (@words) { ++$wordIndex; $rest = $_; while ($rest) { if (($rest =~ /($word)/) || ($rest =~ /($word)/i && ! $checkCase)) { $whichWords[$wordIndex] = 1; push @goodWords, $1; $rest = $'; } else { $rest = ""; } } # while $rest } # foreach word # Now, lets highlight the words $endPosition = $text->index('current'); if ($endPosition =~ /^(\d+)\./) { $start = ($1 - 1).".0"; $numWords += @goodWords; foreach $hword (@goodWords) { $index = $start; $wordLen = length($hword); while ($index) { #print "index $index\n"; $index = $text-> search(-exact, $hword, $index, $endPosition); if ($index) { $end = "$index + $wordLen chars"; #print "$index $end\n"; $text->tagAdd('red', $index, "$index + $wordLen chars"); $index .= " + 1 chars"; } # if index } # while $index } # foreach hword next READFILE; } else { next READFILE; } } # if $word } # foreach word } # while source } # file $text->insert ('1.0', "$numWords matches found in $numLines lines of $numFiles files out of $numFilesSearched files searched\n", 'green'); $text->configure(-state => 'disabled'); MainLoop;