Commit 01365be82f

Shritesh Bhattarai <shritesh@shritesh.com>
2019-04-30 03:54:30
WASI: implement argsAlloc and argsFree (#2364)
* wasi: change URL to canon WASI-core.md * wasi: import args_get and args_sizes_get * wasi: Implement argsAlloc and argsFree * test return value for wasi arg syscalls * wasi: return unexpectedErrorPosix in argsAlloc * wasi: Add TODO for ArgIterator
1 parent 77383f9
Changed files (3)
std/os/wasi/core.zig
@@ -10,6 +10,9 @@ pub const ciovec_t = extern struct {
 
 pub const SIGABRT: signal_t = 6;
 
+pub extern "wasi_unstable" fn args_get(argv: [*][*]u8, argv_buf: [*]u8) errno_t;
+pub extern "wasi_unstable" fn args_sizes_get(argc: *usize, argv_buf_size: *usize) errno_t;
+
 pub extern "wasi_unstable" fn proc_raise(sig: signal_t) errno_t;
 
 pub extern "wasi_unstable" fn proc_exit(rval: exitcode_t) noreturn;
std/os/wasi.zig
@@ -1,7 +1,7 @@
 pub use @import("wasi/core.zig");
 
 // Based on https://github.com/CraneStation/wasi-sysroot/blob/wasi/libc-bottom-half/headers/public/wasi/core.h
-// and https://github.com/CraneStation/wasmtime/blob/master/docs/WASI-api.md
+// and https://github.com/WebAssembly/WASI/blob/master/design/WASI-core.md
 
 pub const STDIN_FILENO = 0;
 pub const STDOUT_FILENO = 1;
std/os.zig
@@ -2134,6 +2134,11 @@ pub const ArgIterator = struct {
     inner: InnerType,
 
     pub fn init() ArgIterator {
+        if (builtin.os == Os.wasi) {
+            // TODO: Figure out a compatible interface accomodating WASI
+            @compileError("ArgIterator is not yet supported in WASI. Use argsAlloc and argsFree instead.");
+        }
+
         return ArgIterator{ .inner = InnerType.init() };
     }
 
@@ -2166,6 +2171,34 @@ pub fn args() ArgIterator {
 
 /// Caller must call argsFree on result.
 pub fn argsAlloc(allocator: *mem.Allocator) ![]const []u8 {
+    if (builtin.os == Os.wasi) {
+        var count: usize = undefined;
+        var buf_size: usize = undefined;
+
+        const args_sizes_get_ret = os.wasi.args_sizes_get(&count, &buf_size);
+        if (args_sizes_get_ret != os.wasi.ESUCCESS) {
+            return unexpectedErrorPosix(args_sizes_get_ret);
+        }
+
+        var argv = try allocator.alloc([*]u8, count);
+        defer allocator.free(argv);
+
+        var argv_buf = try allocator.alloc(u8, buf_size);
+        const args_get_ret = os.wasi.args_get(argv.ptr, argv_buf.ptr);
+        if (args_get_ret != os.wasi.ESUCCESS) {
+            return unexpectedErrorPosix(args_get_ret);
+        }
+
+        var result_slice = try allocator.alloc([]u8, count);
+        
+        var i: usize = 0;
+        while (i < count) : (i += 1) {
+            result_slice[i] = mem.toSlice(u8, argv[i]);
+        }
+
+        return result_slice;
+    }
+
     // TODO refactor to only make 1 allocation.
     var it = args();
     var contents = try Buffer.initSize(allocator, 0);
@@ -2203,6 +2236,16 @@ pub fn argsAlloc(allocator: *mem.Allocator) ![]const []u8 {
 }
 
 pub fn argsFree(allocator: *mem.Allocator, args_alloc: []const []u8) void {
+    if (builtin.os == Os.wasi) {
+        const last_item = args_alloc[args_alloc.len - 1];
+        const last_byte_addr = @ptrToInt(last_item.ptr) + last_item.len + 1; // null terminated
+        const first_item_ptr = args_alloc[0].ptr;
+        const len = last_byte_addr - @ptrToInt(first_item_ptr);
+        allocator.free(first_item_ptr[0..len]);
+
+        return allocator.free(args_alloc);
+    }
+
     var total_bytes: usize = 0;
     for (args_alloc) |arg| {
         total_bytes += @sizeOf([]u8) + arg.len;