/*
 * BuildJava.java --
 *
 *	This file is used to invoke JAVAC.EXE to compile Jacl and
 *	Tcl Blend.
 *
 * Copyright (c) 1997 Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and
 * redistribution of this file, and for a DISCLAIMER OF ALL
 * WARRANTIES.
 *
 * SCCS: @(#) BuildJava.java 1.5 98/02/09 18:48:06
 *
 */

import java.io.*;

/*
 * This Java class is used to invoke JAVAC.EXE on Windows platforms to
 * compile Java sources files whose names are stored in a file. We
 * need to do this because the standard Windows .BAT file doesn't seem
 * to support this.
 */

public class BuildJava {


/*
 *----------------------------------------------------------------------
 *
 * main --
 *
 *	Main routine for the BuildJava class.
 *
 * Results:	
 *	None.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

public static void
main(
    String argv[])			// Command-line arguments.
{
    if (argv.length != 2) {
	System.err.println("usage: java " + BuildJava.class.getName() +
		" argsFile javac");
	System.exit(-1);
    }

    FileInputStream fs;
    byte charArray[];

    File file = new File(argv[0]);
    if (!file.exists()) {
	System.err.println("no source to compile");
	System.exit(0);
    }

    /*
     * Read the contents of the argsFile into a String.
     */

    try {
	fs = new FileInputStream(argv[0]);
	charArray = new byte[fs.available()];
	fs.read(charArray);
	fs.close();
    } catch (IOException e) {
	System.err.println(e);
	System.exit(-1);
	return;
    }

    StringBuffer sbuf = new StringBuffer();
    sbuf.append(argv[1]);
    sbuf.append(" ");

    /*
     * Sun JAVAC wants all file separators be \ on Windows. If you
     * use / you'd get weird error messages.
     */

    String s = new String(charArray);
    for (int i=0; i<s.length(); i++) {
	if (s.charAt(i) == '/') {
	    sbuf.append('\\');
	} else if (s.charAt(i) == '\n') {
	    sbuf.append(" ");
	} else if (s.charAt(i) == '\r') {
	    sbuf.append(" ");
	} else {
	    sbuf.append(s.charAt(i));
	}
    }

    /*
     * Run JAVAC with the args.
     */

    try {
	Process p = Runtime.getRuntime().exec(sbuf.toString());
	GetOutput g1 = new GetOutput(p.getInputStream());
	GetOutput g2 = new GetOutput(p.getErrorStream());
	g1.setDaemon(true);
	g2.setDaemon(true);
	g1.start();
	g2.start();

	try {
	    p.waitFor();
	    g1.waitFor();
	    g2.waitFor();
	} catch (InterruptedException e) {
	    g1.stop();
	    g2.stop();
	    System.err.println("BuildJava: interrupted");
	    System.exit(-1);
	}

	System.exit(p.exitValue());
    } catch (Exception e) {
	System.err.println(e);
	System.exit(-1);
	return;
    }
}

} // end BuildJava


/*
 * We need to read the stdout and stderr of the JAVAC process while
 * it's running.  If we don't do that, JAVAC will be stopped when the
 * stdout or stderr buffers are overflowed and we'll get into
 * a deadlock.
 *
 * The only way to do this is by spwaning two threads, each reading from
 * an output stream of the JAVAC process.
 */

class GetOutput extends Thread {

/*
 * Either stdout or stderr of the process. (Process.getInputStream
 * actually returns the stdout of a process!)
 */

InputStream stream;

/*
 * Set to true when we get an EOF from the stream.
 */

boolean done;


/*
 *----------------------------------------------------------------------
 *
 * GetOutput --
 *
 *	Creates a new instance of GetOutput.
 *
 * Results:	
 *	None.
 *
 * Side effects:
 *	Member fields are initialized.
 *
 *----------------------------------------------------------------------
 */

GetOutput(
    InputStream s)		// Initial value for stream.
{
    stream = s;
    done = false;
}

/*
 *----------------------------------------------------------------------
 *
 * run --
 *
 *	The body of the thread. The thread exits when this method
 *	returns. Characters from the stream are read and printed to 
 *	System.err.
 *
 * Results:	
 *	None.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

public synchronized void
run()
{
    while (true) {
	int c;

	try {
	     c = stream.read();
	} catch (IOException e) {
	    done = true;
	    notify();
	    return;
	}

	if (c == -1) {
	    done = true;
	    notify();
	    return;
	}
	System.err.print((char)c);
    }
}

/*
 *----------------------------------------------------------------------
 *
 * waitFor --
 *
 *	Waits for the thread to finish reading from the stream.
 *
 * Results:	
 *	None.
 *
 * Side effects:
 *	Blocks until the done flag is set to true.
 *
 *----------------------------------------------------------------------
 */

synchronized void
waitFor()
{
    try {
	while (!done) {
	    wait();
	}
    } catch (InterruptedException e) {
	return;
    }
}

} // end GetOutput
