Run C program with interactive IO using ProcessBuilder - java

I’m developing an IDE kind of software for C/C++ using java (although there are lots of available, but I want my own) that can compile and execute C or C++ program. So I tried a simple program to compile and execute the C program in java using Process and ProcessBuilder.
Here is my simple java program which compiles and execute C program:
public class RunProgram {
public static void main(String[] args) throws Exception {
new ProcessBuilder("gcc", "-o", "first", "first.c").start().waitFor(); //To Compile the source file using gcc and wait for compilation
/*
Although I've to handle error-stream but
for now, my assumption is that there is no error
in program.
*/
ProcessBuilder run = new ProcessBuilder("./first");
execute.redirectErrorStream(true);
Process runProcess = run.start();
StreamReader sr = new StreamReader(runProcess.getInputStream());
new Thread(sr).start(); //A new thread to handle output of program .
//rest of coding to provide input using OutputStream of 'runProcess' and to close the stream.
}
}
class StreamReader implements Runnable {
private InputStream reader;
public StreamReader(InputStream inStream) {
reader = inStream;
}
#Override
public void run() {
byte[] buf = new byte[1024];
int size = 0;
try {
while ((size = reader.read(buf)) != -1) {
System.out.println(new String(buf));
}
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
And here is my first.c program.
#include<stdio.h>
int main() {
int a;
int k;
printf("input a: ");
scanf("%d", &a);
for(k = 0; k < a; k++)
printf("k = %d\n", k);
return 0;
}
I want to create interactive IO console just like most of the IDEs or command terminals(Terminal in Linux bases OS and command prompt in Windows based OS). For above example: firstly, it should print “Input a: “and then wait for input to be provided and then rest of program. But It won’t work as I thought, as it doesn’t print the result of printf statement appeared before scanf until I provide input possibly using OutputStream.
I googled for my problem and visited many links but didn't get solution. Mean while, I found this link which suggest to append fflush after every printf statement or use setbuf or setvbuf methods (from some other sub-links) to clear the buffer. But a new person (who is going to learn C) might not be aware of fflush or these functions and he/she will never use it, as it doesn’t require in other IDEs or not even on terminals.
How can I solve this problem and can build integrated console for my IDE
Here is a glimpse of what I want:

From the comments above, think adding a little bit of explanation of how buffering for I/O streams works makes sense here.
What happens behind the scenes when calling printf(3) and the like is that the data is written to a buffer until the buffer fills up or some trigger happens.
The content of the buffer is then copied from the buffer to the actual output device/another output buffer ...
The trigger is usually encountering a line end (\n under Linux/Unix).
Thus a crude version of this buffering is:
struct buffered_file_t {
char* buffer;
size_t capacity;
size_t current_char;
FILE* file;
};
void flush_buffered(struct buffered_file_t* file) {
assert(0 != file);
assert(0 != file->buffer);
fwrite(file->buffer, file->current_char, 1, file->file);
file->current_char = 0;
}
void print(struct buffered_file_t* file, const char* str) {
assert(0 != file);
assert(0 != file->buffer);
assert(0 != str);
for(size_t i = 0; 0 != str[i]; ++i) {
if(file->current_char >= file->capacity - 1) flush_buffered(file);
file->buffer[file->current_char++] = str[i];
if('\n' == str[i]) flush_buffered(file);
}
}
Now, if you invoke print like
const size_t BUFSIZE = 100;
struct buffered_file_t stdout_buffered = {
.buffer = calloc(1, BUFSIZE),
.capacity = BUFSIZE,
.current_char = 0,
.file= stdout,
};
print(&stdout_buffered, "Naglfar\n");
print(&stdout_buffered, "Surthur");
You won't see Surthur appear onstdout ever.
In order to have it written from the buffer to stdout, you have to either
call flush_buffered explicitly
Disable buffering by reducing the buffer size (buffered_file.capacity = 1 in the example above)
In your case, you cannot invoke fflush(3) explicitly (that's what you stated as requirement). thus the only means left is disabling buffering.
How to do this is OS dependent, IMHO.
For Linux, look at stdbuf(1) from the Coreutils package to find out how to diable buffering for certain streams of foreign processes.

Under GNU/Linux, for switching off buffering for the standard I/O streams, you could use stdbuf(1)like so:
....
ProcessBuilder run = new ProcessBuilder("stdbuf", "-o0", "./first");
....
Add -e0 and -i0 options if you want to turn off buffering for stderr and stdin as well.
Of course, it would be nicer if you would not have to rely upon external tools but could do switching off buffering in your own code - simplest thing is to have a look at the source of stdbuf, but I guess it would end up in you having to use the JNI, and then, I guess, I would just stick to stdbuf ...

Related

Using Haskell's GHCI through a Java Program

What I would like to do is wrap my Java program around the GHCI.
In my mind it should work like this:
Starting my Java program
Write down some Haskell function as Input for Java (i.e. reverse [1,2,3,4])
See the appropriate Haskell Output on my Java Console
Because I did not want to mess around with any language bridges I tried the clumsy way and used the Runtime.exec() approach.
This is my Code:
public static void main(String[] args) throws Exception {
Runtime r = Runtime.getRuntime();
Process p = r.exec("ghci");
OutputStream output = p.getOutputStream();
output.write("let x = 5\r\n".getBytes());
output.write("x".getBytes());
int tmp;
String result = "";
while ((tmp = p.getInputStream().read()) != -1) {
result += (char) tmp;
}
System.out.println(result);
p.destroy(); }
My problem here is that the read() method always returns a -1 and I cannot get the output. I dont even know if what I wrote created any Output.
Help would be appreciated. Thanks!
It is clear that Process p = r.exec("ghci"); did not successful for which read() method always returns a -1. Provide full path and check.
Process p = r.exec("/fullpath/ghci 2>&1");
p.waitFor();//You need to use this line of code
For confirmation first execute ls command first
Process p = r.exec("ls 2>&1");
Also modify your codes like below and try:-
public static void main(String[] args) throws Exception {
Runtime r = Runtime.getRuntime();
Process p = r.exec("ghci");
p.waitFor();
OutputStream output = p.getOutputStream();
ByteArrayOutputStream byte1=new ByteArrayOutputStream();
output.write(byte1.toByteArray());
String result=byte1.toString();
System.out.println(result);
p.destroy();
}

Java Application waits for finishing the java exec command to go on working properly again

I'm trying to call a java.jar(it is working by double click) from a java application.And it is working with that code below.The main problem is that when the called jar start to work (a gui application), ı cannot use the my main(another gui application) application.I think it is waiting the exec command's end. How can I manage to run this 2 application properly?
public void handle(Event arg0) {
Runtime runTime = Runtime.getRuntime();
try {
Process process = runTime
.exec("java -jar \"D:\\WORKSPACE\\Deploy\\Binary\\XXXX.jar\"");
BufferedInputStream inputStream = new BufferedInputStream(process.getInputStream());
BufferedInputStream errorStream = new BufferedInputStream(process.getErrorStream());
int n1;
byte[] c1 = new byte[4096];
StringBuffer standardOutput = new StringBuffer();
while ((inputStream.read(c1) != -1)) {
standardOutput.append(c1.toString());
}
System.out.println("Standard Output: " + standardOutput.toString());
int n2;
byte[] c2 = new byte[4096];
StringBuffer standardError = new StringBuffer();
while (errorStream.read(c2) != -1) {
standardError.append(c2.toString());
}
System.out.println("Standard Error: " + standardError.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
});
The issue is with your stream consuming code...
while ((inputStream.read(c1) != -1)) {
standardOutput.append(c1.toString());
}
System.out.println("Standard Output: " + standardOutput.toString());
int n2;
byte[] c2 = new byte[4096];
StringBuffer standardError = new StringBuffer();
while (errorStream.read(c2) != -1) {
standardError.append(c2.toString());
}
While you are trying to read from either stream, you will block the calling thread, which is probably the Event Dispatching Thread.
What you need is two things.
A Thread to handle executing the process and
A Thread to handle reading the streams
For example Printing a Java InputStream from a Process
I would also strongly encourage the use of ProcessBuilder, apart from the fact that it encourages you to use separate strings for each argument you want to pass to the process (making it significantly easier to deal with arguments that use spaces) you can also redirect the error string into in the InputStream, making it even easier to manage...

A usable solution for console output capturing - java

I am making a program that will have the ability to run the java compiler and jvm right from within it (Don't ask me why I am reinventing the wheel, if your reply does not help, save it, I am already quite frustrated spending hours on solutions that do not work!). So far I have managed it to track whenever I input something in my textField that starts with java so that it will actually wrap up the text and give it a run like so:
if(String.valueOf(object).startsWith("java")){
try{
Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec(String.valueOf(object));
}
catch(Exception e){gsc.mainWindow.printf("error");}
Consider gsc.mainWindow.printf(...); my output to a JTextArea within a JFrame.
What I have managed now is to run the commands, but anything fails I shall be able to print it directly to my output. I know this has been answered a ton of times before, read about 10 ways to do this, but none of them worked or was understandable to the point that I could run it. I need the code to be simple enough as this will have to be outputting what the proccess will be writing in the default system's Console (cmd,terminal) and then stop (I thought that this can be a method call alltogether). I am quite bad with this kind of stuff, even a multithread solution could fit my needs, nothing too professional really, I just need it to work. Any information you need, ask away!
Thanks in advance! :)
I don't know you if you want to read this, but you know, in the Java world, you should always look for a solution before implementing your own. And the solution for common problems, most of the time, comes from Apache Commons or other Apache projects. Saying that everything but your solution doesn't work or is too complicated to you will only cost you time and money (and your job, eventually).
Apache Commons Exec is what you need to solve your problem faster and easier.
---- Edit ----
Here is some code of how to capture the output of the child process. There's a class just for it, the PumpStreamHandler:
DefaultExecutor exec = new DefaultExecutor();
PumpStreamHandler streamHandler = new PumpStreamHandler();
exec.setStreamHandler(streamHandler);
CommandLine commandline = CommandLine.parse(command); //where command is your command line
exec.execute(commandline);
---- Edit 2 ----
Here is the copy-paste solution you want to capture the message using an OutputStream:
public abstract class LogOutputStream extends OutputStream {
protected static final String LINE_SEPERATOR = System.getProperty("line.separator");
public static final int DEFAULT_BUFFER_LENGTH = 2048;
protected boolean hasBeenClosed = false;
protected byte[] buf;
protected int count;
private int bufLength;
public LogOutputStream() {
bufLength = DEFAULT_BUFFER_LENGTH;
buf = new byte[DEFAULT_BUFFER_LENGTH];
count = 0;
}
public void close() {
flush();
hasBeenClosed = true;
}
public void write(final int b) throws IOException {
if (hasBeenClosed) {
throw new IOException("The stream has been closed.");
}
if (b == 0) {
return;
}
if (count == bufLength) {
final int newBufLength = bufLength + DEFAULT_BUFFER_LENGTH;
final byte[] newBuf = new byte[newBufLength];
System.arraycopy(buf, 0, newBuf, 0, bufLength);
buf = newBuf;
bufLength = newBufLength;
}
buf[count] = (byte) b;
count++;
}
public void flush() {
if (count == 0) {
return;
}
if (count == LINE_SEPERATOR.length()) {
if (((char) buf[0]) == LINE_SEPERATOR.charAt(0)
&& ((count == 1) ||
((count == 2) && ((char) buf[1]) == LINE_SEPERATOR.charAt(1)))) {
reset();
return;
}
}
final byte[] theBytes = new byte[count];
System.arraycopy(buf, 0, theBytes, 0, count);
log(new String(theBytes));
reset();
}
private void reset() {
count = 0;
}
public abstract void log(String message);
}
Then just create a subclass of it, implement the public void log(String message) with the code that updates the UI, and it's done.

Java - Flushing the OutputStream of a process doesn't send the data immediately if it's too small

I'm firing up an external process from Java and grabbing its stdin, stdout and stderr via process.getInputStream() etc. My issue is: when I want to write data to my output stream (the proc's stdin) it's not getting sent until I actually call close() on the stream. I am explicitly calling flush().
I did some experimenting and noticed that if I increased the number of bytes I was sending, it would eventually go through. The magic number, on my system, is 4058 bytes.
To test I'm sending the data over to a perl script which reads like this:
#!/usr/bin/perl
use strict;
use warnings;
print "Perl starting";
while(<STDIN>) {
print "Perl here, printing this: $_"
}
Now, here's the java code:
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
public class StreamsExecTest {
private static String readInputStream(InputStream is) throws IOException {
int guessSize = is.available();
byte[] bytes = new byte[guessSize];
is.read(bytes); // This call has side effect of filling the array
String output = new String(bytes);
return output;
}
public static void main(String[] args) {
System.out.println("Starting up streams test!");
ProcessBuilder pb;
pb = new ProcessBuilder("./test.pl");
// Run the proc and grab the streams
try {
Process p = pb.start();
InputStream pStdOut = p.getInputStream();
InputStream pStdErr = p.getErrorStream();
OutputStream pStdIn = p.getOutputStream();
int counter = 0;
while (true) {
String output = readInputStream(pStdOut);
if (!output.equals("")) {
System.out.println("<OUTPUT> " + output);
}
String errors = readInputStream(pStdErr);
if (!errors.equals("")) {
System.out.println("<ERRORS> " + errors);
}
if (counter == 50) {
// Write to the stdin of the execed proc. The \n should
// in turn trigger it to treat it as a line to process
System.out.println("About to send text to proc's stdin");
String message = "hello\n";
byte[] pInBytes = message.getBytes();
pStdIn.write(pInBytes);
pStdIn.flush();
System.out.println("Sent " + pInBytes.length + " bytes.");
}
if (counter == 100) {
break;
}
Thread.sleep(100);
counter++;
}
// Cleanup
pStdOut.close();
pStdErr.close();
pStdIn.close();
p.destroy();
} catch (Exception e) {
// Catch everything
System.out.println("Exception!");
e.printStackTrace();
System.exit(1);
}
}
}
So when I run this, I get effectively nothing back. If immediately after calling flush(), I call close() on pStdIn, it works as expected. This isn't what I want though; I want to be able to continually hold the stream open and write to it whenever it so pleases me. As mentioned before, if message is 4058 bytes or larger, this will work without the close().
Is the operating system (running on 64bit Linux, with a 64bit Sun JDK for what it's worth) buffering the data before sending it? I could see Java having no real control over that, once the JVM makes the system call to write to the pipe all it can do is wait. There's another puzzle though:
The Perl script prints line before going into the while loop. Since I check for any input from Perl's stdout on every iteration of my Java loop, I would expect to see it on the first run through the loop, see the attempt at sending data from Java->Perl and then nothing. But I actually only see the initial message from Perl (after that OUTPUT message) when the write to the output stream happens. Is something blocking that I'm not aware of?
Any help greatly appreciated!
You haven't told Perl to use unbuffered output. Look in perlvar and search for $| for different ways to set unbuffered mode. In essence, one of:
HANDLE->autoflush( EXPR )
$OUTPUT_AUTOFLUSH
$|
Perl may be buffering it before it starts printing anything.
is.read(bytes); // This call has side effect of filling the array
No it doesn't. It has the effect of reading between 1 and bytes.length-1 bytes into the array. See the Javadoc.
I don't see any obvious buffering in your code, so it may be on the Perl side. What happens if you put a newline \n at the end of your print statement?
Note also that you can't, in general, read the stdin and stderr on the main thread like that. You'll be subject to deadlock - e.g., if the child process prints lots of stderr, while the parent is reading stdin, the stderr buffer will fill and the child process will block, but the parent will stay blocked forever trying to read stdin.
You need to use separate threads to read stderr and stding (also separate from the main thread, which here is used to pump input to the process).

How can I print .exe printf() messages from java program

I have one application that prints messages from Test.exe in console .My java program creates one process by executing this Test.exe.
This application prints messages by reading from input-stream of that process.
The problem, that I am facing is,
I have two scenarios:
1) When I double click test.exe, messages("Printing : %d") are printing for every second.
2)But when I run my java application,whole messages are printing at last(not for every second) before terminating Test.exe.If .exe has a very huge messages to print,then it will print those messages(I think whenever buffer becomes full)and flushing will be done.
But how can I print messages same as 1st case.
Help from anyone would be appreciated. :)
Here is the code for this Test.exe.
#include <stdio.h>
#include <windows.h>
void main(void)
{
int i=0;
while (1)
{
Sleep(500);
printf("\nPrinting : %d",i);
i++;
if (i==10)
//if(i==100)
{
return 0;
}
}
}
And my Java application is below:
public class MainClass {
public static void main(String[] args) {
String str = "G:\\Charan\\Test\\Debug\\Test.exe";
try {
Process testProcess = Runtime.getRuntime().exec(str);
InputStream inputStream = new BufferedInputStream(
testProcess.getInputStream());
int read = 0;
byte[] bytes = new byte[1000];
String text;
while (read >= 0) {
if (inputStream.available() > 0 ) {
read = inputStream.read(bytes);
if (read > 0) {
text = new String(bytes, 0, read);
System.out.println(text);
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Is it possible in reverse order.If I input some text from console,Java should read and pass that String to .exe(or testProcess).How .exe scan something from Java program.
Could anyone help me..
Given that you're trying to print stdout from that process line by line, I would created a BufferedReader object using the process' input stream and use the readLine() method on that. You can get a BufferedReader object using the following chain of constructors:
BufferedReader testProcessReader = new BufferedReader(new InputStreamReader(testProcess.getInputStream()));
And to read line by line:
String line;
while ((line = testProcessReader.readLine()) != null) {
System.out.println(line);
}
The assumption here is that Test.exe is flushing its output, which is required by any read from the Java side. You can flush the output from C by calling fflush(stdout) after every call to printf().
If you don't flush, the data only lives in a buffer. When considering performance, it's a trade-off, how often you want the data to be written vs. how many writes / flush operations you want to save. If performance is critical, you can consider looking into a more efficient inter-process communication mechanism to pass data between the processes instead of stdout. Since you are on Windows, the first step might be to take a look at the Microsoft IPC help page.
Seems to have something to do with not flushing. I guess it's on both sides - The C library you use seems to only automatically flush output when writing to a terminal. Flush manually after calling printf.
On the Java side, try reading from a non-buffered stream.

Categories