/******************************************************************************* * Copyright (c) 2004, 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 - Initial API and implementation *******************************************************************************/ package org.eclipse.cdt.internal.core; import java.io.IOException; import java.io.OutputStream; import org.eclipse.cdt.core.IConsoleParser; /** * Intercepts an output to console and forwards it to console parsers for processing * * @author vhirsl */ public class ConsoleOutputSniffer { /* * Private class to sniffer the output stream for this snifffer. */ private class ConsoleOutputStream extends OutputStream { // Stream's private buffer for the stream's read contents. private StringBuffer currentLine = new StringBuffer(); private OutputStream outputStream = null; public ConsoleOutputStream(OutputStream outputStream) { this.outputStream = outputStream; } /* (non-Javadoc) * @see java.io.OutputStream#write(int) */ @Override public void write(int b) throws IOException { currentLine.append((char) b); checkLine(false); // Continue writing the bytes to the console's output. if (outputStream != null) { outputStream.write(b); } } /* (non-Javadoc) * @see java.io.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 || (len < 0) || (len > b.length)) { throw new IndexOutOfBoundsException(); } else if (len == 0) { return; } currentLine.append(new String(b, 0, len)); checkLine(false); // Continue writing the bytes to the console's output. if (outputStream != null) outputStream.write(b, off, len); } /* (non-Javadoc) * @see java.io.OutputStream#close() */ @Override public void close() throws IOException { checkLine(true); closeConsoleOutputStream(); } /* (non-Javadoc) * @see java.io.OutputStream#flush() */ @Override public void flush() throws IOException { if (outputStream != null) { outputStream.flush(); } } /* * Checks to see if the already read input constitutes * a complete line (e.g. does the sniffing). If so, then * send it to processLine. * * @param flush */ private void checkLine(boolean flush) { String buffer = currentLine.toString(); int i = 0; while ((i = buffer.indexOf('\n')) != -1) { // get rid of any trailing whitespace but keep leading whitespaces (bug 199245) int end= i; while(end > 0 && buffer.charAt(end-1) <= ' ') { // see String.trim() end--; } if (end > 0) { String line = buffer.substring(0, end); processLine(line); } buffer = buffer.substring(i + 1); // skip the \n and advance } currentLine.setLength(0); if (flush) { if (buffer.length() > 0) { processLine(buffer); } } else { currentLine.append(buffer); } } } // end ConsoleOutputStream class private int nOpens = 0; private OutputStream consoleOutputStream; private OutputStream consoleErrorStream; private IConsoleParser[] parsers; public ConsoleOutputSniffer(IConsoleParser[] parsers) { this.parsers = parsers; } public ConsoleOutputSniffer(OutputStream outputStream, OutputStream errorStream, IConsoleParser[] parsers) { this(parsers); this.consoleOutputStream = outputStream; this.consoleErrorStream = errorStream; } /** * Returns an output stream that will be sniffed. * This stream should be hooked up so the command * output stream goes into here. */ public OutputStream getOutputStream() { incNOpens(); return new ConsoleOutputStream(consoleOutputStream); } /** * Returns an error stream that will be sniffed. * This stream should be hooked up so the command * error stream goes into here. */ public OutputStream getErrorStream() { incNOpens(); return new ConsoleOutputStream(consoleErrorStream); } private synchronized void incNOpens() { nOpens++; } /* */ public synchronized void closeConsoleOutputStream() throws IOException { if (nOpens > 0 && --nOpens == 0) { for (int i = 0; i < parsers.length; ++i) { parsers[i].shutdown(); } } } /* * Processes the line by passing the line to the parsers. * * @param line */ private synchronized void processLine(String line) { for (int i = 0; i < parsers.length; ++i) { parsers[i].processLine(line); } } }