1. Pipe Input/Output

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?

new topic     » topic index » view message » categorize

2. Re: Pipe Input/Output

ryanj said...

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.

ryanj said...

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) 
new topic     » goto parent     » topic index » view message » categorize

3. Re: Pipe Input/Output

Ok, thanks. That clears it up. Everything you just said should be in the manual. smile

new topic     » goto parent     » topic index » view message » categorize

4. Re: Pipe Input/Output

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

new topic     » goto parent     » topic index » view message » categorize

5. Re: Pipe Input/Output

achury said...

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

new topic     » goto parent     » topic index » view message » categorize

6. Re: Pipe Input/Output

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 
new topic     » goto parent     » topic index » view message » categorize

7. Re: Pipe Input/Output

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 
new topic     » goto parent     » topic index » view message » categorize

8. Re: Pipe Input/Output

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) 
new topic     » goto parent     » topic index » view message » categorize

Search



Quick Links

User menu

Not signed in.

Misc Menu