#!/usr/bin/perl -w # chkpath2.pl # 14/07/2020 - Re-worked the partial matching, to not report false positive # 22/05/2020 - Allow 'path\sub' to also be matched # 2018-01-16 - add info if no find given # 14/12/2015 - missing a path? # 01/03/2015 - More UI updates # 18/05/2014 - Improve UI 0=not found, 1=found, others use error use strict; use warnings; my ($dir,$sdir); my $verbosity = 0; my $check_partial = 1; sub VERB1() { return ($verbosity >= 1); } sub VERB2() { return ($verbosity >= 2); } sub VERB5() { return ($verbosity >= 5); } sub VERB9() { return ($verbosity >= 9); } sub prt($) { print shift; } my $find_path = ''; my $ret = 0; my $path_env = $ENV{"PATH"}; sub add_escape($) { my $txt = shift; my $ntxt = ''; my $len = length($txt); my ($i,$ch); for ($i = 0; $i < $len; $i++) { $ch = substr($txt,$i,1); if ($ch eq '\\') { $ntxt .= '\\'; } elsif ($ch eq ':') { $ntxt .= '\\'; } $ntxt .= $ch; } return $ntxt; } sub path_d2u($) { my ($du) = shift; $du =~ s/\\/\//g; return $du; } sub same_dir($$) { my ($dir1,$dir2) = @_; my $len1 = length($dir1); my $len2 = length($dir2); return 0 if ($len1 != $len2); my ($i,$ch1,$ch2); $dir1 =~ s/\\/\//g; $dir2 =~ s/\\/\//g; for ($i = 0; $i < $len1; $i++) { $ch1 = uc(substr($dir1,$i,1)); $ch2 = uc(substr($dir2,$i,1)); return 0 if ($ch1 ne $ch2); } return 1; } # assumed if (part_the_same($dir,$find_path)) sub part_the_same($$) { my ($dir1,$dir2) = @_; my $len1 = length($dir1); my $len2 = length($dir2); return 0 if ($len1 == 0); return 0 if ($len2 == 0); if ($len2 > $len1) { prt("[v9] no partial, since find $len2 '$dir2' is greater than test $len1 '$dir1'\n") if (VERB9()); return 0; } # NB: '/(\\|\/)/' used in other scripts, FAILS!!!! ################################################## my @arr1 = split(/\\|\//,$dir1); my @arr2 = split(/\\|\//,$dir2); $len1 = scalar @arr1; $len2 = scalar @arr2; my ($sub1,$sub2,$i,$j,$i2); $j = 0; $sub2 = lc($arr2[$j]); for ($i = 0; $i < $len1; $i++) { $sub1 = lc($arr1[$i]); $i2 = $i + 1; if ($sub1 eq $sub2) { # got a match, of 1 item if ($len2 == 1) { prt("[v9] found partial since only matching 1 '$sub1'\n") if (VERB9()); return 1; } if ($i2 < $len1) { # we have more dir $sub1 = lc($arr1[$i2]); # so get next for ($j = 1; $j < $len2; $j++) { $sub2 = lc($arr2[$j]); # get next of find last if ($sub1 ne $sub2); # match failed $i2++; # go to next in dir if ($i2 < $len1) { $sub1 = lc($arr1[$i2]); # so get next } else { $sub1 = ''; } } if ($j == $len2) { prt("[v9] found partial '$dir2' in '$dir1' on last matching '$sub1'\n") if (VERB9()); return 1; } } else { prt("[v9] partial failed '$dir2' in '$dir1', on '$sub2' since no more dir\n") if (VERB9()); } } } prt("[v9] partial failed '$dir2' in '$dir1'...\n") if (VERB9()); return 0; } sub give_help { prt("chkpath [options] path_to_find\n"); prt("options:\n"); prt(" --help (-h or -?) = This help and exit 0\n"); prt(" --verb[n] (-v) = Bump or set verbosity (0,1,2,5,9) def=$verbosity\n"); prt("\n"); prt(" Try to match exactly the path_to_find, with those in the PATH environment variable.\n"); prt(" If no exact match, try for a partial match.\n"); prt(" Exit(0) if neither exact nor patial found\n"); prt(" Exit(1) if either found.\n"); prt(" Exit(2) if some error.\n"); } foreach $dir (@ARGV) { if ($dir =~ /^-/) { $sdir = $dir; $sdir = substr($sdir,1) while ($sdir =~ /^-/); if ($sdir =~ /^v/) { $verbosity++; if ($sdir =~ /^v.*(\d+)$/) { $verbosity = $1; } else { $sdir = substr($sdir,1); while ($sdir =~ /^v/) { $sdir = substr($sdir,1); $verbosity++; } } } elsif (($sdir =~ /^h/)||($sdir eq '?')) { give_help(); exit 0; } else { prt("Unknown command [$dir]!\n"); $ret = 3; # set ERROR prt("Exit with [$ret]\n"); exit $ret; } } else { $find_path = $dir; prt("Finding path [$find_path]\n") if (VERB5()); } } my $fcnt = 0; my $dcnt = 0; my $notfnd = 0; if (defined $path_env) { my @folds = split(/;/,$path_env); $fcnt = scalar @folds; prt( "Got $fcnt directories...\n" ) if (VERB5()); my $len = length($find_path); my $find = add_escape($find_path); my ($len2); my $edir = ''; my $msg = ''; my $ccnt = ''; my $pcnt = 0; foreach $dir (@folds) { $len2 = length($dir); next if ($len2 == 0); $dcnt++; $ccnt = sprintf("%2d",$dcnt); if ( -d $dir) { $msg = 'ok'; } else { $msg = 'NF!'; $notfnd++; } $edir = add_escape($dir); if ($len2 == 0) { prt("[v9] $ccnt of $fcnt: Skip blank dir\n") if (VERB9()); next; } prt("[v9] $ccnt of $fcnt: Compare '$dir' $msg, with '$find_path'\n") if (VERB9()); if ($len) { if (same_dir($dir,$find_path)) { $ret = 1; # set SUCCESS prt("$ccnt of $fcnt: Found [$dir] $msg\n") if (VERB1()); last; } } else { if ($dcnt == 1) { prt("No 'path' given to find, so just listing ALL env 'PATH'...\n"); } prt("$ccnt: [$dir] $msg\n"); } } if (!$ret && $len && $check_partial) { prt("[v9] No exact match found, so try for a partial match...\n") if (VERB9()); foreach $dir (@folds) { $pcnt++; $len2 = length($dir); next if ($len2 == 0); if (part_the_same($dir,$find_path)) { $ret = 1; # set SUCCESS prt("[v2] No exact match found, but found the following PARTIAL...\n") if (VERB2()); prt("$pcnt of $fcnt: Found [$dir] with [$find_path]\n") if (VERB1()); # last; } } } } if (length($find_path) == 0) { prt("Note: Given NO path to find... so list all $dcnt ($fcnt) in 'PATH'..."); if ($notfnd > 0) { prt(" $notfnd path not found..."); } $notfnd = $fcnt - $dcnt; if ($notfnd) { prt(" skipped $notfnd blank..."); } prt("\n"); $ret = 2; # set ERROR } prt("Exit with [$ret]\n") if (VERB1()); exit $ret; # eof