const std = @import("std"); const Io = std.Io; const zeashell = @import("zeashell"); pub fn main(init: std.process.Init) !void { // Prints to stderr, unbuffered, ignoring potential errors. // std.debug.print("All your {s} are belong to us.\n", .{"codebase"}); // This is appropriate for anything that lives as long as the process. const arena: std.mem.Allocator = init.arena.allocator(); // Accessing command line arguments: // const args = try init.minimal.args.toSlice(arena); // for (args) |arg| { // std.log.info("arg: {s}", .{arg}); // } // In order to do I/O operations need an `Io` instance. const io = init.io; // Stdout is for the actual output of your application, for example if you // are implementing gzip, then only the compressed bytes should be sent to // stdout, not any debugging messages. var stdout_buffer: [1024]u8 = undefined; var stdout_file_writer: Io.File.Writer = .init(.stdout(), io, &stdout_buffer); const stdout_writer = &stdout_file_writer.interface; try zeashell.printAnotherMessage(stdout_writer); try stdout_writer.flush(); // Don't forget to flush! var stdin_buffer: [1024]u8 = undefined; var stdin_file_reader: Io.File.Reader = .init(.stdin(), io, &stdin_buffer); const stdin = &stdin_file_reader.interface; while (true) { // always start with pwd in the prompt std.debug.print("\n", .{}); pwd(); std.debug.print("> ", .{}); const cmd_text = stdin.takeDelimiter('\n') catch break orelse break; var cmd_text_tokenized = std.mem.tokenizeAny(u8, cmd_text, " "); const executable = cmd_text_tokenized.next() orelse continue; // execute built-in commands // std.debug.print("{s}", .{executable}); if (std.mem.eql(u8, executable, "exit")) { std.process.exit(0); } else if (std.mem.eql(u8, executable, "cd")) { const directory_token = cmd_text_tokenized.next() orelse continue; const directory_token_as_sentinel = try std.fmt.allocPrintSentinel(arena, "{s}", .{directory_token}, 0); const exit_code = std.c.chdir(directory_token_as_sentinel); if (exit_code != 0) { std.debug.print("Failed to change directory: exit code {d}", .{exit_code}); } } else if (std.mem.eql(u8, executable, "pwd")) { pwd(); } else { // get current pid post fork const pid = std.c.fork(); if (pid == 0) { var path_args = std.mem.splitScalar(u8, init.environ_map.get("PATH") orelse "/bin:/usr/bin", ':'); // count args in tokenized string var counter = cmd_text_tokenized; var argc: usize = 1; // argv[0] is executable while (counter.next() != null) argc += 1; // std.c.execve needs sentinel terminated array or sentinal termincated strings var args_as_sentinel = try arena.allocSentinel(?[*:0]u8, argc, null); args_as_sentinel[0] = (try arena.dupeZ(u8, executable)).ptr; var i: usize = 1; while (cmd_text_tokenized.next()) |arg| : (i += 1) { args_as_sentinel[i] = (try arena.dupeZ(u8, arg)).ptr; } while (path_args.next()) |path_entry| { // std.c.execve needs sentinel terminated array const potential_executable_path = try std.fmt.allocPrintSentinel(arena, "{s}/{s}", .{ path_entry, executable }, 0); _ = std.c.execve(potential_executable_path, args_as_sentinel, std.c.environ); // only reachable if execve returns -1 exit code // std.log.info("Return code: -1", .{}); } std.debug.print("command not found: {s}\n", .{executable}); std.process.exit(127); } else { var status: c_int = undefined; // const child_pid _ = std.c.waitpid(pid, &status, 0); // std.log.info("child pid {d} finished with exit code {d}", .{ child_pid, status }); } } } } // test "simple test" { // const gpa = std.testing.allocator; // var list: std.ArrayList(i32) = .empty; // defer list.deinit(gpa); // Try commenting this out and see if zig detects the memory leak! // try list.append(gpa, 42); // try std.testing.expectEqual(@as(i32, 42), list.pop()); // } // test "fuzz example" { // try std.testing.fuzz({}, testOne, .{}); // } fn convertu8SliceToCString(slice: []u8, allocator: *std.mem.Allocator) !void { const c_safe_slice = try allocator.allocSentinel(u8, slice.len, 0); defer allocator.free(c_safe_slice); return c_safe_slice; } // fn convertu8ArrayHashMapToCString(map: []u8 ?[]u8, allocator: *std.mem.Allocator) !void {} fn pwd() void { var cwdBuf: [512]u8 = undefined; // [*]u8 = undefined; const cwd_pointer = std.c.getcwd(&cwdBuf, cwdBuf.len); if (cwd_pointer != null) { const cwd_non_null = std.mem.sliceTo(cwd_pointer.?, 0); std.debug.print("{s}", .{cwd_non_null}); } else { std.debug.print("Failed to print directory", .{}); } }