Replace.cs revision 304732
1304732Scy/* 2304732Scy** 2016 February 26 3304732Scy** 4304732Scy** The author disclaims copyright to this source code. In place of 5304732Scy** a legal notice, here is a blessing: 6304732Scy** 7304732Scy** May you do good and not evil. 8304732Scy** May you find forgiveness for yourself and forgive others. 9304732Scy** May you share freely, never taking more than you give. 10304732Scy** 11304732Scy************************************************************************* 12304732Scy** This file contains C# code to perform regular expression replacements 13304732Scy** using the standard input and output channels. 14304732Scy*/ 15304732Scy 16304732Scyusing System; 17304732Scyusing System.Diagnostics; 18304732Scyusing System.IO; 19304732Scyusing System.Reflection; 20304732Scyusing System.Runtime.InteropServices; 21304732Scyusing System.Text.RegularExpressions; 22304732Scy 23304732Scy/////////////////////////////////////////////////////////////////////////////// 24304732Scy 25304732Scy#region Assembly Metadata 26304732Scy[assembly: AssemblyTitle("Replace Tool")] 27304732Scy[assembly: AssemblyDescription("Replace text using standard input/output.")] 28304732Scy[assembly: AssemblyCompany("SQLite Development Team")] 29304732Scy[assembly: AssemblyProduct("SQLite")] 30304732Scy[assembly: AssemblyCopyright("Public Domain")] 31304732Scy[assembly: ComVisible(false)] 32304732Scy[assembly: Guid("95a0513f-8863-48cd-a76f-cb80868cb578")] 33304732Scy[assembly: AssemblyVersion("1.0.*")] 34304732Scy 35304732Scy#if DEBUG 36304732Scy[assembly: AssemblyConfiguration("Debug")] 37304732Scy#else 38304732Scy[assembly: AssemblyConfiguration("Release")] 39304732Scy#endif 40304732Scy#endregion 41304732Scy 42304732Scy/////////////////////////////////////////////////////////////////////////////// 43304732Scy 44304732Scynamespace Replace 45304732Scy{ 46304732Scy /// <summary> 47304732Scy /// This enumeration is used to represent all the possible exit codes from 48304732Scy /// this tool. 49304732Scy /// </summary> 50304732Scy internal enum ExitCode 51304732Scy { 52304732Scy /// <summary> 53304732Scy /// The file download was a success. 54304732Scy /// </summary> 55304732Scy Success = 0, 56304732Scy 57304732Scy /// <summary> 58304732Scy /// The command line arguments are missing (i.e. null). Generally, 59304732Scy /// this should not happen. 60304732Scy /// </summary> 61304732Scy MissingArgs = 1, 62304732Scy 63304732Scy /// <summary> 64304732Scy /// The wrong number of command line arguments was supplied. 65304732Scy /// </summary> 66304732Scy WrongNumArgs = 2, 67304732Scy 68304732Scy /// <summary> 69304732Scy /// The "matchingOnly" flag could not be converted to a value of the 70304732Scy /// <see cref="Boolean"/> type. 71304732Scy /// </summary> 72304732Scy BadMatchingOnlyFlag = 3, 73304732Scy 74304732Scy /// <summary> 75304732Scy /// An exception was caught in <see cref="Main" />. Generally, this 76304732Scy /// should not happen. 77304732Scy /// </summary> 78304732Scy Exception = 4 79304732Scy } 80304732Scy 81304732Scy /////////////////////////////////////////////////////////////////////////// 82304732Scy 83304732Scy internal static class Replace 84304732Scy { 85304732Scy #region Private Support Methods 86304732Scy /// <summary> 87304732Scy /// This method displays an error message to the console and/or 88304732Scy /// displays the command line usage information for this tool. 89304732Scy /// </summary> 90304732Scy /// <param name="message"> 91304732Scy /// The error message to display, if any. 92304732Scy /// </param> 93304732Scy /// <param name="usage"> 94304732Scy /// Non-zero to display the command line usage information. 95304732Scy /// </param> 96304732Scy private static void Error( 97304732Scy string message, 98304732Scy bool usage 99304732Scy ) 100304732Scy { 101304732Scy if (message != null) 102304732Scy Console.WriteLine(message); 103304732Scy 104304732Scy string fileName = Path.GetFileName( 105304732Scy Process.GetCurrentProcess().MainModule.FileName); 106304732Scy 107304732Scy Console.WriteLine(String.Format( 108304732Scy "usage: {0} <regExPattern> <regExSubSpec> <matchingOnly>", 109304732Scy fileName)); 110304732Scy } 111304732Scy #endregion 112304732Scy 113304732Scy /////////////////////////////////////////////////////////////////////// 114304732Scy 115304732Scy #region Program Entry Point 116304732Scy /// <summary> 117304732Scy /// This is the entry-point for this tool. It handles processing the 118304732Scy /// command line arguments, reading from the standard input channel, 119304732Scy /// replacing any matching lines of text, and writing to the standard 120304732Scy /// output channel. 121304732Scy /// </summary> 122304732Scy /// <param name="args"> 123304732Scy /// The command line arguments. 124304732Scy /// </param> 125304732Scy /// <returns> 126304732Scy /// Zero upon success; non-zero on failure. This will be one of the 127304732Scy /// values from the <see cref="ExitCode" /> enumeration. 128304732Scy /// </returns> 129304732Scy private static int Main( 130304732Scy string[] args 131304732Scy ) 132304732Scy { 133304732Scy // 134304732Scy // NOTE: Sanity check the command line arguments. 135304732Scy // 136304732Scy if (args == null) 137304732Scy { 138304732Scy Error(null, true); 139304732Scy return (int)ExitCode.MissingArgs; 140304732Scy } 141304732Scy 142304732Scy if (args.Length != 3) 143304732Scy { 144304732Scy Error(null, true); 145304732Scy return (int)ExitCode.WrongNumArgs; 146304732Scy } 147304732Scy 148304732Scy try 149304732Scy { 150304732Scy // 151304732Scy // NOTE: Create a regular expression from the first command 152304732Scy // line argument. Then, grab the replacement string, 153304732Scy // which is the second argument. 154304732Scy // 155304732Scy Regex regEx = new Regex(args[0]); 156304732Scy string replacement = args[1]; 157304732Scy 158304732Scy // 159304732Scy // NOTE: Attempt to convert the third argument to a boolean. 160304732Scy // 161304732Scy bool matchingOnly; 162304732Scy 163304732Scy if (!bool.TryParse(args[2], out matchingOnly)) 164304732Scy { 165304732Scy Error(null, true); 166304732Scy return (int)ExitCode.BadMatchingOnlyFlag; 167304732Scy } 168304732Scy 169304732Scy // 170304732Scy // NOTE: Grab the standard input and output channels from the 171304732Scy // console. 172304732Scy // 173304732Scy TextReader inputTextReader = Console.In; 174304732Scy TextWriter outputTextWriter = Console.Out; 175304732Scy 176304732Scy // 177304732Scy // NOTE: Loop until end-of-file is hit on the standard input 178304732Scy // stream. 179304732Scy // 180304732Scy while (true) 181304732Scy { 182304732Scy // 183304732Scy // NOTE: Read a line from the standard input channel. If 184304732Scy // null is returned here, there is no more input and 185304732Scy // we are done. 186304732Scy // 187304732Scy string inputLine = inputTextReader.ReadLine(); 188304732Scy 189304732Scy if (inputLine == null) 190304732Scy break; 191304732Scy 192304732Scy // 193304732Scy // NOTE: Perform regular expression replacements on this 194304732Scy // line, if any. Then, write the modified line to 195304732Scy // the standard output channel. 196304732Scy // 197304732Scy string outputLine = regEx.Replace(inputLine, replacement); 198304732Scy 199304732Scy if (!matchingOnly || !String.Equals( 200304732Scy inputLine, outputLine, StringComparison.Ordinal)) 201304732Scy { 202304732Scy outputTextWriter.WriteLine(outputLine); 203304732Scy } 204304732Scy } 205304732Scy 206304732Scy // 207304732Scy // NOTE: At this point, everything has succeeded. 208304732Scy // 209304732Scy return (int)ExitCode.Success; 210304732Scy } 211304732Scy catch (Exception e) 212304732Scy { 213304732Scy // 214304732Scy // NOTE: An exception was caught. Report it via the console 215304732Scy // and return failure. 216304732Scy // 217304732Scy Error(e.ToString(), false); 218304732Scy return (int)ExitCode.Exception; 219304732Scy } 220304732Scy } 221304732Scy #endregion 222304732Scy } 223304732Scy} 224