[Title] add ansicode console
authorYoonKi Park <yoonki.park@samsung.com>
Mon, 21 Nov 2011 01:53:13 +0000 (10:53 +0900)
committerYoonKi Park <yoonki.park@samsung.com>
Mon, 21 Nov 2011 01:53:13 +0000 (10:53 +0900)
[Redmine#] 2029

com.samsung.slp.common/src/com/samsung/slp/common/console/AnsicodeAdapter.java [new file with mode: 0644]
com.samsung.slp.common/src/com/samsung/slp/common/process/PTY.java [new file with mode: 0644]
com.samsung.slp.common/src/com/samsung/slp/common/process/PTYInputStream.java [new file with mode: 0644]
com.samsung.slp.common/src/com/samsung/slp/common/process/PTYOutputStream.java [new file with mode: 0644]
com.samsung.slp.common/src/com/samsung/slp/common/process/ProcessClosure.java [new file with mode: 0644]
com.samsung.slp.common/src/com/samsung/slp/common/process/ProcessFactory.java [new file with mode: 0644]
com.samsung.slp.common/src/com/samsung/slp/common/process/ProcessLauncher.java [new file with mode: 0644]
com.samsung.slp.common/src/com/samsung/slp/common/process/Spawner.java [new file with mode: 0644]
com.samsung.slp.common/src/com/samsung/slp/common/process/SpawnerInputStream.java [new file with mode: 0644]
com.samsung.slp.common/src/com/samsung/slp/common/process/SpawnerOutputStream.java [new file with mode: 0644]
com.samsung.slp.common/src/com/samsung/slp/common/util/ConsoleManager.java

diff --git a/com.samsung.slp.common/src/com/samsung/slp/common/console/AnsicodeAdapter.java b/com.samsung.slp.common/src/com/samsung/slp/common/console/AnsicodeAdapter.java
new file mode 100644 (file)
index 0000000..a3a9c2c
--- /dev/null
@@ -0,0 +1,193 @@
+package com.samsung.slp.common.console;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.LineStyleEvent;
+import org.eclipse.swt.custom.StyleRange;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.widgets.Display;
+
+public class AnsicodeAdapter {
+       public static final char ESCAPE = '\033'; // ANSI Escape Character that starts commands
+
+/*    public static final Color BLACK = Color.BLACK;           
+    public static final Color RED = Color.RED.darker();    
+    public static final Color GREEN = Color.GREEN.darker();  
+    public static final Color YELLOW = Color.YELLOW.darker(); 
+    public static final Color BLUE = new Color(66, 66, 255).darker();  
+    public static final Color MAGENTA = Color.MAGENTA.darker();
+    public static final Color CYAN = Color.CYAN.darker();   
+    public static final Color WHITE = Color.GRAY.brighter(); 
+
+    public static final Color INTENSE_BLACK = Color.GRAY.darker(); 
+    public static final Color INTENSE_RED = Color.RED;             
+    public static final Color INTENSE_GREEN = Color.GREEN;           
+    public static final Color INTENSE_YELLOW = Color.YELLOW;          
+    public static final Color INTENSE_BLUE = new Color(66, 66, 255);
+    public static final Color INTENSE_MAGENTA = Color.MAGENTA;         
+    public static final Color INTENSE_CYAN = Color.CYAN;            
+    public static final Color INTENSE_WHITE = Color.WHITE;           
+
+    private static final Color normal[] = {BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE};
+    private static final Color bright[] = {INTENSE_BLACK, INTENSE_RED, INTENSE_GREEN, INTENSE_YELLOW, INTENSE_BLUE, INTENSE_MAGENTA,
+            INTENSE_CYAN, INTENSE_WHITE};*/
+    
+    private Color foreground;
+       private Color background;
+       private int fontStyles;
+       
+        //"\e[31mHello World\e[m" 
+       private static String ansiString;
+       private static LineStyleEvent lineEvent;
+       private static AnsicodeAdapter instance;
+       private static boolean hasAnsicode = false;
+       
+       private static int commandSGR = 'm';
+       private static int commandDSR = 'n';
+       private static int[] commands = {'m','n'};
+       private static List<StyleRange> styles = new ArrayList<StyleRange>();
+       public AnsicodeAdapter() {}
+       
+       /**
+        * Get instance of AnsicodeAdapter
+        * @param string The String should end with '\n'
+        * @return Returns the AnsicodeAdapter's incstance
+        */
+       public static AnsicodeAdapter getInstance(LineStyleEvent event)
+       {
+               if (instance == null) 
+                       instance = new AnsicodeAdapter();
+               lineEvent = event;
+               ansiString = event.lineText;
+               parseLineStyle();
+               return instance;                
+       }
+       public static AnsicodeAdapter getDefault()
+       {
+               if (instance == null) 
+                       instance = new AnsicodeAdapter();
+               return instance;                
+       }
+       public static List getRangeStyle() {
+               return styles;
+       }
+       private static void parseLineStyle() {
+               String str;
+               
+               for (int i = 0; i < ansiString.length(); i++) {
+               if (ansiString.charAt(i) == '\033') {
+                       if (ansiString.indexOf(commandSGR, i) < ansiString.length()) {
+                               
+                               int startCommand = ansiString.indexOf('m', i); 
+                               if (startCommand < 0) {
+                                       //
+                                       return;
+                               }
+                               String colorCodes = ansiString.substring(i+2,startCommand);
+                               String codes[] = colorCodes.split(";");
+                               
+                               int styleStart = startCommand+1;
+                               int styleEnd = 0;
+                               int endCommand = ansiString.indexOf('\033',styleStart);
+                               if (endCommand < 0 ) {
+                                       styleEnd = ansiString.length()-1;
+                               } else {
+                                       styleEnd = endCommand;
+                               }
+                               String styleString = ansiString.substring(styleStart, styleEnd); //remove [m
+                               
+                               StyleRange currentStyle = new StyleRange();
+                               currentStyle.start = lineEvent.lineOffset;
+                               //currentStyle.start = event.lineOffset + styleStart;
+                               currentStyle.length= styleString.length();
+                               Display display = Display.getCurrent();
+                               Color blue = display.getSystemColor(SWT.COLOR_BLUE);
+                               
+                               //currentStyle.background = blue;
+                               currentStyle.foreground = blue;
+                               styles.add(currentStyle); 
+                       ////////
+                       i = styleEnd;
+
+                   }
+               }
+       }
+       }
+       private void getStyleAttribute(String codes[]) {
+                boolean brighter = false;
+               for (int j = 0; j < codes.length; j++) {
+
+                   if (codes[j].matches("[\\d]*")) {
+                       int code = Integer.parseInt(codes[j]);
+                       if (code == 0) {
+                               brighter = false;  //reset / normal
+                       } else if (code == 1) {
+                               brighter = true;
+                       } else if (code >= 30 && code <= 37) {
+                               
+                       }
+                   }
+               }
+       }
+       public Color getForeground() {
+               return foreground;
+       }
+       public Color getBackground() {
+               return background;
+       }
+       public int getFontStyle() {
+               return fontStyles;
+       }
+       public String getStripAnsiString(String ansiString) {
+               StringBuilder sb = new StringBuilder();
+               
+               char command = 0;
+               for (int i=0; i<ansiString.length(); i++) {                     
+               if (ansiString.charAt(i) == ESCAPE) {
+                       int min = ansiString.length() ;
+                       int startCommand = 0;
+                       
+                       for (int j=0 ; j<commands.length ; j++) {
+                               startCommand = ansiString.indexOf(commands[j], i);
+                               if (min > startCommand && startCommand > -1) {
+                                       min = startCommand;
+                               }
+                       }
+                               command=ansiString.charAt(min);
+                       startCommand=min;
+                       
+                       if ( startCommand < ansiString.length()) {
+                               
+                               String colorCodes = ansiString.substring(i+2,startCommand); 
+                               String codes[] = colorCodes.split(";");
+                               
+                               int styleStart = startCommand+1;
+                               int styleEnd = 0;
+                               int endEscape = ansiString.indexOf(ESCAPE,styleStart);
+                               if (endEscape < 0 ) {
+                                       styleEnd = ansiString.length();
+                                       i = ansiString.length();
+                               } else {
+                                       int endCommand = ansiString.indexOf(command,endEscape); 
+                                       if (endCommand < 0 ) {
+                                               styleEnd = ansiString.length();
+                                               i = ansiString.length();
+                                       } else {
+                                               styleEnd = endEscape;
+                                               i = endCommand;
+                                       }       
+                               }
+                               String styleString = null;
+                               styleString = ansiString.substring(styleStart, styleEnd); 
+                               sb.append(styleString);
+                   }                   
+               }else {
+                       sb.append(ansiString.charAt(i));
+               }
+       }
+               return sb.toString();
+       }
+       
+}
diff --git a/com.samsung.slp.common/src/com/samsung/slp/common/process/PTY.java b/com.samsung.slp.common/src/com/samsung/slp/common/process/PTY.java
new file mode 100644 (file)
index 0000000..5c248ee
--- /dev/null
@@ -0,0 +1,173 @@
+package com.samsung.slp.common.process;
+
+/*******************************************************************************
+ * Copyright (c) 2002, 2010 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     QNX Software Systems - Initial API and implementation
+ *     Wind River Systems, Inc. - bug 248071
+ *******************************************************************************/
+
+import java.io.IOException;
+import com.samsung.slp.common.log.Logger;
+
+/**
+ * PTY - pseudo terminal support.
+ */
+public class PTY {
+
+       final boolean console;
+       String slave;
+       PTYInputStream in;
+       PTYOutputStream out;
+       /**
+        * NOTE: Field is accessed by the native layer. Do not refactor!
+        */
+       int master;
+
+       private static boolean hasPTY;
+       private static boolean setTerminalSizeErrorAlreadyLogged;
+
+       /**
+        * The master fd is used on two streams. We need to wrap the fd
+        * so that when stream.close() is called the other stream is disabled.
+        */
+       public class MasterFD {
+
+               public int getFD() {
+                       return master;
+               }
+
+               void setFD(int fd) {
+                       master = fd;
+               }
+       }
+
+       /**
+        * Create PTY for use with Eclipse console.
+        * Identical to {@link PTY#PTY(boolean) PTY(true)}.
+        */
+       public PTY() throws IOException {
+               this(true);
+       }
+
+       /**
+        * Create pseudo terminal.
+        * 
+        * <p>
+        * The provided flag indicates whether the pseudo terminal is used with the interactive
+        * Eclipse console:
+        * <ul>
+        * <li>If <code>true</code> the terminal is configured with no echo and stderr is
+        * redirected to a pipe instead of the PTY.</li>
+        * <li>If <code>false</code> the terminal is configured with echo and stderr is
+        * connected to the PTY. This mode is best suited for use with a proper terminal emulation.
+        * Note that this mode might not be supported on all platforms.
+        * Known platforms which support this mode are:
+        * <code>linux-x86</code>, <code>linux-x86_64</code>, <code>solaris-sparc</code>, <code>macosx</code>.
+        * </li>
+        * </ul>
+        * </p>
+        * 
+        * @param console  whether terminal is used with Eclipse console
+        * @throws IOException  if the PTY could not be created
+        * @since 5.2
+        */
+       public PTY(boolean console) throws IOException {
+               this.console = console;
+               
+               if (hasPTY) {
+                       slave= openMaster(console);
+               }
+
+               if (slave == null) {
+                       //throw new IOException(CCorePlugin.getResourceString("Util.exception.cannotCreatePty")); //$NON-NLS-1$
+                       throw new IOException("Util.exception.cannotCreatePty"); //$NON-NLS-1$
+               }
+
+               in = new PTYInputStream(new MasterFD());
+               out = new PTYOutputStream(new MasterFD());
+       }
+       
+       public String getSlaveName() {
+               return slave;
+       }
+
+       public MasterFD getMasterFD() {
+               return new MasterFD();
+       }
+
+       /**
+        * @return whether this pseudo terminal is for use with the Eclipse console.
+        * 
+        * @since 5.2
+        */
+       public final boolean isConsole() {
+               return console;
+       }
+       
+       public PTYOutputStream getOutputStream() {
+               return out;
+       }
+       
+       public PTYInputStream getInputStream() {
+               return in;
+       }
+
+       /**
+        * Change terminal window size to given width and height.
+        * <p>
+        * This should only be used when the pseudo terminal is configured
+        * for use with a terminal emulation, i.e. when {@link #isConsole()} 
+        * returns <code>false</code>.
+        * </p>
+        * <p>
+        * <strong>Note:</strong> This method may not be supported on all platforms.
+        * Known platforms which support this method are:
+        * <code>linux-x86</code>, <code>linux-x86_64</code>, <code>solaris-sparc</code>, <code>macosx</code>.
+        * </p>
+        * 
+        * @since 5.2
+        */
+       public final void setTerminalSize(int width, int height) {
+               try {
+                       change_window_size(master, width, height);
+               } catch (UnsatisfiedLinkError ule) {
+                       if (!setTerminalSizeErrorAlreadyLogged) {
+                               setTerminalSizeErrorAlreadyLogged = true;
+                               //CCorePlugin.log(CCorePlugin.getResourceString("Util.exception.cannotSetTerminalSize"), ule); //$NON-NLS-1$
+                               Logger.error(ule.getMessage() , ule);           
+                       }
+               }
+       }
+
+       /**
+        * @return whether PTY support is available on this platform
+        */
+       public static boolean isSupported() {
+               return hasPTY;
+       }
+
+       native String openMaster(boolean console);
+
+       native int change_window_size(int fdm, int width, int height);
+
+       static {
+               try {
+                       System.loadLibrary("pty"); //$NON-NLS-1$
+                       hasPTY = true;
+               } catch (SecurityException e) {
+                       // Comment out it worries the users too much
+                       //CCorePlugin.log(e);
+               } catch (UnsatisfiedLinkError e) {
+                       // Comment out it worries the users too much
+                       //CCorePlugin.log(e);
+               }                       
+       }
+       
+}
+
diff --git a/com.samsung.slp.common/src/com/samsung/slp/common/process/PTYInputStream.java b/com.samsung.slp.common/src/com/samsung/slp/common/process/PTYInputStream.java
new file mode 100644 (file)
index 0000000..59ef2e2
--- /dev/null
@@ -0,0 +1,96 @@
+package com.samsung.slp.common.process;
+
+/*******************************************************************************
+ * Copyright (c) 2000, 2011 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     QNX Software Systems - Initial API and implementation
+ *     Wind River Systems   - bug 286162
+ *******************************************************************************/
+import java.io.IOException;
+import java.io.InputStream;
+
+import com.samsung.slp.common.process.PTY.MasterFD;
+
+class PTYInputStream extends InputStream {
+
+       MasterFD master;
+
+       /**
+        * From a Unix valid file descriptor set a Reader.
+        * @param fd file descriptor.
+        */
+       public PTYInputStream(MasterFD fd) {
+               master = fd;
+       }
+
+       /**
+        * Implementation of read for the InputStream.
+        *
+        * @exception IOException on error.
+        */
+       @Override
+       public int read() throws IOException {
+               byte b[] = new byte[1];
+               if (1 != read(b, 0, 1))
+                       return -1;
+               return b[0];
+       }
+
+       /**
+        * @see InputStream#read(byte[], int, int)
+        */
+       @Override
+       public int read(byte[] buf, int off, int len) throws IOException {
+               if (buf == null) {
+                       throw new NullPointerException();
+               } else if ((off < 0) || (off > buf.length)
+                                       || (len < 0) || ((off + len) > buf.length)
+                                       || ((off + len) < 0)) {
+                       throw new IndexOutOfBoundsException();
+               } else if (len == 0) {
+                       return 0;
+               }
+               byte[] tmpBuf = new byte[len];
+
+               len = read0(master.getFD(), tmpBuf, len);
+               if (len <= 0)
+                       return -1;
+
+               System.arraycopy(tmpBuf, 0, buf, off, len);
+               return len;
+       }
+
+       /**
+        * Close the Reader
+        * @exception IOException on error.
+        */
+       @Override
+       public void close() throws IOException {
+               if (master.getFD() == -1)
+                       return;
+               close0(master.getFD());
+               // ignore error on close - see bug 286162
+//             if (status == -1)
+//                     throw new IOException(CCorePlugin.getResourceString("Util.exception.closeError")); //$NON-NLS-1$
+               master.setFD(-1);
+       }
+
+       @Override
+       protected void finalize() throws IOException {
+               close();
+       }
+
+       private native int read0(int fd, byte[] buf, int len) throws IOException;
+       private native int close0(int fd) throws IOException;
+
+       static {
+               System.loadLibrary("pty"); //$NON-NLS-1$
+       }
+
+}
+
diff --git a/com.samsung.slp.common/src/com/samsung/slp/common/process/PTYOutputStream.java b/com.samsung.slp.common/src/com/samsung/slp/common/process/PTYOutputStream.java
new file mode 100644 (file)
index 0000000..57ceb35
--- /dev/null
@@ -0,0 +1,89 @@
+package com.samsung.slp.common.process;
+/*******************************************************************************
+ * Copyright (c) 2000, 2011 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     QNX Software Systems - Initial API and implementation
+ *******************************************************************************/
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import com.samsung.slp.common.process.PTY.MasterFD;
+
+public class PTYOutputStream extends OutputStream {
+
+       MasterFD master;
+
+       /**
+        * From a Unix valid file descriptor set a Reader.
+        * @param fd file descriptor.
+        */
+       public PTYOutputStream(MasterFD fd) {
+               master = fd;
+       }
+
+       /**
+        * @see OutputStream#write(byte[], int, int)
+        */
+       @Override
+       public void write(byte[] b, int off, int len) throws IOException {
+               if (b == null) {
+                       throw new NullPointerException();
+               } else if (
+                       (off < 0)
+                               || (off > b.length)
+                               || (len < 0)
+                               || ((off + len) > b.length)
+                               || ((off + len) < 0)) {
+                       throw new IndexOutOfBoundsException();
+               } else if (len == 0) {
+                       return;
+               }
+               byte[] tmpBuf = new byte[len];
+               System.arraycopy(b, off, tmpBuf, off, len);
+               write0(master.getFD(), tmpBuf, len);
+       }
+       /**
+        * Implementation of read for the InputStream.
+        *
+        * @exception IOException on error.
+        */
+       @Override
+       public void write(int b) throws IOException {
+               byte[] buf = new byte[1];
+               buf[0] = (byte) b;
+               write(buf, 0, 1);
+       }
+
+       /**
+        * Close the Reader
+        * @exception IOException on error.
+        */
+       @Override
+       public void close() throws IOException {
+               if (master.getFD() == -1)
+                       return;
+               int status = close0(master.getFD());
+               if (status == -1)
+                       throw new IOException("close error"); //$NON-NLS-1$
+               master.setFD(-1);
+       }
+
+       @Override
+       protected void finalize() throws IOException {
+               close();
+       }
+
+       private native int write0(int fd, byte[] b, int len) throws IOException;
+       private native int close0(int fd) throws IOException;
+
+       static {
+               System.loadLibrary("pty"); //$NON-NLS-1$
+       }
+
+}
diff --git a/com.samsung.slp.common/src/com/samsung/slp/common/process/ProcessClosure.java b/com.samsung.slp.common/src/com/samsung/slp/common/process/ProcessClosure.java
new file mode 100644 (file)
index 0000000..61cca31
--- /dev/null
@@ -0,0 +1,236 @@
+package com.samsung.slp.common.process;
+
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+
+import com.samsung.slp.common.console.AnsicodeAdapter;
+
+/**
+ * Bundled state of a launched process including the threads linking the process
+ * in/output to console documents.
+ */
+public class ProcessClosure {
+
+       /**
+        * Thread which continuously reads from a input stream and pushes the read
+        * data to an output stream which is immediately flushed afterwards.
+        */
+       protected static class ReaderThread extends Thread {
+
+               private InputStream fInputStream;
+               private OutputStream fOutputStream;
+               private boolean fFinished = false;
+               private String lineSeparator;
+               /*
+                * outputStream can be null
+                */
+               public ReaderThread(ThreadGroup group, String name, InputStream in, OutputStream out) {
+                       super(group, name);
+                       fOutputStream = out;
+                       fInputStream = in;
+                       setDaemon(true);
+                       lineSeparator = System.getProperty("line.separator"); //$NON-NLS-1$
+               }
+
+               @Override
+               public void run() {
+                       try {
+                               try {
+                                       BufferedReader reader = new BufferedReader(new InputStreamReader(fInputStream));
+                                       String line;
+                                       while ((line = reader.readLine()) != null) {
+                                               line = AnsicodeAdapter.getDefault().getStripAnsiString(line);
+                                               line += lineSeparator;
+                                               fOutputStream.write(line.getBytes());
+                                       }
+                               } catch (IOException x) {
+                                       // ignore
+                               } finally {
+                                       try {
+                                               //                                      writer.flush();
+                                               fOutputStream.flush();
+                                       } catch (IOException e) {
+                                               // ignore
+                                       }
+                                       try {
+                                               fInputStream.close();
+                                       } catch (IOException e) {
+                                               // ignore
+                                       }
+                               }
+                       } finally {
+                               complete();
+                       }
+               }
+
+               public synchronized boolean finished() {
+                       return fFinished;
+               }
+
+               public synchronized void waitFor() {
+                       while (!fFinished) {
+                               try {
+                                       wait();
+                               } catch (InterruptedException e) {
+                               }
+                       }
+               }
+
+               public synchronized void complete() {
+                       fFinished = true;
+                       notify();
+               }
+
+               public void close() {
+                       try {
+                               fOutputStream.close();
+                       } catch (IOException e) {
+                               // ignore
+                       }
+               }
+       }
+
+       protected static int fCounter = 0;
+
+       protected Process fProcess;
+
+       protected OutputStream fOutput;
+       protected OutputStream fError;
+
+       protected ReaderThread fOutputReader;
+       protected ReaderThread fErrorReader;
+
+       /**
+        * Creates a process closure and connects the launched process with a
+        * console document.
+        * 
+        * @param outputStream
+        *            prcess stdout is written to this stream. Can be
+        *            <code>null</code>, if not interested in reading the output
+        * @param errorStream
+        *            prcess stderr is written to this stream. Can be
+        *            <code>null</code>, if not interested in reading the output
+        */
+       public ProcessClosure(Process process, OutputStream outputStream, OutputStream errorStream) {
+               fProcess = process;
+               fOutput = outputStream;
+               fError = errorStream;
+       }
+
+       /**
+        * Live links the launched process with the configured in/out streams using
+        * reader threads.
+        */
+       public void runNonBlocking() {
+               ThreadGroup group = new ThreadGroup("SRuncher" + fCounter++); //$NON-NLS-1$
+
+               InputStream stdin = fProcess.getInputStream();
+               InputStream stderr = fProcess.getErrorStream();
+
+               fOutputReader = new ReaderThread(group, "OutputReader", stdin, fOutput); //$NON-NLS-1$
+               fErrorReader = new ReaderThread(group, "ErrorReader", stderr, fError); //$NON-NLS-1$
+
+               fOutputReader.start();
+               fErrorReader.start();
+       }
+
+       public void runBlocking() {
+               runNonBlocking();
+
+               boolean finished = false;
+               while (!finished) {
+                       try {
+                               fProcess.waitFor();
+                       } catch (InterruptedException e) {
+                               //System.err.println("Closure exception " +e);
+                       }
+                       try {
+                               fProcess.exitValue();
+                               finished = true;
+                       } catch (IllegalThreadStateException e) {
+                               //System.err.println("Closure exception " +e);
+                       }
+               }
+
+               // @@@FIXME: Windows 2000 is screwed; double-check using output threads
+               if (!fOutputReader.finished()) {
+                       fOutputReader.waitFor();
+               }
+
+               if (!fErrorReader.finished()) {
+                       fErrorReader.waitFor();
+               }
+
+               fOutputReader.close();
+               fErrorReader.close();
+               // it seems that thread termination and stream closing is working
+               // without
+               // any help
+               fProcess = null;
+               fOutputReader = null;
+               fErrorReader = null;
+       }
+
+       public boolean isAlive() {
+               if (fProcess != null) {
+                       if (fOutputReader.isAlive() || fErrorReader.isAlive()) {
+                               return true;
+                       }
+                       fProcess = null;
+                       fOutputReader.close();
+                       fErrorReader.close();
+                       fOutputReader = null;
+                       fErrorReader = null;
+               }
+               return false;
+       }
+
+       /**
+        * The same functionality as "isAlive()"
+        * but does not affect out streams,
+        * because they can be shared among processes
+        */
+       public boolean isRunning() {
+               if (fProcess != null) {
+                       if (fOutputReader.isAlive() || fErrorReader.isAlive()) {
+                               return true;
+                       }
+                       fProcess = null;
+               }
+               return false;
+       }
+       /**
+        * Forces the termination the launched process
+        */
+       public void terminate() {
+               if (fProcess != null) {
+                       fProcess.destroy();
+                       fProcess = null;
+               }
+               if (!fOutputReader.finished()) {
+                       fOutputReader.waitFor();
+               }
+               if (!fErrorReader.finished()) {
+                       fErrorReader.waitFor();
+               }
+               fOutputReader.close();
+               fErrorReader.close();
+               fOutputReader = null;
+               fErrorReader = null;
+       }
+}
+
diff --git a/com.samsung.slp.common/src/com/samsung/slp/common/process/ProcessFactory.java b/com.samsung.slp.common/src/com/samsung/slp/common/process/ProcessFactory.java
new file mode 100644 (file)
index 0000000..39428ae
--- /dev/null
@@ -0,0 +1,99 @@
+package com.samsung.slp.common.process;
+
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     QNX Software Systems - Initial API and implementation
+ *******************************************************************************/
+
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * @noextend This class is not intended to be subclassed by clients.
+ * @noinstantiate This class is not intended to be instantiated by clients.
+ */
+public class ProcessFactory {
+
+       static private ProcessFactory instance;
+       private boolean hasSpawner;
+       private Runtime runtime;
+
+       private ProcessFactory() {
+               hasSpawner = false;
+               String OS = System.getProperty("os.name").toLowerCase(); //$NON-NLS-1$
+               runtime = Runtime.getRuntime();
+               try {
+                       // Spawner does not work for Windows 98 fallback
+                       if (OS != null && OS.equals("windows 98")) { //$NON-NLS-1$
+                               hasSpawner = false;
+                       } else {
+                               System.loadLibrary("spawner"); //$NON-NLS-1$
+                               hasSpawner = true;
+                       }
+               } catch (SecurityException e) {
+                       e.printStackTrace();
+               } catch (UnsatisfiedLinkError e) {
+                       e.printStackTrace();
+               }
+       }
+
+       public static ProcessFactory getFactory() {
+               if (instance == null)
+                       instance = new ProcessFactory();
+               return instance;
+       }
+
+       public Process exec(String cmd) throws IOException {
+               if (hasSpawner)
+                       return new Spawner(cmd);
+               return runtime.exec(cmd);
+       }
+
+       public Process exec(String[] cmdarray) throws IOException {
+               if (hasSpawner)
+                       return new Spawner(cmdarray);
+               return runtime.exec(cmdarray);
+       }
+
+       public Process exec(String[] cmdarray, String[] envp) throws IOException {
+               if (hasSpawner)
+                       return new Spawner(cmdarray, envp);
+               return runtime.exec(cmdarray, envp);
+       }
+
+       public Process exec(String cmd, String[] envp) throws IOException {
+               if (hasSpawner)
+                       return new Spawner(cmd, envp);
+               return runtime.exec(cmd, envp);
+       }
+
+       public Process exec(String cmd, String[] envp, File dir)
+               throws IOException {
+               if (hasSpawner)
+                       return new Spawner(cmd, envp, dir);
+               return runtime.exec(cmd, envp, dir);
+       }
+
+       public Process exec(String cmdarray[], String[] envp, File dir)
+               throws IOException {
+               if (hasSpawner)
+                       return new Spawner(cmdarray, envp, dir);
+               return runtime.exec(cmdarray, envp, dir);
+       }
+
+       public Process exec(String cmdarray[], String[] envp, File dir, PTY pty)
+               throws IOException {
+               if (hasSpawner)
+                       return new Spawner(cmdarray, envp, dir, pty);
+               //throw new UnsupportedOperationException(CCorePlugin.getResourceString("Util.exception.cannotCreatePty")); //$NON-NLS-1$
+               throw new UnsupportedOperationException("Util.exception.cannotCreatePty"); //$NON-NLS-1$
+       }
+}
+
diff --git a/com.samsung.slp.common/src/com/samsung/slp/common/process/ProcessLauncher.java b/com.samsung.slp.common/src/com/samsung/slp/common/process/ProcessLauncher.java
new file mode 100644 (file)
index 0000000..dab4a47
--- /dev/null
@@ -0,0 +1,190 @@
+package com.samsung.slp.common.process;
+
+/*******************************************************************************
+ * Copyright (c) 2006 Intel Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Intel Corporation - Initial API and implementation
+ *******************************************************************************/
+
+
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+/**
+ * This class implements external process launching for internal builder. 
+ *
+ * NOTE: This class is subject to change and discuss, 
+ * and is currently available in experimental mode only
+ */
+public class ProcessLauncher {
+       public final static int STATE_DONE = 0;
+       public final static int STATE_RUNNING = 1;
+       public final static int STATE_CANCELED = 2;
+       public final static int STATE_ILLEGAL = -1;
+       
+       protected String[] cmd;
+       protected String[] env;
+       protected File cwd;
+       protected OutputStream out;
+       protected OutputStream err;
+       protected IProgressMonitor monitor;
+       protected boolean show;
+       protected String error;
+       protected String lineSeparator;
+       protected Process process;
+       protected ProcessClosure closure = null;
+       protected int state;
+
+       /**
+        * Returns command line as a string array
+        */
+       public String[] getCommandArray() {
+               return cmd;
+       }
+       
+       /**
+        * Returns command line in a single string
+        */
+       public String getCommandLine() {
+               StringBuffer buf = new StringBuffer();
+               if (cmd != null) {
+                       for (int i = 0; i < cmd.length; i++) {
+                               buf.append(cmd[i]);
+                               buf.append(' ');
+                       }
+                       buf.append(lineSeparator);
+               }
+               
+               return buf.toString();
+       }
+       
+       /**
+        * Returns process environment
+        */
+       public String[] getEnvironment() {
+               return env;
+       }
+       
+       /**
+        * Returns command working directory
+        */
+       public File getWorkingDir() {
+               return cwd;
+       }
+       
+       /**
+        * Returns error message (if any)
+        */
+       public String getErrorMessage() {
+               return error;
+       }
+       
+       /**
+        * Returns exit code of a process
+        */
+       public int getExitCode() {
+               if (process == null || closure.isAlive()) return 0;
+               try { return process.waitFor(); }
+               catch (InterruptedException e) { return 0; } 
+       }
+       
+       /**
+        * Initializes launcher
+        * @param _cmd Command path
+        * @param args Command arguments
+        * @param _env Environment 
+        * @param _cwd Working directory
+        * @param _out Output stream
+        * @param _err Error output stream
+        * @param _monitor Progress monitor 
+        * @param _show If true, print command line before launching
+        */
+       public ProcessLauncher(IPath _cmd, String[] args, String[] _env, IPath _cwd, OutputStream _out, OutputStream _err, IProgressMonitor _monitor, boolean _show) {
+               cmd = createCmdArray(_cmd.toOSString(), args);
+               env = _env;
+               cwd = _cwd.toFile(); 
+               out = _out;
+               err = _err;
+               monitor = _monitor;
+               show = _show;
+               error = ""; //$NON-NLS-1$
+               lineSeparator = System.getProperty("line.separator", "\n"); //$NON-NLS-1$ //$NON-NLS-2$
+       }
+       
+       /**
+        * Launches a process
+        */
+       public void launch() {
+               try {
+                       if (show)
+                               printCommandLine();
+                       state = STATE_RUNNING;
+                       process = ProcessFactory.getFactory().exec(cmd, env, cwd); 
+                       closure = new ProcessClosure(process, out, err);
+                       // Close the input of the process since we will never write to it
+                       try {
+                               process.getOutputStream().close();
+                       } catch (IOException e) {
+                               // do nothing
+                       }
+                       closure.runNonBlocking();
+               } catch (IOException e) {
+                       error = e.getMessage();
+                       closure = null;
+               }
+       }
+       
+       /**
+        * Returns process state
+        */
+       public int queryState() {
+               if (state == STATE_RUNNING) {
+                       if (closure == null) 
+                               state = STATE_ILLEGAL;
+                       else if (monitor.isCanceled()) {
+                               closure.terminate();
+                               error = "CommandLauncher.error.commandCanceled"; //$NON-NLS-1$
+                               state = STATE_CANCELED;
+                       } else if (!closure.isRunning()) {
+                               state = STATE_DONE;
+                       }
+               }
+       
+               return state;
+       }
+
+       /**
+        * Creates a string array representing the command that will be passed 
+        * to the process
+        */
+       protected String[] createCmdArray(String cmdPath, String[] cmdArgs) {
+               String[] args = new String[1 + cmdArgs.length];
+               args[0] = cmdPath;
+               System.arraycopy(cmdArgs, 0, args, 1, cmdArgs.length);
+               
+               return args;
+       }
+       
+       /**
+        * Prints command line
+        */
+       protected void printCommandLine() {
+               if (out != null) {
+                       try {
+                               out.write(getCommandLine().getBytes());
+                               out.flush();
+                       } catch (IOException e) {
+                               // do nothing
+                       }
+               }
+       }
+}
diff --git a/com.samsung.slp.common/src/com/samsung/slp/common/process/Spawner.java b/com.samsung.slp.common/src/com/samsung/slp/common/process/Spawner.java
new file mode 100644 (file)
index 0000000..a920154
--- /dev/null
@@ -0,0 +1,513 @@
+package com.samsung.slp.common.process;
+
+/*******************************************************************************
+ * Copyright (c) 2000, 2011 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     QNX Software Systems - Initial API and implementation
+ *     Wind River Systems   - bug 248071, bug 286162
+ *******************************************************************************/
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.StringTokenizer;
+
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.osgi.util.NLS;
+
+import com.samsung.slp.common.log.Logger;
+
+public class Spawner extends Process {
+
+       public int NOOP = 0;
+       public int HUP = 1;
+       public int KILL = 9;
+       public int TERM = 15;
+
+       /**
+        * On Windows, what this does is far from easy to explain. 
+        * Some of the logic is in the JNI code, some in the spawner.exe code.
+        * 
+        * <ul>
+        * <li>If the process this is being raised against was launched by us (the Spawner)
+        *    <ul>
+        *    <li>If the process is a cygwin program (has the cygwin1.dll loaded), then issue a 'kill -SIGINT'. If
+        *    the 'kill' utility isn't available, send the process a CTRL-C
+        *    <li>If the process is <i>not</i> a cygwin program, send the process a CTRL-C
+        *    </ul>
+        * <li>If the process this is being raised against was <i>not</i> launched by us, use 
+        * DebugBreakProcess to interrupt it (sending a CTRL-C is easy only if we share a console 
+        * with the target process) 
+        * </ul>
+        * 
+        * On non-Windows, raising this just raises a POSIX SIGINT  
+        * 
+        */
+       public int INT = 2;
+
+       /**
+        * A fabricated signal number for use on Windows only. Tells the starter program to send a CTRL-C
+        * regardless of whether the process is a Cygwin one or not.
+        * 
+        * @since 5.2
+        */
+       public int CTRLC = 1000;  // arbitrary high number to avoid collision
+
+       int pid = 0;
+       int status;
+       final int[] fChannels = new int[3];
+       boolean isDone;
+       OutputStream out;
+       InputStream in;
+       InputStream err;
+       private PTY fPty;
+
+       public Spawner(String command, boolean bNoRedirect) throws IOException {
+               StringTokenizer tokenizer = new StringTokenizer(command);
+               String[] cmdarray = new String[tokenizer.countTokens()];
+               for (int n = 0; tokenizer.hasMoreTokens(); n++)
+                       cmdarray[n] = tokenizer.nextToken();
+               if (bNoRedirect)
+                       exec_detached(cmdarray, new String[0], "."); //$NON-NLS-1$
+               else
+                       exec(cmdarray, new String[0], "."); //$NON-NLS-1$
+       }
+       /**
+        * Executes the specified command and arguments in a separate process with the
+        * specified environment and working directory.
+        **/
+       protected Spawner(String[] cmdarray, String[] envp, File dir) throws IOException {
+               String dirpath = "."; //$NON-NLS-1$
+               if (dir != null)
+                       dirpath = dir.getAbsolutePath();
+               exec(cmdarray, envp, dirpath);
+       }
+
+       protected Spawner(String[] cmdarray, String[] envp, File dir, PTY pty) throws IOException {
+               String dirpath = "."; //$NON-NLS-1$
+               if (dir != null)
+                       dirpath = dir.getAbsolutePath();
+               fPty = pty;
+               exec_pty(cmdarray, envp, dirpath, pty);
+       }
+       /**
+        * Executes the specified string command in a separate process.
+        **/
+       protected Spawner(String command) throws IOException {
+               this(command, null);
+       }
+
+       /**
+        * Executes the specified command and arguments in a separate process.
+        **/
+       protected Spawner(String[] cmdarray) throws IOException {
+               this(cmdarray, null);
+       }
+
+       /**
+        * Executes the specified command and arguments in a separate process with the
+        * specified environment.
+        **/
+       protected Spawner(String[] cmdarray, String[] envp) throws IOException {
+               this(cmdarray, envp, null);
+       }
+
+       /**
+        * Executes the specified string command in a separate process with the specified
+        * environment.
+        **/
+       protected Spawner(String cmd, String[] envp) throws IOException {
+               this(cmd, envp, null);
+       }
+
+       /**
+        * Executes the specified string command in a separate process with the specified
+        * environment and working directory.
+        **/
+       protected Spawner(String command, String[] envp, File dir) throws IOException {
+               StringTokenizer tokenizer = new StringTokenizer(command);
+               String[] cmdarray = new String[tokenizer.countTokens()];
+               for (int n = 0; tokenizer.hasMoreTokens(); n++)
+                       cmdarray[n] = tokenizer.nextToken();
+               String dirpath = "."; //$NON-NLS-1$
+               if (dir != null)
+                       dirpath = dir.getAbsolutePath();
+               exec(cmdarray, envp, dirpath);
+       }
+
+       @Override
+       protected void finalize() throws Throwable {
+               closeUnusedStreams();
+       }
+       
+       /**
+        * See java.lang.Process#getInputStream ();
+        * The client is responsible for closing the stream explicitly.
+        **/
+       @Override
+       public synchronized InputStream getInputStream() {
+               if(null == in) {
+                       if (fPty != null) {
+                               in = fPty.getInputStream();
+                       } else {
+                               in = new SpawnerInputStream(fChannels[1]);
+                       }
+               }
+               return in;
+       }
+
+       /**
+        * See java.lang.Process#getOutputStream ();
+        * The client is responsible for closing the stream explicitly.
+        **/
+       @Override
+       public synchronized OutputStream getOutputStream() {
+               if(null == out) {
+                       if (fPty != null) {
+                               out = fPty.getOutputStream();
+                       } else {
+                               out = new SpawnerOutputStream(fChannels[0]);
+                       }
+               }
+               return out;
+       }
+
+       /**
+        * See java.lang.Process#getErrorStream ();
+        * The client is responsible for closing the stream explicitly.
+        **/
+       @Override
+       public synchronized InputStream getErrorStream() {
+               if(null == err) {
+                       if (fPty != null && !fPty.isConsole()) {
+                               // If PTY is used and it's not in "Console" mode, then stderr is
+                               // redirected to the PTY's output stream.  Therefore, return a 
+                               // dummy stream for error stream.
+                               err = new InputStream() {
+                                       @Override
+                                       public int read() throws IOException {
+                                               return -1;
+                                       }
+                               };
+                       } else {
+                               err = new SpawnerInputStream(fChannels[2]);
+                       }
+               }
+               return err;
+       }
+
+       /**
+        * See java.lang.Process#waitFor ();
+        **/
+       @Override
+       public synchronized int waitFor() throws InterruptedException {
+               while (!isDone) {
+                       wait();
+               }
+               
+               // For situations where the user does not call destroy(),
+               // we try to kill the streams that were not used here.
+               // We check for streams that were not created, we create
+               // them to attach to the pipes, and then we close them
+               // to release the pipes.
+               // Streams that were created by the client need to be
+               // closed by the client itself.
+               //
+               // But 345164
+               closeUnusedStreams();
+               return status;
+       }
+
+       /**
+        * See java.lang.Process#exitValue ();
+        **/
+       @Override
+       public synchronized int exitValue() {
+               if (!isDone) {
+                       throw new IllegalThreadStateException("Process not Terminated"); //$NON-NLS-1$
+               }
+               return status;
+       }
+
+       /**
+        * See java.lang.Process#destroy ();
+        * 
+        * Clients are responsible for explicitly closing any streams
+        * that they have requested through
+        *   getErrorStream(), getInputStream() or getOutputStream()
+        **/
+       @Override
+       public synchronized void destroy() {
+               // Sends the TERM
+               terminate();
+               
+               // Close the streams on this side.
+               //
+               // We only close the streams that were
+               // never used by any client.
+               // So, if the stream was not created yet,
+               // we create it ourselves and close it
+               // right away, so as to release the pipe.
+               // Note that even if the stream was never
+               // created, the pipe has been allocated in
+               // native code, so we need to create the
+               // stream and explicitly close it.
+               //
+               // We don't close streams the clients have
+               // created because we don't know when the
+               // client will be finished using them.
+               // It is up to the client to close those
+               // streams.
+               //
+               // But 345164
+               closeUnusedStreams();
+               
+               // Grace before using the heavy gone.
+               if (!isDone) {
+                       try {
+                               wait(1000);
+                       } catch (InterruptedException e) {
+                       }
+               }
+               if (!isDone) {
+                       kill();
+               }
+       }
+
+       /**
+        * On Windows, interrupt the spawned program by using Cygwin's utility 'kill -SIGINT' if it's a Cgywin
+        * program, otherwise send it a CTRL-C. If Cygwin's 'kill' command is not available, send a CTRL-C. On
+        * linux, interrupt it by raising a SIGINT.
+        */
+       public int interrupt() {
+               return raise(pid, INT);
+       }
+
+       /**
+        * On Windows, interrupt the spawned program by send it a CTRL-C (even if it's a Cygwin program). On
+        * linux, interrupt it by raising a SIGINT. 
+        * 
+        * @since 5.2
+        */
+       public int interruptCTRLC() {
+        if (Platform.getOS().equals(Platform.OS_WIN32)) {
+               return raise(pid, CTRLC);
+        }
+        else {
+               return interrupt();
+        }
+       }
+
+       public int hangup() {
+               return raise(pid, HUP);
+       }
+
+       public int kill() {
+               return raise(pid, KILL);
+       }
+
+       public int terminate() {
+               return raise(pid, TERM);
+       }
+
+       public boolean isRunning() {
+               return (raise(pid, NOOP) == 0);
+       }
+
+       private void exec(String[] cmdarray, String[] envp, String dirpath) throws IOException {
+               String command = cmdarray[0];
+               SecurityManager s = System.getSecurityManager();
+               if (s != null)
+                       s.checkExec(command);
+               if (envp == null)
+                       envp = new String[0];
+
+               Reaper reaper = new Reaper(cmdarray, envp, dirpath);
+               reaper.setDaemon(true);
+               reaper.start();
+
+               // Wait until the subprocess is started or error.
+               synchronized (this) {
+                       while (pid == 0) {
+                               try {
+                                       wait();
+                               } catch (InterruptedException e) {
+                               }
+                       }
+               }
+
+               // Check for errors.
+               if (pid == -1) {
+                       throw new IOException(reaper.getErrorMessage());
+               }
+       }
+
+       private void exec_pty(String[] cmdarray, String[] envp, String dirpath, PTY pty) throws IOException {
+               String command = cmdarray[0];
+               SecurityManager s = System.getSecurityManager();
+               if (s != null)
+                       s.checkExec(command);
+               if (envp == null)
+                       envp = new String[0];
+
+               final String slaveName = pty.getSlaveName();
+               final int masterFD = pty.getMasterFD().getFD();
+               final boolean console = pty.isConsole();
+               //int fdm = pty.get
+               Reaper reaper = new Reaper(cmdarray, envp, dirpath) {
+                       /* (non-Javadoc)
+                        * @see org.eclipse.cdt.utils.spawner.Spawner.Reaper#execute(java.lang.String[], java.lang.String[], java.lang.String, int[])
+                        */
+                       @Override
+                       int execute(String[] cmd, String[] env, String dir, int[] channels) throws IOException {
+                               return exec2(cmd, env, dir, channels, slaveName, masterFD, console);
+                       }
+               };
+               reaper.setDaemon(true);
+               reaper.start();
+
+               // Wait until the subprocess is started or error.
+               synchronized (this) {
+                       while (pid == 0) {
+                               try {
+                                       wait();
+                               } catch (InterruptedException e) {
+                               }
+                       }
+               }
+
+               // Check for errors.
+               if (pid == -1) {
+                       throw new IOException("Exec_tty error:" + reaper.getErrorMessage()); //$NON-NLS-1$
+               }
+       }
+
+       public void exec_detached(String[] cmdarray, String[] envp, String dirpath) throws IOException {
+               String command = cmdarray[0];
+               SecurityManager s = System.getSecurityManager();
+               if (s != null)
+                       s.checkExec(command);
+
+               if (envp == null)
+                       envp = new String[0];
+               pid = exec1(cmdarray, envp, dirpath);
+               if (pid == -1) {
+                       throw new IOException("Exec error"); //$NON-NLS-1$
+               }
+               fChannels[0] = -1;
+               fChannels[1] = -1;
+               fChannels[2] = -1;
+       }
+
+       /**
+        * Close any streams not used by clients.
+        */
+       private synchronized void closeUnusedStreams() {
+               try {
+                       if(null == err)
+                               getErrorStream().close();
+               } catch (IOException e) {}
+               try {
+                       if(null == in)
+                               getInputStream().close();
+               } catch (IOException e) {}
+               try {
+                       if(null == out)
+                               getOutputStream().close();
+               } catch (IOException e) {}
+       }
+
+       /**
+        * Native method use in normal exec() calls. 
+        */
+       native int exec0( String[] cmdarray, String[] envp, String dir, int[] chan) throws IOException;
+
+       /**
+        * Native method use in no redirect meaning to streams will created. 
+        */
+       native int exec1( String[] cmdarray, String[] envp, String dir) throws IOException;
+
+       /**
+        * Native method when executing with a terminal emulation. 
+        */
+       native int exec2( String[] cmdarray, String[] envp, String dir, int[] chan, String slaveName, int masterFD, boolean console) throws IOException;
+
+       /**
+        * Native method to drop a signal on the process with pid.
+        */
+       public native int raise(int processID, int sig);
+
+       /*
+        * Native method to wait(3) for process to terminate.
+        */
+       native int waitFor(int processID);
+
+       static {
+               try {
+                       System.loadLibrary("spawner"); //$NON-NLS-1$
+               } catch (SecurityException e) {
+                       Logger.error(e.getMessage() , e);       
+               } catch (UnsatisfiedLinkError e) {
+                       Logger.error(e.getMessage() , e);       
+               }
+       }
+
+       // Spawn a thread to handle the forking and waiting
+       // We do it this way because on linux the SIGCHLD is
+       // send to the one thread.  So do the forking and
+       // the wait in the same thread.
+       class Reaper extends Thread {
+               String[] fCmdarray;
+               String[] fEnvp;
+               String fDirpath;
+               volatile Throwable fException;
+
+               public Reaper(String[] array, String[] env, String dir) {
+                       super("Spawner Reaper"); //$NON-NLS-1$
+                       fCmdarray = array;
+                       fEnvp = env;
+                       fDirpath = dir;
+                       fException = null;
+               }
+
+               int execute(String[] cmdarray, String[] envp, String dir, int[] channels) throws IOException {
+                       return exec0(cmdarray, envp, dir, channels);
+               }
+
+               @Override
+               public void run() {
+                       try {
+                               pid = execute(fCmdarray, fEnvp, fDirpath, fChannels);
+                       } catch (Exception e) {
+                               pid = -1;
+                               fException= e;
+                       }
+
+                       // Tell spawner that the process started.
+                       synchronized (Spawner.this) {
+                               Spawner.this.notifyAll();
+                       }
+
+                       if (pid != -1) {
+                               // Sync with spawner and notify when done.
+                               status = waitFor(pid);
+                               synchronized (Spawner.this) {
+                                       isDone = true;
+                                       Spawner.this.notifyAll();
+                               }
+                       }
+               }
+
+               public String getErrorMessage() {
+                       final String reason= fException != null ? fException.getMessage() : "Unknown reason"; //$NON-NLS-1$
+                       //return NLS.bind(CCorePlugin.getResourceString("Util.error.cannotRun"), fCmdarray[0], reason); //$NON-NLS-1$
+                       return "Util.error.cannotRun";
+               }
+       }
+}
+
diff --git a/com.samsung.slp.common/src/com/samsung/slp/common/process/SpawnerInputStream.java b/com.samsung.slp.common/src/com/samsung/slp/common/process/SpawnerInputStream.java
new file mode 100644 (file)
index 0000000..80d89fc
--- /dev/null
@@ -0,0 +1,114 @@
+package com.samsung.slp.common.process;
+/*******************************************************************************
+ *Copyright (c) 2000, 2011 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     QNX Software Systems - Initial API and implementation
+ *******************************************************************************/
+
+
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * @noextend This class is not intended to be subclassed by clients.
+ * @noinstantiate This class is not intended to be instantiated by clients.
+ */
+class SpawnerInputStream extends InputStream {
+       private int fd;
+
+       /**
+        * From a Unix valid file descriptor set a Reader.
+        * @param fd file descriptor.
+        */
+       public SpawnerInputStream(int fd) {
+               this.fd = fd;
+       }
+
+       /**
+        * Implementation of read for the InputStream.
+        *
+        * @exception IOException on error.
+        */
+       @Override
+       public int read() throws IOException {
+               byte b[] = new byte[1];
+               if (1 != read(b, 0, 1))
+                       return -1;
+               return b[0];
+       }
+
+       /**
+        * @see InputStream#read(byte[], int, int)
+        */
+       @Override
+       public int read(byte[] buf, int off, int len) throws IOException {
+               if (buf == null) {
+                       throw new NullPointerException();
+               } else if (
+                       (off < 0)
+                               || (off > buf.length)
+                               || (len < 0)
+                               || ((off + len) > buf.length)
+                               || ((off + len) < 0)) {
+                       throw new IndexOutOfBoundsException();
+               } else if (len == 0) {
+                       return 0;
+               }
+               byte[] tmpBuf = off > 0 ? new byte[len] : buf;
+
+               len = read0(fd, tmpBuf, len);
+               if (len <= 0)
+                       return -1;
+
+               if (tmpBuf != buf) {
+                       System.arraycopy(tmpBuf, 0, buf, off, len);
+               }
+               return len;
+       }
+
+       /**
+        * Close the Reader
+        * @exception IOException on error.
+        */
+       @Override
+       public void close() throws IOException {
+               if (fd == -1)
+                       return;
+               int status = close0(fd);
+               if (status == -1)
+                       throw new IOException("Util.exception.closeError"); //$NON-NLS-1$
+               fd = -1;
+       }
+
+       @Override
+       public int available() throws IOException {
+               try {
+                       return available0(fd);
+               }
+               catch (UnsatisfiedLinkError e) {
+                       // for those platforms that do not implement available0
+                       return super.available();
+               }
+       }
+
+       @Override
+       protected void finalize() throws IOException {
+               close();
+       }
+       
+       private native int read0(int fileDesc, byte[] buf, int len) throws IOException;
+       private native int close0(int fileDesc) throws IOException;
+       private native int available0(int fileDesc) throws IOException;
+
+       static {
+               System.loadLibrary("spawner"); //$NON-NLS-1$
+       }
+
+
+}
diff --git a/com.samsung.slp.common/src/com/samsung/slp/common/process/SpawnerOutputStream.java b/com.samsung.slp.common/src/com/samsung/slp/common/process/SpawnerOutputStream.java
new file mode 100644 (file)
index 0000000..8a0bbb0
--- /dev/null
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2011 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     QNX Software Systems - Initial API and implementation
+ *******************************************************************************/
+package com.samsung.slp.common.process;
+
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * @noextend This class is not intended to be subclassed by clients.
+ * @noinstantiate This class is not intended to be instantiated by clients.
+ */
+public class SpawnerOutputStream extends OutputStream {
+       private int fd;
+
+       /**
+        * From a Unix valid file descriptor set a Reader.
+        * @param fd file descriptor.
+        */
+       public SpawnerOutputStream(int fd) {
+               this.fd = fd;
+       }
+
+       /**
+        * @see OutputStream#write(byte[], int, int)
+        */
+       @Override
+       public void write(byte[] b, int off, int len) throws IOException {
+               if (b == null) {
+                       throw new NullPointerException();
+               } else if (
+                       (off < 0)
+                               || (off > b.length)
+                               || (len < 0)
+                               || ((off + len) > b.length)
+                               || ((off + len) < 0)) {
+                       throw new IndexOutOfBoundsException();
+               } else if (len == 0) {
+                       return;
+               }
+               byte[] tmpBuf = new byte[len];
+               System.arraycopy(b, off, tmpBuf, off, len);
+               write0(fd, tmpBuf, len);
+       }
+       /**
+        * Implementation of read for the InputStream.
+        *
+        * @exception IOException on error.
+        */
+       @Override
+       public void write(int b) throws IOException {
+               byte[] buf = new byte[1];
+               buf[0] = (byte) b;
+               write(buf, 0, 1);
+       }
+
+       /**
+        * Close the Reader
+        * @exception IOException on error.
+        */
+       @Override
+       public void close() throws IOException {
+               if (fd == -1)
+                       return;
+               int status = close0(fd);
+               if (status == -1)
+                       throw new IOException("close error"); //$NON-NLS-1$
+               fd = -1;
+       }
+
+       @Override
+       protected void finalize() throws IOException {
+               close();
+       }
+
+       private native int write0(int fd, byte[] b, int len) throws IOException;
+       private native int close0(int fd);
+
+       static {
+               System.loadLibrary("spawner"); //$NON-NLS-1$
+       }
+
+}
index f23cf9a..0e59a30 100644 (file)
@@ -33,12 +33,14 @@ import org.eclipse.ui.console.IConsoleView;
 import org.eclipse.ui.console.MessageConsole;
 import org.eclipse.ui.console.MessageConsoleStream;
 
+import com.samsung.slp.common.process.ProcessClosure;
+
 public class ConsoleManager
 {
        private static IConsoleManager consoleManager = ConsolePlugin.getDefault().getConsoleManager();
        private String consoleName;
        private boolean consoleFocus;
-       
+       private MessageConsole console;
        /**
         * Constructs a new console manager.
         * 
@@ -50,9 +52,8 @@ public class ConsoleManager
                this.consoleFocus = focus;
        }
 
-       private MessageConsole getConsole(){
+       private MessageConsole getMessageConsole(){
                boolean found = false;
-               MessageConsole console = null;
 
                IConsole[] consoles = consoleManager.getConsoles();
                for (int i = 0; i < consoles.length; i++) {
@@ -73,6 +74,9 @@ public class ConsoleManager
                
                return console;
        }
+       public IConsole getConsole() {
+               return console;
+       }
        /**
         * Remove a MessageConsole instance specified key title from list, if it is present
         * 
@@ -99,7 +103,7 @@ public class ConsoleManager
         * @return the MessageConsoleStream connected to MessageConsole
         */
        public MessageConsoleStream getMessageConsoleStream(boolean isError) {
-               final MessageConsoleStream output = getConsole().newMessageStream();
+               final MessageConsoleStream output = getMessageConsole().newMessageStream();
                output.setActivateOnWrite(false);
                
                final int colorId;
@@ -127,12 +131,12 @@ public class ConsoleManager
         * @return the MessageConsoleStream connected to MessageConsole
         */
        public MessageConsoleStream getMessageConsoleStream() {
-               return getConsole().newMessageStream();
+               return getMessageConsole().newMessageStream();
        }
        public void print(final String line) {
                Runnable runnable = new Runnable() {
                        public void run() {
-                               final MessageConsoleStream output = getConsole().newMessageStream();
+                               final MessageConsoleStream output = getMessageConsole().newMessageStream();
                                output.print(line);
                                try {
                                        output.close();
@@ -146,7 +150,7 @@ public class ConsoleManager
                
        }
        public void println(String line) {
-               final MessageConsoleStream output = getConsole().newMessageStream();
+               final MessageConsoleStream output = getMessageConsole().newMessageStream();
                output.println(line);
                try {
                        output.close();
@@ -155,11 +159,29 @@ public class ConsoleManager
                         ConsolePlugin.log(e);
                }
        }
+       public void printlnStreams(Process process) {
+               
+               MessageConsoleStream stdoutStream = getMessageConsole().newMessageStream();
+               MessageConsoleStream stderrStream = getMessageConsole().newMessageStream();
+               
+               clear();
+               // waitAndRead while process is running
+               ProcessClosure closure = new ProcessClosure(process, stdoutStream, stderrStream);
+               closure.runBlocking(); // a blocking cal
+               
+               try {
+                       stdoutStream.close();
+                       stderrStream.close();
+               }
+               catch( IOException e ) {
+                       // ignore.
+               }
+       }
        public void clear()
        {
                Runnable runnable = new Runnable() {
                        public void run() {
-                               IDocument document = getConsole().getDocument();
+                               IDocument document = getMessageConsole().getDocument();
                                if (document != null) {
                                        document.set("");
                                }