const std = @import("std"); const mem = std.mem; const fmt = std.fmt; const debug = std.debug; // read n bytes or return err fn readExactly(reader: anytype, buffer: []u8) !void{ var have: usize = 0; while(have < buffer.len){ const amt = try reader.read(buffer[have..]); if(amt == 0){ return error.EndOfStream; } have += amt; } } pub fn main() !void{ const stdin = std.io.getStdIn().reader(); const stdout = std.io.getStdOut().writer(); var buffer: [64]u8 = [_]u8{0} ** 64; var len_bytes_buf: [2]u8 = [_]u8{0} ** 2; var reply_buffer: [64]u8 = [_]u8{0} ** 64; while(true){ // read msg length (2 bytes, big-endian) readExactly(stdin, &len_bytes_buf) catch |err|{ if(err == error.EndOfStream){ break; } return err; }; const msg_len = @as(u16, len_bytes_buf[0]) << 8 | len_bytes_buf[1]; // convert to u16, big-endian //std.debug.print("Full buffer: ", .{}); //for(buffer[0..msg_len]) |b|{ // std.debug.print("{c}", .{b}); //} //std.debug.print("\n", .{}); if(msg_len == 0 or msg_len > buffer.len){ try stdout.writeAll(&[2]u8{ 0, 0 }); continue; } readExactly(stdin, buffer[0..msg_len]) catch |err|{ // read msg if(err == error.EndOfStream){ break; } return err; }; //debug.print("RECV: '{s}'\n", .{buffer[0..msg_len]}); var fbs = std.io.fixedBufferStream(&reply_buffer); var writer = fbs.writer(); if(mem.eql(u8, buffer[0..msg_len], "hello")){ try writer.writeAll("Hello world!"); }else if(mem.startsWith(u8, buffer[0..msg_len], "factorial ")){ const prefix_len = "factorial ".len; const n_str = buffer[prefix_len..msg_len]; //std.debug.print("n_str = '{s}' ({} chars)\n", .{ n_str, n_str.len }); const n = fmt.parseInt(isize, n_str, 10) catch { //std.debug.print("error:PARSE ERROR for '{s}'\n", .{n_str}); try writer.writeAll("error:badarg"); //try writer.writeAll("0"); try sendResponse(stdout, fbs.getWritten()); continue; }; if(n < 0){ //try writer.writeAll("error:badarg"); //std.debug.print("n < 0 -> badarg\n", .{}); //try writer.writeAll("0"); try writer.writeAll("error:badarg: n < 0"); }else if(n > 34){ //std.debug.print("n > 34 -> too large\n", .{}); //try writer.writeAll("0"); try writer.writeAll("error:input too large, max is 34"); }else{ var result: u128 = 1; var i = @as(u128, @intCast(n)); while (i > 1) : (i -= 1) result *= i; //std.debug.print("factorial({d}) = {d}\n", .{n, result}); try fmt.formatInt(result, 10, .lower, .{}, writer); } }else{ try writer.writeAll("error:unknown command"); } try sendResponse(stdout, fbs.getWritten()); } } fn sendResponse(writer: anytype, response: []const u8) !void{ const len: u16 = @intCast(response.len); //std.debug.print("SEND: len={d} (0x{X:0>4}) data='{s}'\n", .{ len, len, response }); try writer.writeByte(@intCast((len >> 8) & 0xFF)); // high byte try writer.writeByte(@intCast(len & 0xFF)); // low byte try writer.writeAll(response); }