#!/usr/bin/perl -w # NAME: adjpath.pl # AIM: Examine the current PATH environment variable, and output adjustments as needed # 2016-09-25 - Be able to remove the pause from the 'setpath.bat' -N # 19/06/2016 - Add -r path toe REMOVE a path from PATH # 02/01/2015 - Update in UI # 25/09/2014 geoff mclane http://geoffair.net/mperl use strict; use warnings; use File::Basename; # split path ($name,$dir,$ext) = fileparse($file [, qr/\.[^.]*/] ) use Cwd; my $os = $^O; my $perl_dir = '/home/geoff/bin'; my $PATH_SEP = '/'; my $temp_dir = '/tmp'; if ($os =~ /win/i) { $perl_dir = 'C:\GTools\perl'; $temp_dir = $perl_dir; $PATH_SEP = "\\"; } unshift(@INC, $perl_dir); require 'lib_utils.pl' or die "Unable to load 'lib_utils.pl' Check paths in \@INC...\n"; # log file stuff our ($LF); my $pgmname = $0; if ($pgmname =~ /(\\|\/)/) { my @tmpsp = split(/(\\|\/)/,$pgmname); $pgmname = $tmpsp[-1]; } my $outfile = $temp_dir.$PATH_SEP."temp.$pgmname.txt"; open_log($outfile); # user variables my $VERS = "0.0.5 2016-09-25"; ##my $VERS = "0.0.4 2016-06-25"; ##my $VERS = "0.0.3 2015-01-02"; ##my $VERS = "0.0.2 2014-01-13"; my $load_log = 0; my $verbosity = 0; my $add_pause = 1; my $out_file = ''; my @excluded = (); my $add_path = ''; # multiple stored in @inserts my @inserts = (); my $sub_paths = ''; # can be ';' separated list # ### DEBUG ### my $debug_on = 0; my $def_file = 'C:\Qt\4.8.6\bin'; ### program variables my @warnings = (); my $cwd = cwd(); sub VERB1() { return $verbosity >= 1; } sub VERB2() { return $verbosity >= 2; } sub VERB5() { return $verbosity >= 5; } sub VERB9() { return $verbosity >= 9; } 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 process_in_file($) { my ($inf) = @_; if (! open INF, "<$inf") { pgm_exit(1,"ERROR: Unable to open file [$inf]\n"); } my @lines = ; close INF; my $lncnt = scalar @lines; prt("Processing $lncnt lines, from [$inf]...\n"); my ($line,$inc,$lnn); $lnn = 0; foreach $line (@lines) { chomp $line; $lnn++; if ($line =~ /\s*#\s*include\s+(.+)$/) { $inc = $1; prt("$lnn: $inc\n"); } } } sub in_excluded($) { my $dir = shift; my ($tst1,$tst2); foreach $tst1 (@excluded) { $tst1 =~ s/\\$//; return 1 if ($dir eq $tst1); $tst2 = $dir; return 1 if (lc($tst2) eq lc($tst1)); } return 0; } sub in_removal($$) { my ($dir,$ra) = @_; my ($tst1,$tst2); foreach $tst1 (@{$ra}) { $tst1 =~ s/\\$//; return 1 if ($dir eq $tst1); $tst2 = $dir; return 1 if (lc($tst2) eq lc($tst1)); } return 0; } sub check_for_insert($$) { my ($pos,$rstg) = @_; my ($ra,$dir,$cnt,$dn); foreach $ra (@inserts) { $dn = ${$ra}[2]; next if ($dn > 0); $cnt = ${$ra}[1]; $dir = ${$ra}[0]; next if ($cnt == -1); prt("Checking insert $dir;$cnt at position $pos\n") if (VERB9()); if ($cnt <= $pos) { ${$ra}[2] = 1; ${$rstg} = $dir; return 1; } } return 0; } sub get_last_inserts($$) { my ($pos,$rstg) = @_; my ($ra,$dir,$cnt,$dn); foreach $ra (@inserts) { $dn = ${$ra}[2]; next if ($dn > 0); $cnt = ${$ra}[1]; $dir = ${$ra}[0]; ${$ra}[2] = 1; ${$rstg} = $dir; return 1; } return 0; } sub same_path2($$) { my ($dir,$add) = @_; return 1 if ($dir eq $add); my $lcdir1 = path_u2d(lc($dir)); my $lcdir2 = path_u2d(lc($add)); ut_fix_directory(\$lcdir1); ut_fix_directory(\$lcdir2); return 1 if ($lcdir1 eq $lcdir2); return 0; } sub same_path($) { my $dir = shift; return 0 if (length($add_path) == 0); my ($ra); foreach $ra (@inserts) { $add_path = ${$ra}[0]; ###prt("Check $add_path with $dir\n"); return 1 if (same_path2($dir,$add_path)); } return 0; } #################################################### ### Get PATH environment variable, and enumerate ### #################################################### sub process_path() { my $path = $ENV{PATH}; my @arr = split(';',$path); # split the path my ($dir,$ok,$min,$len,$cnt,$tst,$ocnt,$acnt,$xcnt,$icnt,$msg,@a2,$ra,$tmp); $min = 0; $ocnt = 0; $icnt = 0; my $do_cmp = (length($add_path) ? 1 : 0); my $fnd_path = 0; my %found = (); foreach $dir (@arr) { $len = length($dir); next if ($len == 0); $min = $len if ($len > $min); $ocnt++; if ($do_cmp) { $fnd_path = same_path($dir); if ($fnd_path) { prt("Found $add_path in list... ($dir)\n"); $found{$dir} = 1; $found{$add_path} = 1; } } } prt("Found $ocnt directories in ENV PATH... "); if (length($add_path)) { $cnt = 0; foreach $ra (@inserts) { $cnt++; $tmp = ${$ra}[0]; if (defined $found{$tmp}) { prt("$cnt: $tmp found "); } else { prt("$cnt: $tmp NF "); } } } else { prt("None to add..."); } my @removals = (); my $remcnt = 0; if (length($sub_paths)) { @removals = split(';',$sub_paths); $remcnt = scalar @removals; prt(", Have $remcnt to remove..."); } prt("\n"); ########################################################### my @invalid = (); my @dupe = (); my %dupes = (); my @valid = (); $cnt = 0; $xcnt = 0; my $rcnt = 0; foreach $dir (@arr) { next if (length($dir) == 0); $ok = 'NF'; if (-d $dir) { $ok = 'ok'; } else { push(@invalid,$dir); } $tst = $dir; $tst =~ s/\\$//; if (defined $dupes{$tst}) { push(@dupe,$tst); next; } $dupes{$tst} = 1; if (in_excluded($tst)) { $ok = 'EXCLUDED'; $xcnt++; } if (in_removal($tst,\@removals)) { $ok = 'REMOVE'; $rcnt++; } $cnt++; if (!defined $found{$dir} && !defined $found{$tst}) { while (check_for_insert($cnt,\$tst)) { if (-d $tst) { if (!defined $found{$tst}) { push(@valid,$tst); $tst .= ' ' while (length($tst) < $min); $acnt = sprintf("%2d",$cnt); prt("$acnt: $tst ok ADDED\n"); $cnt++; $icnt++; } } else { pgm_exit(1,"UGH: dir [$tst] does NOT exists!\n"); } } } push(@valid,$dir) if ($ok eq 'ok'); $dir .= ' ' while (length($dir) < $min); $acnt = sprintf("%2d",$cnt); if (($ok ne 'ok') || VERB1()) { prt("$acnt: $dir $ok\n"); } } $cnt++; while (get_last_inserts($cnt,\$tst)) { if (-d $tst) { if (!defined $found{$tst}) { push(@valid,$tst); $tst .= ' ' while (length($tst) < $min); $acnt = sprintf("%2d",$cnt); prt("$acnt: $tst ok ADDED\n"); $cnt++; $icnt++; } } else { pgm_exit(1,"UGH: dir [$tst] does NOT exists!\n"); } } $cnt = scalar @valid; prt("Listed $cnt valid. "); my $exit_val = 0; if ($xcnt || $icnt || $rcnt) { prt("$xcnt were excluded. ") if ($xcnt); prt("$icnt were added. ") if ($icnt); prt("$rcnt was removed. ") if ($rcnt); prt("\n"); $exit_val = 1; } else { if ($ocnt == $cnt) { prt("PATH unchanged.\n"); $exit_val = 0; } else { $cnt = scalar @invalid; if ($cnt) { prt("$cnt were INVALID paths!\n"); } else { prt("None were invalid\n"); } } } $dir = join(";",@valid); if (length($out_file)) { if ($path eq $dir) { $msg = "\@echo No change in PATH of\n"; $msg .= "\@echo \%PATH\%\n"; $msg .= "\@echo.\n"; $tmp = 'Current'; } else { if ($add_pause) { $msg = "\@echo WARNING! About to change PATH from\n"; $msg .= "\@echo \%PATH\%\n"; $msg .= "\@echo.\n"; $msg .= "\@echo $dir\n"; $msg .= "\@echo.\n"; $msg .= "\@echo *** CONTINUE? *** Only Ctrl+C aborts...\n"; $msg .= "\@pause\n"; } $msg .= "set PATH=".$dir."\n"; $tmp = 'New'; } rename_2_old_bak($out_file); write2file($msg,$out_file); prt("$tmp PATH written to $out_file\n"); } else { if ($xcnt || $icnt || $rcnt) { # if (length($add_path)) { prt("set PATH=".$dir."\n"); prt("Above is new PATH, since no -o out_file given\n"); } } pgm_exit($exit_val,""); } ######################################### ### MAIN ### parse_args(@ARGV); #process_in_file($add_path); process_path(); pgm_exit(0,""); ######################################## 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 ($arg,$sarg,@arr,$cnt,$tmp); my $verb = VERB1(); while (@av) { $arg = $av[0]; if ($arg =~ /^-/) { $sarg = substr($arg,1); $sarg = substr($sarg,1) while ($sarg =~ /^-/); if (($sarg =~ /^h/i)||($sarg eq '?')) { give_help(); pgm_exit(0,"Help exit(0)"); } elsif ($sarg =~ /^v/) { if ($sarg =~ /^v.*(\d+)$/) { $verbosity = $1; } else { while ($sarg =~ /^v/) { $verbosity++; $sarg = substr($sarg,1); } } $verb = VERB1(); prt("Verbosity = $verbosity\n") if ($verb); } elsif ($sarg =~ /^l/) { if ($sarg =~ /^ll/) { $load_log = 2; } else { $load_log = 1; } prt("Set to load log at end. ($load_log)\n") if ($verb); } elsif ($sarg =~ /^o/) { need_arg(@av); shift @av; $sarg = $av[0]; $out_file = $sarg; prt("Set out file to [$out_file].\n") if ($verb); } elsif ($sarg =~ /^x/) { need_arg(@av); shift @av; $sarg = $av[0]; @arr = split(';',$sarg); foreach $sarg (@arr) { push(@excluded,$sarg); prt("Added $sarg to excluded.\n") if ($verb); } } elsif ($sarg =~ /^a/) { need_arg(@av); shift @av; $tmp = ''; $sarg = $arg; if ($sarg =~ /^\w{1}:/) { $tmp = substr($sarg,0,2); $sarg = substr($sarg,2); } @arr = split(':',$sarg); $cnt = scalar @arr; $tmp .= $arr[0]; if (! -d $tmp) { pgm_exit(1,"Error: dir $tmp does not exist! $sarg\n"); } if ($cnt == 1) { push(@inserts,[$tmp,-1,0]); prt("Added $tmp at end of list.\n") if ($verb); } elsif ($cnt == 2) { $cnt = trim_all($arr[1]); if ( !($cnt =~ /^\d+$/) ) { pgm_exit(1,"Addition of $tmp but [$cnt] did not evaluate as an integer! $arg $sarg\n"); } push(@inserts,[$tmp,$cnt,0]); prt("Added $tmp at $cnt in list.\n") if ($verb); } else { pgm_exit(1,"Arg $sarg split $cnt. Shoul be 1 or 2 only\n"); } $add_path = $tmp; } elsif ($sarg =~ /^r/) { need_arg(@av); shift @av; $sarg = $av[0]; $sub_paths .= ";" if (length($sub_paths)); $sub_paths = $sarg; prt("Remove $sarg from path list.\n") if ($verb); } elsif ($sarg =~ /^N/) { $add_pause = 0; prt("Remove add pause to BAT file.\n") if ($verb); } else { pgm_exit(1,"ERROR: Invalid argument [$arg]! Try -?\n"); } } else { $tmp = ''; $sarg = $arg; if ($sarg =~ /^\w{1}:/) { $tmp = substr($sarg,0,2); $sarg = substr($sarg,2); } @arr = split(':',$sarg); $cnt = scalar @arr; $tmp .= $arr[0]; if (! -d $tmp) { pgm_exit(1,"Error: dir $tmp does not exist! $arg\n"); } if ($cnt == 1) { push(@inserts,[$tmp,-1,0]); prt("Added $tmp at end of list.\n") if ($verb); } elsif ($cnt == 2) { $cnt = trim_all($arr[1]); if ( !($cnt =~ /^\d+$/) ) { pgm_exit(1,"Addition of $tmp but [$cnt] did not evaluate as an integer! $arg\n"); } push(@inserts,[$tmp,$cnt,0]); prt("Added $tmp at $cnt in list.\n") if ($verb); } else { pgm_exit(1,"Arg $arg split $cnt. Should be 1 or 2 only\n"); } $add_path = $tmp; #prt("Set input to [$add_path]\n") if ($verb); } shift @av; } if ($debug_on) { prtw("WARNING: DEBUG is ON!\n"); #if (length($add_path) == 0) { # $add_path = $def_file; # push(@inserts,[$add_path,-1,0]); # prt("Set DEFAULT input to [$add_path]\n"); #} if (length($sub_paths) == 0) { $sub_paths = $def_file; prt("Set DEFAULT removal to [$sub_paths]\n"); } } if (length($add_path) == 0) { if (length($sub_paths) == 0) { prtw("WARNING: No ADD, and no SUB path found in command!\n"); } else { } } else { if (! -d $add_path) { pgm_exit(1,"ERROR: Unable to find the path [$add_path]! Check name, location...\n"); } } } sub give_help { prt("$pgmname: version $VERS\n"); prt("Usage: $pgmname [options] [in-path]\n"); prt("Options:\n"); prt(" --help (-h or -?) = This help, and exit 0.\n"); prt(" --verb[n] (-v) = Bump [or set] verbosity. def=$verbosity\n"); prt(" --load (-l) = Load LOG at end. ($outfile)\n"); prt(" --out (-o) = Write output to this file.\n"); prt(" --xclude (-x) = Exclude directory. Can be ';' list.\n"); prt(" --add (-a) = Add a directory. The :n, if present indicates the position.\n"); prt(" --rem (-r) = Remove a directory from the PATH.\n"); prt(" --NOPAUSE (-N) = Skip the pause in the 'setpath.bat' file. (def=$add_pause)\n"); prt("\n"); prt(" Search PATH for given addition, if any... Add if required...\n"); prt(" If no 'position' is indicate, then the entry will be appended to the list.\n"); prt(" A 'position of 0, then the entry will be at the start. Else inserted before the 'position'\n"); prt(" The additional directory must be valid.\n"); } # eof - adjpath.pl