aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorAdam Goertz <adambgoertz@gmail.com>2023-07-12 02:45:51 +0000
committerAndrew Kelley <andrew@ziglang.org>2023-09-29 00:32:43 -0700
commitb3cad98534a4a4406d848f7cbd28165ca005bc8a (patch)
treea73855683e8bb98be5cc7e85270e383632d42f0e /lib
parented19ebc3605ec7e50166adf45f162dcf5540c42e (diff)
downloadzig-b3cad98534a4a4406d848f7cbd28165ca005bc8a.tar.gz
zig-b3cad98534a4a4406d848f7cbd28165ca005bc8a.zip
Support file:/// URIs and relative paths
Diffstat (limited to 'lib')
-rw-r--r--lib/std/Uri.zig45
-rw-r--r--lib/std/os/windows.zig1
-rw-r--r--lib/std/os/windows/shlwapi.zig13
3 files changed, 54 insertions, 5 deletions
diff --git a/lib/std/Uri.zig b/lib/std/Uri.zig
index b27a3d7012..e2c23e5a1d 100644
--- a/lib/std/Uri.zig
+++ b/lib/std/Uri.zig
@@ -134,6 +134,7 @@ pub const ParseError = error{ UnexpectedCharacter, InvalidFormat, InvalidPort };
/// original `text`. Each component that is provided, will be non-`null`.
pub fn parseWithoutScheme(text: []const u8) ParseError!Uri {
var reader = SliceReader{ .slice = text };
+
var uri = Uri{
.scheme = "",
.user = null,
@@ -145,13 +146,14 @@ pub fn parseWithoutScheme(text: []const u8) ParseError!Uri {
.fragment = null,
};
- if (reader.peekPrefix("//")) { // authority part
+ if (reader.peekPrefix("//")) a: { // authority part
std.debug.assert(reader.get().? == '/');
std.debug.assert(reader.get().? == '/');
- const authority = reader.readUntil(isAuthoritySeparator);
- if (authority.len == 0)
- return error.InvalidFormat;
+ var authority = reader.readUntil(isAuthoritySeparator);
+ if (authority.len == 0) {
+ if (reader.peekPrefix("/")) break :a else return error.InvalidFormat;
+ }
var start_of_host: usize = 0;
if (std.mem.indexOf(u8, authority, "@")) |index| {
@@ -224,7 +226,6 @@ pub fn format(
try writer.writeAll(":");
if (uri.host) |host| {
try writer.writeAll("//");
-
if (uri.user) |user| {
try writer.writeAll(user);
if (uri.password) |password| {
@@ -486,6 +487,23 @@ test "should fail gracefully" {
try std.testing.expectEqual(@as(ParseError!Uri, error.InvalidFormat), parse("foobar://"));
}
+test "file" {
+ const parsed = try parse("file:///");
+ try std.testing.expectEqualSlices(u8, "file", parsed.scheme);
+ try std.testing.expectEqual(@as(?[]const u8, null), parsed.host);
+ try std.testing.expectEqualSlices(u8, "/", parsed.path);
+
+ const parsed2 = try parse("file:///an/absolute/path/to/something");
+ try std.testing.expectEqualSlices(u8, "file", parsed2.scheme);
+ try std.testing.expectEqual(@as(?[]const u8, null), parsed2.host);
+ try std.testing.expectEqualSlices(u8, "/an/absolute/path/to/something", parsed2.path);
+
+ const parsed3 = try parse("file://localhost/an/absolute/path/to/another/thing/");
+ try std.testing.expectEqualSlices(u8, "file", parsed3.scheme);
+ try std.testing.expectEqualSlices(u8, "localhost", parsed3.host.?);
+ try std.testing.expectEqualSlices(u8, "/an/absolute/path/to/another/thing/", parsed3.path);
+}
+
test "scheme" {
try std.testing.expectEqualSlices(u8, "http", (try parse("http:_")).scheme);
try std.testing.expectEqualSlices(u8, "scheme-mee", (try parse("scheme-mee:_")).scheme);
@@ -695,3 +713,20 @@ test "URI query escaping" {
defer std.testing.allocator.free(formatted_uri);
try std.testing.expectEqualStrings("/?response-content-type=application%2Foctet-stream", formatted_uri);
}
+
+test "format" {
+ const uri = Uri{
+ .scheme = "file",
+ .user = null,
+ .password = null,
+ .host = null,
+ .port = null,
+ .path = "/foo/bar/baz",
+ .query = null,
+ .fragment = null,
+ };
+ var buf = std.ArrayList(u8).init(std.testing.allocator);
+ defer buf.deinit();
+ try uri.format("+/", .{}, buf.writer());
+ try std.testing.expectEqualSlices(u8, "file:/foo/bar/baz", buf.items);
+}
diff --git a/lib/std/os/windows.zig b/lib/std/os/windows.zig
index d40fee8db2..3522f238ec 100644
--- a/lib/std/os/windows.zig
+++ b/lib/std/os/windows.zig
@@ -30,6 +30,7 @@ pub const gdi32 = @import("windows/gdi32.zig");
pub const winmm = @import("windows/winmm.zig");
pub const crypt32 = @import("windows/crypt32.zig");
pub const nls = @import("windows/nls.zig");
+pub const shlwapi = @import("windows/shlwapi.zig");
pub const self_process_handle = @as(HANDLE, @ptrFromInt(maxInt(usize)));
diff --git a/lib/std/os/windows/shlwapi.zig b/lib/std/os/windows/shlwapi.zig
new file mode 100644
index 0000000000..0f0ceed576
--- /dev/null
+++ b/lib/std/os/windows/shlwapi.zig
@@ -0,0 +1,13 @@
+const std = @import("../../std.zig");
+const windows = std.os.windows;
+
+const DWORD = windows.DWORD;
+const WINAPI = windows.WINAPI;
+const HRESULT = windows.HRESULT;
+const LPCSTR = windows.LPCSTR;
+const LPSTR = windows.LPSTR;
+const LPWSTR = windows.LPWSTR;
+const LPCWSTR = windows.LPCWSTR;
+
+pub extern "shlwapi" fn PathCreateFromUrlW(pszUrl: LPCWSTR, pszPath: LPWSTR, pcchPath: *DWORD, dwFlags: DWORD) callconv(WINAPI) HRESULT;
+pub extern "shlwapi" fn PathCreateFromUrlA(pszUrl: LPCSTR, pszPath: LPSTR, pcchPath: *DWORD, dwFlags: DWORD) callconv(WINAPI) HRESULT;