📄 console.java
字号:
displayPrompt(); return; } cProcess = new ConsoleProcess(command); cProcess.execute(); /*append("\n> " + command, infoColor); try { if (Utilities.JDK_VERSION.charAt(2) < '3') process = Runtime.getRuntime().exec(command); else process = Runtime.getRuntime().exec(command, null, new File(System.getProperty("user.dir"))); process.getOutputStream().close(); } catch (IOException ioe) { error(Jext.getProperty("console.error")); displayPrompt(); return; } stdout = new StdoutThread(); stderr = new StderrThread(); if (process == null) displayPrompt();*/ } class ConsoleProcess { private boolean executed; private Process process; private String command; /**Name of the command, here for being put inside messages*/ private String processName; private int exitCode; private Object exitCodeLock = new Object(); private StdoutThread stdout; private StderrThread stderr; private StdinThread stdin; private String stdinRedir, stdoutRedir; /**Synchronize on this obj(set to null) for event related to threading inside this object.*/ private Object lockObj = new Object(); /* * This should be used to notify stdin when the process actually started. * But this design is probably broken. Better for now just the sleep(500), * even if it's broken at all and it just has happened to always work. */ /*private Object stdinCloseLockObj = new Object(); private boolean processStarted = false;*/ ConsoleProcess(String command) { this.command = handleRedirs(command); executed = false; } int getExitCode() { synchronized(exitCodeLock) { return exitCode; } } public void execute() { if (executed) return; executed = true; /*if (stdinRedir != null) alwaysAllowType = false; //we don't let else alwaysAllowType = false; //since we forbid typing to stdin, then we set this to false anyway.*/ int index = command.indexOf(' '); if (index != -1) processName = command.substring(0, index); else processName = command; info("> " + command); try { if (Utilities.JDK_VERSION.charAt(2) < '3') process = Runtime.getRuntime().exec(command); else process = Runtime.getRuntime().exec(command, null, new File(System.getProperty("user.dir"))); } catch (IOException ioe) { error(Jext.getProperty("console.error")); displayPrompt(); return; } stdout = new StdoutThread(stdoutRedir); stderr = new StderrThread(); if (alwaysAllowType || stdinRedir != null) stdin = new StdinThread(stdinRedir); else stdin = new StdinThread(stdinRedir, true); //this thread will just //close the stream, in this case. It's needed for some problems on Unix(see below) synchronized(lockObj) { stdout.start(); stderr.start(); stdin.start(); } } /** * This handles the parsing of I/O redirections, and sets stdinRedir * and stdoutRedir. */ private String handleRedirs(String toParse) { int i, end; i = toParse.lastIndexOf('>'); if ( i != -1 ) { while (toParse.charAt(++i) == ' '); //skips spaces after > end = toParse.indexOf('<', i); //the name of the file is from the > to the end or to the < if (end == -1) end = toParse.length(); while (toParse.charAt(--end) == ' '); //skips spaces before < end++; stdoutRedir = toParse.substring(i, end); } else { stdoutRedir = null; } i = toParse.lastIndexOf('<'); if ( i != -1 ) { while (toParse.charAt(++i) == ' '); //skips spaces after < end = toParse.indexOf('>', i); //the name of the file is from the < to the end or to the > if (end == -1) end = toParse.length(); while (toParse.charAt(--end) == ' '); //skips spaces before < end++; stdinRedir = toParse.substring(i, end); } else { stdinRedir = null; } int lt = toParse.indexOf('<'); if (lt == -1) lt = toParse.length(); int gt = toParse.indexOf('>'); if (gt == -1) gt = toParse.length(); end = Math.min(lt,gt); return toParse.substring(0, end); } /** * Stops current task. */ public void stop() { synchronized(lockObj) { if (stdout != null) { stdout.interrupt(); stdout = null; } if (stderr != null) { stderr.interrupt(); stderr = null; } if (stdin != null) { stdin.interrupt(); stdin = null; } if (process != null) { process.destroy(); Object[] args = { processName }; error(Jext.getProperty("console.killed", args)); process = null; } } } void sendToProcess(String toPrint) { if (stdin != null) stdin.print(toPrint); } class StdinThread extends Thread { StdinThread(String inFileName) { this(inFileName, false); } StdinThread(String inFileName, boolean justClose) { super("Console stdin"); this.inFileName = inFileName; this.justClose = justClose; } private String toPrint, inFileName; private boolean justClose; /** * Must be called by the AWT-EventQueue thread, to make this one print some text * to the process's stdin. */ synchronized void print(String toPrint) { this.toPrint = toPrint; this.notify(); } public void run() { if (process == null) return; PrintWriter out = new PrintWriter(process.getOutputStream()); if (!justClose) { System.out.println("StdinThread started running"); if (inFileName == null) { try { while(!isInterrupted()) {//this is needed to catch the interrupt when we are not //wait()'ing synchronized (this) { this.wait(); } if (toPrint != null) { out.print(toPrint); out.flush(); toPrint = null; } } } catch (NullPointerException npe) { npe.printStackTrace(); } catch (InterruptedException ie) { ie.printStackTrace();//FIXME: this happens often, so turn it off after debug. } } else { File f = new File(inFileName); if (f.exists()) { FileReader in = null; try { in = new FileReader(f); char[] buf = new char[256]; int nRead; while ( ( nRead = in.read(buf)) != -1) out.write(buf, 0, nRead); } catch(IOException ioe) { ioe.printStackTrace(); } finally { try { in.close(); } catch (IOException ioe) {ioe.printStackTrace();} } } else { error("Jext: file " + inFileName + "not found"); } } //end if (inFileName != null) } //end if (!justClose) /*synchronized(stdinCloseLockObj) { if (! processStarted) stdinCloseLockObj.wait(); }*/ /* If the close happens when the native process has not yet started truly running, * it's very easy for it to deadlock(at least on Linux). So I add these lines.*/ try { sleep(500); } catch (InterruptedException ie) { } out.close(); } } class StdoutThread extends Thread { StdoutThread(String outFileName) { super("Console stdout"); this.outFileName = outFileName; } private String outFileName; public void run() { BufferedReader in = null; try { in = new BufferedReader(new InputStreamReader(process.getInputStream())); System.out.println("StdoutThread started running"); if (outFileName == null) { try { String line; /*synchronized(stdinCloseLockObj) { processStarted = true; stdinCloseLockObj.notify(); }*/ while((line = in.readLine()) != null) output(line); /*int nRead; char[] buf = new char[100]; boolean started = false; while((nRead = in.read(buf)) != -1) { if (!started) { started = true; append("\n", outputColor); } append(new String(buf, 0, nRead), outputColor); //userLimit = outputDocument.getLength();//we display text that the user //can't delete and that getText mustn't read }*/ } catch (IOException io) {} } else { BufferedWriter out = null; try { out = new BufferedWriter(new FileWriter(outFileName)); char[] buf = new char[256]; int nRead; while ( ( nRead = in.read(buf)) != -1) out.write(buf, 0, nRead); } catch(IOException ioe) { ioe.printStackTrace(); } finally { try { out.close(); } catch (IOException ioe) {ioe.printStackTrace();} } } if (isInterrupted()) return; //this should remove some NPE throwns. If we have been interrupted //(by stop()), the process var has been set to null synchronized(lockObj) { synchronized(exitCodeLock) { //this is safe because the other exitCode lock //doesn't contain a lockObj lock exitCode = process.waitFor(); } Object[] args = { processName, new Integer(exitCode) }; info(Jext.getProperty("console.exited", args));//this instead must be audited, //since it calls SwingUtilities.invokeLater. } sleep(500); synchronized(lockObj) { process.destroy(); if (stdin != null) stdin.interrupt(); process = null; //cProcess = null; } SwingUtilities.invokeLater(new Runnable() { public void run() { displayPrompt(); } }); } catch (NullPointerException npe) { npe.printStackTrace(); } catch (InterruptedException ie) { ie.printStackTrace(); } finally { try { in.close(); } catch (IOException ioe) {ioe.printStackTrace();} } } } class StderrThread extends Thread { StderrThread() { super("Console stderr"); } public void run() { try { if (process == null) return; BufferedReader in = new BufferedReader(new InputStreamReader(process.getErrorStream())); String line; while((line = in.readLine()) != null) error(line); //two versions of better code. I must first change //the convention of messages starting with \n, instead of ending with //\n. The second is older and slower, the first not tested. /*char buf[] = new char[64]; int nRead = 0; while(n != -1) { int nRead = in.available(); if (nRead == 0) nRead = in.read(buf); //here we block, not in any other case. else { nRead = Math.min(nRead, 64); nRead = in.read(buf, 0, nRead);//here we're guaranted to read the maximum //we can without blocking } append(new String(buf, 0, nRead), errorColor); //userLimit = outputDocument.getLength();//we display text that the user //can't delete and that getText mustn't read }*/ /*int c; while((c = in.read()) != -1) { append("" + ((char)c), errorColor); }*/ in.close(); } catch(IOException io) { } catch (NullPointerException npe) { } } } } ////////////////////////////////////////////////////////////////////////////////////////////// // NEEDED BY JavaScriptParser PLUGIN ////////////////////////////////////////////////////////////////////////////////////////////// private Writer writerSTDOUT = new Writer() { public void close() { } public void flush() { repaint(); } public void write( char cbuf[], int off, int len ) { Console.this.append(new String(cbuf, off, len), outputColor); } }; private Writer writeSTDERR = new Writer() { public void close() { } public void flush() { repaint(); } public void write( char cbuf[], int off, int len ) { Console.this.append(new String(cbuf, off, len), errorColor); } }; /** * Returns a writer in which external classes can send * <code>String</code> to make them being displayed in the * console as standard output. */ public Writer getStdOut() { return writerSTDOUT; } /** * Returns a writer in which external classes can send * <code>String</code> to make them being displayed in the * console as error output. */ public Writer getStdErr() { return writeSTDERR; } }// End of Console.java
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -