/******************************************************************************* * Copyright (c) 2010 SAP AG * 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: * Lazar Kirchev, SAP AG - initial API and implementation *******************************************************************************/ package org.eclipse.equinox.console.common; import java.io.IOException; import java.io.OutputStream; /** * This class wraps the actual output stream (e.g., a socket output stream) and is responsible for * buffering and flushing the characters to the actual output stream. */ public class ConsoleOutputStream extends OutputStream { /** * A size of the used buffer. */ public static final int BUFFER_SIZE = 2048; public final static byte CR = (byte) '\r'; public final static byte LF = (byte) '\n'; OutputStream out; OutputStream oldOut; private boolean isEcho = true; private boolean queueing = false; private byte prevByte; private byte[] buffer; private int pos; /** * Initiates with instance of the output stream to which it will send data. Here it writes to * a socket output stream. * * @param out OutputStream for console output */ public ConsoleOutputStream(OutputStream out) { this.out = out; buffer = new byte[BUFFER_SIZE]; pos = 0; } /** * An implementation of the corresponding abstract method in OutputStream. */ public synchronized void write(int i) throws IOException { if (!queueing) { if (isEcho) { if (i == '\r' || i == '\0') { queueing = true; prevByte = (byte) i; } else if (i == '\n') { add(CR); add(LF); } else { add(i); } } } else { // awaiting '\n' AFTER '\r', and '\b' AFTER '\0' if (prevByte == '\0' && i == '\b') { isEcho = !isEcho; } else if (isEcho) { if (prevByte == '\r' && i == '\n') { add(CR); add(LF); } else { add(CR); add(LF); add(i); } } queueing = false; flush(); } } /** * Empties the buffer and sends data to the socket output stream. * * @throws IOException */ public synchronized void flush() throws IOException { if (pos > 0) { try { out.write(buffer, 0, pos); out.flush(); } finally { pos = 0; } } } /** * Adds a variable of type integer to the buffer. * * @param i integer to add * @throws java.io.IOException if there are problems adding the integer */ private void add(int i) throws IOException { buffer[pos] = (byte) i; pos++; if (pos == buffer.length) { flush(); } } /** * Closes this OutputStream. * * @throws IOException */ public void close() throws IOException { out.close(); } /** * Substitutes the output stream. The old one is stored so that it can be restored later. * * @param newOut new output stream to use. */ public void setOutput(OutputStream newOut) { if (newOut != null) { oldOut = out; out = newOut; } else { out = oldOut; } } }