using System; using System.Collections.Generic; using System.Threading; namespace RobvanderWoude { internal class ProgressBar { static readonly string progver = "2.00"; static int Main( string[] args ) { #region Initialize Variables int currentvalue = 0; bool currentset = false; int minimumvalue = 0; bool minimumset = false; int maximumvalue = 100; bool maximumset = false; int parsedargs = 0; ConsoleColor poscolor = ConsoleColor.Green; bool poscolorset = false; ConsoleColor negcolor = ConsoleColor.Green; bool negcolorset = false; bool linearscale = false; bool writescale = true; bool debug = false; #if DEBUG debug = true; #endif #endregion Initialize Variables #region Parse Command Line if ( args.Length == 0 ) { return ShowHelp( ); } foreach ( string arg in args ) { if ( arg == "/?" ) { return ShowHelp( ); } if ( arg.ToUpper( ) == "/C" ) { // /C should be the only argument if ( args.Length != 1 ) { return ShowHelp( ); } // Display valid colors Console.WriteLine( "Valid colors:" ); Console.WriteLine( "=============" ); foreach ( ConsoleColor color in Enum.GetValues( typeof( ConsoleColor ) ) ) { Console.ForegroundColor = color; // Prevent "invisible" text when foreground color equals background color if ( Math.Abs( Console.ForegroundColor - Console.BackgroundColor ) < 2 ) { Console.BackgroundColor = (ConsoleColor)( ( (int)color + 7 ) % 16 ); } Console.Write( "{0,-13}", Enum.GetName( typeof( ConsoleColor ), color ) ); Console.ResetColor( ); Console.WriteLine( ); } return 0; } else if ( arg.ToUpper( ) == "/D" ) { debug = true; parsedargs++; } else if ( arg.ToUpper( ) == "/L" ) { linearscale = true; parsedargs++; } else if ( arg.ToUpper( ) == "/NS" ) { writescale = false; parsedargs++; } else if ( int.TryParse( arg, out int test ) ) { if ( !currentset ) // First numeric value is the mandatory current value { currentvalue = test; currentset = true; } else if ( !minimumset ) // Second numeric value can be either the minimum or maximum value { minimumvalue = test; minimumset = true; } else if ( !maximumset ) // Third numeric value must be the maximum value { maximumvalue = test; maximumset = true; } else // No more numeric values allowed { return ShowHelp( "Invalid command line argument \"{0}\"", arg ); } parsedargs++; } else { bool validcolor = false; foreach ( ConsoleColor color in Enum.GetValues( typeof( ConsoleColor ) ) ) { if ( arg.ToUpper( ) == Enum.GetName( typeof( ConsoleColor ), color ).ToUpper( ) ) { if ( !poscolorset ) { poscolor = color; poscolorset = true; validcolor = true; parsedargs++; } else if ( !negcolorset ) { negcolor = color; negcolorset = true; validcolor = true; parsedargs++; } else { validcolor = false; } } } if ( !validcolor ) { return ShowHelp( "Invalid color \"{0}\", use /C switch to show valid colors", arg ); } } } #endregion Parse Command Line #region Validate Command Line if ( !maximumset ) { if ( !minimumset ) { maximumvalue = 100; maximumset = false; minimumvalue = 0; minimumset = false; } else { maximumvalue = minimumvalue; maximumset = true; minimumvalue = 0; minimumset = false; } } if ( minimumvalue * maximumvalue >= 0 ) { if ( negcolorset ) { return ShowHelp( "Specify a second color only if minimum < 0 and maximum > 0" ); } linearscale = true; } if ( currentvalue == maximumvalue + 1 ) { currentvalue = maximumvalue; } else if ( currentvalue < minimumvalue || currentvalue > maximumvalue + 1 ) { return ShowHelp( "Invalid current value \"{0}\"", currentvalue.ToString( ) ); } if ( parsedargs != args.Length ) { return ShowHelp( "Invalid command line, most likely caused by duplicate arguments" ); } #endregion Validate Command Line Console.ResetColor( ); #region Scale if ( writescale ) { string scale; if ( minimumvalue < 0 && maximumvalue > 0 ) { int zeropos = (int)Math.Floor( Console.WindowWidth * (double)-minimumvalue / ( maximumvalue - minimumvalue ) ); scale = string.Format( "{0}{1}0{2}{3}", minimumvalue, new string( ' ', zeropos - minimumvalue.ToString( ).Length ), new string( ' ', Console.WindowWidth - zeropos - minimumvalue.ToString( ).Length ), maximumvalue ); } else { scale = string.Format( "{0}{1}{2}", minimumvalue, new string( ' ', Console.WindowWidth - minimumvalue.ToString( ).Length - maximumvalue.ToString( ).Length ), maximumvalue ); } Console.ForegroundColor = poscolor; Console.WriteLine( scale ); Console.ResetColor( ); if ( debug ) { Thread.Sleep( 1000 ); } } #endregion Scale // Move down 1 line and then return to the one above current one, to make sure we're not at the bottom line of the screen Console.WriteLine( ); int linenumber = Console.CursorTop - 1; Console.SetCursorPosition( 0, linenumber ); // Calculate progress bar length double progress = Math.Min( 1F, ( currentvalue - (double)minimumvalue ) / ( maximumvalue - (double)minimumvalue ) ); int progressbarlength = (int)( progress * Console.WindowWidth ); // Display the calculated progress bar if ( negcolorset ) { if ( linearscale ) { int negbarlength = (int)( -minimumvalue * Console.WindowWidth / ( maximumvalue - minimumvalue ) ); Console.BackgroundColor = negcolor; Console.Write( new string( ' ', Math.Min( progressbarlength, negbarlength ) ) ); if ( progressbarlength > negbarlength ) { Console.BackgroundColor = poscolor; Console.Write( new string( ' ', progressbarlength - negbarlength ) ); } // Erase remainder of line Console.ResetColor( ); Console.Write( new string( ' ', Console.WindowWidth - progressbarlength ) ); } else { if ( currentvalue == 0 ) { Console.ResetColor( ); Console.Write( new string( ' ', Console.WindowWidth ) ); } else { int neghalflength = (int)( -minimumvalue * Console.WindowWidth / ( maximumvalue - minimumvalue ) ); int poshalflength = Console.WindowWidth - neghalflength; if ( currentvalue < 0 ) { progress = (double)currentvalue / minimumvalue; progressbarlength = (int)( progress * neghalflength ); Console.ResetColor( ); Console.Write( new string( ' ', neghalflength - progressbarlength ) ); Console.BackgroundColor = negcolor; Console.Write( new string( ' ', progressbarlength ) ); // Erase remainder of line Console.ResetColor( ); Console.Write( new string( ' ', poshalflength ) ); } else { progress = (double)currentvalue / maximumvalue; progressbarlength = (int)( progress * poshalflength ); Console.ResetColor( ); Console.Write( new string ( ' ', neghalflength ) ); Console.BackgroundColor = poscolor; Console.Write( new String( ' ', progressbarlength ) ); Console.ResetColor( ); // Erase remainder of line Console.ResetColor( ); Console.Write( new string( ' ', poshalflength - progressbarlength ) ); } } } } else { Console.BackgroundColor = poscolor; string progressbar = new string( ' ', progressbarlength ); Console.Write( progressbar ); // Erase remainder of line Console.ResetColor( ); Console.Write( new string( ' ', Console.WindowWidth - progressbarlength ) ); } // Move the cursor back to the start of the line Console.SetCursorPosition( 0, linenumber ); return 0; } static int ShowHelp( params string[] errmsg ) { #region Error Message if ( errmsg.Length > 0 ) { List errargs = new List( errmsg ); errargs.RemoveAt( 0 ); Console.Error.WriteLine( ); Console.ForegroundColor = ConsoleColor.Red; Console.Error.Write( "ERROR:\t" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.WriteLine( errmsg[0], errargs.ToArray( ) ); Console.ResetColor( ); } #endregion Error Message #region Help Text /* ProgressBar.exe, Version 2.00 Batch tool to display a progress bar Usage: ProgressBar current [ options ] or: ProgressBar /C Where: current is the current value Options: minimum is the minimum value (default: 0) maximum is the maximum value (default: 100) color is the progress bar color (default: Green) 2ndcolor is the "sub zero" color (default: Green) /C list valid Colors (no other arguments allowed) /L start progress bar at Left (default: start at 0) /NS do Not show Scale above progress bar Notes: /L means the progress bar starts at the minimum value, whereas by default the progress bar starts at 0. If the range minimum..maximum does not include 0, /L is assumed. Return code -1 in case of (command line) errors, otherwise 0. Written by Rob van der Woude https://www.robvanderwoude.com */ #endregion Help Text #region Display Help Text Console.Error.WriteLine( ); Console.Error.WriteLine( "ProgressBar.exe, Version {0}", progver ); Console.Error.WriteLine( "Batch tool to display a progress bar" ); Console.Error.WriteLine( ); Console.Error.Write( "Usage: " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.WriteLine( "ProgressBar current [ options ]" ); Console.ResetColor( ); Console.Error.WriteLine( ); Console.Error.Write( "or: " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.WriteLine( "ProgressBar /C" ); Console.ResetColor( ); Console.Error.WriteLine( ); Console.Error.Write( "Where: " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "current" ); Console.ResetColor( ); Console.Error.WriteLine( " is the current value" ); Console.Error.WriteLine( ); Console.Error.Write( "Options: " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "minimum" ); Console.ResetColor( ); Console.Error.WriteLine( " is the minimum value (default: 0)" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( " maximum" ); Console.ResetColor( ); Console.Error.WriteLine( " is the maximum value (default: 100)" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( " color" ); Console.ResetColor( ); Console.Error.WriteLine( " is the progress bar color (default: Green)" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( " 2ndcolor" ); Console.ResetColor( ); Console.Error.WriteLine( " is the \"sub zero\" color (default: Green)" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( " /C" ); Console.ResetColor( ); Console.Error.WriteLine( " list valid Colors (no other arguments allowed)" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( " /L" ); Console.ResetColor( ); Console.Error.WriteLine( " start progress bar at Left (default: start at 0)" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( " /NS" ); Console.ResetColor( ); Console.Error.WriteLine( " do Not show Scale above progress bar" ); Console.Error.WriteLine( ); Console.Error.Write( "Notes: " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "/L" ); Console.ResetColor( ); Console.Error.Write( " means the progress bar starts at the " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "minimum" ); Console.ResetColor( ); Console.Error.WriteLine( " value, whereas" ); Console.Error.WriteLine( " by default the progress bar starts at 0. If the range" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( " minimum..maximum" ); Console.ResetColor( ); Console.Error.Write( " does not include 0, " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "/L" ); Console.ResetColor( ); Console.Error.WriteLine( " is assumed." ); Console.Error.WriteLine( " Return code -1 in case of (command line) errors, otherwise 0." ); Console.Error.WriteLine( ); Console.Error.WriteLine( "Written by Rob van der Woude" ); Console.Error.WriteLine( "https://www.robvanderwoude.com" ); #endregion Display Help Text return -1; } } }