xref: /freebsd/contrib/sqlite3/Replace.cs (revision 491cdc1b53f354691f264552159c76c15b96fea9)
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