Files
RobustToolbox/Robust.Shared/Utility/CommandParsing.cs

134 lines
3.7 KiB
C#

using System;
using System.Buffers;
using System.Collections.Generic;
using System.Text;
using Robust.Shared.Collections;
namespace Robust.Shared.Utility
{
public static class CommandParsing
{
private static readonly SearchValues<char> CommandArgumentSeparator = SearchValues.Create(" ");
/// <summary>
/// Parses a full console command into a list of arguments.
/// </summary>
/// <param name="text">Full input string.</param>
/// <param name="args">List of arguments to write into.</param>
public static void ParseArguments(ReadOnlySpan<char> text, List<string> args)
{
var ranges = new ValueList<(int, int)>();
ParseArguments(text, args, ref ranges);
}
internal static void ParseArguments(
ReadOnlySpan<char> text,
List<string> args,
ref ValueList<(int start, int end)> ranges)
{
var sb = new StringBuilder();
var inQuotes = false;
var startPos = -1;
for (var i = 0; i < text.Length; i++)
{
var chr = text[i];
if (chr == '\\')
{
i += 1;
startPos = i;
if (i == text.Length)
{
sb.Append('\\');
break;
}
sb.Append(text[i]);
continue;
}
if (chr == '"')
{
if (inQuotes)
{
args.Add(sb.ToString());
sb.Clear();
ranges.Add((startPos, i + 1));
startPos = -1;
}
else
{
if (startPos < 0)
startPos = i;
}
inQuotes = !inQuotes;
continue;
}
if (CommandArgumentSeparator.Contains(chr) && !inQuotes)
{
if (sb.Length != 0)
{
args.Add(sb.ToString());
sb.Clear();
ranges.Add((startPos, i));
startPos = -1;
}
continue;
}
if (startPos < 0)
startPos = i;
sb.Append(chr);
}
if (sb.Length != 0)
{
args.Add(sb.ToString());
ranges.Add((startPos, text.Length));
}
}
public static string Escape(string text)
{
return text.Replace("\\", "\\\\").Replace("\"", "\\\"");
}
/// <summary>
/// Split a set of arguments into a string that can be parsed round-trip.
/// </summary>
/// <remarks>
/// <para>
/// This is effectively the inverse of <see cref="ParseArguments"/>.
/// </para>
/// </remarks>
public static string EscapeCommand(params string[] arguments)
{
var sb = new StringBuilder();
var first = true;
foreach (var entry in arguments)
{
if (!first)
sb.Append(' ');
first = false;
var quoted = entry.ContainsAny(CommandArgumentSeparator);
if (quoted)
sb.Append('"');
sb.Append(Escape(entry));
if (quoted)
sb.Append('"');
}
return sb.ToString();
}
}
}