#! /usr/local/bin/perl

die "Usage: r_edit [-iredblLnN] regexp filepat ...\n       rgrep -h for help\n"
    if $#ARGV < $[;

# Modified again for doing a global search and replace to
# fix the "XTickLabel" problem in matlab 4 versus 5.

# This is a quick mod of rgrepmsd.prl, to convert CODAS
# compilation batch files from the small memory model to the
# large.  Other quick special-purpose multi-file editing
# versions can be made by editing the routine "filt_file",
# near the top.  A better strategy for the long term would be
# to put the tree-walking part in the a library, so that the
# special part could be isolated and more easily modified and
# tested.

# Written by Piet van Oostrum <piet@cs.ruu.nl>
# This is really free software
#
# Filename-only and line-number-only code added 
#    by <ben@bytepb.byte.com> on Nov 5, 1993
## DOS modifications: apply file test to file name, not
#  handle.
#  Change "//" to "/" in file pattern (when working with root
#  directory).
#  Strip out single quote characters.  They are needed on
#  file patterns to prevent PERL's globbing; but PERL does
#  not remove them like the Unix shell does before passing
#  the argument on.
#  Removed the file compression section--not useful for DOS.
# In specifying pathnames, use "/", not "\"; PERL does the
# translation when reading directories and opening files.
#
$pats_only = 0;
$nextopt = 1;
$onlyname = 0;
$onlylinenum = 0;
$igncase = '';
$regpat = 0;
$links = 0;
$error = 0;
$skipbin = 1;
$debug = 0;
$tmpfile = "r_edit.tmp";

print "\n";
#do { $regexp = shift (@ARGV); } while &checkopt ($regexp);
$icreg = $igncase;
$igncase = '';

eval 'sub filt_file {

            $count = 0;
            while (<F>) {
               # print;
               #$count += s/clg/clf/g;
               $count += s/\'XTickLabel\'/xtl_str/gi;
               # print;
               print(TMP $_);
            }
            print("$file: $count substitutions\n");
}';

for (@ARGV) {
    tr/'//d;
    if (! &checkopt ($_)) {
        if ( $igncase || $regpat || /[?*[]/ || ! -e) {
            if ($regpat) {
                s/#/\\#/g;
                $_ = "#$_#";
            } else { # translate File pattern into regexp
                $re = '#($|/)'; $save = $_;
                while (/[[*?+()|.^$#]/) {
                    $re .= $`;
                    $c = $&;
                    $_ = $';
                    if ($c eq '*') { $c = '[^/]*'; }
                    elsif ($c eq '?') { $c = '[^/]'; }
                    elsif ($c eq '[') {
                        if (/.\]/) { $c = "[$`$&"; $_ = $'; }
                        else {
                            $error++;
                            printf stderr "Illegal filepattern %s\n", $save;
                        }
                    } else { $c = "\\$c"; }
                    $re .= $c;
                }
                $_ = "$re$_\$#$igncase";
            }
            print "filepat: $_\n" if $debug;
            push (@filepat, $_);
        }
        else { push (@files, $_); print "file: $_\n" if $debug; }
    }
}
exit 0 if $pats_only;
exit 1 if $errors ;

if ($#filepat < $[) {
    eval "sub in_pat {1;}" ;
}
else {
    $subtxt = 'sub in_pat { local ($f) = @_;';
    $or = "";
    for (@filepat) {
        $subtxt .= $or . '$f =~ m' . $_;
        $or = " || ";
    }
    $subtxt .= ';};1';

    if (! eval $subtxt) {
        print $@;
        exit 1;
    }
} 

@files = (".") if $#files < $[;

for $file (@files) {
    &do_grep ($file);
}

sub do_grep {
    local ($file) = @_;
    local (*F, $ln, $f, $g, @dirfiles);
    if (-f $file) {
        if (open (F, $file)) {
            if (-B $file && $skipbin) {
                close (F); return;
            }
            open (TMP, ">$tmpfile") || die "Can't open $tmpfile\n";
            print "Reading $file\n" if $debug;
            &filt_file;
            close(TMP) || die "closing TMP\n";
            close(F)   || die "closing F\n";
            unlink($file) || die "can't unlink $file\n";
            rename($tmpfile,$file) || die "Can't rename $tmpfile to $file\n";
        } else {
            print stderr "Cannot open $file\n";
        }
    }
    elsif (-d $file) {
        print "Entering $file\n" if $debug;
        if (opendir (F, $file)) {
            @dirfiles = readdir (F);
            closedir (F);
            for $f (@dirfiles) {
                next if ($f eq '.' || $f eq '..');
                $g = "$file/$f";
                $g =~ s#//#/#;
                next if (-l $g && ($links < 1 || $links == 1 && -d $g));
                if (-f $g && &in_pat ($g) || -d _) {
                    &do_grep ($g);
                }
            }
        } else {
            print stderr "Can't open $file\n";
        }
    }
}

sub checkopt {
    local ($_) = $_[0];
    if (/^-/ && $nextopt) {
        $nextopt = 1;
        @opt = split (/-*/,$_); shift (@opt);
        for $opt (@opt) {
            if ($opt eq 'i') { $igncase = 'i'; }
            elsif ($opt eq 'd') { $debug = 1; }
            elsif ($opt eq 'l') { $links = 1; }
            elsif ($opt eq 'L') { $links = 2; }
            elsif ($opt eq 'b') { $skipbin = 0; }
            elsif ($opt eq 'r') { $regpat = 1; }
            elsif ($opt eq 'p') { $pats_only = 1; $debug = 1; }
            elsif ($opt eq 'N') { $onlyname = 1; }
            elsif ($opt eq 'n') { $onlylinenum = 1; }
            elsif ($opt eq 'e') { $nextopt = 0; }
            elsif ($opt eq 'h' || $opt eq 'H') { & help; }
            else { $error++; printf stderr "Unknown option -%s\n", $opt; }
        }
        return 1;
    }
    $nextopt = 1;
    return 0;
}

sub help {
    print <<'HELP'; exit 0;
Usage: rgrep [-iredblL] regexp filepat ...
  regexp = perl regular expression to search
  filepat ... = a list of files and directories to be searched or
      file patterns to match filenames.
      filepat will be interpreted as file or directory name if it exists
      as such, and does not contain the metacharacters [ ] ? or *. After
      the options -i and -r all filepats will be considered patterns.
      rgrep will search all files in any of the directories given (and its
      subdirectories) that match any of the filepats, except binary files.
      Compressed files will be searched in uncompressed form.
      Note: filepats may contain / contrary to find usage.
  -b  Don't skip binary files.
  -i  Ignore case, either in the regexp or in filename matching (depending
      on the location). Before the regexp only applies to the regexp,
      otherwise to the filepats following it.
  -r  The following filepats are treated as real perl regexps rather than
      shell style filename patterns. In this case / is not a special
      character, i.e. it is matched by . and matching is not anchored (you
      must supply ^ and $ yourself). E.g. a.b matches the file /xa/by/zz.
  -l  Do follow symbolic links only for files (default is do not follow).
  -L  Do follow symbolic links for files and directories.
  -n  Print only the names and line number
  -N  Print only the names of the files where the regexp is found
  -e  Do not interpret following argument as option. Useful if regexp or
      filepat starts with a -.
  -d  Debugging: Give a lot of output on what happens.
  -p  Patterns only: Just print the files and patterns and then exit.
  -h  print this message and exit.
Piet van Oostrum <piet@cs.ruu.nl>
HELP
}

