--- /dev/null
+package org.simantics.gnuplot;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringWriter;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+/**
+ * @author Tuukka Lehtonen
+ * @since 1.24
+ */
+public class Gnuplot {
+
+ private static final String GNUPLOT_VERSION_STRING_STARTS_WITH = "gnuplot ";
+ private static final String GNUPLOT_ENV = "GNUPLOT";
+ private static final String PATH_ENV = "PATH";
+
+ private Path executable;
+
+ public Gnuplot(Path executable) {
+ this.executable = executable;
+ }
+
+ public static Gnuplot detect() throws IOException {
+ try {
+ return new Gnuplot(findGnuplotPath());
+ } catch (InterruptedException e) {
+ throw new IOException(e);
+ }
+ }
+
+ private static String readInput(InputStream in) throws IOException {
+ StringWriter sw = new StringWriter();
+ for (int l = 0; l < GNUPLOT_VERSION_STRING_STARTS_WITH.length(); ++l) {
+ int c;
+ c = in.read();
+ if(c <= 0)
+ break;
+ sw.write(c);
+ }
+ return sw.toString();
+ }
+
+ private static boolean testExecutable(Path exe) throws IOException, InterruptedException {
+ Process process = new ProcessBuilder(exe.toString(), "-V").start();
+ try {
+ if (GNUPLOT_VERSION_STRING_STARTS_WITH.startsWith( readInput(process.getInputStream()) ))
+ return true;
+ return false;
+ } finally {
+ process.getInputStream().close();
+ process.getErrorStream().close();
+ process.waitFor();
+ }
+ }
+
+ private static Path findExecutable(String[] paths, String executableName, boolean fail) throws IOException, InterruptedException {
+ for (String p : paths) {
+ Path exe = Paths.get(p);
+ if (executableName != null)
+ exe = exe.resolve(executableName);
+ if (Files.exists(exe) && Files.isExecutable(exe) && testExecutable(exe)) {
+ return exe;
+ }
+ }
+ if (fail)
+ throw new UnsupportedOperationException("Couldn't find executable '" + executableName + "' on the system path.");
+ return null;
+ }
+
+ private static Path findExecutable(String path, boolean splitPath, boolean fail) throws IOException, InterruptedException {
+ switch (OSType.calculate()) {
+ case APPLE:
+ case SUN:
+ case LINUX:
+ return findExecutable(splitPath ? path.split(":") : new String[] { path }, "gnuplot", fail);
+ case WINDOWS:
+ return findExecutable(splitPath ? path.split(";") : new String[] { path }, "gnuplot.exe", fail);
+ default:
+ throw new UnsupportedOperationException("unsupported platform");
+ }
+ }
+
+ private static Path findGnuplotPath() throws IOException, InterruptedException {
+ String path = System.getenv(GNUPLOT_ENV);
+ if (path != null) {
+ // Does GNUPLOT point directly to the executable?
+ Path p = findExecutable(new String[] { path }, null, false);
+ if (p != null)
+ return p;
+ // Does GNUPLOT point to the gnuplot installation bin directory?
+ p = findExecutable(path, false, false);
+ if (p != null)
+ return p;
+ // Does GNUPLOT point to the gnuplot installation root directory?
+ p = findExecutable(path + "/bin", false, false);
+ if (p != null)
+ return p;
+ }
+ path = System.getenv(PATH_ENV);
+ return findExecutable(path, true, true);
+ }
+
+ private void execute0(Path workingDirectory, Path stdout, Path stderr, String... cmdline) throws IOException {
+ Process process = new ProcessBuilder(cmdline)
+ .directory(workingDirectory.toFile())
+ .start();
+ process.getOutputStream().close();
+ Thread stdoutDumper = new Thread(new InputStreamToFileCopier(process.getInputStream(), stdout));
+ Thread stderrDumper = new Thread(new InputStreamToFileCopier(process.getErrorStream(), stderr));
+ stdoutDumper.start();
+ stderrDumper.start();
+ try {
+ stdoutDumper.join();
+ stderrDumper.join();
+ process.waitFor();
+ } catch (InterruptedException e) {
+ throw new IOException(e);
+ }
+ }
+
+ public void execute(Path workingDirectory, Path stdout, Path stderr, Path script) throws IOException {
+ execute0(workingDirectory, stdout, stderr, executable.toString(), "-c", script.toString());
+ }
+
+ public void execute(Path workingDirectory, Path stdout, Path stderr, String... commands) throws IOException {
+ StringBuilder e = new StringBuilder().append('"');
+ boolean first = true;
+ for (String cmd : commands) {
+ if (!first)
+ e.append("; ");
+ first = false;
+ e.append(cmd);
+ }
+ e.append('"');
+ execute0(workingDirectory, stdout, stderr, executable.toString(), "-e", e.toString());
+ }
+
+ public GnuplotSession newSession(Path workingDirectory, Path stdout, Path stderr) throws IOException {
+ Process process = new ProcessBuilder(executable.toString())
+ .directory(workingDirectory.toFile())
+ .start();
+ return new GnuplotSession(workingDirectory, stdout, stderr, process);
+ }
+
+ static enum OSType {
+ APPLE, LINUX, SUN, WINDOWS, UNKNOWN;
+
+ public static OSType calculate() {
+ String osName = System.getProperty("os.name");
+ assert osName != null;
+ osName = osName.toLowerCase();
+ if (osName.startsWith("mac os x"))
+ return APPLE;
+ if (osName.startsWith("windows"))
+ return WINDOWS;
+ if (osName.startsWith("linux"))
+ return LINUX;
+ if (osName.startsWith("sun"))
+ return SUN;
+ return UNKNOWN;
+ }
+ }
+
+}