Something went wrong. Try again.
messing around and building a toy shell in Zig
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130const 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", .{}); }}