tags:

views:

392

answers:

2

Hello,

I am executing a TCL script from PHP using proc_open.

  1. I first open the TCL shell 2) Send a command using fwrite 3) What I need is fread to wait/block until the command sent by fwrite is complete and get all the contents .The command may take some time to complete. (I am able to read just 2 lines and then it is going off to the next loop)

Can someone guide me.

The present code is

<?php

$app = 'tclsh84';
$descriptorspec = array(
0 => array("pipe","r"),
1 => array("pipe","w"),
2 => array("file","C:/wamp/www/tcl/bin/g.txt","w")
) ;
$process = proc_open($app, $descriptorspec, $pipes);
if (is_resource($process)) 
{


for($i=0;$i<4;$i++)
{

 fwrite($pipes[0], 'source c:/wamp/www/tcl/bin/test.tcl'."\n");
$content= fread($pipes[1],8192)
print "$content";

}    
   fclose($pipes[0]);    

   fclose($pipes[1]);


   proc_close($process);
}
?>
A: 

try:

$content = '';
while(!feof($pipes[1]))
  $content .= fread($pipes[1],8192);

Does that wait?

bucabay
No it does not wait. Ok Is there any way I can wait until the command that has been sent by fwrite completes ?
mithunmo
+1  A: 

I'm thinking about a combination of

You want to wait until the tcl application doesn't write something to its stdout for a certain amount of time (presuming that this means the end of the last command) and then send the next command/line to its stdin?

edit:
Seems like you can send all commands to the tcl shell at once and they are processed one by one, i.e. the shell reads the next input line/command when it's done with the previous one. I've tested this with the script.

incr a 1
after 1000
puts [concat [clock seconds] $a]

and

<?php
$app = 'c:/programme/tcl/bin/tclsh85.exe';
$descriptorspec = array(
  0 => array("pipe","r"),
  1 => array("pipe","w"),
  2 => array("file","C:/god.txt","w")
) ;
$process = proc_open($app, $descriptorspec, $pipes);
if (is_resource($process)) {
  fwrite($pipes[0], "set a 1\n");
  for($i=0;$i<4;$i++) {
    fwrite($pipes[0], "source c:/helloworld.tcl\n");
  }
  // when all scripts are done the shell shall exit
  fwrite($pipes[0], "exit\n");
  fclose($pipes[0]);

  do {
    $read=array($pipes[1]); $write=array(); $except=array($pipes[1]);
    // wait up to 1 second for new output of the tcl process
    $ready = stream_select($read, $write, $except, 1, 0);
    if ( $ready && $read /* is not empty */) {
      // get the partial output
      $r = fread($pipes[1], 2048);
      echo $r;
    }
    // is the process still running?
    $status = proc_get_status($process);
  } while($status['running']);
  fclose($pipes[1]);
  proc_close($process);
}
?>

You probably want to add some more error handling. E.g. if stream_select() returns x times with an timeout something might have gone wrong.

edit2:
Let the shell print something you can scan for after each script.

<?php
// something that's not in the "normal" output of the scripts
$id = 'done'. time();

$app = 'c:/programme/tcl/bin/tclsh85.exe';
$descriptorspec = array(
  0 => array("pipe","r"),
  1 => array("pipe","w"),
  2 => array("file","C:/god.txt","w")
) ;
$process = proc_open($app, $descriptorspec, $pipes);
if (is_resource($process)) {
  fwrite($pipes[0], "set a 1\n");
  for($i=0;$i<4;$i++) {
    $output = '';
    $continue = true;
    $cTimeout = 0;
    echo 'loop ', $i, "\n";
    fwrite($pipes[0], "source c:/helloworld.tcl\n");
    fwrite($pipes[0], "puts $id\n");
    echo "waiting for idle\n";
    do {
      $read=array($pipes[1]);
      $write=array();
      $except=array($pipes[1]);
      $ready = stream_select($read, $write, $except, 1, 0);
      if ( $ready && $read ) {
        $output .= fread($pipes[1], 2048);
        // if the delimiter id shows up in $output
        if ( false!==strpos($output, $id) ) {
            // the script is done
          $continue = false;
        }
      }
    } while($continue);
    echo 'loop ', $i, " finished\n";
  }
  proc_close($process);
}
?>
VolkerK
I am sending a command (proc name to execute ) . I want to wait until this completes its execution. Is there a way to wait for that ?I don't need to read the data it sends.I just need to wait until it completes.
mithunmo
Exactly when do you have to wait? You're sending the string 'source xyz' four times to the stdin of the process. Do you have to wait for each script to be processed before you can send another "source..."? Or do you (only) have to wait until all scripts (in their entirety) are done?
VolkerK
I have to wait for each script call (proc in tcl ) to complete . Hope you got my point. In my case i have to wait 4 times.
mithunmo
Oh, that's probably a bit more complicated... Let's see how the tcl interpreter signals that it's done with one script... Do you use ActiveTcl (8.x) ?
VolkerK
yes I am using ActiveTCL 8.4 . Thanks so much for your time.
mithunmo
btw: Do you have control over the scripts? I.e. can you make them do specific things to signal the end? Like printing something "special" or raise an event, something like that? I just tried tclsh85.exe with a simple hello world script (I don't know jack about tcl) and with an "exit" the interpreter process just ends (plop, end of process). Otherwise (with only a puts in it) it just prints the input prompt % and waits for input.
VolkerK
No I do not have any control over the TCL script execution,I can only send what commands to execute on the TCL interpreter. Let me know if there is a way to wait for the fwrite($pipes[0],'some command') to complete?
mithunmo
Maybe it _is_ sufficient to wait for the completion of all scripts/the shell. See my last edit.
VolkerK
Thanks a lot for your time Volker. But I need to wait until each command is completed . May be it can't be done. Can someone give some more inputs on this.
mithunmo
"I need to wait until each command is completed" - because you have to wait for/react on the partial results? The easiest way I can think of is to print something "special" and scan for that output on $pipe[1], see edit2. It has to be the same tcl process that runs those scripts? If not it would be even simpler to spawn x processes and wait until they have terminated.
VolkerK
This is exactly what I needed .I really appreciate your time and effort.
mithunmo