summaryrefslogtreecommitdiff
path: root/src/main.zig
blob: 92067a45aba864472ab8fb5c1cc22fd682132ea4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
const std = @import("std");

var stdin_buffer: [4096]u8 = undefined;
var stdin_reader = std.fs.File.stdin().readerStreaming(&stdin_buffer);
const stdin = &stdin_reader.interface;

var stdout_writer = std.fs.File.stdout().writerStreaming(&.{});
const stdout = &stdout_writer.interface;

const CommandResult = enum {
    continue_loop,
    exit_shell,
};

fn parseCommand(input: []const u8) struct { name: []const u8, args: ?[]const u8 } {
    const space_pos = std.mem.indexOfScalar(u8, input, ' ');
    if (space_pos) |pos| {
        return .{
            .name = input[0..pos],
            .args = input[pos + 1 ..],
        };
    }
    return .{
        .name = input,
        .args = null,
    };
}

fn isBuiltin(cmd_name: []const u8) bool {
    const builtins = [_][]const u8{ "exit", "echo", "type" };
    for (builtins) |builtin| {
        if (std.mem.eql(u8, cmd_name, builtin)) {
            return true;
        }
    }
    return false;
}

fn executeCommand(cmd_name: []const u8, args: ?[]const u8) !CommandResult {
    if (std.mem.eql(u8, cmd_name, "exit")) {
        return .exit_shell;
    }

    if (std.mem.eql(u8, cmd_name, "echo")) {
        if (args) |a| {
            try stdout.print("{s}\n", .{a});
        } else {
            try stdout.print("\n", .{});
        }
        return .continue_loop;
    }

    if (std.mem.eql(u8, cmd_name, "type")) {
        if (args) |a| {
            if (isBuiltin(a)) {
                try stdout.print("{s} is a shell builtin\n", .{a});
            } else {
                try stdout.print("{s}: not found\n", .{a});
            }
        }
        return .continue_loop;
    }

    // Command not found
    try stdout.print("{s}: command not found\n", .{cmd_name});
    return .continue_loop;
}

pub fn main() !void {
    while (true) {
        try stdout.print("$ ", .{});

        const command = try stdin.takeDelimiter('\n');
        if (command) |cmd| {
            const parsed = parseCommand(cmd);
            const result = try executeCommand(parsed.name, parsed.args);

            if (result == .exit_shell) {
                break;
            }
        } else {
            break;
        }
    }
}