浏览代码

Implement #IP1

Alois Mahdal 1周前
父节点
当前提交
f5cdcd40c5
共有 1 个文件被更改,包括 34 次插入44 次删除
  1. 34
    44
      app/main.go

+ 34
- 44
app/main.go 查看文件

@@ -5,42 +5,23 @@ import (
5 5
 	"fmt"
6 6
 	"io"
7 7
 	"os"
8
+	"os/exec"
8 9
 	"strings"
9 10
 )
10 11
 
11
-func getenv(key string, fallback string) string {
12
-	value, ok := os.LookupEnv(key)
13
-	if ok {
14
-		return value
15
-	} else {
16
-		return fallback
17
-	}
18
-}
12
+type ExitStatus uint16
19 13
 
20 14
 type Context struct {
21 15
 	stdout io.Writer
22 16
 	stderr io.Writer
23 17
 	stdin  io.Reader
24
-	paths  []string
25 18
 }
26 19
 
27 20
 func makeContext() Context {
28
-	path_str := getenv("PATH", "")
29
-	paths := make([]string, 0)
30
-	for elem := range strings.SplitSeq(path_str, ":") {
31
-		if elem == "" {
32
-			continue
33
-		}
34
-		if !strings.HasPrefix(elem, "/") {
35
-			continue
36
-		}
37
-		paths = append(paths, elem)
38
-	}
39 21
 	return Context{
40 22
 		stdout: os.Stdout,
41 23
 		stderr: os.Stderr,
42 24
 		stdin:  os.Stdin,
43
-		paths:  paths,
44 25
 	}
45 26
 }
46 27
 
@@ -103,7 +84,7 @@ func getCommand(ctx *Context) (Command, error) {
103 84
 	if err != nil {
104 85
 		return makeCommandNone(), err
105 86
 	}
106
-	command, err := parseCommand(command_line, ctx.paths)
87
+	command, err := parseCommand(command_line)
107 88
 	// fmt.Printf("getCommand():command=%#v\n", command)
108 89
 	if err != nil {
109 90
 		fmt.Fprintln(ctx.stderr, err)
@@ -136,7 +117,7 @@ func (e ParseCommandError) Error() string {
136 117
 	}
137 118
 }
138 119
 
139
-func parseCommand(command_line string, paths []string) (Command, error) {
120
+func parseCommand(command_line string) (Command, error) {
140 121
 	tokens := tokenize(command_line)
141 122
 	if len(tokens) == 0 {
142 123
 		return makeCommandNone(), nil
@@ -150,29 +131,18 @@ func parseCommand(command_line string, paths []string) (Command, error) {
150 131
 	if tokens[0] == "type" {
151 132
 		return makeCommandBuiltin(CommandTypeBuiltinType, tokens), nil
152 133
 	}
153
-	for _, path := range paths {
154
-		full_path := fmt.Sprintf("%s/%s", path, tokens[0])
155
-		// fmt.Printf("parseCommand():full_path=%#v\n", full_path)
156
-		stat, err := os.Stat(full_path)
157
-		if err != nil {
158
-			continue
159
-		}
160
-		if stat.IsDir() {
161
-			continue
162
-		}
163
-		if stat.Mode()&0100 == 0 {
164
-			continue
165
-		}
166
-		return makeCommandExternal(tokens, full_path), nil
134
+	exec_path, err := exec.LookPath(tokens[0])
135
+	if err != nil {
136
+		return makeCommandNone(), ParseCommandError{ParseCommandErrorCodeNotFound, tokens[0]}
167 137
 	}
168
-	return makeCommandNone(), ParseCommandError{ParseCommandErrorCodeNotFound, tokens[0]}
138
+	return makeCommandExternal(tokens, exec_path), nil
169 139
 }
170 140
 
171
-func handleCommand(ctx Context, command Command) {
141
+func handleCommand(ctx Context, command Command) ExitStatus {
172 142
 	// fmt.Printf("handleCommand():command=%#v\n", command)
173 143
 	switch command.command_type {
174 144
 	case CommandTypeNone:
175
-		return
145
+		return 0
176 146
 	case CommandTypeBuiltinExit:
177 147
 		os.Exit(0)
178 148
 	case CommandTypeBuiltinEcho:
@@ -180,12 +150,12 @@ func handleCommand(ctx Context, command Command) {
180 150
 	case CommandTypeBuiltinType:
181 151
 		if len(command.tokens) != 2 {
182 152
 			fmt.Fprintln(ctx.stderr, "usage: type COMMAND")
183
-			return
153
+			return 2
184 154
 		}
185
-		parsed, err := parseCommand(command.tokens[1], ctx.paths)
155
+		parsed, err := parseCommand(command.tokens[1])
186 156
 		if err != nil {
187 157
 			fmt.Fprintln(ctx.stderr, err)
188
-			return
158
+			return 0
189 159
 		}
190 160
 		switch parsed.command_type {
191 161
 		case CommandTypeNone:
@@ -195,7 +165,27 @@ func handleCommand(ctx Context, command Command) {
195 165
 		default:
196 166
 			fmt.Fprintf(ctx.stdout, "%s is a shell builtin\n", parsed.tokens[0])
197 167
 		}
168
+	case CommandTypeExternal:
169
+		cmd := exec.Command(command.exec_path, command.tokens[1:]...)
170
+		cmd.Args = command.tokens
171
+		cmd.Stdout = ctx.stdout
172
+		cmd.Stderr = ctx.stderr
173
+		cmd.Stdin = ctx.stdin
174
+		err := cmd.Run()
175
+		if err != nil {
176
+			if exiterr, ok := err.(*exec.ExitError); ok {
177
+				return ExitStatus(exiterr.ExitCode())
178
+				// fmt.Printf("handleCommand():exiterr=%#v\n", exiterr.ExitCode())
179
+			} else {
180
+				fmt.Printf("handleCommand():err=%#v\n", err)
181
+				return ExitStatus(65535)
182
+			}
183
+		}
184
+		return ExitStatus(0)
185
+	default:
186
+		panic("unknown command type")
198 187
 	}
188
+	return ExitStatus(65535)
199 189
 }
200 190
 
201 191
 func main() {
@@ -206,6 +196,6 @@ func main() {
206 196
 			fmt.Fprintln(os.Stderr, "Error reading input: ", err)
207 197
 			os.Exit(1)
208 198
 		}
209
-		handleCommand(ctx, command)
199
+		_ = handleCommand(ctx, command)
210 200
 	}
211 201
 }