main.go 1.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. package main
  2. import (
  3. "bufio"
  4. "fmt"
  5. "io"
  6. "os"
  7. )
  8. type Context struct {
  9. stdout io.Writer
  10. stderr io.Writer
  11. stdin io.Reader
  12. }
  13. type GetCommandResult int
  14. const (
  15. GetCommandResultOk GetCommandResult = iota
  16. GetCommandResultError
  17. )
  18. type Command struct {
  19. command_type CommandType
  20. tokens []string
  21. }
  22. func makeCommandNone() Command {
  23. return Command{
  24. command_type: CommandTypeNone,
  25. tokens: nil,
  26. }
  27. }
  28. func makeCommand(command_type CommandType, tokens []string) Command {
  29. if command_type == CommandTypeNone {
  30. return Command{
  31. command_type: command_type,
  32. tokens: nil,
  33. }
  34. } else {
  35. return Command{
  36. command_type: command_type,
  37. tokens: tokens,
  38. }
  39. }
  40. }
  41. type CommandType int
  42. const (
  43. CommandTypeNone CommandType = iota
  44. CommandTypeExternal
  45. CommandTypeBuiltinExit
  46. )
  47. func getCommand(ctx *Context) (Command, error) {
  48. fmt.Print("$ ")
  49. command_line, err := bufio.NewReader(ctx.stdin).ReadString('\n')
  50. if err != nil {
  51. return makeCommandNone(), err
  52. }
  53. command, err := parseCommand(command_line)
  54. if err != nil {
  55. fmt.Fprintln(ctx.stderr, err)
  56. return makeCommandNone(), nil
  57. }
  58. return command, nil
  59. }
  60. func parseTokens(str string) []string {
  61. tokens := make([]string, 2)
  62. tokens[0] = str[:len(str)-1]
  63. return tokens
  64. }
  65. func parseCommand(command_line string) (Command, error) {
  66. tokens := parseTokens(command_line)
  67. if tokens[0] == "exit" {
  68. return makeCommand(CommandTypeBuiltinExit, tokens), nil
  69. }
  70. return makeCommandNone(), fmt.Errorf("%s: command not found", tokens[0])
  71. }
  72. func handleCommand(ctx Context, command Command) {
  73. _ = ctx
  74. switch command.command_type {
  75. case CommandTypeNone:
  76. return
  77. case CommandTypeBuiltinExit:
  78. os.Exit(0)
  79. }
  80. }
  81. func main() {
  82. ctx := Context{
  83. stdout: os.Stdout,
  84. stderr: os.Stderr,
  85. stdin: os.Stdin,
  86. }
  87. for {
  88. command, err := getCommand(&ctx)
  89. if err != nil {
  90. fmt.Fprintln(os.Stderr, "Error reading input: ", err)
  91. os.Exit(1)
  92. }
  93. handleCommand(ctx, command)
  94. }
  95. }