Last active
June 22, 2020 10:30
-
-
Save cartr/8a1ea5b3a889686360c903cfa5339a84 to your computer and use it in GitHub Desktop.
This file contains 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
const std = @import("std"); | |
const TestCase = struct { | |
input: [:0]const u8, output: []const []const u8 | |
}; | |
// Test cases from https://docs.microsoft.com/en-us/cpp/cpp/main-function-command-line-args?view=vs-2019#results-of-parsing-command-lines | |
// "f.exe " added to some tests to satisfy CommandLineToArgvW's assumption | |
// about the initial argument; Zig parser passes these tests without doing this | |
const MICROSOFT_TEST_CASES = [_]TestCase{ | |
.{ | |
.output = &[_][]const u8{ "a b c", "d", "e" }, | |
.input = | |
\\"a b c" d e | |
}, | |
.{ | |
.output = &[_][]const u8{ "f.exe", "ab\"c", "\\", "d" }, | |
.input = | |
\\f.exe "ab\"c" "\\" d | |
}, | |
.{ | |
.output = &[_][]const u8{ "a\\\\\\b", "de fg", "h" }, | |
.input = | |
\\a\\\b d"e f"g h | |
}, | |
.{ | |
.output = &[_][]const u8{ "f.exe", "a\\\"b", "c", "d" }, | |
.input = | |
\\f.exe a\\\"b c d | |
}, | |
.{ | |
.output = &[_][]const u8{ "f.exe", "a\\\\b c", "d", "e" }, | |
.input = | |
\\f.exe a\\\\"b c" d e | |
}, | |
}; | |
// Test cases from https://github.com/ziglang/zig/blob/d907f574e02aadf8196e616bcc2fb2813cf2c82c/lib/std/process.zig#L575-L590 | |
// "f.exe " added to some tests to satisfy CommandLineToArgvW's assumption | |
// about the initial argument | |
const ZIG_TEST_CASES = [_]TestCase{ | |
.{ | |
.input = "a b\tc d", | |
.output = &[_][]const u8{ "a", "b", "c", "d" }, | |
}, | |
.{ | |
.input = "\"abc\" d e", | |
.output = &[_][]const u8{ "abc", "d", "e" }, | |
}, | |
.{ | |
.input = "a\\\\\\b d\"e f\"g h", | |
.output = &[_][]const u8{ "a\\\\\\b", "de fg", "h" }, | |
}, | |
.{ | |
.input = "f.exe a\\\\\\\"b c d", | |
.output = &[_][]const u8{ "f.exe", "a\\\"b", "c", "d" }, | |
}, | |
.{ | |
.input = "f.exe a\\\\\\\\\"b c\" d e", | |
.output = &[_][]const u8{ "f.exe", "a\\\\b c", "d", "e" }, | |
}, | |
// Neither CommandLineToArgvW nor C's argv implement this "unclosed quotes\ | |
// are literal" behavior; not sure why Zig does this | |
//.{ | |
// .input = "a b\tc \"d f", | |
// .output = &[_][]const u8{ "a", "b", "c", "\"d", "f" } | |
//}, | |
.{ | |
.input = "\".\\..\\zig-cache\\build\" \"bin\\zig.exe\" \".\\..\" \".\\..\\zig-cache\" \"--help\"", | |
.output = &[_][]const u8{ | |
".\\..\\zig-cache\\build", | |
"bin\\zig.exe", | |
".\\..", | |
".\\..\\zig-cache", | |
"--help", | |
}, | |
}, | |
}; | |
const TEST_CASES = MICROSOFT_TEST_CASES ++ ZIG_TEST_CASES; | |
test "Zig argument parsing is correct" { | |
for (TEST_CASES) |case| { | |
var it = std.process.ArgIteratorWindows.initWithCmdLine(case.input.ptr); | |
for (case.output) |expected_arg| { | |
const arg = it.next(std.testing.allocator).? catch unreachable; | |
defer std.testing.allocator.free(arg); | |
std.testing.expectEqualSlices(u8, expected_arg, arg); | |
} | |
std.testing.expect(it.next(std.testing.allocator) == null); | |
} | |
} | |
pub extern "shell32" fn CommandLineToArgvW(lpCmdLine: std.os.windows.LPCWSTR, out_pNumArgs: *c_int) callconv(.Stdcall) ?[*]std.os.windows.LPWSTR; | |
test "CommandLineToArgvW parses arguments correctly" { | |
for (TEST_CASES) |case| { | |
var num_args: c_int = undefined; | |
var input_utf16 = try std.unicode.utf8ToUtf16LeWithNull(std.testing.allocator, case.input); | |
defer std.testing.allocator.free(input_utf16); | |
var args = CommandLineToArgvW(input_utf16, &num_args).?; | |
var i: usize = 0; | |
while (i < num_args) { | |
var arg_utf8 = try std.unicode.utf16leToUtf8Alloc(std.testing.allocator, std.mem.span(args[i])); | |
defer std.testing.allocator.free(arg_utf8); | |
std.testing.expectEqualSlices(u8, case.output[i], arg_utf8); | |
i += 1; | |
} | |
std.testing.expectEqual(num_args, @intCast(c_int, case.output.len)); | |
} | |
} |
This file contains 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
// Adapted from https://docs.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-commandlinetoargvw#examples | |
#include <windows.h> | |
#include <stdio.h> | |
#include <shellapi.h> | |
int __cdecl main(int argc, char* argv[]) | |
{ | |
LPWSTR* szArglist; | |
int nArgs; | |
int i; | |
wprintf(L"C runtime parse:\n"); | |
for (i = 0; i < argc; i++) printf("%d: %s\n", i, argv[i]); | |
wprintf(L"CommandLineToArgvW parse:\n"); | |
szArglist = CommandLineToArgvW(GetCommandLineW(), &nArgs); | |
if (NULL == szArglist) | |
{ | |
wprintf(L"CommandLineToArgvW failed\n"); | |
return 0; | |
} | |
else for (i = 0; i < nArgs; i++) printf("%d: %ws\n", i, szArglist[i]); | |
// Free memory allocated for CommandLineToArgvW arguments. | |
LocalFree(szArglist); | |
return(1); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment