Last active
September 14, 2020 11:13
-
-
Save raygun101/1d93f2a7f04e1c51bfb9b82290a5b453 to your computer and use it in GitHub Desktop.
馃嵃 Layered Cakewalk [Dart] - Parses/splits a command-line String into a List<String> of the individual argument elements processing quotes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Original implementation: https://stackoverflow.com/a/39177861/638848 | |
// | |
// Re-made by: Leslie Godwin ([email protected]) | |
import 'dart:convert'; | |
/// Parses/splits a command-line String into a List<String> of the individual argument elements. | |
/// Handles whitespace, quotes and back\slash escape. | |
/// | |
/// ### Example: | |
/// ``` | |
/// command-line $> command -x value -y "value with 'spaces'" -z value\ with\'\ spaces | |
/// result-arguments : ["command", "-x", "value", "y", "value with 'spaces'", "-z", "value with' spaces"] | |
/// ``` | |
class CommandlineSplittingConverter extends Converter<String, List<String>> | |
{ | |
@override | |
List<String> convert(String input) | |
{ | |
if (input == null || input.isEmpty) { return []; } // 猡达笍 | |
final result = <String>[]; | |
var current = ""; | |
String inEscape = null; | |
int inPosition = null; | |
for (int index = 0; index < input.length; index++) | |
{ | |
final token = input[index]; | |
if (inEscape != null) | |
{ | |
switch (inEscape) | |
{ | |
case "\\": | |
inEscape = null; | |
inPosition = null; | |
current += token; | |
continue; // 猡达笍 | |
default: | |
if (token == inEscape) | |
{ | |
result.add(current); // allow empty | |
current = ""; | |
inEscape = null; | |
inPosition = null; | |
} | |
else | |
{ | |
current += token; | |
} | |
} | |
} | |
else | |
{ | |
switch (token) | |
{ | |
case "'": // ' (Single quote) | |
case '"': // "" (Double quote) | |
case "\\": // \ (Escape) | |
inEscape = token; | |
inPosition = index; | |
continue; // 猡达笍 | |
case " ": // space | |
if (current.isNotEmpty) | |
{ | |
result.add(current); | |
current = ""; | |
} | |
continue; // 猡达笍 | |
default: | |
current += token; | |
} | |
} | |
} | |
if (inEscape != null) | |
{ | |
throw new FormatException("Unbalanced quote $inEscape in input.", input, inPosition); | |
} | |
if (current.isNotEmpty) | |
{ | |
result.add(current); | |
} | |
return result; | |
} | |
} | |
// //Tests | |
// | |
// Set<E> diff <E> (Iterable<E> lhs, Iterable<E> rhs) | |
// { | |
// final a = Set.of(lhs); | |
// final b = Set.of(rhs); | |
// return a.difference(b)..addAll(b.difference(a)); | |
// } | |
// Set<String> commandlineDiff (String lhs, List<String> rhs) | |
// { | |
// return diff(CommandlineSplittingConverter().convert(lhs), rhs); | |
// } | |
// test("$CommandlineSplittingConverter", () | |
// { | |
// expect | |
// ( | |
// commandlineDiff("", []), | |
// isEmpty | |
// ); | |
// expect | |
// ( | |
// commandlineDiff("command", ["command"]), | |
// isEmpty | |
// ); | |
// expect | |
// ( | |
// commandlineDiff("command -arg 1 -arg2 'f r\"ed'", ["command", "-arg", "1", "-arg2", "f r\"ed"]), | |
// isEmpty | |
// ); | |
// expect | |
// ( | |
// commandlineDiff('command -arg 1 -arg2 "f r\'ed"', ["command", "-arg", "1", "-arg2", "f r'ed"]), | |
// isEmpty | |
// ); | |
// expect | |
// ( | |
// commandlineDiff("command -x value -y \"value with 'spaces'\" -z value\\ with\\'\\ spaces", ["command", "-x", "value", "-y", "value with 'spaces'", "-z", "value with' spaces"]), | |
// isEmpty | |
// ); | |
// expect | |
// ( | |
// () => CommandlineSplittingConverter().convert('command -arg 1 -arg2 "f r\'ed'), | |
// throwsFormatException | |
// ); | |
// }); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment