Philipp Traeder wrote:
> 
> Good morning everybody,

Hello,

> I am writing a small console application, allowing the user to perform
> some actions via a shell-like interface. The basics of this were rather
> easy, and with the help of some very nice CPAN modules (i.e.
> Base::Shell), I have got tab-completion, a help system and much more
> already.
> 
> The core of the application looks (a bit simplifid and in pseudo-code)
> more or less like this:
> 
> while ("true") {
>     $cmd = $term->ReadLine($prompt);
>     if ($cmd eq "help") {
>         # process help
>     }
>     elsif ($cmd eq "exit"}
>         last;
>     }
>     # ...process other actions
> }

Not related to your question but, have you thought of using a dispatch
table instead?

sub help {
    # process help
    }

sub long_action {
    # process long_action
    }

my %process = (
    help        => \&help,
    long_action => \&long_action,
    simple_cmd  => sub { print "Anonymous sub for simple command\n" },
    );

while ( 1 ) {
    my $cmd = $term->ReadLine( $prompt );
    if ( exists $process{ $cmd } ) {
        last if $cmd eq 'exit';
        $process{ $cmd }();
        }
    else {
        print STDERR "Unknown command '$cmd'\n";
        }
    }


> Now I would like to be able to execute a lengthy action that takes
> several minutes. I think I can execute this with a fork, allowing the
> user to keep on working while the action is being executed. The
> appropriate action code would look more or less like this:
> 
>     # ...
>     elsif ($cmd eq 'long_action') {
>         if (!fork) {
>              # execute the action in the child process
>              sleep 10;
> 
>              # TODO: notify the user that the action is finished.
> 
>              exit;
>         }
> 
>     }

It is pretty simple, the perlipc man page has some good examples, but it
is basically like this:

    elsif ( $cmd eq 'long_action' ) {
        defined( my $pid = fork ) or die "Cannot fork: $!";
        unless ( $pid ) {
            # execute the action in the child process
            sleep 10;

            # TODO: notify the user that the action is finished.
            print "'long_action' has finished processing\n";
            exit;
        }
    }


> What I would like to do is perform the action in the forked child
> process, and on completion the user should get a message about the
> result of the action (which would be true or false, most likely).
> The result should look like this for the user:
> 
> myshell> normal_action
> performing normal action...done.
> myshell> long_action
> initiating lengthy action....done.
> myshell>
> lenghty action completed successfully.
> myshell>
> 
> Please note that the user should get back the prompt after he started
> 'long_action', and when the action is finished, he should be informed by
> a message in the shell.
> 
> With this I have got two problems:
> a) I am executing the action in a child process. What would be the best
> way for the child process to inform its parent that the execution has
> been finished?

This gets more complicated.  Does the parent really have to know when
the child has finished?  waitpid() with the WNOHANG option might do what
you want or you could use signals or you could use some form of IPC like
System V IPC or sockets, etc., etc.


> b) How can I set up the ReadLine() part in a way that the user is able
> to type new actions, but can receive new messages (from finished long
> actions) as well? I have played around with Term::ReadKey, and ended up
> with something like this:
> 
>     my ($complete, $key);
>     my $string = '';
>     print $prompt;
>     # ask for input until we have got a complete string
>     while (not $complete) {
>         print "so far : $string\n";
>         # read a single key
>         while (not defined ($key = ReadKey(-1))) {
>             # No key yet
>             # $string seems to be empty here!
>             print "*" . $string;
>             sleep 1;
>             if ($string eq 'test') {
>                 print "youve written nothing serious so far!\n";
>                 print $prompt . $string;
>                 $string = '';
>             }
>         }
>         if ($key eq "\n") {
>             $complete = 1;
>         }
>         else {
>             $string .= $key;
>         }
>     }
> 
> This construct should theoretically more or less allow me to check for
> individual keystrokes of the user and parallely to print messages if
> necessary, but it does not do what I would expect: If I call
> ReadKey(-1), it does not seem to "know" the $string variable in the
> inner while loop, and if I call ReadKey(0), it looks like all keys are
> fetched first, and afterwards the "print" statements are executed.

Sorry, I don't know enough about Term::ReadKey to help with that.  :-(

HTH


John
-- 
use Perl;
program
fulfillment

-- 
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to