1 package org.simantics.gnuplot;
3 import java.io.IOException;
4 import java.io.InputStream;
5 import java.io.StringWriter;
6 import java.nio.file.Files;
7 import java.nio.file.Path;
8 import java.nio.file.Paths;
11 * @author Tuukka Lehtonen
14 public class Gnuplot {
16 private static final String GNUPLOT_VERSION_STRING_STARTS_WITH = "gnuplot ";
17 private static final String GNUPLOT_ENV = "GNUPLOT";
18 private static final String PATH_ENV = "PATH";
20 private Path executable;
22 public Gnuplot(Path executable) throws IOException {
23 if (!Files.exists(executable))
24 throw new IOException("Provided gnuplot executable does not exist: " + executable);
25 if (!Files.isExecutable(executable))
26 throw new IOException("Provided gnuplot executable is not marked executable: " + executable);
27 this.executable = executable;
31 public String toString() {
32 return executable.toString();
35 public static Gnuplot detect() throws IOException {
37 return new Gnuplot(findGnuplotPath());
38 } catch (InterruptedException e) {
39 throw new IOException(e);
43 private static String readInput(InputStream in) throws IOException {
44 StringWriter sw = new StringWriter();
45 for (int l = 0; l < GNUPLOT_VERSION_STRING_STARTS_WITH.length(); ++l) {
55 private static boolean testExecutable(Path exe) throws IOException, InterruptedException {
56 Process process = new ProcessBuilder(exe.toString(), "-V").start();
58 if (GNUPLOT_VERSION_STRING_STARTS_WITH.startsWith( readInput(process.getInputStream()) ))
62 process.getInputStream().close();
63 process.getErrorStream().close();
68 private static Path findExecutable(String[] paths, String executableName, boolean fail) throws IOException, InterruptedException {
69 for (String p : paths) {
70 Path exe = Paths.get(p);
71 if (executableName != null)
72 exe = exe.resolve(executableName);
73 if (Files.exists(exe) && Files.isExecutable(exe) && testExecutable(exe)) {
78 throw new UnsupportedOperationException("Couldn't find executable '" + executableName + "' on the system path.");
82 private static Path findExecutable(String path, boolean splitPath, boolean fail) throws IOException, InterruptedException {
83 switch (OSType.calculate()) {
87 return findExecutable(splitPath ? path.split(":") : new String[] { path }, "gnuplot", fail);
89 return findExecutable(splitPath ? path.split(";") : new String[] { path }, "gnuplot.exe", fail);
91 throw new UnsupportedOperationException("unsupported platform");
95 private static Path findGnuplotPath() throws IOException, InterruptedException {
96 String path = System.getenv(GNUPLOT_ENV);
98 // Does GNUPLOT point directly to the executable?
99 Path p = findExecutable(new String[] { path }, null, false);
102 // Does GNUPLOT point to the gnuplot installation bin directory?
103 p = findExecutable(path, false, false);
106 // Does GNUPLOT point to the gnuplot installation root directory?
107 p = findExecutable(path + "/bin", false, false);
111 path = System.getenv(PATH_ENV);
112 return findExecutable(path, true, true);
115 private void execute0(Path workingDirectory, Path stdout, Path stderr, String... cmdline) throws IOException {
116 ProcessBuilder builder = new ProcessBuilder(cmdline)
117 .directory(workingDirectory.toFile());
120 builder.redirectOutput(stdout.toFile());
122 builder.redirectError(stderr.toFile());
124 Process process = builder.start();
125 Thread stdoutDumper = stdout == null ? new Thread(new InputStreamToFileCopier(process.getInputStream(), null)) : null;
126 Thread stderrDumper = stderr == null ? new Thread(new InputStreamToFileCopier(process.getErrorStream(), null)) : null;
127 if (stdoutDumper != null)
128 stdoutDumper.start();
129 if (stderrDumper != null)
130 stderrDumper.start();
132 process.getOutputStream().close();
134 if (stdoutDumper != null)
136 if (stderrDumper != null)
139 } catch (InterruptedException e) {
140 throw new IOException(e);
144 public void execute(Path workingDirectory, Path stdout, Path stderr, boolean redirectStderr, InputStream input, String charset) throws IOException {
145 try (GnuplotSession session = newSession(workingDirectory, stdout, stderr, redirectStderr)) {
146 session.evaluateStream(input, charset);
150 public void execute(Path workingDirectory, Path stdout, Path stderr, Path script) throws IOException {
151 execute0(workingDirectory, stdout, stderr, executable.toString(), "-c", script.toString());
154 public void execute(Path workingDirectory, Path stdout, Path stderr, String... commands) throws IOException {
155 StringBuilder e = new StringBuilder().append('"');
156 boolean first = true;
157 for (String cmd : commands) {
164 execute0(workingDirectory, stdout, stderr, executable.toString(), "-e", e.toString());
167 private ProcessBuilder buildSessionProcess(Path workingDirectory, Path stdout, Path stderr, boolean redirectErrorStream) {
168 ProcessBuilder builder = new ProcessBuilder(executable.toString())
169 .directory(workingDirectory != null ? workingDirectory.toFile() : null)
170 .redirectErrorStream(redirectErrorStream);
172 builder.redirectOutput(stdout.toFile());
174 builder.redirectError(stderr.toFile());
178 public GnuplotSession newSession(Path workingDirectory, Path stdout) throws IOException {
179 return newSession(workingDirectory, stdout, null, true);
182 public GnuplotSession newSession(Path workingDirectory, Path stdout, Path stderr, boolean redirectStderr) throws IOException {
183 return new GnuplotSession(workingDirectory, stdout == null, stderr == null,
184 buildSessionProcess(workingDirectory, stdout, stderr, redirectStderr).start());
188 APPLE, LINUX, SUN, WINDOWS, UNKNOWN;
190 public static OSType calculate() {
191 String osName = System.getProperty("os.name");
192 assert osName != null;
193 osName = osName.toLowerCase();
194 if (osName.startsWith("mac os x"))
196 if (osName.startsWith("windows"))
198 if (osName.startsWith("linux"))
200 if (osName.startsWith("sun"))