| ... | @@ -303,7 +303,8 @@ pub const ArgIteratorWasi = struct { | ... | @@ -303,7 +303,8 @@ pub const ArgIteratorWasi = struct { |
| 303 | | 303 | |
| 304 | /// Optional parameters for `ArgIteratorGeneral` | 304 | /// Optional parameters for `ArgIteratorGeneral` |
| 305 | pub const ArgIteratorGeneralOptions = struct { | 305 | pub const ArgIteratorGeneralOptions = struct { |
| 306 | comments_supported: bool = false, | 306 | comments: bool = false, |
| | 307 | single_quotes: bool = false, |
| 307 | }; | 308 | }; |
| 308 | | 309 | |
| 309 | /// A general Iterator to parse a string into a set of arguments | 310 | /// 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. |
| 523 | pub const ArgIterator = struct { | 534 | pub 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 | } |
| 665 | | 676 | |
| 666 | test "general arg parsing" { | 677 | test "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\\\\" }); |
| 675 | | 686 | |
| 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 | } |
| 684 | | 699 | |
| 685 | fn testGeneralCmdLine(input_cmd_line: []const u8, expected_args: []const []const u8) !void { | 700 | fn 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 b | 712 | \\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\\" }); |
| 702 | | 716 | |
| 703 | try testResponseFileCmdLine( | 717 | try testResponseFileCmdLine( |
| 704 | \\j | 718 | \\j |
| 705 | \\ k l # this is a comment \\ \\\ \\\\ "none" "\\" "\\\" | 719 | \\ k l # this is a comment \\ \\\ \\\\ "none" "\\" "\\\" |
| 706 | \\ "m" #another comment | 720 | \\ "m" #another comment |
| 707 | \\ | 721 | \\ |
| 708 | , &[_][]const u8{ "j", "k", "l", "m" }); | 722 | , &.{ "j", "k", "l", "m" }); |
| 709 | | 723 | |
| 710 | try testResponseFileCmdLine( | 724 | try testResponseFileCmdLine( |
| 711 | \\ "" q "" | 725 | \\ "" q "" |
| 712 | \\ "r s # t" "u\" v" #another comment | 726 | \\ "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" }); |
| 715 | | 729 | |
| 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 | } |
| 721 | | 739 | |
| 722 | fn testResponseFileCmdLine(input_cmd_line: []const u8, expected_args: []const []const u8) !void { | 740 | fn 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| { |