package game; import com.badlogic.gdx.Gdx; import game.pythonapi.PyDebug; import game.pythonapi.PyDisplay; import game.pythonapi.PyNetworking; import game.pythonapi.PyTest; import gui.windows.device.Terminal; import org.python.core.PyException; import org.python.util.PythonInterpreter; import other.coreutils.FileUtils; import other.coreutils.ShellUtils; import other.coreutils.TextUtils; import java.io.FileNotFoundException; import java.io.OutputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; public class Command { private final String input; private final Terminal terminal; private final Operation operation; private List<String> pipedInput; private List<String> pipedOutput; private final Queue<Character> out = new ConcurrentLinkedQueue<Character>(); private final OutputStream outputStream; /** * Runs the desired command on a separate thread. Not that any program would * be intensive at all, but sleep(n) or large iterations will not lock up * the game. */ public Command(String input, final Terminal terminal, Operation operation) { this.input = input; this.terminal = terminal; this.operation = operation; outputStream = new OutputStream() { @Override public void write(int i) { terminal.addText((char) i); out.offer((char) i); } }; } public boolean run() { List<String> parameters = parameters(); Gdx.app.debug("Terminal Command", input + " " + parameters.toString()); if (parameters.isEmpty()) { return false; } try { runChooser(parameters); // stop the command list altogether, that is how linux does it } catch (IllegalAccessException e) { e.printStackTrace(); return false; } catch (InvocationTargetException e) { e.printStackTrace(); return false; } catch (FileNotFoundException e) { Gdx.app.debug("Terminal Info", e.getMessage(), e); terminal.addTextln("file not found"); return false; } catch (PyException e) { Gdx.app.error("Terminal Error", e.getMessage(), e); return false; } return true; } private List<String> parameters() { List<String> parameters = new ArrayList<String>(); String s = input; while (s.matches("\\s*[(?:\".*?\")|\\S+].*")) { if (s.startsWith(" ")) { s = s.replaceFirst("\\s+", ""); } String inputTemp = s; s = s.replaceFirst("(?:\".*?\")|\\S+", ""); int l = s.length(); String next = inputTemp.substring(0, inputTemp.length() - l); parameters.add(next); } return parameters; } private void runChooser(List<String> parameters) throws FileNotFoundException, InvocationTargetException, IllegalAccessException { if (FileUtils.METHOD_MAP.containsKey(parameters.get(0))) { FileUtils fileUtils = new FileUtils(this); Method method = FileUtils.METHOD_MAP.get(parameters.get(0)); parameters.remove(0); method.invoke(fileUtils, parameters, pipedInput); return; } else if (TextUtils.METHOD_MAP.containsKey(parameters.get(0))) { TextUtils textUtils = new TextUtils(this); Method method = TextUtils.METHOD_MAP.get(parameters.get(0)); parameters.remove(0); method.invoke(textUtils, parameters, pipedInput); return; } else if (ShellUtils.METHOD_MAP.containsKey(parameters.get(0))) { ShellUtils shellUtils = new ShellUtils(this); Method method = ShellUtils.METHOD_MAP.get(parameters.get(0)); parameters.remove(0); method.invoke(shellUtils, parameters, pipedInput); return; } else { runPython(parameters, pipedInput); } pipedOutput.add(""); for (char c : out) { if (c == '\n') { pipedOutput.add(""); } else { String element = pipedOutput.get(pipedOutput.size() - 1) + c; pipedOutput.set(pipedOutput.size() - 1, element); } } } private void runPython(List<String> parameters, List<String> pipedText) throws FileNotFoundException { PythonInterpreter pi = new PythonInterpreter(); other.File file; file = terminal.getDevice().getBin().getFile(parameters.get(0)); // executable files may only be run if they are in the bin directory if (file == null) { throw new FileNotFoundException(); } Gdx.app.debug("Terminal Info", "python file: " + file.getName()); if (parameters.size() > 1) { parameters.remove(0); // first parameter is always the command } pi.set("terminal", terminal); pi.set("DISPLAY", new PyDisplay(terminal)); pi.set("DEBUG", new PyDebug(terminal)); pi.set("NETWORKING", new PyNetworking(terminal)); pi.set("TEST", new PyTest(terminal)); pi.set("parameters", parameters); pi.set("piped_text", pipedText); // pi.set("Display", new PyDisplay(Terminal)); pi.setIn(terminal.getInputStream()); pi.setOut(outputStream); // there really is no good way of doing this // if (!checkPythonForCheats(file)) { // return; // screw it, for now let them hack away // } pi.exec(file.getData()); } public enum Operation { PIPE/* '|' */, SUCCESSFUL/* '&&' */, NOT_SUCCESSFUL/* '||' */, EITHER/* ';' */ } public List<String> getPipedOutput() { return pipedOutput; } public void setPipedInput(List<String> pipedInput) { this.pipedInput = pipedInput; } public Operation getOperation() { return operation; } public Queue<Character> getOut() { return out; } public Terminal getTerminal() { return terminal; } public OutputStream getOutputStream() { return outputStream; } }