2

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);
}
?>
Vidya
  • 7,717
  • 12
  • 48
  • 75
  • Are you sure that the script generates more output than you get? The php documentation of fread suggests that it will not return less than the specified amount unless it encounters EOF (if reading from a userspace stream). – Inshallah Aug 25 '09 at 07:21
  • Fread doesnt stop for the command on the TCL to complete . It goes off to the next loop. – Vidya Aug 25 '09 at 07:33

2 Answers2

1

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
  • 95,432
  • 20
  • 163
  • 226
  • 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. – Vidya Aug 25 '09 at 11:37
  • 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 Aug 25 '09 at 11:45
  • 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. – Vidya Aug 25 '09 at 11:48
  • 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 Aug 25 '09 at 11:50
  • 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 Aug 25 '09 at 12:01
  • 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? – Vidya Aug 25 '09 at 12:12
  • Maybe it _is_ sufficient to wait for the completion of all scripts/the shell. See my last edit. – VolkerK Aug 25 '09 at 12:49
  • 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. – Vidya Aug 25 '09 at 13:36
  • "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 Aug 25 '09 at 15:38
  • This is exactly what I needed .I really appreciate your time and effort. – Vidya Aug 26 '09 at 04:29
0

Try:

$content = '';

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

Does that wait?

markus
  • 40,136
  • 23
  • 97
  • 142
bucabay
  • 5,235
  • 2
  • 26
  • 37
  • No it does not wait. Ok Is there any way I can wait until the command that has been sent by fwrite completes ? – Vidya Aug 25 '09 at 11:36