/*
* 05/11/2010
*
* Copyright (C) 2010 Robert Futrell
* robert_futrell at users.sourceforge.net
* http://fifesoft.com/rsyntaxtextarea
*
* This library is distributed under a modified BSD license. See the included
* RSTALanguageSupport.License.txt file for details.
*/
package org.fife.rsta.ac;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* I/O related utility methods. We should think of a better location for
* these methods.
*
* @author Robert Futrell
* @version 1.0
*/
public class IOUtil {
private static Map DEFAULT_ENV;
/**
* Private constructor to prevent instantiation.
*/
private IOUtil() {
}
/**
* Gets the environment of the current process. Works with Java 1.4 as
* well as 1.5+.
*
* @return A mapping of environment variable names to values.
*/
private static Map getDefaultEnvMap() {
// If we've already created it...
if (DEFAULT_ENV!=null) {
return DEFAULT_ENV;
}
// In Java 5+, we can just get the environment directly
try {
Method m = System.class.getDeclaredMethod("getenv", null);
DEFAULT_ENV = (Map)m.invoke(null, null);
} catch (Exception e) { // Java 1.4
DEFAULT_ENV = new HashMap();
StringBuffer stdout = new StringBuffer();
String command = null;
// Windows
if (File.separatorChar=='\\') {
command = "cmd.exe /c set";
}
// Unix
else {
command = "/bin/sh -c env";
}
try {
Process p = Runtime.getRuntime().exec(command);
IOUtil.waitForProcess(p, stdout, null);
} catch (IOException ioe) {
ioe.printStackTrace();
}
String str = stdout.toString();
BufferedReader r = new BufferedReader(new StringReader(str));
String line = null;
try {
while ((line=r.readLine())!=null) {
int equals = line.indexOf('=');
if (equals>-1) { // Always true
String key = line.substring(0, equals);
String value = line.substring(equals+1);
DEFAULT_ENV.put(key, value);
}
}
r.close();
} catch (IOException ioe) { // Never happens
ioe.printStackTrace();
}
}
return DEFAULT_ENV;
}
/**
* Returns the value of an environment variable. This method is here so
* we don't get an exception when calling <tt>System.getenv()</tt> in Java
* 1.4 (which we support).
*
* @param var The environment variable.
* @return The value of the variable, or <code>null</code> if it is not
* defined.
*/
public static String getEnvSafely(String var) {
String value = null;
try {
value = System.getenv(var);
} catch (java.lang.Error e) { // Throws exception in 1.4
// Windows
if (File.separatorChar=='\\') {
String command = "cmd.exe /c set " + var;
StringBuffer stdout = new StringBuffer();
try {
Process p = Runtime.getRuntime().exec(command);
IOUtil.waitForProcess(p, stdout, null);
} catch (IOException ioe) {
ioe.printStackTrace();
}
// set will return multiple matches if "var" is a prefix of
// other vars, but we'll just check the first line for "var=".
String str = stdout.toString();
int equals = str.indexOf('=');
int newline = str.indexOf('\n');
if (equals==var.length() && newline>equals) {
String test = str.substring(0, var.length());
// Be careful with casing - Windows doesn't always return
// the same casing as what you enter.
if (test.equalsIgnoreCase(var)) {
value = str.substring(var.length()+1, str.length()-1);
}
}
}
// Unix
else {
String command = "/bin/sh -c env | grep \"var\"=";
StringBuffer stdout = new StringBuffer();
try {
Process p = Runtime.getRuntime().exec(command);
IOUtil.waitForProcess(p, stdout, null);
} catch (IOException ioe) {
ioe.printStackTrace();
}
// env will return multiple matches if "var" is a prefix of
// other vars, but we'll just check the first line for "var=".
String str = stdout.toString();
int equals = str.indexOf('=');
int newline = str.indexOf('\n');
if (equals==var.length() && newline>equals) {
String test = str.substring(0, var.length());
if (test.equals(var)) {
value = str.substring(var.length()+1, str.length()-1);
}
}
}
}
return value;
}
/**
* Returns the environment of the current process, with some variables
* possibly added/overwritten. This method works even with Java 1.4.
*
* @param toAdd The environment variables to add/overwrite in the returned
* array. This array should have an even length, with even indices
* containing variable names and odd indices containing the variable
* values.
* @return The environment variables. This array's entries will be of the
* form "<code>name=value</code>", so it can be passed directly
* into <code>Runtime.exec()</code>.
*/
public static String[] getEnvironmentSafely(String[] toAdd) {
Map env = getDefaultEnvMap();
// Put any vars they want to explicitly specify
if (toAdd!=null) {
Map temp = new HashMap(env);
for (int i=0; i<toAdd.length; i+=2) {
temp.put(toAdd[i], toAdd[i+1]);
}
env = temp;
}
// Create an array of "name=value" items, like Runtime.exec() wants
int count = env.size();
String[] vars = new String[count];
int i = 0;
for (Iterator j=env.entrySet().iterator(); j.hasNext(); ) {
Map.Entry entry = (Map.Entry)j.next();
vars[i++] = entry.getKey() + "=" + entry.getValue();
}
return vars;
}
/**
* Runs a process, possibly capturing its stdout and/or stderr.
*
* @param p The process.
* @param stdout A buffer in which to put stdout, or <code>null</code> if
* you don't want to keep it.
* @param stderr A buffer in which to keep stderr, or <code>null</code>
* if you don't want to keep it.
* @return The return code of the process.
* @throws IOException If an IO error occurs.
*/
// TODO: Allow a timeout to be passed in
public static int waitForProcess(Process p, StringBuffer stdout,
StringBuffer stderr) throws IOException {
InputStream in = p.getInputStream();
InputStream err = p.getErrorStream();
Thread t1 = new Thread(new OutputCollector(in, stdout));
Thread t2 = new Thread(new OutputCollector(err, stderr));
t1.start();
t2.start();
int rc = -1;
try {
rc = p.waitFor();
t1.join();
t2.join();
} catch (InterruptedException ie) {
p.destroy();
} finally {
in.close();
err.close();
}
return rc;
}
/**
* Utility testing method.
*
* @param args Command line arguments.
*/
public static void main(String[] args) {
for (int i=0; i<args.length; i++) {
String value = IOUtil.getEnvSafely(args[i]);
System.out.println(args[i] + "=" + value);
}
}
}