#Sane way to parse socket stream to ChildProcess.exec() args?

1 messages · Page 1 of 1 (latest)

flat abyss
#

Hi!

What would be a sane way to parse a socket stream to the 'argv: []const []const u8' required by std.ChildProcess.exec()?

I currently have the following disaster code 😅

Even without tokenizer (looping over each character) it ends up in a similar mess. I'm sure there's some simpler way I'm missing.

fn exec(stream: *net.Stream, payload: []u8) !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    const allocator = gpa.allocator();
    defer _ = gpa.deinit();

    var raw_args = std.ArrayList(u8).init(allocator);

    var p = payload;
    while (true) {
        try raw_args.appendSlice(p[1..]);
        if (payload[0] == '0') break;
        p = try recv(stream, buffer);
    }

    var argarrays = std.ArrayList(std.ArrayList(u8)).init(allocator);
    defer argarrays.deinit();

    var args = std.ArrayList([]u8).init(allocator);
    defer args.deinit();

    var iter = std.mem.tokenize(u8, raw_args.items, " ");

    while (iter.next()) |arg| {
        var l = std.ArrayList(u8).init(allocator);
        for (arg) |c| try l.append(c);

        try argarrays.append(l);
        try args.append(l.items);
    }
    defer for (argarrays.items) |a| a.deinit();
    
    raw_args.deinit();

    var result = try std.ChildProcess.exec(.{ 
        .allocator = allocator,
        .argv = args.items 
    });
    defer {
        allocator.free(result.stdout);
        allocator.free(result.stderr);
    }
native shore
#
fn exec(stream: *net.Stream, allocator: std.mem.Allocator, payload: []u8) !void {
    var raw_args = std.ArrayList(u8).init(allocator);
    defer raw_args.deinit();

    var p = payload;
    while (true) {
        try raw_args.appendSlice(p[1..]);
        if (payload[0] == '0') break;
        p = try recv(stream, buffer);
    }

    var args = std.ArrayList([]const u8).init(allocator);
    defer args.deinit();

    var iter = std.mem.tokenizeScalar(u8, raw_args.items, ' ');
    while (iter.next()) |arg| try args.append(arg);

    var result = try std.ChildProcess.exec(.{ .allocator = allocator, .argv = args.items });
    defer {
        allocator.free(result.stdout);
        allocator.free(result.stderr);
    }
}
  1. don't create gpas this deep in the call stack, it limits reusability
  2. always defer right after init to avoid leaks
  3. you already have a byte array to point to with the slices you create
flat abyss
native shore
#

don't do that, I said std.ArrayList([]const u8)