|
|
@@ -34,15 +34,17 @@ const (
|
|
34
|
34
|
|
|
35
|
35
|
type Command struct {
|
|
36
|
36
|
command_type CommandType
|
|
37
|
|
- tokens []string
|
|
|
37
|
+ args []string
|
|
38
|
38
|
exec_path string
|
|
|
39
|
+ name string
|
|
39
|
40
|
}
|
|
40
|
41
|
|
|
41
|
42
|
func makeCommandNone() Command {
|
|
42
|
43
|
return Command{
|
|
43
|
44
|
command_type: CommandTypeNone,
|
|
44
|
|
- tokens: nil,
|
|
|
45
|
+ args: nil,
|
|
45
|
46
|
exec_path: "",
|
|
|
47
|
+ name: "",
|
|
46
|
48
|
}
|
|
47
|
49
|
}
|
|
48
|
50
|
|
|
|
@@ -53,17 +55,25 @@ func makeCommandBuiltin(command_type CommandType, tokens []string) Command {
|
|
53
|
55
|
case CommandTypeExternal:
|
|
54
|
56
|
panic("invalid usage")
|
|
55
|
57
|
default:
|
|
|
58
|
+ if len(tokens) < 1 {
|
|
|
59
|
+ panic("assertion failed: token list must not be empty")
|
|
|
60
|
+ }
|
|
56
|
61
|
return Command{
|
|
57
|
62
|
command_type: command_type,
|
|
58
|
|
- tokens: tokens,
|
|
|
63
|
+ name: tokens[0],
|
|
|
64
|
+ args: tokens[1:],
|
|
59
|
65
|
}
|
|
60
|
66
|
}
|
|
61
|
67
|
}
|
|
62
|
68
|
|
|
63
|
69
|
func makeCommandExternal(tokens []string, exec_path string) Command {
|
|
|
70
|
+ if len(tokens) < 1 {
|
|
|
71
|
+ panic("assertion failed: token list must not be empty")
|
|
|
72
|
+ }
|
|
64
|
73
|
return Command{
|
|
65
|
74
|
command_type: CommandTypeExternal,
|
|
66
|
|
- tokens: tokens,
|
|
|
75
|
+ name: tokens[0],
|
|
|
76
|
+ args: tokens[1:],
|
|
67
|
77
|
exec_path: exec_path,
|
|
68
|
78
|
}
|
|
69
|
79
|
}
|
|
|
@@ -153,11 +163,11 @@ func handleCommand(ctx Context, command Command) ExitStatus {
|
|
153
|
163
|
os.Exit(0)
|
|
154
|
164
|
|
|
155
|
165
|
case CommandTypeBuiltinEcho:
|
|
156
|
|
- fmt.Fprintln(ctx.stdout, strings.Join(command.tokens[1:], " "))
|
|
|
166
|
+ fmt.Fprintln(ctx.stdout, strings.Join(command.args, " "))
|
|
157
|
167
|
return 0
|
|
158
|
168
|
|
|
159
|
169
|
case CommandTypeBuiltinPwd:
|
|
160
|
|
- if len(command.tokens) != 1 {
|
|
|
170
|
+ if len(command.args) != 0 {
|
|
161
|
171
|
fmt.Fprintln(ctx.stderr, "usage: pwd")
|
|
162
|
172
|
return 2
|
|
163
|
173
|
}
|
|
|
@@ -169,11 +179,11 @@ func handleCommand(ctx Context, command Command) ExitStatus {
|
|
169
|
179
|
return 0
|
|
170
|
180
|
|
|
171
|
181
|
case CommandTypeBuiltinType:
|
|
172
|
|
- if len(command.tokens) != 2 {
|
|
|
182
|
+ if len(command.args) != 1 {
|
|
173
|
183
|
fmt.Fprintln(ctx.stderr, "usage: type COMMAND")
|
|
174
|
184
|
return 2
|
|
175
|
185
|
}
|
|
176
|
|
- parsed, err := parseCommand(command.tokens[1])
|
|
|
186
|
+ parsed, err := parseCommand(command.args[0])
|
|
177
|
187
|
if err != nil {
|
|
178
|
188
|
fmt.Fprintln(ctx.stderr, err)
|
|
179
|
189
|
return 0
|
|
|
@@ -182,15 +192,15 @@ func handleCommand(ctx Context, command Command) ExitStatus {
|
|
182
|
192
|
case CommandTypeNone:
|
|
183
|
193
|
panic("impossible parseCommand() result")
|
|
184
|
194
|
case CommandTypeExternal:
|
|
185
|
|
- fmt.Fprintf(ctx.stdout, "%s is %s\n", parsed.tokens[0], parsed.exec_path)
|
|
|
195
|
+ fmt.Fprintf(ctx.stdout, "%s is %s\n", parsed.name, parsed.exec_path)
|
|
186
|
196
|
default:
|
|
187
|
|
- fmt.Fprintf(ctx.stdout, "%s is a shell builtin\n", parsed.tokens[0])
|
|
|
197
|
+ fmt.Fprintf(ctx.stdout, "%s is a shell builtin\n", parsed.name)
|
|
188
|
198
|
}
|
|
189
|
199
|
return 0
|
|
190
|
200
|
|
|
191
|
201
|
case CommandTypeExternal:
|
|
192
|
|
- cmd := exec.Command(command.exec_path, command.tokens[1:]...)
|
|
193
|
|
- cmd.Args = command.tokens
|
|
|
202
|
+ cmd := exec.Command(command.exec_path, command.args...)
|
|
|
203
|
+ cmd.Args[0] = command.name
|
|
194
|
204
|
cmd.Stdout = ctx.stdout
|
|
195
|
205
|
cmd.Stderr = ctx.stderr
|
|
196
|
206
|
cmd.Stdin = ctx.stdin
|