/*
* $Id$
*
* Copyright (c) 2004-2005 by the TeXlapse Team.
* 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
*/
package net.sourceforge.texlipse.builder;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import net.sourceforge.texlipse.TexlipsePlugin;
import net.sourceforge.texlipse.actions.InputQueryDialog;
import org.eclipse.swt.widgets.Display;
/**
* Scans the input stream for the given trigger strings and produces a query dialog if sees one.
*
* @author Kimmo Karlsson
*/
public class OutputScanner {
// input stream to scan
private BufferedInputStream in;
// output stream to write user's responses
private OutputStream out;
// the trigger strings to scan for
private String[] triggerString;
// true, if the user pressed ok in the dialog
private boolean okPressed;
// the text that the user wrote to the dialog
private String query;
// the scanned input
private StringBuilder sb;
// the length of the occured trigger string
protected int currentTriggerStringLength;
// output messages to console
private String consoleOutput;
/**
* Create new OutputProducer.
*
* @param in
* @param out
* @param trig
* @param console
*/
public OutputScanner(InputStream in, OutputStream out, String[] trig, String console) {
this.in = new BufferedInputStream(in);
this.out = out;
this.triggerString = trig;
this.okPressed = false;
this.query = null;
this.sb = new StringBuilder();
this.consoleOutput = console;
}
/**
* @return the contents of the buffer
*/
public String getText() {
return sb.toString();
}
/**
* Read output from the stream and save it into a buffer.
* If the trigger string occurs in the stream, a question dialog will be popped up.
*
* Reading is done byte-by-byte because we don't know when the stream is
* going to pause. Reading by buffers would mean that we could end up waiting
* input from the program when the program is waiting input from us, i.e. a deadlock.
*
* @return true if the output was read successfully into the buffer
*/
public boolean scanOutput() {
try {
// this was the index we had parsed the output to
// when the user pressed ok on our dialog
int startOfLine = 0;
int okIndex = 0;
int maxLength = 0;
if (triggerString != null) {
//determine max length of a triggerString
for (int i = 0; i < triggerString.length; i++) {
if (maxLength < triggerString[i].length())
maxLength = triggerString[i].length();
}
}
int avail = 0;
while (true) {
int nextByte = in.read();
if (nextByte == -1) break;
sb.append((char)nextByte);
avail--;
if (avail <= 0) avail = in.available();
//TriggerStrings can only occur if the program is waiting for input => in.available() == 0
if (triggerString != null && avail == 0) {
for (int i = 0; i < triggerString.length; i++) {
if (sb.length() > maxLength)
okIndex = sb.length() - maxLength;
int foundIndex = sb.indexOf(triggerString[i], okIndex);
if (foundIndex >= 0) {
currentTriggerStringLength = triggerString[i].length();
boolean retry = askUserInput();
if (!retry) {
return false;
} else {
okIndex = foundIndex+1;
break;
}
}
}
}
if (consoleOutput != null && (char)nextByte == '\n') {
int lf = 1;
if (sb.charAt(sb.length()-2) == '\r') { // fix for windows linefeeds
lf++;
}
// don't print the whole buffer as the printToConsole() outputs a linefeed
BuilderRegistry.printToConsole(consoleOutput + "> " + sb.substring(startOfLine, sb.length()-lf));
startOfLine = sb.length();
}
}
} catch (IOException e) {
}
return true;
}
/**
* Create the build error input query dialog.
* @param message
* @return
*/
private static InputQueryDialog createQueryDialog(String message) {
return InputQueryDialog.createQuery("Question from an external program",
"External program has a question:\n\n" + message,
"Enter text", "Cancel build");
}
/**
* Display a question dialog with two buttons.
*
* @return true, if the user pressed the "enter text" -button
*/
private boolean askUserInput() {
Display display = TexlipsePlugin.getDefault().getWorkbench().getDisplay();
display.syncExec(new Runnable() {
public void run() {
int i = sb.lastIndexOf("!");
if (i < 0) {
i = currentTriggerStringLength;
} else {
i+=2;
}
InputQueryDialog dlg = createQueryDialog(sb.substring(i));
okPressed = (dlg.open() == 0);
query = dlg.getInput();
}});
if (okPressed) {
try {
if (query == null) {
query = "";
}
query += System.getProperty("line.separator");
out.write(query.getBytes());
out.flush();
} catch (IOException e) {
return false;
}
return true;
}
return false;
}
}