Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid
 
PerlMonks  

Tacking a function on to STDOUT?

by Anonymous Monk
on May 28, 2001 at 02:03 UTC ( [id://83647]=perlquestion: print w/replies, xml ) Need Help??

Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I need to rig it so that, everytime I print something to STDOUT, it triggers a subroutine first, and passes the text to be printed to the sub as an argument. for instance:
print STDOUT "Here's some text!"; sub filterText { # this might filter out certain words, encode text, etc. }
what i want here, is that the script automatically takes any text sent to STDOUT in print() calls, and runs it through filterText(), almost like doing this, but automatically.
print filterText("Here's some text!");

Replies are listed 'Best First'.
Re: Tacking a function on to STDOUT?
by RhetTbull (Curate) on May 28, 2001 at 03:26 UTC
    Try Filter::Handle. It does exactly what you're looking for. You can tie a sub to a file handle including STDOUT so that your text gets processed by the sub before being printed. That let's you use plain old "print", etc.
Re: Tacking a function on to STDOUT?
by jorg (Friar) on May 28, 2001 at 03:18 UTC
    You're kind of suggesting the right solution already. The best way to do this is to make a  sub printfiltered {} that filters the text you want to print before printing it to STDOUT. This leaves you with the flexibility of still printing the 'unfiltered' way to STDOUT by just calling print.
    Doing this the true object oriented way, one would override the print method but i'm not sure if perl allows you to do that. (pretty sure it does not actually)
    There *might* be a way of redirecting STDOUT to a variable and then have a separate process checking that variable every other millisecond to filter it and print it to STDOUT, but let's keep things simple and maintainable shall we ?

    Jorg

    "Do or do not, there is no try" -- Yoda
Re: Tacking a function on to STDOUT?
by larryk (Friar) on May 28, 2001 at 15:11 UTC
    I thought you might be able to do...
    #!perl -w use strict; sub my_print(@) { my @stuff = @_; print STDOUT time,": @stuff\n"; } *print = *my_print; print "Hello World!";
    but you can't so don't listen to me.

    the warning message isn't useful in this case but if I change it to &print = &my_print; it prints...

    Can't modify non-lvalue subroutine call at C:\Perl\scripts\newprint.pl + line 8. 991047768:
    so it reckons I can't do it but it has printed the time and the newline from the function just without the @_.

    can this be made to work?

    larryk

    "Argument is futile - you will be ignorralated!"

      Certain perl built-ins can be overriden and others can't. For a discussion on this, see this node. The following code shows one way to override a built-in:
Re: Tacking a function on to STDOUT?
by tachyon (Chancellor) on May 28, 2001 at 03:35 UTC
    Is there some reason not to use your own solution?
    print filterText("Here's some text!");

    A search and replace and you are away. Any other solution seems likely to be more complex. You could for instance redirect STDOUT to a file and fork a second process to filter then print data as it arrives in this file. Seems overly complex though.

    tachyon

Re: Tacking a function on to STDOUT?
by ariels (Curate) on May 29, 2001 at 11:17 UTC
    You should be using Filter::Handle, no doubt. But if you want to do it yourself (say as a quick and dirty hack), it's actually fairly easy. The perldoc perltie manpage has the details.

    Of course, you're still probably best off dividing it into 2 parts, a file containing the module IO::SubHandle: (properly located) and the main program.

    #!/usr/local/bin/perl -w package IO::SubHandle; use strict; sub TIEHANDLE { my $class = shift; local *FH = shift; my $sub = shift; bless { handle => *FH{IO}, routine => $sub }, $class; } sub PRINT { my $self = shift; my $fh = $self->{handle}; print $fh ($self->{routine}->(@_)); } # Not clear how to handle this! sub PRINTF { my $self = shift; my $fmt = shift; $self->PRINT(sprintf($fmt => @_)); } package main; use IO::SubHandle; sub filterText { ("Filter [@{[scalar @_]}]: ", @_); } print "This is your normal STDOUT\n"; tie *STDOUT, 'IO::SubHandle' => *STDOUT, \&filterText; print "This is your filtered STDOUT\n"; print STDOUT "This also gets filtered...\n"; print STDERR "STDERR is safe...\n"; printf STDOUT "PRINTF(pi = \%g) tied too (but #args different)\n", 3.1 +4159;

    Depending on what operations you perform, you may need to tie some more methods! Note also how the printf tie probably isn't implemented "correctly"; you'll need to define precisely what it should do, then you can do it.

Re: Tacking a function on to STDOUT?
by Anonymous Monk on May 29, 2001 at 17:46 UTC
    Both the cookbook and the perlopentut manual page will show you how you can archieve what you want to do using open. open (FH. "-|") will do a fork, and attach stdout of one process to stdin of the other, which means you can process your own output. This requires no changes in existing code - all you need to do is add the wrapper function. If you decide to no longer process your output, all you need to do is remove the open. No overhead of calling subroutines, or changes to the main parts of your program.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://83647]
Approved by root
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others romping around the Monastery: (4)
As of 2024-04-19 02:11 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found