| ... | @@ -465,58 +465,72 @@ pub fn iterateAllocator(a: Args, gpa: Allocator) Iterator.InitError!Iterator { | ... | @@ -465,58 +465,72 @@ pub fn iterateAllocator(a: Args, gpa: Allocator) Iterator.InitError!Iterator { |
| 465 | | 465 | |
| 466 | pub const ToSliceError = Iterator.Windows.InitError || Iterator.Wasi.InitError; | 466 | pub const ToSliceError = Iterator.Windows.InitError || Iterator.Wasi.InitError; |
| 467 | | 467 | |
| 468 | /// Returned value may reference several allocations; call `freeSlice` to | 468 | /// Returned value may reference several allocations and may point into `a`. |
| 469 | /// release. | 469 | /// Thefore, an arena-style allocator must be used. |
| 470 | /// | 470 | /// |
| 471 | /// * On Windows, the result is encoded as | 471 | /// * On Windows, the result is encoded as |
| 472 | /// [WTF-8](https://wtf-8.codeberg.page/). | 472 | /// [WTF-8](https://wtf-8.codeberg.page/). |
| 473 | /// * On other platforms, the result is an opaque sequence of bytes with no | 473 | /// * On other platforms, the result is an opaque sequence of bytes with no |
| 474 | /// particular encoding. | 474 | /// particular encoding. |
| 475 | pub fn toSlice(a: Args, gpa: Allocator) ToSliceError![][:0]u8 { | 475 | /// |
| 476 | var it = try a.iterateAllocator(gpa); | 476 | /// See also: |
| 477 | defer it.deinit(); | 477 | /// * `iterate` |
| | 478 | /// * `iterateAllocator` |
| | 479 | pub fn toSlice(a: Args, arena: Allocator) ToSliceError![]const [:0]const u8 { |
| | 480 | if (native_os == .windows) { |
| | 481 | var it = try a.iterateAllocator(arena); |
| | 482 | var contents: std.ArrayList(u8) = .empty; |
| | 483 | var slice_list: std.ArrayList(usize) = .empty; |
| | 484 | while (it.next()) |arg| { |
| | 485 | try contents.appendSlice(arena, arg[0 .. arg.len + 1]); |
| | 486 | try slice_list.append(arena, arg.len); |
| | 487 | } |
| | 488 | const contents_slice = contents.items; |
| | 489 | const slice_sizes = slice_list.items; |
| | 490 | const slice_list_bytes = std.math.mul(usize, @sizeOf([]u8), slice_sizes.len) catch return error.OutOfMemory; |
| | 491 | const total_bytes = std.math.add(usize, slice_list_bytes, contents_slice.len) catch return error.OutOfMemory; |
| | 492 | const buf = try arena.alignedAlloc(u8, .of([]u8), total_bytes); |
| | 493 | errdefer arena.free(buf); |
| | 494 | |
| | 495 | const result_slice_list = std.mem.bytesAsSlice([:0]u8, buf[0..slice_list_bytes]); |
| | 496 | const result_contents = buf[slice_list_bytes..]; |
| | 497 | @memcpy(result_contents[0..contents_slice.len], contents_slice); |
| | 498 | |
| | 499 | var contents_index: usize = 0; |
| | 500 | for (slice_sizes, 0..) |len, i| { |
| | 501 | const new_index = contents_index + len; |
| | 502 | result_slice_list[i] = result_contents[contents_index..new_index :0]; |
| | 503 | contents_index = new_index + 1; |
| | 504 | } |
| 478 | | 505 | |
| 479 | var contents: std.ArrayList(u8) = .empty; | 506 | return result_slice_list; |
| 480 | defer contents.deinit(gpa); | 507 | } else if (native_os == .wasi and !builtin.link_libc) { |
| | 508 | var count: usize = undefined; |
| | 509 | var buf_size: usize = undefined; |
| 481 | | 510 | |
| 482 | var slice_list: std.ArrayList(usize) = .empty; | 511 | switch (std.os.wasi.args_sizes_get(&count, &buf_size)) { |
| 483 | defer slice_list.deinit(gpa); | 512 | .SUCCESS => {}, |
| | 513 | else => |err| return std.posix.unexpectedErrno(err), |
| | 514 | } |
| 484 | | 515 | |
| 485 | while (it.next()) |arg| { | 516 | if (count == 0) return &.{}; |
| 486 | try contents.appendSlice(gpa, arg[0 .. arg.len + 1]); | | |
| 487 | try slice_list.append(gpa, arg.len); | | |
| 488 | } | | |
| 489 | | 517 | |
| 490 | const contents_slice = contents.items; | 518 | const argv = try arena.alloc([*:0]u8, count); |
| 491 | const slice_sizes = slice_list.items; | 519 | const argv_buf = try arena.alloc(u8, buf_size); |
| 492 | const slice_list_bytes = std.math.mul(usize, @sizeOf([]u8), slice_sizes.len) catch return error.OutOfMemory; | | |
| 493 | const total_bytes = std.math.add(usize, slice_list_bytes, contents_slice.len) catch return error.OutOfMemory; | | |
| 494 | const buf = try gpa.alignedAlloc(u8, .of([]u8), total_bytes); | | |
| 495 | errdefer gpa.free(buf); | | |
| 496 | | | |
| 497 | const result_slice_list = std.mem.bytesAsSlice([:0]u8, buf[0..slice_list_bytes]); | | |
| 498 | const result_contents = buf[slice_list_bytes..]; | | |
| 499 | @memcpy(result_contents[0..contents_slice.len], contents_slice); | | |
| 500 | | | |
| 501 | var contents_index: usize = 0; | | |
| 502 | for (slice_sizes, 0..) |len, i| { | | |
| 503 | const new_index = contents_index + len; | | |
| 504 | result_slice_list[i] = result_contents[contents_index..new_index :0]; | | |
| 505 | contents_index = new_index + 1; | | |
| 506 | } | | |
| 507 | | 520 | |
| 508 | return result_slice_list; | 521 | switch (std.os.wasi.args_get(argv.ptr, argv_buf.ptr)) { |
| 509 | } | 522 | .SUCCESS => {}, |
| | 523 | else => |err| return std.posix.unexpectedErrno(err), |
| | 524 | } |
| 510 | | 525 | |
| 511 | /// Frees memory allocate by `toSlice`. | 526 | const args = try arena.alloc([:0]const u8, count); |
| 512 | pub fn freeSlice(gpa: Allocator, to_slice_result: []const [:0]u8) void { | 527 | for (args, argv) |*dst, src| dst.* = std.mem.sliceTo(src, 0); |
| 513 | var total_bytes: usize = 0; | 528 | return args; |
| 514 | for (to_slice_result) |arg| { | 529 | } else { |
| 515 | total_bytes += @sizeOf([]u8) + arg.len + 1; | 530 | const args = try arena.alloc([:0]const u8, a.vector.len); |
| | 531 | for (args, a.vector) |*dst, src| dst.* = std.mem.sliceTo(src, 0); |
| | 532 | return args; |
| 516 | } | 533 | } |
| 517 | const unaligned_allocated_buf = @as([*]const u8, @ptrCast(to_slice_result.ptr))[0..total_bytes]; | | |
| 518 | const aligned_allocated_buf: []align(@alignOf([]u8)) const u8 = @alignCast(unaligned_allocated_buf); | | |
| 519 | return gpa.free(aligned_allocated_buf); | | |
| 520 | } | 534 | } |
| 521 | | 535 | |
| 522 | test "Iterator.Windows" { | 536 | test "Iterator.Windows" { |