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 {...@@ -303,7 +303,8 @@ pub const ArgIteratorWasi = struct {
303303
304/// Optional parameters for `ArgIteratorGeneral`304/// Optional parameters for `ArgIteratorGeneral`
305pub const ArgIteratorGeneralOptions = struct {305pub const ArgIteratorGeneralOptions = struct {
306 comments_supported: bool = false,306 comments: bool = false,
307 single_quotes: bool = false,
307};308};
308309
309/// A general Iterator to parse a string into a set of arguments310/// A general Iterator to parse a string into a set of arguments
...@@ -387,7 +388,7 @@ pub fn ArgIteratorGeneral(comptime options: ArgIteratorGeneralOptions) type {...@@ -387,7 +388,7 @@ pub fn ArgIteratorGeneral(comptime options: ArgIteratorGeneralOptions) type {
387 0 => return false,388 0 => return false,
388 ' ', '\t', '\r', '\n' => continue,389 ' ', '\t', '\r', '\n' => continue,
389 '#' => {390 '#' => {
390 if (options.comments_supported) {391 if (options.comments) {
391 while (true) : (self.index += 1) {392 while (true) : (self.index += 1) {
392 switch (self.cmd_line[self.index]) {393 switch (self.cmd_line[self.index]) {
393 '\n' => break,394 '\n' => break,
...@@ -417,7 +418,11 @@ pub fn ArgIteratorGeneral(comptime options: ArgIteratorGeneralOptions) type {...@@ -417,7 +418,11 @@ pub fn ArgIteratorGeneral(comptime options: ArgIteratorGeneralOptions) type {
417 const character = if (self.index != self.cmd_line.len) self.cmd_line[self.index] else 0;418 const character = if (self.index != self.cmd_line.len) self.cmd_line[self.index] else 0;
418 switch (character) {419 switch (character) {
419 0 => return true,420 0 => return true,
420 '"' => {421 '"', '\'' => {
422 if (!options.single_quotes and character == '\'') {
423 backslash_count = 0;
424 continue;
425 }
421 const quote_is_real = backslash_count % 2 == 0;426 const quote_is_real = backslash_count % 2 == 0;
422 if (quote_is_real) {427 if (quote_is_real) {
423 in_quote = !in_quote;428 in_quote = !in_quote;
...@@ -460,7 +465,13 @@ pub fn ArgIteratorGeneral(comptime options: ArgIteratorGeneralOptions) type {...@@ -460,7 +465,13 @@ pub fn ArgIteratorGeneral(comptime options: ArgIteratorGeneralOptions) type {
460 self.start = self.end;465 self.start = self.end;
461 return token;466 return token;
462 },467 },
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 }
464 const quote_is_real = backslash_count % 2 == 0;475 const quote_is_real = backslash_count % 2 == 0;
465 self.emitBackslashes(backslash_count / 2);476 self.emitBackslashes(backslash_count / 2);
466 backslash_count = 0;477 backslash_count = 0;
...@@ -522,7 +533,7 @@ pub fn ArgIteratorGeneral(comptime options: ArgIteratorGeneralOptions) type {...@@ -522,7 +533,7 @@ pub fn ArgIteratorGeneral(comptime options: ArgIteratorGeneralOptions) type {
522/// Cross-platform command line argument iterator.533/// Cross-platform command line argument iterator.
523pub const ArgIterator = struct {534pub const ArgIterator = struct {
524 const InnerType = switch (builtin.os.tag) {535 const InnerType = switch (builtin.os.tag) {
525 .windows => ArgIteratorGeneral(.{ .comments_supported = false }),536 .windows => ArgIteratorGeneral(.{}),
526 .wasi => if (builtin.link_libc) ArgIteratorPosix else ArgIteratorWasi,537 .wasi => if (builtin.link_libc) ArgIteratorPosix else ArgIteratorWasi,
527 else => ArgIteratorPosix,538 else => ArgIteratorPosix,
528 };539 };
...@@ -664,27 +675,30 @@ pub fn argsFree(allocator: mem.Allocator, args_alloc: []const [:0]u8) void {...@@ -664,27 +675,30 @@ pub fn argsFree(allocator: mem.Allocator, args_alloc: []const [:0]u8) void {
664}675}
665676
666test "general arg parsing" {677test "general arg parsing" {
667 try testGeneralCmdLine("a b\tc d", &[_][]const u8{ "a", "b", "c", "d" });678 try testGeneralCmdLine("a b\tc d", &.{ "a", "b", "c", "d" });
668 try testGeneralCmdLine("\"abc\" d e", &[_][]const u8{ "abc", "d", "e" });679 try testGeneralCmdLine("\"abc\" d e", &.{ "abc", "d", "e" });
669 try testGeneralCmdLine("a\\\\\\b d\"e f\"g h", &[_][]const u8{ "a\\\\\\b", "de fg", "h" });680 try testGeneralCmdLine("a\\\\\\b d\"e f\"g h", &.{ "a\\\\\\b", "de fg", "h" });
670 try testGeneralCmdLine("a\\\\\\\"b c d", &[_][]const u8{ "a\\\"b", "c", "d" });681 try testGeneralCmdLine("a\\\\\\\"b c d", &.{ "a\\\"b", "c", "d" });
671 try testGeneralCmdLine("a\\\\\\\\\"b c\" d e", &[_][]const u8{ "a\\\\b c", "d", "e" });682 try testGeneralCmdLine("a\\\\\\\\\"b c\" d e", &.{ "a\\\\b c", "d", "e" });
672 try testGeneralCmdLine("a b\tc \"d f", &[_][]const u8{ "a", "b", "c", "d f" });683 try testGeneralCmdLine("a b\tc \"d f", &.{ "a", "b", "c", "d f" });
673 try testGeneralCmdLine("j k l\\", &[_][]const u8{ "j", "k", "l\\" });684 try testGeneralCmdLine("j k l\\", &.{ "j", "k", "l\\" });
674 try testGeneralCmdLine("\"\" x y z\\\\", &[_][]const u8{ "", "x", "y", "z\\\\" });685 try testGeneralCmdLine("\"\" x y z\\\\", &.{ "", "x", "y", "z\\\\" });
675686
676 try testGeneralCmdLine("\".\\..\\zig-cache\\build\" \"bin\\zig.exe\" \".\\..\" \".\\..\\zig-cache\" \"--help\"", &[_][]const u8{687 try testGeneralCmdLine("\".\\..\\zig-cache\\build\" \"bin\\zig.exe\" \".\\..\" \".\\..\\zig-cache\" \"--help\"", &.{
677 ".\\..\\zig-cache\\build",688 ".\\..\\zig-cache\\build",
678 "bin\\zig.exe",689 "bin\\zig.exe",
679 ".\\..",690 ".\\..",
680 ".\\..\\zig-cache",691 ".\\..\\zig-cache",
681 "--help",692 "--help",
682 });693 });
694
695 try testGeneralCmdLine(
696 \\ 'foo' "bar"
697 , &.{ "'foo'", "bar" });
683}698}
684699
685fn testGeneralCmdLine(input_cmd_line: []const u8, expected_args: []const []const u8) !void {700fn testGeneralCmdLine(input_cmd_line: []const u8, expected_args: []const []const u8) !void {
686 var it = try ArgIteratorGeneral(.{ .comments_supported = false })701 var it = try ArgIteratorGeneral(.{}).init(std.testing.allocator, input_cmd_line);
687 .init(std.testing.allocator, input_cmd_line);
688 defer it.deinit();702 defer it.deinit();
689 for (expected_args) |expected_arg| {703 for (expected_args) |expected_arg| {
690 const arg = it.next().?;704 const arg = it.next().?;
...@@ -697,30 +711,34 @@ test "response file arg parsing" {...@@ -697,30 +711,34 @@ test "response file arg parsing" {
697 try testResponseFileCmdLine(711 try testResponseFileCmdLine(
698 \\a b712 \\a b
699 \\c d\713 \\c d\
700 , &[_][]const u8{ "a", "b", "c", "d\\" });714 , &.{ "a", "b", "c", "d\\" });
701 try testResponseFileCmdLine("a b c d\\", &[_][]const u8{ "a", "b", "c", "d\\" });715 try testResponseFileCmdLine("a b c d\\", &.{ "a", "b", "c", "d\\" });
702716
703 try testResponseFileCmdLine(717 try testResponseFileCmdLine(
704 \\j718 \\j
705 \\ k l # this is a comment \\ \\\ \\\\ "none" "\\" "\\\"719 \\ k l # this is a comment \\ \\\ \\\\ "none" "\\" "\\\"
706 \\ "m" #another comment720 \\ "m" #another comment
707 \\721 \\
708 , &[_][]const u8{ "j", "k", "l", "m" });722 , &.{ "j", "k", "l", "m" });
709723
710 try testResponseFileCmdLine(724 try testResponseFileCmdLine(
711 \\ "" q ""725 \\ "" q ""
712 \\ "r s # t" "u\" v" #another comment726 \\ "r s # t" "u\" v" #another comment
713 \\727 \\
714 , &[_][]const u8{ "", "q", "", "r s # t", "u\" v" });728 , &.{ "", "q", "", "r s # t", "u\" v" });
715729
716 try testResponseFileCmdLine(730 try testResponseFileCmdLine(
717 \\ -l"advapi32" a# b#c d#731 \\ -l"advapi32" a# b#c d#
718 \\e\\\732 \\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" });
720}738}
721739
722fn testResponseFileCmdLine(input_cmd_line: []const u8, expected_args: []const []const u8) !void {740fn 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 })
724 .init(std.testing.allocator, input_cmd_line);742 .init(std.testing.allocator, input_cmd_line);
725 defer it.deinit();743 defer it.deinit();
726 for (expected_args) |expected_arg| {744 for (expected_args) |expected_arg| {
src/main.zig+1-1
...@@ -4230,7 +4230,7 @@ pub const ClangArgIterator = struct {...@@ -4230,7 +4230,7 @@ pub const ClangArgIterator = struct {
4230 };4230 };
4231 }4231 }
42324232
4233 const ArgIteratorResponseFile = process.ArgIteratorGeneral(.{ .comments_supported = true });4233 const ArgIteratorResponseFile = process.ArgIteratorGeneral(.{ .comments = true, .single_quotes = true });
42344234
4235 /// Initialize the arguments from a Response File. "*.rsp"4235 /// Initialize the arguments from a Response File. "*.rsp"
4236 fn initArgIteratorResponseFile(allocator: Allocator, resp_file_path: []const u8) !ArgIteratorResponseFile {4236 fn initArgIteratorResponseFile(allocator: Allocator, resp_file_path: []const u8) !ArgIteratorResponseFile {