1. Pipe Input/Output
- Posted by ryanj Apr 04, 2014
- 1997 views
I'm looking at http://openeuphoria.org/docs/std_pipeio.html. Does this library mean I can start processes and communicate with them? It isn't very clear what this library can do, and there have been tickets open on this library since 2010. I want to use this library, but how does it work?
2. Re: Pipe Input/Output
- Posted by jimcbrown (admin) Apr 05, 2014
- 1955 views
I'm looking at http://openeuphoria.org/docs/std_pipeio.html. Does this library mean I can start processes and communicate with them?
Yes, that's the whole point of the library. It's a platform-independent way of launching and communicating with processes.
It isn't very clear what this library can do, and there have been tickets open on this library since 2010. I want to use this library, but how does it work?
Take a look at pipes.ex/pipe_sub.ex in demos for an example.
Basically, you create a pipe with pipeio:create(), then you launch the process with pipeio:exec("command line here", thepipeyoumade).
Then, you write to the new process's standard input and read from its standard output. (This can be a little confusing, but the constants are defined from the child process's point of view. So since the child process has to read from its stadard input and write to its standard output, someone else has to write data into the child process's standard input and presumably is also reading the data written into the child process's standard output.)
So,
childsSTDIN = thepipeyoumade[STDIN] integer b = pipeio:write(childsSTDIN, "some data") childsSTDOUT = thepipeyoumade[STDOUT] integer n = pipeio:read(childsSTDOUT, number_of_bytes_to_read)
When you are done, clean up by doing pipeio:kill(thepipeyoumade) (maybe this should have been better named close_process() or cleanup() or something, but kill matches the API call name that is used internally).
From the process side (if it's an Euphoria process), simply read your data as normal from stdin (gets(0) or getc(0), etc) and write your data to stdout (puts(1, "data", etc) and you're done.
One annoying thing about pipeio is that if data isn't ready, it makes you wait instead of just saying "0 bytes read" or something. On *nix, here's how to fix that.
include std/pipeio.e object thepipeyoumade = pipeio:create() thepipeyoumade = pipeio:exec("command line here", thepipeyoumade) include std/dll.e object STDLIB = dll:open_dll({ "libc.so", "libc.dylib", "" }) object FNCTL = dll:define_c_func(STDLIB, "fnctl", {dll:C_INT, dll:C_INT, dll:C_INT}, dll:C_INT) object O_NONBLOCK = 2048, O_ASYNC = 8192, F_SETFL = 4 c_func(FNCTL, {thepipeyoumade[STDIN], F_SETFL, or_bits(O_NONBLOCK, O_ASYNC)}) c_func(FNCTL, {thepipeyoumade[STDOUT], F_SETFL, or_bits(O_NONBLOCK, O_ASYNC)}) c_func(FNCTL, {thepipeyoumade[STDERR], F_SETFL, or_bits(O_NONBLOCK, O_ASYNC)}) childsSTDIN = thepipeyoumade[STDIN] integer b = pipeio:write(childsSTDIN, "some data") childsSTDOUT = thepipeyoumade[STDOUT] integer n = pipeio:read(childsSTDOUT, number_of_bytes_to_read) pipeio:kill(thepipeyoumade)
3. Re: Pipe Input/Output
- Posted by ryanj Apr 05, 2014
- 1942 views
Ok, thanks. That clears it up. Everything you just said should be in the manual.
4. Re: Pipe Input/Output
- Posted by achury Jul 08, 2015
- 1577 views
Please help me. What is that I'm doing bad?
include std/pipeio.e include std/io.e object Correo object childsSTDIN sequence MailString Correo = pipeio:create() ? Correo Correo=pipeio:exec("c:\\sendmail\\sendmail.exe -t -i ", Correo) ? Correo childsSTDIN = Correo[pipeio:STDIN] MailString="To: achury@cantv.net\nFrom: marcoachury@gmail.com\nSubject: Just a test\n\nJust a test\n\n" & io:EOF integer b = pipeio:write(childsSTDIN, MailString) ? b pipeio:kill(Correo)
Edit: Added <eucode> tags for you. The double-hash tag is for ##inline code## only. -Greg
5. Re: Pipe Input/Output
- Posted by ghaberek (admin) Jul 08, 2015
- 1566 views
Please help me. What is that I'm doing bad?
include std/pipeio.e include std/io.e object Correo object childsSTDIN sequence MailString Correo = pipeio:create() ? Correo Correo=pipeio:exec("c:\\sendmail\\sendmail.exe -t -i ", Correo) ? Correo childsSTDIN = Correo[pipeio:STDIN] MailString="To: achury@cantv.net\nFrom: marcoachury@gmail.com\nSubject: Just a test\n\nJust a test\n\n" & io:EOF integer b = pipeio:write(childsSTDIN, MailString) ? b pipeio:kill(Correo)
I noticed a few things wrong here:
- In order to signal the process that you're done writing, you should call pipeio:close().
- Do not call pipeio:kill() because that may end your process too early.
- You do not need to append io:EOF to the end of the string. Calling pipeio:close() indicates the end of the data.
-Greg
6. Re: Pipe Input/Output
- Posted by jmduro Jul 08, 2015
- 1570 views
Here is a working example I use almost every day.
public function execCommand(sequence cmd) sequence s = "" object z = pipe:create() object p = pipe:exec(cmd, z) if atom(p) then logMsg(sprintf("Failed to exec() with error %x", pipe:error_no())) pipe:kill(p) return -1 end if object c = pipe:read(p[pipe:STDOUT], 256) while sequence(c) and length(c) do s &= c if atom(c) then logMsg(sprintf("Failed on read with error %x", pipe:error_no())) pipe:kill(p) return -1 end if c = pipe:read(p[pipe:STDOUT], 256) end while --Close pipes and make sure process is terminated pipe:kill(p) return s end function
7. Re: Pipe Input/Output
- Posted by jmduro Jul 08, 2015
- 1579 views
logMsg is not necessary. It is defined as follows
global integer f_debug = 1 -- debug file global integer debugLevel = 0 -- 0=no debug, 1=debug file only, 2=debug_file and screen output ------------------------------------------------------------------------------ public function dateStamp(sequence msg) -- prefixes the message by date and time for logging sequence cur_date cur_date = date() return sprintf("%d-%02d-%02d %02d:%02d:%02d -> %s\n", { (cur_date[1] + 1900), cur_date[2], cur_date[3], cur_date[4], cur_date[5], cur_date[6], msg }) end function ------------------------------------------------------------------------------ public procedure logMsg(sequence msg) -- records logs if debugLevel>0 then puts(f_debug, dateStamp(msg)) flush(f_debug) end if if debugLevel>1 then puts(1, dateStamp(msg)) end if end procedure
8. Re: Pipe Input/Output
- Posted by achury Jul 08, 2015
- 1551 views
Thanks a lot for your help. Now I have nice mailer that dont requires to create temp files.
Replace kill with close solved my problem. This is the final code if someone needed.
include std/pipeio.e object Correo object childsSTDIN sequence MailString Correo = pipeio:create() Correo=pipeio:exec("c:\\sendmail\\sendmail.exe -t -i ", Correo) -- Sendmail from http://glob.com.au/sendmail/ childsSTDIN = Correo[pipeio:STDIN] -- To: and From: may be defined on sendmail.ini or included on MailString -- Double \n may be required after email headers MailString="Subject: Just a subject\n\nJust a body text\n\n" integer b = pipeio:write(childsSTDIN, MailString) Correo=pipeio:close(0)