authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-02-04 19:55:32+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-02-05 02:59:13-05:00
log7d04ab1f14269b25a7ac03c3f787b3f3ee3453c3
tree098412327e45adf16215b2b700c5182dd2975fb2
parent01d48e55a5aa683828dcb88fee2d811c8262d3e9

std.process: add option to support single quotes to ArgIteratorGeneral


2 files changed, 42 insertions(+), 24 deletions(-)

lib/std/process.zig+41-23
......@@ -303,7 +303,8 @@ pub const ArgIteratorWasi = struct {
303303
304304/// Optional parameters for `ArgIteratorGeneral`
305305pub const ArgIteratorGeneralOptions = struct {
306 comments_supported: bool = false,
306 comments: bool = false,
307 single_quotes: bool = false,
307308};
308309
309310/// A general Iterator to parse a string into a set of arguments
......@@ -387,7 +388,7 @@ pub fn ArgIteratorGeneral(comptime options: ArgIteratorGeneralOptions) type {
387388 0 => return false,
388389 ' ', '\t', '\r', '\n' => continue,
389390 '#' => {
390 if (options.comments_supported) {
391 if (options.comments) {
391392 while (true) : (self.index += 1) {
392393 switch (self.cmd_line[self.index]) {
393394 '\n' => break,
......@@ -417,7 +418,11 @@ pub fn ArgIteratorGeneral(comptime options: ArgIteratorGeneralOptions) type {
417418 const character = if (self.index != self.cmd_line.len) self.cmd_line[self.index] else 0;
418419 switch (character) {
419420 0 => return true,
420 '"' => {
421 '"', '\'' => {
422 if (!options.single_quotes and character == '\'') {
423 backslash_count = 0;
424 continue;
425 }
421426 const quote_is_real = backslash_count % 2 == 0;
422427 if (quote_is_real) {
423428 in_quote = !in_quote;
......@@ -460,7 +465,13 @@ pub fn ArgIteratorGeneral(comptime options: ArgIteratorGeneralOptions) type {
460465 self.start = self.end;
461466 return token;
462467 },
463 '"' => {
468 '"', '\'' => {
469 if (!options.single_quotes and character == '\'') {
470 self.emitBackslashes(backslash_count);
471 backslash_count = 0;
472 self.emitCharacter(character);
473 continue;
474 }
464475 const quote_is_real = backslash_count % 2 == 0;
465476 self.emitBackslashes(backslash_count / 2);
466477 backslash_count = 0;
......@@ -522,7 +533,7 @@ pub fn ArgIteratorGeneral(comptime options: ArgIteratorGeneralOptions) type {
522533/// Cross-platform command line argument iterator.
523534pub const ArgIterator = struct {
524535 const InnerType = switch (builtin.os.tag) {
525 .windows => ArgIteratorGeneral(.{ .comments_supported = false }),
536 .windows => ArgIteratorGeneral(.{}),
526537 .wasi => if (builtin.link_libc) ArgIteratorPosix else ArgIteratorWasi,
527538 else => ArgIteratorPosix,
528539 };
......@@ -664,27 +675,30 @@ pub fn argsFree(allocator: mem.Allocator, args_alloc: []const [:0]u8) void {
664675}
665676
666677test "general arg parsing" {
667 try testGeneralCmdLine("a b\tc d", &[_][]const u8{ "a", "b", "c", "d" });
668 try testGeneralCmdLine("\"abc\" d e", &[_][]const u8{ "abc", "d", "e" });
669 try testGeneralCmdLine("a\\\\\\b d\"e f\"g h", &[_][]const u8{ "a\\\\\\b", "de fg", "h" });
670 try testGeneralCmdLine("a\\\\\\\"b c d", &[_][]const u8{ "a\\\"b", "c", "d" });
671 try testGeneralCmdLine("a\\\\\\\\\"b c\" d e", &[_][]const u8{ "a\\\\b c", "d", "e" });
672 try testGeneralCmdLine("a b\tc \"d f", &[_][]const u8{ "a", "b", "c", "d f" });
673 try testGeneralCmdLine("j k l\\", &[_][]const u8{ "j", "k", "l\\" });
674 try testGeneralCmdLine("\"\" x y z\\\\", &[_][]const u8{ "", "x", "y", "z\\\\" });
675
676 try testGeneralCmdLine("\".\\..\\zig-cache\\build\" \"bin\\zig.exe\" \".\\..\" \".\\..\\zig-cache\" \"--help\"", &[_][]const u8{
678 try testGeneralCmdLine("a b\tc d", &.{ "a", "b", "c", "d" });
679 try testGeneralCmdLine("\"abc\" d e", &.{ "abc", "d", "e" });
680 try testGeneralCmdLine("a\\\\\\b d\"e f\"g h", &.{ "a\\\\\\b", "de fg", "h" });
681 try testGeneralCmdLine("a\\\\\\\"b c d", &.{ "a\\\"b", "c", "d" });
682 try testGeneralCmdLine("a\\\\\\\\\"b c\" d e", &.{ "a\\\\b c", "d", "e" });
683 try testGeneralCmdLine("a b\tc \"d f", &.{ "a", "b", "c", "d f" });
684 try testGeneralCmdLine("j k l\\", &.{ "j", "k", "l\\" });
685 try testGeneralCmdLine("\"\" x y z\\\\", &.{ "", "x", "y", "z\\\\" });
686
687 try testGeneralCmdLine("\".\\..\\zig-cache\\build\" \"bin\\zig.exe\" \".\\..\" \".\\..\\zig-cache\" \"--help\"", &.{
677688 ".\\..\\zig-cache\\build",
678689 "bin\\zig.exe",
679690 ".\\..",
680691 ".\\..\\zig-cache",
681692 "--help",
682693 });
694
695 try testGeneralCmdLine(
696 \\ 'foo' "bar"
697 , &.{ "'foo'", "bar" });
683698}
684699
685700fn testGeneralCmdLine(input_cmd_line: []const u8, expected_args: []const []const u8) !void {
686 var it = try ArgIteratorGeneral(.{ .comments_supported = false })
687 .init(std.testing.allocator, input_cmd_line);
701 var it = try ArgIteratorGeneral(.{}).init(std.testing.allocator, input_cmd_line);
688702 defer it.deinit();
689703 for (expected_args) |expected_arg| {
690704 const arg = it.next().?;
......@@ -697,30 +711,34 @@ test "response file arg parsing" {
697711 try testResponseFileCmdLine(
698712 \\a b
699713 \\c d\
700 , &[_][]const u8{ "a", "b", "c", "d\\" });
701 try testResponseFileCmdLine("a b c d\\", &[_][]const u8{ "a", "b", "c", "d\\" });
714 , &.{ "a", "b", "c", "d\\" });
715 try testResponseFileCmdLine("a b c d\\", &.{ "a", "b", "c", "d\\" });
702716
703717 try testResponseFileCmdLine(
704718 \\j
705719 \\ k l # this is a comment \\ \\\ \\\\ "none" "\\" "\\\"
706720 \\ "m" #another comment
707721 \\
708 , &[_][]const u8{ "j", "k", "l", "m" });
722 , &.{ "j", "k", "l", "m" });
709723
710724 try testResponseFileCmdLine(
711725 \\ "" q ""
712726 \\ "r s # t" "u\" v" #another comment
713727 \\
714 , &[_][]const u8{ "", "q", "", "r s # t", "u\" v" });
728 , &.{ "", "q", "", "r s # t", "u\" v" });
715729
716730 try testResponseFileCmdLine(
717731 \\ -l"advapi32" a# b#c d#
718732 \\e\\\
719 , &[_][]const u8{ "-ladvapi32", "a#", "b#c", "d#", "e\\\\\\" });
733 , &.{ "-ladvapi32", "a#", "b#c", "d#", "e\\\\\\" });
734
735 try testResponseFileCmdLine(
736 \\ 'foo' "bar"
737 , &.{ "foo", "bar" });
720738}
721739
722740fn testResponseFileCmdLine(input_cmd_line: []const u8, expected_args: []const []const u8) !void {
723 var it = try ArgIteratorGeneral(.{ .comments_supported = true })
741 var it = try ArgIteratorGeneral(.{ .comments = true, .single_quotes = true })
724742 .init(std.testing.allocator, input_cmd_line);
725743 defer it.deinit();
726744 for (expected_args) |expected_arg| {
src/main.zig+1-1
......@@ -4230,7 +4230,7 @@ pub const ClangArgIterator = struct {
42304230 };
42314231 }
42324232
4233 const ArgIteratorResponseFile = process.ArgIteratorGeneral(.{ .comments_supported = true });
4233 const ArgIteratorResponseFile = process.ArgIteratorGeneral(.{ .comments = true, .single_quotes = true });
42344234
42354235 /// Initialize the arguments from a Response File. "*.rsp"
42364236 fn initArgIteratorResponseFile(allocator: Allocator, resp_file_path: []const u8) !ArgIteratorResponseFile {