| ... | ... | @@ -303,7 +303,8 @@ pub const ArgIteratorWasi = struct { |
| 303 | 303 | |
| 304 | 304 | /// Optional parameters for `ArgIteratorGeneral` |
| 305 | 305 | pub const ArgIteratorGeneralOptions = struct { |
| 306 | | comments_supported: bool = false, |
| 306 | comments: bool = false, |
| 307 | single_quotes: bool = false, |
| 307 | 308 | }; |
| 308 | 309 | |
| 309 | 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 | 388 | 0 => return false, |
| 388 | 389 | ' ', '\t', '\r', '\n' => continue, |
| 389 | 390 | '#' => { |
| 390 | | if (options.comments_supported) { |
| 391 | if (options.comments) { |
| 391 | 392 | while (true) : (self.index += 1) { |
| 392 | 393 | switch (self.cmd_line[self.index]) { |
| 393 | 394 | '\n' => break, |
| ... | ... | @@ -417,7 +418,11 @@ pub fn ArgIteratorGeneral(comptime options: ArgIteratorGeneralOptions) type { |
| 417 | 418 | const character = if (self.index != self.cmd_line.len) self.cmd_line[self.index] else 0; |
| 418 | 419 | switch (character) { |
| 419 | 420 | 0 => return true, |
| 420 | | '"' => { |
| 421 | '"', '\'' => { |
| 422 | if (!options.single_quotes and character == '\'') { |
| 423 | backslash_count = 0; |
| 424 | continue; |
| 425 | } |
| 421 | 426 | const quote_is_real = backslash_count % 2 == 0; |
| 422 | 427 | if (quote_is_real) { |
| 423 | 428 | in_quote = !in_quote; |
| ... | ... | @@ -460,7 +465,13 @@ pub fn ArgIteratorGeneral(comptime options: ArgIteratorGeneralOptions) type { |
| 460 | 465 | self.start = self.end; |
| 461 | 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 | 475 | const quote_is_real = backslash_count % 2 == 0; |
| 465 | 476 | self.emitBackslashes(backslash_count / 2); |
| 466 | 477 | backslash_count = 0; |
| ... | ... | @@ -522,7 +533,7 @@ pub fn ArgIteratorGeneral(comptime options: ArgIteratorGeneralOptions) type { |
| 522 | 533 | /// Cross-platform command line argument iterator. |
| 523 | 534 | pub const ArgIterator = struct { |
| 524 | 535 | const InnerType = switch (builtin.os.tag) { |
| 525 | | .windows => ArgIteratorGeneral(.{ .comments_supported = false }), |
| 536 | .windows => ArgIteratorGeneral(.{}), |
| 526 | 537 | .wasi => if (builtin.link_libc) ArgIteratorPosix else ArgIteratorWasi, |
| 527 | 538 | else => ArgIteratorPosix, |
| 528 | 539 | }; |
| ... | ... | @@ -664,27 +675,30 @@ pub fn argsFree(allocator: mem.Allocator, args_alloc: []const [:0]u8) void { |
| 664 | 675 | } |
| 665 | 676 | |
| 666 | 677 | test "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\"", &.{ |
| 677 | 688 | ".\\..\\zig-cache\\build", |
| 678 | 689 | "bin\\zig.exe", |
| 679 | 690 | ".\\..", |
| 680 | 691 | ".\\..\\zig-cache", |
| 681 | 692 | "--help", |
| 682 | 693 | }); |
| 694 | |
| 695 | try testGeneralCmdLine( |
| 696 | \\ 'foo' "bar" |
| 697 | , &.{ "'foo'", "bar" }); |
| 683 | 698 | } |
| 684 | 699 | |
| 685 | 700 | fn 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); |
| 688 | 702 | defer it.deinit(); |
| 689 | 703 | for (expected_args) |expected_arg| { |
| 690 | 704 | const arg = it.next().?; |
| ... | ... | @@ -697,30 +711,34 @@ test "response file arg parsing" { |
| 697 | 711 | try testResponseFileCmdLine( |
| 698 | 712 | \\a b |
| 699 | 713 | \\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\\" }); |
| 702 | 716 | |
| 703 | 717 | try testResponseFileCmdLine( |
| 704 | 718 | \\j |
| 705 | 719 | \\ k l # this is a comment \\ \\\ \\\\ "none" "\\" "\\\" |
| 706 | 720 | \\ "m" #another comment |
| 707 | 721 | \\ |
| 708 | | , &[_][]const u8{ "j", "k", "l", "m" }); |
| 722 | , &.{ "j", "k", "l", "m" }); |
| 709 | 723 | |
| 710 | 724 | try testResponseFileCmdLine( |
| 711 | 725 | \\ "" q "" |
| 712 | 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 | 730 | try testResponseFileCmdLine( |
| 717 | 731 | \\ -l"advapi32" a# b#c d# |
| 718 | 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 | 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 | 742 | .init(std.testing.allocator, input_cmd_line); |
| 725 | 743 | defer it.deinit(); |
| 726 | 744 | for (expected_args) |expected_arg| { |