Replace.cs 7.1 KB

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