using System; using System.Diagnostics; using System.IO; using System.Text.RegularExpressions; namespace RobvanderWoude { class Which { static int Main( string[] args ) { string[] internals = "APPEND ASSOC BREAK CALL CD CHCP CHDIR CLS COLOR COPY DATE DEL DIR DPATH ECHO ENDLOCAL ERASE EXIT FOR FTYPE GOTO IF KEYS MD MKDIR MKLINK MOVE PATH PAUSE POPD PROMPT PUSHD RD REM REN RENAME RMDIR SET SETLOCAL SHIFT START TIME TITLE TRUENAME TYPE VER VERIFY VOL".Split( ' ' ); string[] path = ( Environment.CurrentDirectory + ";" + Environment.GetEnvironmentVariable( "PATH" ) ).Split( ';' ); string[] pathext = ( ";" + Environment.GetEnvironmentVariable( "PATHEXT" ).ToLower( ) ).Split( ';' ); bool all = false; bool extonly = false; string prog = string.Empty; bool set_all = false; bool set_prog = false; bool set_ext = false; bool found = false; #region Command Line Parsing if ( args.Length == 0 ) { return WriteError( ); } foreach ( string arg in args ) { if ( arg[0] == '/' ) { if ( arg.ToUpper( ) == "/A" ) { if ( set_all ) { return WriteError( "Duplicate command line switch: " + arg ); } else { all = true; set_all = true; } } else if ( arg.ToUpper( ) == "/X" ) { if ( set_ext ) { return WriteError( "Duplicate command line switch: " + arg ); } else { extonly = true; set_ext = true; } } else { if ( arg == "/?" ) { return WriteError( ); } else { return WriteError( "Invalid command line switch: " + arg ); } } } else { if ( set_prog ) { return WriteError( "Invalid or duplicate command line argument: " + arg ); } else { char[] forbidden = { '\\', '?', '*', ':', ';', '/' }; if ( arg.IndexOfAny( forbidden ) == -1 ) { prog = arg; set_prog = true; } else { return WriteError( "Invalid characters in specified program name: " + arg ); } } } } #endregion Command Line Parsing try { if ( !extonly ) { // Try DOSKEY macros first Process doskey = new Process( ); doskey.StartInfo.Arguments = "/macros"; doskey.StartInfo.CreateNoWindow = false; doskey.StartInfo.FileName = Environment.GetFolderPath( Environment.SpecialFolder.System ) + "\\doskey.exe"; doskey.StartInfo.LoadUserProfile = false; doskey.StartInfo.RedirectStandardError = false; doskey.StartInfo.RedirectStandardInput = false; doskey.StartInfo.RedirectStandardOutput = true; doskey.StartInfo.UseShellExecute = false; doskey.Start( ); doskey.WaitForExit( 1000 ); do { string line = doskey.StandardOutput.ReadLine( ); if ( !found || all ) { if ( !string.IsNullOrWhiteSpace( line ) ) { if ( line.IndexOf( '=' ) > 0 ) { string pattern = "^" + prog.ToUpper( ).Replace( ".", "\\." ) + "="; if ( Regex.IsMatch( line.ToUpper( ), pattern ) ) { Console.ForegroundColor = ConsoleColor.White; Console.Write( "[{0}]::", doskey.StartInfo.FileName.ToUpper( ) ); Console.ResetColor( ); Console.WriteLine( line ); found = true; } } } } } while ( doskey.StandardOutput.Peek( ) != -1 ); doskey.Close( ); // Next try internal commands if ( !found || all ) { if ( prog.IndexOf( '.' ) == -1 ) { foreach ( string intern in internals ) { if ( intern == prog.ToUpper( ) ) { Console.ForegroundColor = ConsoleColor.White; Console.Write( "[{0}]::", Environment.GetEnvironmentVariable( "COMSPEC" ).ToUpper( ) ); Console.ResetColor( ); Console.WriteLine( prog.ToUpper( ) ); found = true; } } } } } // Finally try external commands if ( !found || all ) { foreach ( string folder in path ) { if ( !found || all ) { if ( !string.IsNullOrWhiteSpace( folder ) ) { string dir = ( folder + "\\" ).Replace( "\\\\", "\\" ); foreach ( string ext in pathext ) { if ( !found || all ) { // The EXTERNAL program FILE to be searched MUST have an extension, either // specified on the command line or one of the extensions listed in PATHEXT. if ( ( prog + ext ).IndexOf( '.' ) > -1 ) { if ( File.Exists( dir + prog + ext ) ) { Console.WriteLine( dir + prog + ext ); found = true; } } } } } } } } if ( found ) { return 0; } else { return 1; } } catch ( Exception e ) { return WriteError( e.Message ); } } #region Error Handling public static int WriteError( Exception e = null ) { return WriteError( e == null ? null : e.Message ); } public static int WriteError( string errorMessage ) { if ( string.IsNullOrEmpty( errorMessage ) == false ) { Console.Error.WriteLine( ); Console.ForegroundColor = ConsoleColor.Red; Console.Error.Write( "ERROR: " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.WriteLine( errorMessage ); Console.ResetColor( ); } /* Which, Version 1.30 Port of the UNIX command to Windows Usage: WHICH progname [ /A ] [ /X ] Where: progname the program name or internal command to be searched for /A returns All matches (default: stop at first match) /X returns eXternal commands only, no DOSKEY macros or internal commands (default: all types) Note: By default, this program first compares the specified name against a list of active DOSKEY macros, next against a (hard-coded) list of CMD's internal commands, and finally it tries to find a matching program file in the current directory and the PATH, using the extensions listed in PATHEXT. Written by Rob van der Woude http://www.robvanderwoude.com */ Console.Error.WriteLine( ); Console.Error.WriteLine( "Which, Version 1.30" ); Console.Error.WriteLine( "Port of the UNIX command to Windows" ); Console.Error.WriteLine( ); Console.Error.Write( "Usage: " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.WriteLine( "WHICH progname [ /A ] [ /X ]" ); Console.ResetColor( ); Console.Error.WriteLine( ); Console.Error.Write( "Where: " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "progname" ); Console.ResetColor( ); Console.Error.WriteLine( " the program name or internal command to be searched for" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( " /A" ); Console.ResetColor( ); Console.Error.Write( " returns " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "A" ); Console.ResetColor( ); Console.Error.WriteLine( "ll matches (default: stop at first match)" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( " /X" ); Console.ResetColor( ); Console.Error.Write( " returns e" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "X" ); Console.ResetColor( ); Console.Error.WriteLine( "ternal commands only, no DOSKEY macros or" ); Console.Error.WriteLine( " internal commands (default: all types)" ); Console.Error.WriteLine( ); Console.Error.WriteLine( "Note: By default, this program first compares the specified name against" ); Console.Error.WriteLine( " a list of active DOSKEY macros, next against a (hard-coded) list" ); Console.Error.WriteLine( " of CMD's internal commands, and finally it tries to find a matching" ); Console.Error.WriteLine( " program file in the current directory and the PATH, using the" ); Console.Error.WriteLine( " extensions listed in PATHEXT." ); Console.Error.WriteLine( ); Console.Error.WriteLine( "Written by Rob van der Woude" ); Console.Error.WriteLine( "http://www.robvanderwoude.com" ); return 1; } #endregion } }