#!/usr/bin/perl -w
# 398GX2X - e created by Pip@CPAN.Org to manage file editing
# 2do:
#   add dvl shortcuts (or path searching with globs?)
#   once new Simp works, mk `e dvl` bring up project selector
# Notz:
#   OOP (Conway) p.96 minimum class documentation:
#   * name && purpose
#   * version of class documentation documents
#   * synopsis of how to use class
#   * more extensive description of class usage including:
#     - creation details
#     - (both object && class) methods available
#     - special features
#     - limitations
#   * diagnostics list with descriptions && known error conditions
#       which cannot be diagnosed
#   * environment variables that can (or must) be used
#   * other modules needed && how to get them if not via CPAN
#   * bugs && suggested workarounds
#   * cross-references to any other relevant documentation
#   * copyright notice
#   * name && contact details of author(s)
=head1 NAME
  Full::Class::Name - one line summary of purpose of class
=head1 VERSION
  This document refers to version N.NN of Full::Class::Name,
    released MMMM DD, YYYY.
=head1 SYNOPSIS
  # Short examples of Perl code that illustrate the use of the class
=head1 DESCRIPTION
=head2 Overview
=head2 Constructor && initialization
=head2 Class && object methods
=head2 Any other important information
=head1 ENVIRONMENT
  List of environment variables && other O/S related information
    on which the class relies
=head1 DIAGNOSTICS
=over 4
=item "eror message that may appear"
  Explanation of message
=item "another eror message that may appear"
  Explanation of another message
...
=back
=head1 BUGS
  Description of known bugs (&& any work-arounds).
  Usually also includes an invitation to send the author bug reports.
=head1 FILES
  List of any files or other Perl modules needed by the class && a
    brief explanation why.
=head1 SEE ALSO
  Cross-references to any other relevant documentation.
=head1 AUTHOR(S)
  Name(s) <e-mail address(es)>
=head1 COPYRIGHT
  Copyright (c) YYYY(s), Author(s).  All Rights Reserved.
  This module is Free Software.  It may be used under the terms of the
  GNU GPL version 2.
=cut

use strict;
use Time::PT;

my $verb = 1; # verbose flag
my $dbug = 0; # debug   flag
my $skip = 0; # skip    flag
my $edit = $ENV{'EDITOR'};
my $home = $ENV{'HOME'};
my $ttyn = $ENV{'TTY'} || ''; 
   $ttyn = shift || '' unless(length $ttyn);
