forked from jjfiv/CSC262P1
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathShellEnvironment.java
More file actions
222 lines (206 loc) · 6.23 KB
/
ShellEnvironment.java
File metadata and controls
222 lines (206 loc) · 6.23 KB
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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
package edu.smith.cs.csc262.coopsh;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import edu.smith.cs.csc262.coopsh.apps.Cat;
import edu.smith.cs.csc262.coopsh.apps.Pwd;
import edu.smith.cs.csc262.coopsh.apps.WordCount;
import edu.smith.cs.csc262.coopsh.apps.Echo;
import edu.smith.cs.csc262.coopsh.apps.Head;
import edu.smith.cs.csc262.coopsh.apps.ListFiles;
import edu.smith.cs.csc262.coopsh.apps.RegexGrep;
import edu.smith.cs.csc262.coopsh.apps.SetVar;
import edu.smith.cs.csc262.coopsh.apps.SimpleGrep;
import edu.smith.cs.csc262.coopsh.apps.Sort;
import edu.smith.cs.csc262.coopsh.apps.Tail;
import edu.smith.cs.csc262.coopsh.text.ShellParser;
import edu.smith.cs.csc262.coopsh.text.Token;
/**
* This represents the state of our shell. The current working directory is a
* File, and there is a Map of environment variables. "cd" is already
* implemented, and if you use {@linkplain #makeFile(String)} instead of
* creating new {@linkplain java.io.File} objects directly, it will try to use
* this current working directory.
*
* You will mostly be editing the {@linkplain #makeProgram(String, String[])}
* method.
*
* @author jfoley
*
*/
public class ShellEnvironment {
/**
* This is the answer for pwd.
*/
public File currentDirectory;
/**
* This is the answer for env.
*/
public Map<String, String> variables;
/**
* Create a shell environment from the current directory.
*
* @param currentDirectory - try {@code new File(".")}.
*/
public ShellEnvironment(File currentDirectory) {
this.currentDirectory = currentDirectory;
this.variables = new HashMap<>(System.getenv());
this.executeChangeDir(".");
}
/**
* This is the core method of this environment. This is the "exec" system call
* for our toy OS here.
*
* @param name - the name of the program to run.
* @param args - the arguments to pass to that program.
* @return a Task object.
*/
public Task makeProgram(String name, String[] args) {
switch (name) {
// Program: return a new Task object.
case "cat":
return new Cat(this, args);
case "pwd":
return new Pwd(this, args);
case "echo":
return new Echo(this, args);
case "head":
return new Head(this, args);
case "ls":
return new ListFiles(this, args);
case "grep":
return new SimpleGrep(this, args);
case "rgrep":
return new RegexGrep(this, args);
case "tail":
return new Tail(this, args);
case "set":
return new SetVar(this, args);
case "sort":
return new Sort(this, args);
case "wc":
return new WordCount(this, args);
// cd is special.
case "cd":
if (args.length != 1)
throw new IllegalArgumentException("More than one argument to cd!");
executeChangeDir(args[0]);
return null;
// Agh!
default:
throw new RuntimeException("No such program: " + name);
}
}
/**
* This tries to append the string to the current directory if it makes sense...
*
* @param path - the path the user typed in.
* @return a file from the local directory or an absolute path depending on
* whether it starts with a /
*/
public File makeFile(String path) {
if (path.startsWith("/")) {
return new File(path);
} else {
return new File(this.currentDirectory, path);
}
}
/**
* This is how "cd" works in our shell. It's kind of magical.
*
* @param path
*/
private void executeChangeDir(String path) {
//split string for tilde case
String tildeCheck = path.substring(0,1);
//String remainder = path.substring(2);
//case for if it is the shortcut to the home directory
if(tildeCheck.equals("~/") || tildeCheck.equals("~\\")|| tildeCheck.equals("~")) {
//take us back to the home directory
File home = new File(System.getProperty("user.home"));
this.currentDirectory=home;
//System.out.println(currentDirectory);
if(path.length()<2){
return;
}
else{
path = path.substring(2);
}
}
// Well, now we have a path.
this.currentDirectory = makeFile(path);
// Now make it meaningful...
// Only cd into directories...
while (this.currentDirectory.isFile() || !this.currentDirectory.exists()) {
this.currentDirectory = this.currentDirectory.getParentFile();
}
// Ask the real OS to clean up the path for us.
// It's a syscall, at least on *nix so it might fail.
try {
this.currentDirectory = this.currentDirectory.getCanonicalFile();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* Don't worry about the implementation here. This parses a subset of shell
* syntax, and finds the statements separated by pipes.
*
* @param line a string
* @return a list of tasks, that were maybe separated by pipes before.
*/
public List<Task> execute(String line) {
List<Token> input = ShellParser.parse(this, line);
List<Task> programs = new ArrayList<>();
for (List<Token> part : ShellParser.splitAtOperator("|", input)) {
List<String> spec = ShellParser.toStrings(part);
String program = spec.get(0);
String[] arguments = spec.subList(1, spec.size()).toArray(new String[0]);
Task maybe = makeProgram(program, arguments);
if (maybe != null) {
programs.add(maybe);
}
}
if (programs.size() != 0) {
// All programs "pipe" to the Console in our OS.
programs.add(new ConsolePrinter(this));
for (int i = 0; i < programs.size() - 1; i++) {
programs.get(i).pipesTo(programs.get(i + 1));
}
}
return programs;
}
/**
* Look up an environment variable in this environment.
* @param name - the name of the variable.
* @return the string value.
*/
public String getVariable(String name) {
return variables.get(name);
}
/**
* Set a variable in the environment. We may never use this...
* @param name - the name of the variable.
* @param value - the new value.
*/
public void setVariable(String name, String value) {
System.out.println("value : " + value );
this.variables.put(name, value);
}
/**
* Look up a variable in the environment, or use a backup.
* @param name - the variable name.
* @param whenNull - the backup variable.
* @return the value or the backup.
*/
public String getOrElse(String name, String whenNull) {
String found = getVariable(name);
if (found == null) {
return whenNull;
}
return found;
}
}