1*affba8c7SCy Schubert /* 2*affba8c7SCy Schubert ** 2016 February 26 3*affba8c7SCy Schubert ** 4*affba8c7SCy Schubert ** The author disclaims copyright to this source code. In place of 5*affba8c7SCy Schubert ** a legal notice, here is a blessing: 6*affba8c7SCy Schubert ** 7*affba8c7SCy Schubert ** May you do good and not evil. 8*affba8c7SCy Schubert ** May you find forgiveness for yourself and forgive others. 9*affba8c7SCy Schubert ** May you share freely, never taking more than you give. 10*affba8c7SCy Schubert ** 11*affba8c7SCy Schubert ************************************************************************* 12*affba8c7SCy Schubert ** This file contains C# code to perform regular expression replacements 13*affba8c7SCy Schubert ** using the standard input and output channels. 14*affba8c7SCy Schubert */ 15*affba8c7SCy Schubert 16*affba8c7SCy Schubert using System; 17*affba8c7SCy Schubert using System.Diagnostics; 18*affba8c7SCy Schubert using System.IO; 19*affba8c7SCy Schubert using System.Reflection; 20*affba8c7SCy Schubert using System.Runtime.InteropServices; 21*affba8c7SCy Schubert using System.Text.RegularExpressions; 22*affba8c7SCy Schubert 23*affba8c7SCy Schubert /////////////////////////////////////////////////////////////////////////////// 24*affba8c7SCy Schubert 25*affba8c7SCy Schubert #region Assembly Metadata 26*affba8c7SCy Schubert [assembly: AssemblyTitle("Replace Tool")] 27*affba8c7SCy Schubert [assembly: AssemblyDescription("Replace text using standard input/output.")] 28*affba8c7SCy Schubert [assembly: AssemblyCompany("SQLite Development Team")] 29*affba8c7SCy Schubert [assembly: AssemblyProduct("SQLite")] 30*affba8c7SCy Schubert [assembly: AssemblyCopyright("Public Domain")] 31*affba8c7SCy Schubert [assembly: ComVisible(false)] 32*affba8c7SCy Schubert [assembly: Guid("95a0513f-8863-48cd-a76f-cb80868cb578")] 33*affba8c7SCy Schubert [assembly: AssemblyVersion("1.0.*")] 34*affba8c7SCy Schubert 35*affba8c7SCy Schubert #if DEBUG 36*affba8c7SCy Schubert [assembly: AssemblyConfiguration("Debug")] 37*affba8c7SCy Schubert #else 38*affba8c7SCy Schubert [assembly: AssemblyConfiguration("Release")] 39*affba8c7SCy Schubert #endif 40*affba8c7SCy Schubert #endregion 41*affba8c7SCy Schubert 42*affba8c7SCy Schubert /////////////////////////////////////////////////////////////////////////////// 43*affba8c7SCy Schubert 44*affba8c7SCy Schubert namespace Replace 45*affba8c7SCy Schubert { 46*affba8c7SCy Schubert /// <summary> 47*affba8c7SCy Schubert /// This enumeration is used to represent all the possible exit codes from 48*affba8c7SCy Schubert /// this tool. 49*affba8c7SCy Schubert /// </summary> 50*affba8c7SCy Schubert internal enum ExitCode 51*affba8c7SCy Schubert { 52*affba8c7SCy Schubert /// <summary> 53*affba8c7SCy Schubert /// The file download was a success. 54*affba8c7SCy Schubert /// </summary> 55*affba8c7SCy Schubert Success = 0, 56*affba8c7SCy Schubert 57*affba8c7SCy Schubert /// <summary> 58*affba8c7SCy Schubert /// The command line arguments are missing (i.e. null). Generally, 59*affba8c7SCy Schubert /// this should not happen. 60*affba8c7SCy Schubert /// </summary> 61*affba8c7SCy Schubert MissingArgs = 1, 62*affba8c7SCy Schubert 63*affba8c7SCy Schubert /// <summary> 64*affba8c7SCy Schubert /// The wrong number of command line arguments was supplied. 65*affba8c7SCy Schubert /// </summary> 66*affba8c7SCy Schubert WrongNumArgs = 2, 67*affba8c7SCy Schubert 68*affba8c7SCy Schubert /// <summary> 69*affba8c7SCy Schubert /// The "matchingOnly" flag could not be converted to a value of the 70*affba8c7SCy Schubert /// <see cref="Boolean"/> type. 71*affba8c7SCy Schubert /// </summary> 72*affba8c7SCy Schubert BadMatchingOnlyFlag = 3, 73*affba8c7SCy Schubert 74*affba8c7SCy Schubert /// <summary> 75*affba8c7SCy Schubert /// An exception was caught in <see cref="Main" />. Generally, this 76*affba8c7SCy Schubert /// should not happen. 77*affba8c7SCy Schubert /// </summary> 78*affba8c7SCy Schubert Exception = 4 79*affba8c7SCy Schubert } 80*affba8c7SCy Schubert 81*affba8c7SCy Schubert /////////////////////////////////////////////////////////////////////////// 82*affba8c7SCy Schubert 83*affba8c7SCy Schubert internal static class Replace 84*affba8c7SCy Schubert { 85*affba8c7SCy Schubert #region Private Support Methods 86*affba8c7SCy Schubert /// <summary> 87*affba8c7SCy Schubert /// This method displays an error message to the console and/or 88*affba8c7SCy Schubert /// displays the command line usage information for this tool. 89*affba8c7SCy Schubert /// </summary> 90*affba8c7SCy Schubert /// <param name="message"> 91*affba8c7SCy Schubert /// The error message to display, if any. 92*affba8c7SCy Schubert /// </param> 93*affba8c7SCy Schubert /// <param name="usage"> 94*affba8c7SCy Schubert /// Non-zero to display the command line usage information. 95*affba8c7SCy Schubert /// </param> Error( string message, bool usage )96*affba8c7SCy Schubert private static void Error( 97*affba8c7SCy Schubert string message, 98*affba8c7SCy Schubert bool usage 99*affba8c7SCy Schubert ) 100*affba8c7SCy Schubert { 101*affba8c7SCy Schubert if (message != null) 102*affba8c7SCy Schubert Console.WriteLine(message); 103*affba8c7SCy Schubert 104*affba8c7SCy Schubert string fileName = Path.GetFileName( 105*affba8c7SCy Schubert Process.GetCurrentProcess().MainModule.FileName); 106*affba8c7SCy Schubert 107*affba8c7SCy Schubert Console.WriteLine(String.Format( 108*affba8c7SCy Schubert "usage: {0} <regExPattern> <regExSubSpec> <matchingOnly>", 109*affba8c7SCy Schubert fileName)); 110*affba8c7SCy Schubert } 111*affba8c7SCy Schubert #endregion 112*affba8c7SCy Schubert 113*affba8c7SCy Schubert /////////////////////////////////////////////////////////////////////// 114*affba8c7SCy Schubert 115*affba8c7SCy Schubert #region Program Entry Point 116*affba8c7SCy Schubert /// <summary> 117*affba8c7SCy Schubert /// This is the entry-point for this tool. It handles processing the 118*affba8c7SCy Schubert /// command line arguments, reading from the standard input channel, 119*affba8c7SCy Schubert /// replacing any matching lines of text, and writing to the standard 120*affba8c7SCy Schubert /// output channel. 121*affba8c7SCy Schubert /// </summary> 122*affba8c7SCy Schubert /// <param name="args"> 123*affba8c7SCy Schubert /// The command line arguments. 124*affba8c7SCy Schubert /// </param> 125*affba8c7SCy Schubert /// <returns> 126*affba8c7SCy Schubert /// Zero upon success; non-zero on failure. This will be one of the 127*affba8c7SCy Schubert /// values from the <see cref="ExitCode" /> enumeration. 128*affba8c7SCy Schubert /// </returns> Main( string[] args )129*affba8c7SCy Schubert private static int Main( 130*affba8c7SCy Schubert string[] args 131*affba8c7SCy Schubert ) 132*affba8c7SCy Schubert { 133*affba8c7SCy Schubert // 134*affba8c7SCy Schubert // NOTE: Sanity check the command line arguments. 135*affba8c7SCy Schubert // 136*affba8c7SCy Schubert if (args == null) 137*affba8c7SCy Schubert { 138*affba8c7SCy Schubert Error(null, true); 139*affba8c7SCy Schubert return (int)ExitCode.MissingArgs; 140*affba8c7SCy Schubert } 141*affba8c7SCy Schubert 142*affba8c7SCy Schubert if (args.Length != 3) 143*affba8c7SCy Schubert { 144*affba8c7SCy Schubert Error(null, true); 145*affba8c7SCy Schubert return (int)ExitCode.WrongNumArgs; 146*affba8c7SCy Schubert } 147*affba8c7SCy Schubert 148*affba8c7SCy Schubert try 149*affba8c7SCy Schubert { 150*affba8c7SCy Schubert // 151*affba8c7SCy Schubert // NOTE: Create a regular expression from the first command 152*affba8c7SCy Schubert // line argument. Then, grab the replacement string, 153*affba8c7SCy Schubert // which is the second argument. 154*affba8c7SCy Schubert // 155*affba8c7SCy Schubert Regex regEx = new Regex(args[0]); 156*affba8c7SCy Schubert string replacement = args[1]; 157*affba8c7SCy Schubert 158*affba8c7SCy Schubert // 159*affba8c7SCy Schubert // NOTE: Attempt to convert the third argument to a boolean. 160*affba8c7SCy Schubert // 161*affba8c7SCy Schubert bool matchingOnly; 162*affba8c7SCy Schubert 163*affba8c7SCy Schubert if (!bool.TryParse(args[2], out matchingOnly)) 164*affba8c7SCy Schubert { 165*affba8c7SCy Schubert Error(null, true); 166*affba8c7SCy Schubert return (int)ExitCode.BadMatchingOnlyFlag; 167*affba8c7SCy Schubert } 168*affba8c7SCy Schubert 169*affba8c7SCy Schubert // 170*affba8c7SCy Schubert // NOTE: Grab the standard input and output channels from the 171*affba8c7SCy Schubert // console. 172*affba8c7SCy Schubert // 173*affba8c7SCy Schubert TextReader inputTextReader = Console.In; 174*affba8c7SCy Schubert TextWriter outputTextWriter = Console.Out; 175*affba8c7SCy Schubert 176*affba8c7SCy Schubert // 177*affba8c7SCy Schubert // NOTE: Loop until end-of-file is hit on the standard input 178*affba8c7SCy Schubert // stream. 179*affba8c7SCy Schubert // 180*affba8c7SCy Schubert while (true) 181*affba8c7SCy Schubert { 182*affba8c7SCy Schubert // 183*affba8c7SCy Schubert // NOTE: Read a line from the standard input channel. If 184*affba8c7SCy Schubert // null is returned here, there is no more input and 185*affba8c7SCy Schubert // we are done. 186*affba8c7SCy Schubert // 187*affba8c7SCy Schubert string inputLine = inputTextReader.ReadLine(); 188*affba8c7SCy Schubert 189*affba8c7SCy Schubert if (inputLine == null) 190*affba8c7SCy Schubert break; 191*affba8c7SCy Schubert 192*affba8c7SCy Schubert // 193*affba8c7SCy Schubert // NOTE: Perform regular expression replacements on this 194*affba8c7SCy Schubert // line, if any. Then, write the modified line to 195*affba8c7SCy Schubert // the standard output channel. 196*affba8c7SCy Schubert // 197*affba8c7SCy Schubert string outputLine = regEx.Replace(inputLine, replacement); 198*affba8c7SCy Schubert 199*affba8c7SCy Schubert if (!matchingOnly || !String.Equals( 200*affba8c7SCy Schubert inputLine, outputLine, StringComparison.Ordinal)) 201*affba8c7SCy Schubert { 202*affba8c7SCy Schubert outputTextWriter.WriteLine(outputLine); 203*affba8c7SCy Schubert } 204*affba8c7SCy Schubert } 205*affba8c7SCy Schubert 206*affba8c7SCy Schubert // 207*affba8c7SCy Schubert // NOTE: At this point, everything has succeeded. 208*affba8c7SCy Schubert // 209*affba8c7SCy Schubert return (int)ExitCode.Success; 210*affba8c7SCy Schubert } 211*affba8c7SCy Schubert catch (Exception e) 212*affba8c7SCy Schubert { 213*affba8c7SCy Schubert // 214*affba8c7SCy Schubert // NOTE: An exception was caught. Report it via the console 215*affba8c7SCy Schubert // and return failure. 216*affba8c7SCy Schubert // 217*affba8c7SCy Schubert Error(e.ToString(), false); 218*affba8c7SCy Schubert return (int)ExitCode.Exception; 219*affba8c7SCy Schubert } 220*affba8c7SCy Schubert } 221*affba8c7SCy Schubert #endregion 222*affba8c7SCy Schubert } 223*affba8c7SCy Schubert } 224