#!/perl -w # NAME: findinpath.pl # AIM: Given an input file, find it in the PATH enviroment variable ... # 2019-02-25 - avoid duplicates like '1: C:\Windows\system32\curl.exe' and '2: C:\WINDOWS\system32\curl.exe' # 2018-01-16 - Review - reduce noise unless -vN given # 04/05/2013 - Allow additional paths to be searched # 19/10/2011 - show the number of the PATH found in if 1 and exact # 14/07/2010 - checkout, and add 'potential' finds, like '*item*'... # 05/05/2008 - geoff mclane - http://geoffair.net/mperl use strict; use warnings; use File::stat; # to get the file date and size use Env qw(PATH); # for reading PATH environment variable #unshift(@INC, 'C:/GTools/perl'); #require 'logfile.pl' or die "Unable to load logfile.pl ...\n"; # log file stuff #my ($LF); my $pgmname = $0; if ($pgmname =~ /\w{1}:\\.*/) { my @tmpsp = split(/\\/,$pgmname); $pgmname = $tmpsp[-1]; } #my $outfile = "temp.$pgmname.txt"; #open_log($outfile); my $inp_file = ''; #my $inp_file = 'java.exe'; #my $inp_file = 'Perl58.dll'; my $CHKPATH = $ENV{PATH}; #prt( "Check PATH=$CHKPATH ...\n" ); my @patharr = split(';', $CHKPATH); my @pathfnd = (); my @potential = (); ###my $pcnt = scalar @patharr; my $verbosity = 0; my $debug = 0; # set to run in editplus my $def_inf = 'java'; my $min_size = 12; my @user_paths = (); my $recursive = 0; my @warnings = (); sub VERB1() { return $verbosity >= 1; } sub VERB2() { return $verbosity >= 2; } sub VERB5() { return $verbosity >= 5; } sub VERB9() { return $verbosity >= 9; } sub in_file_has_wild($) { my ($inf) = @_; if ($inf =~ /(\*|\?)/) { return 1; } return 0; } sub prt($) { my ($txt) = shift; print $txt; } sub mydie($) { my ($txt) = shift; die $txt; } sub show_warnings($) { my ($val) = @_; if (@warnings) { prt( "\nGot ".scalar @warnings." WARNINGS...\n" ); foreach my $itm (@warnings) { prt("$itm\n"); } prt("\n"); } else { prt( "\nNo warnings issued.\n\n" ) if (VERB9()); } } sub pgm_exit($$) { my ($val,$msg) = @_; if (length($msg)) { $msg .= "\n" if (!($msg =~ /\n$/)); prt($msg); } show_warnings($val); # close_log($outfile,$load_log); exit($val); } sub prtw($) { my ($tx) = shift; $tx =~ s/\n$//; prt("$tx\n"); push(@warnings,$tx); } sub path_u2d($) { my ($ud) = shift; $ud =~ s/\//\\/g; return $ud; } sub strip_quotes($) { my ($txt) = shift; if (substr($txt,0,1) eq '"') { $txt = substr($txt,1); if (substr($txt,-1,1) eq '"') { $txt = substr($txt,0,length($txt)-1); } } return $txt; } # My particular time 'translation' - replaced date_string sub YYYYMMDD($) { # 0 1 2 3 4 5 6 7 8 my ($tm) = shift; my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($tm); $year += 1900; $mon += 1; my $ymd = "$year/"; if ($mon < 10) { $ymd .= '0'.$mon.'/'; } else { $ymd .= "$mon/"; } if ($mday < 10) { $ymd .= '0'.$mday; } else { $ymd .= "$mday"; } return $ymd; } # My particular 'nice number' sub get_nn($) { # perl nice number nicenum add commas my ($n) = shift; if (length($n) > 3) { my $mod = length($n) % 3; my $ret = (($mod > 0) ? substr( $n, 0, $mod ) : ''); my $mx = int( length($n) / 3 ); for (my $i = 0; $i < $mx; $i++ ) { if (($mod == 0) && ($i == 0)) { $ret .= substr( $n, ($mod+(3*$i)), 3 ); } else { $ret .= ',' . substr( $n, ($mod+(3*$i)), 3 ); } } return $ret; } return $n; } sub check_path($$$$$$$$$); sub check_path($$$$$$$$$) { my ($path,$inf,$rfndcnt,$rmin0,$rmin1,$rmin2,$rmin3,$rpathcnt,$rpotcnt) = @_; my ($sb,$len,$dtt,$sz,$ff,$file); my $tfind = $path."\\".$inf; my @dirs = (); if ( ( -f $tfind) && ($sb = stat($tfind))) { $dtt = YYYYMMDD($sb->mtime); $sz = get_nn( $sb->size ); prt( "Found in [$path]\\$inf, $dtt, $sz bytes\n" ) if (VERB2()); # 0 1 2 3 4 push(@pathfnd,[$path,$sz,$dtt,$tfind,${$rpathcnt}]); ${$rfndcnt}++; $len = length($tfind); ${$rmin0} = $len if ($len > ${$rmin0}); $len = length($path); ${$rmin1} = $len if ($len > ${$rmin1}); $len = length($dtt); ${$rmin2} = $len if ($len > ${$rmin2}); $len = length($sz); ${$rmin3} = $len if ($len > ${$rmin3}); } elsif ( -d $path ) { # no stat - check ALL the files in this directory if (opendir(DIR,$path)) { my @files = readdir(DIR); closedir(DIR); foreach $file (@files) { next if (($file eq '.')||($file eq '..')); $ff = "$path\\$file"; if ((-f $ff) && ($sb = stat($ff))) { if ($file =~ /$inf/i) { $dtt = YYYYMMDD($sb->mtime); $sz = get_nn( $sb->size ); prt( "Found potential in [$path]\\$ff, $dtt, $sz bytes\n" ) if (VERB2()); # 0 1 2 3 4 push(@potential,[$path,$sz,$dtt,$ff,${$rpathcnt}]); ${$rpotcnt}++; $len = length($ff); ${$rmin0} = $len if ($len > ${$rmin0}); $len = length($path); ${$rmin1} = $len if ($len > ${$rmin1}); $len = length($dtt); ${$rmin2} = $len if ($len > ${$rmin2}); $len = length($sz); ${$rmin3} = $len if ($len > ${$rmin3}); } } elsif (-d $ff) { push(@dirs,$ff); } } } } else { prt("Path: [$path] NOT VALID!\n") if (VERB1()); } if ($recursive) { foreach $path (@dirs) { check_path($path,$inf,$rfndcnt,$rmin0,$rmin1,$rmin2,$rmin3,$rpathcnt,$rpotcnt); } } } sub find_in_path($$) { my ($inf,$rpatharr) = @_; my $path = ''; my $tfind = ''; my $fndcnt = 0; my $dospath = ''; my $repeats = 0; # count of REPEATED paths, skipped my $pcnt = scalar @{$rpatharr}; my ($sb,$dtt,$sz,$min1,$min2,$min3,$i,$i2,$len); my ($cnt,@files,$file,$ff,$potcnt,$min0,$pathcnt,$msg); prt("Checking for [$inf], in $pcnt PATHS... "); $cnt = scalar @user_paths; if ($cnt) { prt("plus $cnt user paths"); prt(" recursively") if ($recursive); } prt("\n"); $min0 = 0; $min1 = 0; $min2 = 0; $min3 = 0; $cnt = 0; $potcnt = 0; $pathcnt = 0; # count of paths with length my %donepaths = (); foreach $path (@{$rpatharr}) { $cnt++; $path = strip_quotes($path); if ($path =~ /(\\|\/)$/) { $path = substr($path,0,length($path)-1); } if (length($path)) { $pathcnt++; $dospath = uc(path_u2d($path)); if (defined $donepaths{$dospath}) { prt( "$cnt of $pcnt: SKIP [$path]... repeated '$dospath'\n" ) if (VERB1()); $repeats++; next; } $donepaths{$dospath} = 1; prt( "$cnt of $pcnt: Checking [$path]...\n" ) if (VERB1()); $tfind = $path."\\".$inf; if ( ( -f $tfind) && ($sb = stat($tfind))) { $dtt = YYYYMMDD($sb->mtime); $sz = get_nn( $sb->size ); prt( "Found in [$path]\\$inf, $dtt, $sz bytes\n" ) if (VERB2()); # 0 1 2 3 4 push(@pathfnd,[$path,$sz,$dtt,$tfind,$pathcnt]); $fndcnt++; $len = length($tfind); $min0 = $len if ($len > $min0); $len = length($path); $min1 = $len if ($len > $min1); $len = length($dtt); $min2 = $len if ($len > $min2); $len = length($sz); $min3 = $len if ($len > $min3); } elsif ( -d $path ) { # no stat - check ALL the files in this directory if (opendir(DIR,$path)) { @files = readdir(DIR); closedir(DIR); foreach $file (@files) { next if (($file eq '.')||($file eq '..')); $ff = "$path\\$file"; if ((-f $ff) && ($sb = stat($ff))) { if ($file =~ /$inf/i) { $dtt = YYYYMMDD($sb->mtime); $sz = get_nn( $sb->size ); prt( "Found potential in [$path]\\$ff, $dtt, $sz bytes\n" ) if (VERB2()); # 0 1 2 3 4 push(@potential,[$path,$sz,$dtt,$ff,$pathcnt]); $potcnt++; $len = length($ff); $min0 = $len if ($len > $min0); $len = length($path); $min1 = $len if ($len > $min1); $len = length($dtt); $min2 = $len if ($len > $min2); $len = length($sz); $min3 = $len if ($len > $min3); } } } } } else { prt("Path: [$path] NOT VALID!\n") if (VERB1()); } } } foreach $path (@user_paths) { $cnt++; $path = strip_quotes($path); if ($path =~ /(\\|\/)$/) { $path = substr($path,0,length($path)-1); } if (length($path)) { $pathcnt++; prt( "$cnt of $pcnt: Checking [$path]...\n" ) if (VERB1()); #my ($path,$inf,$rfndcnt,$rmin0,$rmin1,$rmin2,$rmin3,$rpathcnt,$rpotcnt) = @_; check_path($path,$inf,\$fndcnt,\$min0,\$min1,\$min2,\$min3,\$pathcnt,\$potcnt); } } $min3 = $min_size if ($min3 < $min_size); if (($fndcnt == 0)&&($potcnt == 0)) { prt( "[$inf] NOT FOUND..., in any form...\n" ); } else { if ($potcnt) { prt("Got $potcnt potential finds of [*$inf*]...\n"); for ($i = 0; $i < $potcnt; $i++) { $i2 = $i + 1; $path = $potential[$i][0]; $sz = $potential[$i][1]; $dtt = $potential[$i][2]; $ff = $potential[$i][3]; $ff .= ' ' while (length($ff) < $min0); $path .= ' ' while (length($path) < $min1); $dtt .= ' ' while (length($dtt) < $min2); $sz = ' '.$sz while (length($sz) < $min3); #prt("$i2: $path $dtt $sz\n"); prt("$i2: $ff $dtt $sz\n"); } } if ($fndcnt) { $msg = "Got $fndcnt exact finds of [$inf]..."; $msg .= " paths $pathcnt/$cnt" if ($fndcnt == 1); $msg .= " rpts $repeats" if ($repeats > 0); prt("$msg\n"); for ($i = 0; $i < $fndcnt; $i++) { $i2 = $i + 1; $path = $pathfnd[$i][0]; $sz = $pathfnd[$i][1]; $dtt = $pathfnd[$i][2]; $ff = $pathfnd[$i][3]; $ff .= ' ' while (length($ff) < $min0); $path .= ' ' while (length($path) < $min1); $dtt .= ' ' while (length($dtt) < $min2); $sz = ' '.$sz while (length($sz) < $min3); #prt("$i2: $path $dtt $sz\n"); prt("$i2: $ff $dtt $sz\n"); } } else { prt("Got NO exact finds of [$inf]...\n"); } } } sub fix_path_array() { my @newarr = (); my ($path,$len,$env,$sub); foreach $path (@patharr) { $len = length($path); next if ($len == 0); if ($path =~ /\%(.+)\%/) { $env = $1; $sub = $ENV{$env}; if ((defined $sub) && length($sub)) { prt("Env '$env', sub $sub, Path '$path' fixed...\n") if (VERB2()); $path =~ s/\%(.+)\%/$sub/; prt("To Path '$path'\n") if (VERB2()); } else { pgm_exit(1, "Env '$env', Path '$path' to be fixed...\n"); } } } } ############################# # ### MAIN ### parse_args(@ARGV); fix_path_array(); #prt( "Checking for [$inp_file], in $pcnt PATHs ...\n" ); find_in_path($inp_file,\@patharr); #close_log($outfile,0); exit(0); ########################### sub give_help() { prt( "Usage: $pgmname [options] filename\n" ); prt("Options:\n"); prt(" -h (-?) = This help, and exit.\n"); prt(" -p path = Add an additional path to be searched.\n"); prt(" -r = Search additional path recursively.\n"); prt(" -v[num] = Bump/Set verbosity.\n"); mydie("Will attempt to FIND the file name in the paths ...\n" ); } sub need_arg { my ($arg,@av) = @_; pgm_exit(1,"ERROR: [$arg] must have a following argument!\n") if (!@av); } sub parse_args { my (@av) = @_; my $inf = ''; my ($sarg); while (@av) { my $arg = $av[0]; if ($arg =~ /^-/) { $sarg = substr($arg,1); $sarg = substr($sarg,1) while ($sarg =~ /^-/); if (($sarg =~ /^h/i)||($sarg eq '?')) { give_help(); } elsif ($sarg =~ /^v/i) { if ($sarg =~ /^v(\d+)$/i) { $verbosity = $1; } elsif ($sarg =~ /^v=(\d+)$/i) { $verbosity = $1; } elsif ($sarg =~ /^v$/i) { $verbosity++; } else { prt( "ERROR: Unknown -v argument [$arg]!\n" ); give_help(); } prt("Bump verbosity to $verbosity...\n") if (VERB1()); } elsif ($sarg =~ /^p/) { need_arg(@av); shift @av; $sarg = $av[0]; if (-d $sarg) { push(@user_paths,$sarg); prt("Added user path to search $sarg...\n") if (VERB1()); } else { pgm_exit(1,"ERROR: Unable to locate path [$sarg].\n"); } } elsif ($sarg =~ /^r/) { $recursive = 1; prt("Set recursive on user paths...\n") if (VERB1()); } else { prt( "ERROR: Unknown argument [$arg]!\n" ); give_help(); } } else { if (length($inf)) { prt( "ERROR: Only find one at a time ... already have $inf, now $arg ...\n" ); give_help(); } else { $inf = $arg; prt("Set input file to [$inf]...\n"); } } shift @av; } if (length($inf)) { $inp_file = $inf; } elsif ( !$debug ) { prt( "ERROR: No input file found ...\n" ); give_help(); } else { $inp_file = $def_inf; #$verbose = 9; } } # eof