#!/usr/local/bin/perl

## Copyright (C) 1995 The New York Group Theory Cooperative
## See magnus/doc/COPYRIGHT for the full notice.

## Contents: rdo, a recursive sh command doer.
##
## Principal Author: Roger Needham
##
## Status: Useable.
##
## Revision History:
##
## Next implementation steps:
##


while ( $ARGV[0] =~ /^-/ ) {
  $_ = shift;
  if ( /^-d$/ ) {
     $dflag = 1;
  }
  elsif ( /^-a$/ ) {
     $aflag = 1;
  }
  elsif ( /^-T$/ ) {
     $Tflag = 1;
  }
  elsif ( /^-c$/ ) {
     $cflag = 1;
  }
  elsif ( /^-i$/ ) {
     $iflag = 1;
  }
  elsif ( /^-r$/ ) {
     $rflag = 1;
  }
  elsif ( /^-h$/ ) {
     &help;
     exit;
  }
  elsif ( /^-v$/ || /^--version$/ ) {
    print "\nrdo version 1.0\n";
    exit;
  }
  else {
    print "Unknown option: $_\n\n";
    &help;
    exit 1;
  }
}

if ( $aflag && ( $Tflag || $dflag ) ) {
  print "\nThe -a option conflicts with -T and -d.\n";
  &help;
  exit;
}

unless ( @ARGV ) {
  &help;
  exit;
}

$command = shift;
if ( @ARGV ) { $name_pattern = shift; }

if ( $cflag && !$name_pattern ) {
  print "\n-c option with no filename pattern means do nothing. Done.\n";
  exit;
}

if ($rflag) {
  open(FIND, "/usr/bin/ls |") || die "Couldn't run ls: $!\n";
} else {
  open(FIND, "/usr/bin/find . -print |") || die "Couldn't run find: $!\n";
}

while ( $filename = <FIND> ) {
  chop $filename;
  next if ( $filename eq "." );
  next if ( $filename eq ".." );
  if ( $name_pattern ) {
    if ( $cflag ) {
      next if $filename =~ /$name_pattern/o;
    } else {
      next unless $filename =~ /$name_pattern/o;
    }
  }
  if ( $Tflag ) { next unless -T $filename; }
  if ( !$aflag ) {
    if ( $dflag ) { next unless -d $filename; }
    else { next if -d $filename; }
  }

  push(@files, $filename);
}
close(FIND);


foreach $filename (@files) {

  if ( index($command, "@") == -1 ) {
    $real_command = "$command $filename";
  } else {
    $real_command = $command;
    while ( ($i = index($real_command, "@")) != -1 ) {
      substr($real_command, $i, 1) = $filename;
    }
  }

  if ( !$iflag || &y_or_n_p("\ndo\n  $real_command\n", "y") ) {
    system "$real_command";
  }
}



## Subroutines:

sub y_or_n_p {
  local($yn_prompt, $yn_default) = @_;
  local($yn_reply);
  print "$yn_prompt (y/n)";
  if ( $yn_default ) {
    print "[$yn_default]";
  }
  print "? ";
  while ( 1 ) {
    $yn_reply = <STDIN>;
    chop $yn_reply;
    if ( $yn_default && !$yn_reply ) { $yn_reply = $yn_default; }
    if ( ($yn_reply ne "y") && ($yn_reply ne "n") ) {
      print "\nPlease answer y or n: ";
    } else {
      return ($yn_reply eq "y");
    }
  }
}


sub help {
  print "\n\nUsage: rdo [ -daTcir ] <sh command> [ <perl-style regexp> ]";
  print "\n\n  rdo applies a given sh command to all files at and below the\n";
  print "current directory. The command is not applied to any new files\n";
  print "made by the command. An optional (perl-style) regexp can be given\n";
  print "for the files. For example,\n";
  print "\n  rdo 'chmod u-w' '\\.[Ch]\$'\n";
  print "\nmakes all source and header files at and below . unwritable.\n";
  print "  Wherever '@' appears in the command, it is replaced with the\n";
  print "filename. Thus\n";
  print "\n  rdo -c -T 'cp @ @.bak' ',v\$'\n";
  print "\nmakes backups of all non-rcs text files.\n";
#  print "\n  rdo -c -T 'co -p @ | diff - @ >> difflog 2>&1' '.*,v\$'\n";
#  print "\nmakes a log of all text files which do not match their default\n";
#  print "rcs revision.\n";
  print "If you use one '@', you can't omit it as in the first example.\n";
#  print "  Maniacs can give a perl program to execute before and/or\n";
#  print "after the command:\n";
#  print "\n  rdo -c -T -b 'mkdir(RCS,0700) unless -e RCS' ci '.*,v\$'\n";
#  print "\nchecks in text files, making sure the RCS directory exists\n";
#  print "first.\n";
  print "\nThe command line options are:\n";
  print " -d  Apply command only to directories\n";
  print " -a  Apply command to files and directories\n";
  print " -T  Apply only to text files\n";
  print " -c  Use the complement of the filename regexp\n";
  print " -i  Prompt each time before applying command\n";
  print " -r  Disable recursion\n";
#  print " -b  <perl program> execute before command\n";
#  print " -e  <perl program> execute after command\n";
  print " -h  Print this message and quit\n\n";
}
