| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116 |
- package main
-
- import (
- "bufio"
- "fmt"
- "io"
- "os"
- "strings"
- )
-
- type Context struct {
- stdout io.Writer
- stderr io.Writer
- stdin io.Reader
- }
-
- type GetCommandResult int
-
- const (
- GetCommandResultOk GetCommandResult = iota
- GetCommandResultError
- )
-
- type Command struct {
- command_type CommandType
- tokens []string
- }
-
- func makeCommandNone() Command {
- return Command{
- command_type: CommandTypeNone,
- tokens: nil,
- }
- }
-
- func makeCommand(command_type CommandType, tokens []string) Command {
- if command_type == CommandTypeNone {
- return Command{
- command_type: command_type,
- tokens: nil,
- }
- } else {
- return Command{
- command_type: command_type,
- tokens: tokens,
- }
- }
- }
-
- type CommandType int
-
- const (
- CommandTypeNone CommandType = iota
- CommandTypeExternal
- CommandTypeBuiltinExit
- CommandTypeBuiltinEcho
- )
-
- func getCommand(ctx *Context) (Command, error) {
- fmt.Print("$ ")
- command_line, err := bufio.NewReader(ctx.stdin).ReadString('\n')
- if err != nil {
- return makeCommandNone(), err
- }
- command, err := parseCommand(command_line)
- if err != nil {
- fmt.Fprintln(ctx.stderr, err)
- return makeCommandNone(), nil
- }
- return command, nil
- }
-
- func tokenize(str string) []string {
- tokens := make([]string, 2)
- tokens = strings.Fields(str)
- return tokens
- }
-
- func parseCommand(command_line string) (Command, error) {
- tokens := tokenize(command_line)
- if tokens[0] == "exit" {
- return makeCommand(CommandTypeBuiltinExit, tokens), nil
- }
- if tokens[0] == "echo" {
- return makeCommand(CommandTypeBuiltinEcho, tokens), nil
- }
- return makeCommandNone(), fmt.Errorf("%s: command not found", tokens[0])
- }
-
- func handleCommand(ctx Context, command Command) {
- _ = ctx
- switch command.command_type {
- case CommandTypeNone:
- return
- case CommandTypeBuiltinExit:
- os.Exit(0)
- case CommandTypeBuiltinEcho:
- fmt.Fprintln(ctx.stdout, strings.Join(command.tokens[1:], " "))
- }
- }
-
- func main() {
- ctx := Context{
- stdout: os.Stdout,
- stderr: os.Stderr,
- stdin: os.Stdin,
- }
- for {
- command, err := getCommand(&ctx)
- if err != nil {
- fmt.Fprintln(os.Stderr, "Error reading input: ", err)
- os.Exit(1)
- }
- handleCommand(ctx, command)
- }
- }
|