using System; using System.Collections.Generic; using System.IO; using Microsoft.Win32; namespace RobvanderWoude { class LoCase { public static string progver = "2.04"; static int Main( string[] args ) { bool ignoreerrors = false; bool verbose = false; char[] upcaseletters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray( ); int start = 0; int length = 0; List files = new List( ); List errors = new List( ); #region Command Line Parsing int namedargscount = 0; int unnamedargscount = 0; bool startspecified = false; foreach ( string arg in args ) { if ( arg[0] == '/' ) { namedargscount++; switch ( arg.ToUpper( )[1] ) { case '?': return ShowHelp( ); case 'I': if ( ignoreerrors ) { return ShowHelp( "Duplicate command line switch /I" ); } ignoreerrors = true; break; case 'L': if ( length > 0 ) { return ShowHelp( "Duplicate command line switch /L" ); } if ( arg.Length < 4 || arg[2] != ':' || !int.TryParse( arg.Substring( 3 ), out length ) || length < 1 ) { return ShowHelp( "Invalid length specified: \"{0}\"", arg ); } break; case 'S': if ( start > 0 ) { return ShowHelp( "Duplicate command line switch /S" ); } if ( arg.Length < 4 || arg[2] != ':' || !int.TryParse( arg.Substring( 3 ), out start ) || start < 0 ) { return ShowHelp( "Invalid start specified: \"{0}\"", arg ); } startspecified = true; break; case 'V': if ( verbose ) { return ShowHelp( "Duplicate command line switch /V" ); } verbose = true; break; default: return ShowHelp( "Invalid command line switch \"{0}\"", arg ); } } else { unnamedargscount++; string parentfolder = Directory.GetParent( arg ).FullName; if ( !Directory.Exists( parentfolder ) ) { return ShowHelp( "Invalid parent folder \"{0}\"", parentfolder ); } string filespec = Path.GetFileName( arg ); foreach ( string file in Directory.GetFiles( parentfolder, filespec ) ) { if ( Path.GetFileName( file ).IndexOfAny( upcaseletters ) > -1 ) { if ( !files.Contains( file ) ) { files.Add( file ); } } } } } if ( Console.IsInputRedirected && unnamedargscount > 0 ) { return ShowHelp( "Either use redirected input or specify files, but not both" ); } if ( !startspecified && length > 0 ) { return ShowHelp( "You need to specify a start value with /S if /L is used" ); } #endregion Command Line Parsing if ( Console.IsInputRedirected ) { #region Convert redirected input to lower case string input = Console.In.ReadToEnd( ); string output = string.Empty; if ( start != 0 || length != 0 ) { if ( start > 0 ) { output = input.Substring( 0, start ); } if ( length > 0 && start + length < input.Length ) { output += input.Substring( start, length ).ToLowerInvariant( ); output += input.Substring( start + length ); } else { output += input.Substring( start ).ToLowerInvariant( ); } } else { output = input.ToLowerInvariant( ); } Console.Write( output ); return 0; #endregion Convert redirected input to lower case } else { #region Rename files to lower case foreach ( string file in files ) { if ( File.Exists( file ) ) { string parentfolder = Directory.GetParent( file ).FullName; string filename = Path.GetFileName( file ); if ( filename.IndexOfAny( upcaseletters ) > -1 ) { string newfilename = string.Empty; if ( start != 0 || length != 0 ) { if ( start > 0 ) { newfilename = filename.Substring( 0, start ); } if ( start + length < filename.Length ) { newfilename += filename.Substring( start, length ).ToLowerInvariant( ); newfilename += filename.Substring( start + length ); } else { newfilename += filename.Substring( start ).ToLowerInvariant( ); } } else { newfilename = filename.ToLowerInvariant( ); } newfilename = Path.Combine( parentfolder, newfilename ); try { if ( verbose ) { Console.WriteLine( "\"{0}\" => \"{1}\"", file, newfilename ); } File.Move( file, newfilename ); } catch ( Exception e ) { Console.Error.WriteLine( "Error renaming \"{0}\": {1}", filename, e.Message ); if ( !ignoreerrors ) { return -1; } errors.Add( filename ); } } } else { if ( ignoreerrors ) { return -1; } errors.Add( Path.GetFullPath( file ) ); } } if ( verbose ) { Console.WriteLine( "{0} matching file{1} renamed", ( files.Count == 0 ? "No" : files.Count.ToString( ) ), ( files.Count == 1 ? String.Empty : "s" ) ); } if ( ignoreerrors ) { if ( verbose && errors.Count > 0 ) { if ( errors.Count == 1 ) { Console.Error.WriteLine( "An error occurred while renaming the following file:" ); Console.Error.WriteLine( "====================================================" ); } else { Console.Error.WriteLine( "Errors occurred while renaming the following files:" ); Console.Error.WriteLine( "===================================================" ); } foreach ( string error in errors ) { Console.Error.WriteLine( error ); } } return errors.Count; } else { return files.Count; } #endregion Rename files to lower case } } public 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 /* LoCase.exe, Version 2.03 Either rename specified files or render redirected input to lower case Usage: LOCASE.EXE [ filespec [ filespec [ ... ] ] ] [ options ] or: somecommand | LOCASE.EXE Where: filespec file(s) to be renamed (wildcards allowed, default: *.*) somecommand command whose output will be rendered to lower case Options: /I Ignore file IO errors and continue (see Notes) /S:n [ /L:m ] modify only the substring Starting at n with Length m (default: entire string; default length: until end) /V Verbose mode: displays file renaming and files count Notes: Use doublequotes if filespec contains non-alphnumeric characters. If no folder is specified in filespec, current directory is assumed. Return code (\"ErrorLevel\") equals the number of renamed files, or the number of errors if /I is used, or -1 in case /I is not used and an error occurred. Example: LOCASE D:\folder\MYFILE.TXT /S:1 will rename "D:\folder\MYFILE.TXT" to "D:\folder\Myfile.txt" Example: LOCASE D:\folder\MYFILE.TXT /S:0 /L:2 will rename "D:\folder\MYFILE.TXT" to "D:\folder\myFILE.TXT" Written by Rob van der Woude https://www.robvanderwoude.com */ #endregion Help Text #region Display Help Text Console.Error.WriteLine( ); Console.Error.WriteLine( "LoCase.exe, Version {0}", progver ); Console.Error.WriteLine( "Either rename specified files or render redirected input to lower case" ); Console.Error.WriteLine( ); Console.Error.Write( "Usage: " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.WriteLine( "LOCASE.EXE [ filespec [ filespec [ ... ] ] ] [ options ]" ); Console.ResetColor( ); Console.Error.WriteLine( ); Console.Error.Write( "or: " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.WriteLine( "somecommand | LOCASE.EXE" ); Console.ResetColor( ); Console.Error.WriteLine( ); Console.Error.Write( "Where: " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "filespec" ); Console.ResetColor( ); Console.Error.WriteLine( " file(s) to be renamed (wildcards allowed, default: *.*)" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( " somecommand" ); Console.ResetColor( ); Console.Error.WriteLine( " command whose output will be rendered to lower case" ); Console.Error.Write( "Options: " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "/I I" ); Console.ResetColor( ); Console.Error.WriteLine( "gnore file IO errors and continue (see Notes)" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( " /S:n [ /L:m ]" ); Console.ResetColor( ); Console.Error.Write( " modify only the substring " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "S" ); Console.ResetColor( ); Console.Error.Write( "tarting at " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "n" ); Console.ResetColor( ); Console.Error.Write( " with " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "L" ); Console.ResetColor( ); Console.Error.Write( "ength " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.WriteLine( "m" ); Console.ResetColor( ); Console.Error.WriteLine( " (default: entire string; default length: until end)" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( " /V V" ); Console.ResetColor( ); Console.Error.WriteLine( "erbose mode: displays file renaming and files count" ); Console.Error.WriteLine( ); Console.Error.WriteLine( "Notes: Use doublequotes if filespec contains non-alphnumeric characters." ); Console.Error.WriteLine( " If no folder is specified in filespec, current directory is assumed." ); Console.Error.WriteLine( " Return code (\"ErrorLevel\") equals the number of renamed files," ); Console.Error.WriteLine( " or the number of errors if /I is used, or -1 in case /I is not" ); Console.Error.WriteLine( " used and an error occurred." ); Console.Error.WriteLine( ); Console.Error.Write( "Example: " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.WriteLine( "LOCASE D:\\folder\\MYFILE.TXT /S:1" ); Console.ResetColor( ); Console.Error.Write( " will rename \"D:\\folder\\MYFILE.TXT\" to \"D:\\folder\\M" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.WriteLine( "yfile.txt\"" ); Console.ResetColor( ); Console.Error.WriteLine( ); Console.Error.Write( "Example: " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.WriteLine( "LOCASE D:\\folder\\MYFILE.TXT /S:0 /L:2" ); Console.ResetColor( ); Console.Error.Write( " will rename \"D:\\folder\\MYFILE.TXT\" to \"D:\\folder\\" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "my" ); Console.ResetColor( ); Console.Error.WriteLine( "FILE.TXT\"" ); 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; } } }