my $file = shift || ''; my $optn;
if(length($ttyn)) {
  if   ($ttyn =~ /^(\/dev\/tty)/)   { $ttyn =~ s/^$1//;  }
  elsif($ttyn =~ /^(\/dev\/pts\/)/) { $ttyn =~ s/^$1/x/; }
  elsif(!length($file))             { $file = $ttyn;     }
}
my $ercl = $home . '/.erc/e' . $ttyn; # Local  .erc/e$TTYN filelist
my $ercg = $home . '/.erc/eall';      # Global .erc/eall   filelist
my $cwdr = `pwd`; chomp($cwdr);
my %pref = ('gl' => $ercg,
            'rc' => $ercl,
            'a'  => $home . '/.zshrc',
            'z'  => $home . '/.zshrc',
            'v'  => $home . '/.vimrc',
            'h'  => $home . '/.history',
            'e'  => $home . '/dvl/utl/e',
            'b'  => $home . '/dvl/utl/bak',
            '2'  => $home . '/2do/2do.txt');
my $escf = $file; $escf =~ s/([\.\(\)\s])/\\$1/g;
my @srch = (qr/^.*\/$escf/,
            qr/^.*\/.*$escf/,
            qr/$escf/,
            qr/dvl\/.*$escf/);
my %podr = ('name' => qr/NAME/, 
            'vers' => qr/VERSION/, 
            'syno' => qr/SYNOPSIS/, 
            'desc' => qr/DESCRIPTION/, 
            'lice' => qr/(LICENSE|COPYRIGHT)/, 
            'auth' => qr/AUTHOR.?/ );
my %pkgd = ();
my @ldat = ();
my @gdat = ();
my @pkgz = ();
if(-r $ercl && open(ERCL, "<$ercl")) {
  chomp(@ldat = <ERCL>);
  close(ERCL);
}
if(-r $ercg && open(ERCG, "<$ercg")) {
  chomp(@gdat = <ERCG>);
  close(ERCG);
}
my $line = '';

mkdir("$home/.erc", 0700) unless(-d "$home/.erc"); # mk sure ~/.erc/
if(!length($file) || $file =~ /^(l+|g+)$/) {
  if(@gdat && (!@ldat || $file =~ /^g+$/)) {
    if   (        !length($file)) { $file = $gdat[0];  }
    elsif(@gdat <= length($file)) { $file = $gdat[-1]; }
    else { $file = splice(@gdat, length($file), 1);    }
  } elsif(@ldat) {
    if   (        !length($file)) { $file = $ldat[0];  }
    elsif(@ldat <= length($file)) { $file = $ldat[-1]; }
    else { $file = splice(@ldat, length($file), 1);    }
  }
}
if(exists $pref{$file}) { $file = $pref{$file}; }
if     ($file eq 'dvl') { # special 'dvl' file case
  system('cd ~/dvl; ls'); 
} elsif($file eq 'pkg') { # special 'pkg' file case
#So generation (through `e pkg`) should:
  $pkgd{'fail'} = 1;
#  0) read shift().pm or last edited local for path containing .pm && MANIFEST
  $pkgd{'wich'} = shift || '';
# set abstract string to initially empty
  $pkgd{'abst'} =          '';
# read optional specified pt version
  $optn         = shift || undef;
#  1) obtain pIPtIME from $optn parameter or current system `pt`;
  $pkgd{'ptim'} = Time::PT->new($optn);    # get          current pt()
  $pkgd{'ptpt'} = $pkgd{'ptim'}->expand(); # get expanded current pt()
  # do special checks on wich to qualify valid packages or match wich first
  unless(length($pkgd{'wich'}) && -r $pkgd{'wich'}) {
    unless(-r $pkgd{'wich'}) { # search for LOCAL  .pm matches
      foreach(@ldat) {
        if(/\.pm$/)  { $pkgd{'wich'} = $_; last; } # should it ignore case?
      }
    }
    unless(-r $pkgd{'wich'}) { # search for GLOBAL .pm matches
      foreach(@gdat) {
        if(/\.pm$/)  { $pkgd{'wich'} = $_; last; } # should it ignore case?
      }
    }
  } # find a file that exists
  if(-r $pkgd{'wich'}) {
    $pkgd{'wpth'} = $pkgd{'wich'};
    $pkgd{'wpth'} =~ s/^(.*)\/[^\/]*$/$1/; # isolate path
    $pkgd{'wpth'} =~ s/\/lib\/.*$//; # get MANIFEST below lib/ if .pm there
    $pkgd{'wman'} = $pkgd{'wpth'} . '/MANIFEST';
    $pkgd{'wmsk'} = $pkgd{'wman'} . '.SKIP';
    if(-r $pkgd{'wman'} && open(WMAN, "<$pkgd{'wman'}")) {
      chomp(@{$pkgd{'mdat'}} = <WMAN>); # save MANIFEST data
      close(WMAN);
      foreach(@{$pkgd{'mdat'}}) {
        if     (!exists($pkgd{'wipm'}) && /\.pm$/) {
          $pkgd{'wipm'} = $pkgd{'wpth'} . '/' . $_;
        } elsif( exists($pkgd{'wipm'}) && /\.pm$/) {
          # more .pms than just first found in MANIFEST
          push(@{$pkgd{'wopm'}}, $pkgd{'wpth'} . '/' . $_);
        } elsif(!exists($pkgd{'rdme'}) && /^README$/) { 
          $pkgd{'rdme'} = 1;
        } elsif(!exists($pkgd{'mkfl'}) && /^Makefile\.PL$/) { 
          $pkgd{'mkfl'} = 1;
        } elsif(!exists($pkgd{'test'}) && /^t(est.pl|\/.+\.t)$/) {
          $pkgd{'test'} = 1;
        } elsif(/^bin\//) {
          push(@{$pkgd{'binz'}}, $_);
        }
      }
      if(exists $pkgd{'wipm'} && open(WIPM, "<$pkgd{'wipm'}")) {
        chomp(@{$pkgd{'pdat'}} = <WIPM>); # save .PM data
        close(WIPM); 
        $pkgd{'flag'}->{'namesect'} = 0; 
        $pkgd{'flag'}->{'chngsect'} = 0;
        $pkgd{'flag'}->{'chngtext'} = 0;
        # find Full Pkg Name, VERSION, && all POD headings in .pm file
        foreach(@{$pkgd{'pdat'}}) { 
          if($pkgd{'flag'}->{'namesect'}) {
            if   (/^\s*$/) {
              $pkgd{'flag'}->{'namesect'} = 0 if($pkgd{'abst'});
            } else {
              $pkgd{'abst'} .= ' ' . qq($_);
            }
          } elsif($pkgd{'flag'}->{'chngsect'}) {
            if(/^\s*\*\s*/) {
              $pkgd{'flag'}->{'chngsect'} = 0;
              $pkgd{'flag'}->{'chngtext'} = 1 if(/^\s*\*\s*\S/);
            }
          } elsif(/^package\s+([^;]+);/ && !exists($pkgd{'fnam'})) { 
            $pkgd{'pnam'} = $pkgd{'fnam'} = $1; 
            $pkgd{'pnam'} =~ s/^.*:://; # should be same as wipm less /\.pm$/
            if($pkgd{'wipm'} !~ /$pkgd{'pnam'}\.pm$/) {
              print ":*WARN*: MANIFEST .pm file: $pkgd{'wipm'} differs from\n";
              print "  first found package name: $pkgd{'pnam'}.pm!\n";
            }
          } elsif(/^\s*(my|our)\s+\$VERSION\s*=\s*['"]([^'"]+)['"]\s*;/) {
#  2) update .pm $VERSION line with pIPtIME in new sub copy
            $pkgd{'pver'} = $2; $pkgd{'pver'} =~ s/pIPtIME/$pkgd{'ptim'}/;
          } elsif(/^\s*(require|use)\s+([^ ;]+)/) { # find reqs
            $pkgd{'reqs'}->{$2} = 0;
          } elsif(/^\s*(my|our)\s+\$\w+\s*=\s*eval\(\s*\"\s*use\s+([^ ;]+)/) { # find optional uses
            $pkgd{'reqs'}->{$2} = 0;
          } elsif(/^=head1\s+/) { 
            foreach my $reky (keys(%podr)) {
              if(/$podr{$reky}/) { 
                $pkgd{'flag'}->{$reky}      = 1; 
                $pkgd{'flag'}->{'namesect'} = 1 if($reky eq 'name');
              }
            }
          } elsif(/^=item(\s+.*?)pKGvERS  ptptIME/) { 
            $pkgd{'flag'}->{'chngsect'} = 1;
          }
        }
        $pkgd{'abst'} =~ s/^\s*fULnAME\s*-\s*//;
        $pkgd{'abst'} =~ s/'/\\'/g;
        if(exists $pkgd{'pver'} && $pkgd{'pver'} =~ /^\d+\.\d+\.[0-9A-Za-z._]{7}$/) {
          $pkgd{'fnem'} = $pkgd{'fnam'};
          $pkgd{'fnem'} =~ s/::/-/g; # build Package PaTH
          $pkgd{'ppth'} = $pkgd{'wpth'} . '/' . $pkgd{'fnem'} . '-' . $pkgd{'pver'};
          # update template module CHANGES section only! && only if chngdtext
          if($pkgd{'flag'}->{'chngtext'} && open(WIPM, ">$pkgd{'wipm'}")) {
            foreach(@{$pkgd{'pdat'}}) {
              print WIPM "$_\n";
              if(/^=item(\s+.*?)pKGvERS  ptptIME/) { # get dynamic CHANGES line
                print WIPM "\n* \n\n=item$1$pkgd{'pver'}  $pkgd{'ptpt'}\n";
              }
            }
            close(WIPM);
          } else {
            die "!*EROR*! Please update the CHANGES text for: $pkgd{'wipm'}!\n";
          }
          # loop through .pm data again to perform all template substitutions
          foreach(@{$pkgd{'pdat'}}) { 
            s/pIPtIME/$pkgd{'ptim'}/g;
            s/ptptIME/$pkgd{'ptpt'}/g;
            s/pKGvERS/$pkgd{'pver'}/g;
            s/fULnAME/$pkgd{'fnam'}/g;
            s/fULnEME/$pkgd{'fnem'}/g;
            s/pKGnAME/$pkgd{'pnam'}/g;
          }
          if(exists $pkgd{'wopm'}) {
            foreach my $wopm (@{$pkgd{'wopm'}}) {
              open(WOPM, "<$wopm");
              chomp(@{$pkgd{'wdat'}->{$wopm}} = <WOPM>); # save 2ndary .PM data
              close(WOPM);
              foreach(@{$pkgd{'wdat'}->{$wopm}}) { # scan for reqs && do substs
                if     ($pkgd{'flag'}->{'chngsect'}) {
                  if(/^\s*\*\s*/) {
                    $pkgd{'flag'}->{'chngsect'} = 0;
                    delete($pkgd{'flag'}->{'chngsect'}) if(/^\s*\*\s*\S/);
                  }
                } elsif(/^\s*(my|our)\s+\$VERSION\s*=\s*['"]([^'"]+)['"]\s*;/) {
      #  2) update .pm $VERSION line with pIPtIME in new sub copy of 2ndary
                  $pkgd{'pver'} = $2; $pkgd{'pver'} =~ s/pIPtIME/$pkgd{'ptim'}/;
                } elsif(/^\s*(require|use)\s+([^ ;]+)/) { # find reqs in 2ndary
                  $pkgd{'reqs'}->{$2} = 0;
                } elsif(/^\s*(my|our)\s+\$\w+\s*=\s*eval\(\s*\"\s*use\s+([^ ;]+)/) { # find optional uses in 2ndary
                  $pkgd{'reqs'}->{$2} = 0;
                } elsif(/^=item(\s+.*?)pKGvERS  ptptIME/) { 
                  $pkgd{'flag'}->{'chngsect'} = 1;
                }
              }
              if(exists $pkgd{'flag'}->{'chngsect'}) {
                die "!*EROR*! Please update the CHANGES text for: $wopm!\n";
              }
              # loop through .pm data again to perform all template substitutions
              foreach(@{$pkgd{'wdat'}->{$wopm}}) { 
                s/pIPtIME/$pkgd{'ptim'}/g;
                s/ptptIME/$pkgd{'ptpt'}/g;
                s/pKGvERS/$pkgd{'pver'}/g;
                s/fULnAME/$pkgd{'fnam'}/g;
                s/fULnEME/$pkgd{'fnem'}/g;
                s/pKGnAME/$pkgd{'pnam'}/g;
              }
            }
          }
          chdir($pkgd{'wpth'});
#  3) create a subdir with $pKGnAME-$VERSION
          mkdir($pkgd{'ppth'}, 0755) unless(-d $pkgd{'ppth'});
          if(-d $pkgd{'ppth'}) {
#  4) copy everything in MANIFEST (except in .SKIP) into new sub
            foreach(@{$pkgd{'mdat'}}) { # copy MANIFEST files (handle .SKIP?)
              mkdir("$pkgd{'ppth'}/lib", 0755) unless(-d "$pkgd{'ppth'}/lib" || $_ !~ /^lib\//);
              mkdir("$pkgd{'ppth'}/bin", 0755) unless(-d "$pkgd{'ppth'}/bin" || $_ !~ /^bin\//);
              my $fpth = $pkgd{'ppth'} . '/' . $_;
              $fpth =~ s/^(.*)\/[^\/]*$/$1/; # isolate path
              mkdir($fpth, 0755) unless(-d $fpth);
              open(DSTF, ">$pkgd{'fnem'}-$pkgd{'pver'}/$_") or die "!*EROR*! Couldn't open(DSTF, $pkgd{'fnem'}-$pkgd{'pver'}/$_)!\n";
              if     ($pkgd{'wipm'} =~ /$_$/) { # handle .pm file from template
                foreach $line (@{$pkgd{'pdat'}}) {
                  print DSTF "$line\n";
                }
              } elsif(exists($pkgd{'wdat'}) && exists($pkgd{'wdat'}->{$pkgd{'wpth'} . '/' . $_}) && @{$pkgd{'wdat'}->{$pkgd{'wpth'} . '/' . $_}}) {
                foreach $line (@{$pkgd{'wdat'}->{$pkgd{'wpth'} . '/' . $_}}) {
                  print DSTF "$line\n";
                }
              } elsif(open(SRCF, "<$_")) {
                print DSTF $line while($line = <SRCF>);
                if(/MANIFEST$/) {
                  print DSTF "MANIFEST.SKIP\n" unless(-r     $pkgd{'wmsk'});
                  print DSTF "README\n"        unless(exists $pkgd{'rdme'});
                  print DSTF "Makefile.PL\n"   unless(exists $pkgd{'mkfl'});
                }
                close(SRCF);
              } else {
                print "!*EROR*! Couldn't open SourceFile: $_ for reading!\n";
              }
              close(DSTF);
              if(-x $_) { chmod(0755, "$pkgd{'fnem'}-$pkgd{'pver'}/$_"); }
              else      { chmod(0644, "$pkgd{'fnem'}-$pkgd{'pver'}/$_"); }
            }
#  5) warn if no test.pl script exists
            if(exists $pkgd{'test'}) {
#  6) warn if pod doesn't exist, doesn't have NAME, VERSION, SYNOPSIS, 
#    DESCRIPTION, LICENSE|COPYRIGHT, or AUTHOR.? headings
              foreach(@{$pkgd{'pdat'}}) { # verify POD exists in PM
                if(/^=(head1|cut)/) { $pkgd{'pode'} = 1; last; }
              }
              if(exists $pkgd{'pode'}) {
                # ck for POD head1s
                foreach my $reky (keys(%podr)) {
                  unless(exists $pkgd{'flag'}->{$reky}) {
                    print "!*EROR*! Expected POD heading: $reky missing!\n";
                  }
                }
#  7a) generate MANIFEST.SKIP if it doesn't exist
                unless(-r $pkgd{'wmsk'}) {
                  open(WMSK, ">$pkgd{'fnem'}-$pkgd{'pver'}/MANIFEST.SKIP");
                  print WMSK "\\bCVS\\b\n";
                  print WMSK "^Makefile\$\n";
                  print WMSK "^MANIFEST\\.bak\$\n";
                  print WMSK "^updt.*\$\n";
                  print WMSK "\\.bak\$\n";
                  print WMSK "\\.swp\$\n";
                  print WMSK "\\..*\\.swp\$\n";
                  print WMSK "\\b\\.xvpics\\b\n";
                  print WMSK "~\$\n";
                  close(WMSK);
                }
#  7b) generate README from pod with pIPtIME && pKGnAME if necessary
                unless(exists $pkgd{'rdme'}) { # generate README from pod
                  open(RDME, ">$pkgd{'fnem'}-$pkgd{'pver'}/README");
                  foreach $line (@{$pkgd{'pdat'}}) { 
                    if($line =~ /^=cut/) { last; } # build up to POD =cut line
                    else { 
                      $line =~ s/^#//;
                      $line =~ s/^=(head\d|item)\s*//;
                      if     ($line =~ /^=(over(\s+\d+)|item|back)\s*/) { 
                        $skip = 1; 
                      } elsif($skip) { # special case to skip blank line after
                        $skip = 0; 
                      } else { 
                        print RDME "$line\n"; 
                      }
                    }
                  }
                  close(RDME);
                }
#  8) gen Makefile.PL if none exists (add to MANIFEST copy if necessary)
                unless(exists $pkgd{'mkfl'}) { # generate Makefile.PL
                  open(MKFL, ">$pkgd{'fnem'}-$pkgd{'pver'}/Makefile.PL");
                  print MKFL
"use ExtUtils::MakeMaker;
# See lib/ExtUtils/MakeMaker.pm for details of how to influence
# # the contents of the Makefile that is written.
WriteMakefile(
  'NAME'         => '$pkgd{'fnam'}',
  'VERSION'      => '$pkgd{'pver'}',
  'ABSTRACT'     => '$pkgd{'abst'}',
  'AUTHOR'       => 'Pip Stuart <Pip\@CPAN.Org>',
  'EXE_FILES'    => [ \n";
                  foreach(@{$pkgd{'binz'}}) { 
                    if(-f "$pkgd{'fnem'}-$pkgd{'pver'}/$_" &&
                       -x "$pkgd{'fnem'}-$pkgd{'pver'}/$_") {
                      print MKFL (' ' x 22) . "'$_',\n";
                    }
                  }
                  print MKFL (' ' x 20) . "],
  'PREREQ_PM'    => {";
                  if(exists($pkgd{'reqs'})) {
                    foreach(keys(%{$pkgd{'reqs'}})) {
                      unless(/^(strict|base|vars|constant|overload|fULnAME|Carp|Exporter)$/) {
                        my $wtpm = $_; my $inwo = 0; # flag for found in @wopm
                        $wtpm =~ s/::/\//g; $wtpm .= '.pm';
                        $inwo = 1 if($pkgd{'wipm'} =~ /$wtpm$/);
                        if(exists($pkgd{'wopm'}) && @{$pkgd{'wopm'}}) {
                          foreach my $tswo (@{$pkgd{'wopm'}}) {
                            $inwo = 1 if($tswo =~ /$wtpm$/);
                          }
                        }
                        printf MKFL "\n    %-32s => 0,", "'" . $_ . "'" unless($inwo);
                      }
                    }
                  }
                  print MKFL "
  }, # Module::Name => 1.1,
  'dist'         => { 'COMPRESS' => 'gzip', 'SUFFIX' => 'tgz' },
);";
                  close(MKFL);
                }
                mkdir('.bak', 0755) unless(-d '.bak'); # zp new dir into .bak/
#  9) zp new dir into .bak/NAME.tgz then remove dir
                system("tar czfp .bak/$pkgd{'fnem'}-$pkgd{'pver'}.tgz $pkgd{'fnem'}-$pkgd{'pver'}");
                if(-r ".bak/$pkgd{'fnem'}-$pkgd{'pver'}.tgz") { 
                  # success so go ahead && recursively remove all old data
                  system("rm -rf $pkgd{'fnem'}-$pkgd{'pver'}/"); # rm all
#                  unlink(glob("$pkgd{'fnem'}-$pkgd{'pver'}/*/*/*/*")); # rm sub files
#                  unlink(glob("$pkgd{'fnem'}-$pkgd{'pver'}/*/*/*")); # rm sub files
#                  unlink(glob("$pkgd{'fnem'}-$pkgd{'pver'}/*/*")); # rm sub files
#                  unlink(glob("$pkgd{'fnem'}-$pkgd{'pver'}/*"));   # rm files
#                  rmdir(      "$pkgd{'fnem'}-$pkgd{'pver'}");    # rm dir
                  $pkgd{'pver'} =~ s/\.(.)(.)(.)(.)(.)(.)(.)$/.\e[1;31m$1\e[0;33m$2\e[1;33m$3\e[1;32m$4\e[1;36m$5\e[1;34m$6\e[1;35m$7\e[1;32m/;
                  $pkgd{'pver'} =~ s/^(\d+)\.(\d+)\./\e[1;33m$1\e[1;37m.\e[1;36m$2\e[1;37m./;
                  print "Successfully Packaged: .bak/$pkgd{'fnem'}-$pkgd{'pver'}.tgz!\n"; 
                  $pkgd{'fail'} = 0; 
                }
              } else {
                print "!*EROR*! No POD found within package: $pkgd{'wipm'}!\n";
                print "  Please define some Perl Documentation in your module.\n";
              }
            } else {
              print "!*EROR*! No test file detected in MANIFEST!  Please define either\n";
              print "  a test.pl file or t/TESTNAME.t && add it to MANIFEST.\n";
            }
          }
        } else {
          $pkgd{'pver'} = '' unless(exists $pkgd{'pver'});
          print "!*EROR*! Detected VERSION: $pkgd{'pver'} doesn't match expected\n";
          print "  format of \$MAJOR.\$MINOR.\$PIPTIME! (eg. 1.0.37SLNGN)\n";
        }
      }
    }
  }
  if($pkgd{'fail'}) {
    print "!*EROR*! \`e pkg\` couldn't locate a suitable MANIFEST file!\n";
    print "  Please run it again as \`e pkg /path/to/pkg/MANIFEST\`.\n";
    if($dbug) {
      print "\nPackage Hash:\n";
      print "$_:$pkgd{$_}\n" foreach(keys(%pkgd));
    }
  }
} elsif($file eq 'ul') { # special 'ul' file case for completed pkgs
# first ck if cwd is 2..4 deep from a /lib/
  if(-d '../../lib' && -d '../../.bak') {
    chdir('../..');
  } elsif(-d '../../../lib' && -d '../../../.bak') {
    chdir('../../..');
  } elsif(-d '../../../../lib' && -d '../../../../.bak') {
    chdir('../../../..');
  }
# then look in .bak for the newest x-pt.tgz file && run cpan-upload on it
  unless(-d '.bak') { 
    die "!*EROR*! Couldn't find '.bak' directory with .tgz file to cpan-upload!\n"; 
  }
  chdir('.bak');
  @pkgz =  reverse(sort(glob("*.???????.tgz")));
  unless(@pkgz) {
    die "!*EROR*! Couldn't find .tgz file!\n"; 
  }
  $_ =  $pkgz[0];
  $_ =~ s/\.(.)(.)(.)(.)(.)(.)(.)\.tgz$/.\e[1;31m$1\e[0;33m$2\e[1;33m$3\e[1;32m$4\e[1;36m$5\e[1;34m$6\e[1;35m$7\e[1;32m.tgz/;
  $_ =~ s/-(\d+)\.(\d+)\./-\e[1;33m$1\e[1;37m.\e[1;36m$2\e[1;37m./;
  print "cpan-upload -verbose : $_...\n";
  system("cpan-upload -verbose $pkgz[0]");
  chdir('..');
} else { # regular file case
  foreach my $qrex (@srch) { # search for progressively easier LOCAL  matches
    unless(-r $file) {
      foreach(@ldat) {
        if(/$qrex/)  { $file = $_; last; } # should it ignore case?
      }
    }
  }
  foreach my $qrex (@srch) { # search for progressively easier GLOBAL matches
    unless(-r $file) {
      foreach(@gdat) {
        if(/$qrex/)  { $file = $_; last; } # should it ignore case?
      }
    }
  }
  if($verb) {
    die "!*EROR*! Can't edit directory: $file!" if(-d $file);
  }
  $file =~ s/^\.\//$cwdr\//;
  $file =~ s/^\~\//$home\//;
  $file = $cwdr . '/' . $file unless($file =~ /^\//);
  for(my $i = 0; $i < @ldat; $i++) {
    splice(@ldat, $i--, 1) if($file eq $ldat[$i]);
  }
  for(my $i = 0; $i < @gdat; $i++) {
    splice(@gdat, $i--, 1) if($file eq $gdat[$i]);
  }
  unshift(@ldat, $file);
  unshift(@gdat, $file);
  if(open(ERCL, ">$ercl")) {
    print ERCL "$_\n" foreach(@ldat);
    close(ERCL);
  } else { print("!*EROR*! Couldn't update Local  erc file: $ercl!\n"); }
  if(open(ERCG, ">$ercg")) {
    print ERCG "$_\n" foreach(@gdat);
    close(ERCG);
  } else { print("!*EROR*! Couldn't update Global erc file: $ercg!\n"); }
  system(qq($edit +\\'\\" $file));
}
