process/src/Process/Builders/ArgumentsBuilder.cs
Louis Seubert 833bc2bd9c
All checks were successful
default / default (8.0) (push) Successful in 39s
feat: initial project commit
2024-04-27 20:18:42 +02:00

137 lines
No EOL
3.1 KiB
C#

using System.Globalization;
using System.Text;
namespace Geekeey.Extensions.Process;
/// <summary>
/// Builder that helps format command-line arguments into a string.
/// </summary>
public sealed partial class ArgumentsBuilder
{
private static readonly IFormatProvider DefaultFormatProvider = CultureInfo.InvariantCulture;
private readonly StringBuilder _buffer = new();
/// <summary>
/// Adds the specified value to the list of arguments.
/// </summary>
public ArgumentsBuilder Add(string value, bool escape = true)
{
if (_buffer.Length > 0)
_buffer.Append(' ');
_buffer.Append(escape ? Escape(value) : value);
return this;
}
/// <summary>
/// Adds the specified values to the list of arguments.
/// </summary>
public ArgumentsBuilder Add(IEnumerable<string> values, bool escape = true)
{
foreach (var value in values)
{
Add(value, escape);
}
return this;
}
/// <summary>
/// Adds the specified value to the list of arguments.
/// </summary>
public ArgumentsBuilder Add(IFormattable value, IFormatProvider formatProvider, bool escape = true)
=> Add(value.ToString(null, formatProvider), escape);
/// <summary>
/// Adds the specified value to the list of arguments.
/// The value is converted to string using invariant culture.
/// </summary>
public ArgumentsBuilder Add(IFormattable value, bool escape = true)
=> Add(value, DefaultFormatProvider, escape);
/// <summary>
/// Adds the specified values to the list of arguments.
/// </summary>
public ArgumentsBuilder Add(IEnumerable<IFormattable> values, IFormatProvider formatProvider, bool escape = true)
{
foreach (var value in values)
{
Add(value, formatProvider, escape);
}
return this;
}
/// <summary>
/// Adds the specified values to the list of arguments.
/// The values are converted to string using invariant culture.
/// </summary>
public ArgumentsBuilder Add(IEnumerable<IFormattable> values, bool escape = true)
=> Add(values, DefaultFormatProvider, escape);
/// <summary>
/// Builds the resulting arguments string.
/// </summary>
public string Build() => _buffer.ToString();
}
public partial class ArgumentsBuilder
{
private static string Escape(string argument)
{
// Short circuit if the argument is clean and doesn't need escaping
if (argument.Length > 0 && argument.All(c => !char.IsWhiteSpace(c) && c is not '"'))
return argument;
var buffer = new StringBuilder();
buffer.Append('"');
for (var i = 0; i < argument.Length;)
{
var c = argument[i++];
switch (c)
{
case '\\':
{
var backslashCount = 1;
while (i < argument.Length && argument[i] == '\\')
{
backslashCount++;
i++;
}
if (i == argument.Length)
{
buffer.Append('\\', backslashCount * 2);
}
else if (argument[i] == '"')
{
buffer.Append('\\', backslashCount * 2 + 1).Append('"');
i++;
}
else
{
buffer.Append('\\', backslashCount);
}
break;
}
case '"':
buffer.Append('\\').Append('"');
break;
default:
buffer.Append(c);
break;
}
}
buffer.Append('"');
return buffer.ToString();
}
}