Using standard io stream:stdin and stdout in a matlab exe
Asked Answered
K

2

5

Question

I want it to 'listen' to the standard input stream in a running (compiled) Matlab executable.

This is how I believe it is done in c or a similar language:

#include stdio.h
fgets(line, 256, stdin)

Or more elaborately, it it can be used as such:

if (!fgets(line, 256, stdin))
    return;
if (line[0] == '\n')
    continue;
sscanf(line, "%s", command);

Answer

For completeness I will leave the background and notes intact, but with the help of Amro and EitanT I have managed to work it out.

Background

I have found how to do this in other languages, and here are some instructions for the compilation process.

However, I have not found anywhere how to 'listen' to the input in Matlab. The closest I have come is this description of C-like IO in Octave, but I cannot make progress with this as I looking for a solution in MATLAB.

Note that altering or wrapping the program that sends the data over the stream is not possible, and that I would prefer a pure MATLAB solution rather than wrapping my entire program. If I were to call a trivial function from MATLAB in a different language that would be ok.

What have I tried?

I tried a few functions from the command window like fgets(0) (fid = 0 seems to be the id corresponding to stdin (as mentioned by @EitanT and seen when trying fopen(0)) )but it just returns:

Operation is not implemented for requested file identifier.

I have also considered using the option in MATLAB to invoke system commands or execute java / perl commands, but so far without luck. I am also not sure whether these would still work after compilation.

Furthermore I attempted to use input('prompt','s') this works when I open the program via cmd, but does not do anything until I hit enter. (Which the program that I listen to of course will never do, in the best case I can get \n at the end of each line).

I also tried out waitinput from File Exchange but I think this is a dead end as it did not catch anything and seems to perform quite poorly.

Notes

  1. I am using Windows 7 and MATLAB 2012b.
  2. I found popen on File Exchange but that does not seem to be available for Windows.
  3. When I simply type something like 'show me' this is properly sent to the standard output stream.
Koby answered 27/5, 2013 at 15:10 Comment(4)
Why dont you just use MATLAB Compiler to create a shared library instead of a standalone application. That way you can build your own C/C++ program that interacts with standard input/output as usual and links against the generated MATLAB library. btw the pdf doc you linked to is very outdated. Here is the latest one: mathworks.com/help/pdf_doc/compiler/compiler.pdfConquistador
I must say it is not exactly clear what your problem is.. So let me get this clear; you are trying to use the input function from a compiled MATLAB application and it didnt work. Is that it?Conquistador
@DennisJaheruddin How about writing a MEX program instead of using MATLAB's built-in input() that requires hitting the "enter" key to submit inputs?Klingel
@EitanT Apparently the lack of enter-hitting was not the source of the problem. I have made up an answer but comments are still welcome of course. Thanks for the help!Koby
K
3

It turns out that input reads the standard input stream.

The reason why I failed to collect my inputs, is because I was using it as follows:

input('prompt','s')

As a result the string 'prompt' was sent to the program calling my application, and as it considered this an invalid response/request it did not send anything.

I have succeeded in making a small test program, and unlike I suspected before it is NOT a problem that the other application doesn't hit enter after sending a command.

The general solution

This is the way I have my current setup,

while 1
   stdin = input('','s'); % Note the empty first argument
   if ~isempty(stdin)
    stdout = process_input(stdin);
    stdout % Displaying the result (And thus sending it to stdout)
   end
end
Koby answered 30/5, 2013 at 19:21 Comment(2)
I get a warning with the empty prompt-string. "warning: input prompt not displayed due to mxarraytostring failure". Any idea how I can resolve it (other than putting a non-empty string)?Bhakti
The problem is that the Matlab Compiler wants to make a pointer to the string, which is not really created. I could circumvent this warming with input(char(0),'s');. (some info compgroups.net/comp.soft-sys.matlab/string-ascii-null/806917 )Bhakti
C
5

Let me illustrate with a toy example. Consider the following MATLAB function:

greet.m

function greet()
    str = input('Enter your name: ','s');
    fprintf('Hello %s\n',str)
end

Now lets compile it into a standalone application. Note that if you use the deploytool tool, make sure to choose "Console application" NOT "Windows standalone application" as target. The latter apparently produces an executable where the standard input is connected to the system shell not the MATLAB command prompt..

deploytool

If you prefer to directly compile it yourself, use the following invocation:

mcc -o hello -W main:hello -T link:exe -N -v greet.m

(For reference, the "Windows app" target issues -W WinMain:hello instead)

Running the executable produces:

C:\> hello
Enter your name: Amro
Hello Amro

where the input from the keyboard is correctly handled.

Conquistador answered 29/5, 2013 at 17:7 Comment(7)
I think input waits for a '\n'... maybe I'm wrong but I don't think it's the functionality that Dennis is looking for.Klingel
I agree that the question was not clear as to what Dennis is looking for, but the point I was making is to use "Console app" not "Windows app". For example you can also try: echo Amro | hello and it will also work. That it to say the input stream is correctly connected to the app (whether you get it interactively from the keyboard or pipe stuff into it). So you can use your any other function to read from stdinConquistador
I did in fact choose a windows standalone application, so hopefully that solves most of the problem. I will try it when I have the chance. What I experience when I open the program with cmd is that if I type 123 as response to an input request and then hit enter, it works. But if I don't hit enter nothing happens. Though I am not sure, I suspect that the problem lies in that the other program does not hit enter.Koby
@DennisJaheruddin: As I said in the comments above, the way I see it you should really be building a "C/C++ shared library" not a standalone application. That way you can write your own main procedure that drives the flow of the program..Conquistador
Thanks, your example (and not understanding what my problem was) made me realize that receiving input from cmd is infact the same thing as receiving something via the standard input stream. The building of a console app definately gives the program a more natural feel (as it now actually opens cmd when you double click it), but I will still check whether a standalone application can do the trick as well. If so, then I guess I cannot accept the answer, but regardless I am glad to give you the bounty as you definately enabled me to solve the problem.Koby
You never mentioned the fact that your executable was called from another program, and expected to follow a certain protocol to send/receive messages. Fortunately with IO redirection, it should work regardless of where the input is coming from, or where the output is being sent to.. Anyway, glad I could help :)Conquistador
Reading back it seems I was indeed not very clear about that point. || For future reference: Except for that the windows standalone application does not open properly when double clicked, I did not find any difference between the windows standalone application and the console appplication. Both compilation options seem to work fine when they are opened either via cmd or when called by the other program.Koby
K
3

It turns out that input reads the standard input stream.

The reason why I failed to collect my inputs, is because I was using it as follows:

input('prompt','s')

As a result the string 'prompt' was sent to the program calling my application, and as it considered this an invalid response/request it did not send anything.

I have succeeded in making a small test program, and unlike I suspected before it is NOT a problem that the other application doesn't hit enter after sending a command.

The general solution

This is the way I have my current setup,

while 1
   stdin = input('','s'); % Note the empty first argument
   if ~isempty(stdin)
    stdout = process_input(stdin);
    stdout % Displaying the result (And thus sending it to stdout)
   end
end
Koby answered 30/5, 2013 at 19:21 Comment(2)
I get a warning with the empty prompt-string. "warning: input prompt not displayed due to mxarraytostring failure". Any idea how I can resolve it (other than putting a non-empty string)?Bhakti
The problem is that the Matlab Compiler wants to make a pointer to the string, which is not really created. I could circumvent this warming with input(char(0),'s');. (some info compgroups.net/comp.soft-sys.matlab/string-ascii-null/806917 )Bhakti

© 2022 - 2024 — McMap. All rights reserved.