1N/A
1N/A# Call.pm
1N/A#
1N/A# Copyright (c) 1995-2001 Paul Marquess. All rights reserved.
1N/A#
1N/A# This program is free software; you can redistribute it and/or
1N/A# modify it under the same terms as Perl itself.
1N/A
1N/Apackage Filter::Util::Call ;
1N/A
1N/Arequire 5.002 ;
1N/Arequire DynaLoader;
1N/Arequire Exporter;
1N/Ause Carp ;
1N/Ause strict;
1N/Ause warnings;
1N/Ause vars qw($VERSION @ISA @EXPORT) ;
1N/A
1N/A@ISA = qw(Exporter DynaLoader);
1N/A@EXPORT = qw( filter_add filter_del filter_read filter_read_exact) ;
1N/A$VERSION = "1.0601" ;
1N/A
1N/Asub filter_read_exact($)
1N/A{
1N/A my ($size) = @_ ;
1N/A my ($left) = $size ;
1N/A my ($status) ;
1N/A
1N/A croak ("filter_read_exact: size parameter must be > 0")
1N/A unless $size > 0 ;
1N/A
1N/A # try to read a block which is exactly $size bytes long
1N/A while ($left and ($status = filter_read($left)) > 0) {
1N/A $left = $size - length $_ ;
1N/A }
1N/A
1N/A # EOF with pending data is a special case
1N/A return 1 if $status == 0 and length $_ ;
1N/A
1N/A return $status ;
1N/A}
1N/A
1N/Asub filter_add($)
1N/A{
1N/A my($obj) = @_ ;
1N/A
1N/A # Did we get a code reference?
1N/A my $coderef = (ref $obj eq 'CODE') ;
1N/A
1N/A # If the parameter isn't already a reference, make it one.
1N/A $obj = \$obj unless ref $obj ;
1N/A
1N/A $obj = bless ($obj, (caller)[0]) unless $coderef ;
1N/A
1N/A # finish off the installation of the filter in C.
1N/A Filter::Util::Call::real_import($obj, (caller)[0], $coderef) ;
1N/A}
1N/A
1N/Abootstrap Filter::Util::Call ;
1N/A
1N/A1;
1N/A__END__
1N/A
1N/A=head1 NAME
1N/A
1N/AFilter::Util::Call - Perl Source Filter Utility Module
1N/A
1N/A=head1 SYNOPSIS
1N/A
1N/A use Filter::Util::Call ;
1N/A
1N/A=head1 DESCRIPTION
1N/A
1N/AThis module provides you with the framework to write I<Source Filters>
1N/Ain Perl.
1N/A
1N/AAn alternate interface to Filter::Util::Call is now available. See
1N/AL<Filter::Simple> for more details.
1N/A
1N/AA I<Perl Source Filter> is implemented as a Perl module. The structure
1N/Aof the module can take one of two broadly similar formats. To
1N/Adistinguish between them, the first will be referred to as I<method
1N/Afilter> and the second as I<closure filter>.
1N/A
1N/AHere is a skeleton for the I<method filter>:
1N/A
1N/A package MyFilter ;
1N/A
1N/A use Filter::Util::Call ;
1N/A
1N/A sub import
1N/A {
1N/A my($type, @arguments) = @_ ;
1N/A filter_add([]) ;
1N/A }
1N/A
1N/A sub filter
1N/A {
1N/A my($self) = @_ ;
1N/A my($status) ;
1N/A
1N/A $status = filter_read() ;
1N/A $status ;
1N/A }
1N/A
1N/A 1 ;
1N/A
1N/Aand this is the equivalent skeleton for the I<closure filter>:
1N/A
1N/A package MyFilter ;
1N/A
1N/A use Filter::Util::Call ;
1N/A
1N/A sub import
1N/A {
1N/A my($type, @arguments) = @_ ;
1N/A
1N/A filter_add(
1N/A sub
1N/A {
1N/A my($status) ;
1N/A $status = filter_read() ;
1N/A $status ;
1N/A } )
1N/A }
1N/A
1N/A 1 ;
1N/A
1N/ATo make use of either of the two filter modules above, place the line
1N/Abelow in a Perl source file.
1N/A
1N/A use MyFilter;
1N/A
1N/AIn fact, the skeleton modules shown above are fully functional I<Source
1N/AFilters>, albeit fairly useless ones. All they does is filter the
1N/Asource stream without modifying it at all.
1N/A
1N/AAs you can see both modules have a broadly similar structure. They both
1N/Amake use of the C<Filter::Util::Call> module and both have an C<import>
1N/Amethod. The difference between them is that the I<method filter>
1N/Arequires a I<filter> method, whereas the I<closure filter> gets the
1N/Aequivalent of a I<filter> method with the anonymous sub passed to
1N/AI<filter_add>.
1N/A
1N/ATo make proper use of the I<closure filter> shown above you need to
1N/Ahave a good understanding of the concept of a I<closure>. See
1N/AL<perlref> for more details on the mechanics of I<closures>.
1N/A
1N/A=head2 B<use Filter::Util::Call>
1N/A
1N/AThe following functions are exported by C<Filter::Util::Call>:
1N/A
1N/A filter_add()
1N/A filter_read()
1N/A filter_read_exact()
1N/A filter_del()
1N/A
1N/A=head2 B<import()>
1N/A
1N/AThe C<import> method is used to create an instance of the filter. It is
1N/Acalled indirectly by Perl when it encounters the C<use MyFilter> line
1N/Ain a source file (See L<perlfunc/import> for more details on
1N/AC<import>).
1N/A
1N/AIt will always have at least one parameter automatically passed by Perl
1N/A- this corresponds to the name of the package. In the example above it
1N/Awill be C<"MyFilter">.
1N/A
1N/AApart from the first parameter, import can accept an optional list of
1N/Aparameters. These can be used to pass parameters to the filter. For
1N/Aexample:
1N/A
1N/A use MyFilter qw(a b c) ;
1N/A
1N/Awill result in the C<@_> array having the following values:
1N/A
1N/A @_ [0] => "MyFilter"
1N/A @_ [1] => "a"
1N/A @_ [2] => "b"
1N/A @_ [3] => "c"
1N/A
1N/ABefore terminating, the C<import> function must explicitly install the
1N/Afilter by calling C<filter_add>.
1N/A
1N/AB<filter_add()>
1N/A
1N/AThe function, C<filter_add>, actually installs the filter. It takes one
1N/Aparameter which should be a reference. The kind of reference used will
1N/Adictate which of the two filter types will be used.
1N/A
1N/AIf a CODE reference is used then a I<closure filter> will be assumed.
1N/A
1N/AIf a CODE reference is not used, a I<method filter> will be assumed.
1N/AIn a I<method filter>, the reference can be used to store context
1N/Ainformation. The reference will be I<blessed> into the package by
1N/AC<filter_add>.
1N/A
1N/ASee the filters at the end of this documents for examples of using
1N/Acontext information using both I<method filters> and I<closure
1N/Afilters>.
1N/A
1N/A=head2 B<filter() and anonymous sub>
1N/A
1N/ABoth the C<filter> method used with a I<method filter> and the
1N/Aanonymous sub used with a I<closure filter> is where the main
1N/Aprocessing for the filter is done.
1N/A
1N/AThe big difference between the two types of filter is that the I<method
1N/Afilter> uses the object passed to the method to store any context data,
1N/Awhereas the I<closure filter> uses the lexical variables that are
1N/Amaintained by the closure.
1N/A
1N/ANote that the single parameter passed to the I<method filter>,
1N/AC<$self>, is the same reference that was passed to C<filter_add>
1N/Ablessed into the filter's package. See the example filters later on for
1N/Adetails of using C<$self>.
1N/A
1N/AHere is a list of the common features of the anonymous sub and the
1N/AC<filter()> method.
1N/A
1N/A=over 5
1N/A
1N/A=item B<$_>
1N/A
1N/AAlthough C<$_> doesn't actually appear explicitly in the sample filters
1N/Aabove, it is implicitly used in a number of places.
1N/A
1N/AFirstly, when either C<filter> or the anonymous sub are called, a local
1N/Acopy of C<$_> will automatically be created. It will always contain the
1N/Aempty string at this point.
1N/A
1N/ANext, both C<filter_read> and C<filter_read_exact> will append any
1N/Asource data that is read to the end of C<$_>.
1N/A
1N/AFinally, when C<filter> or the anonymous sub are finished processing,
1N/Athey are expected to return the filtered source using C<$_>.
1N/A
1N/AThis implicit use of C<$_> greatly simplifies the filter.
1N/A
1N/A=item B<$status>
1N/A
1N/AThe status value that is returned by the user's C<filter> method or
1N/Aanonymous sub and the C<filter_read> and C<read_exact> functions take
1N/Athe same set of values, namely:
1N/A
1N/A < 0 Error
1N/A = 0 EOF
1N/A > 0 OK
1N/A
1N/A=item B<filter_read> and B<filter_read_exact>
1N/A
1N/AThese functions are used by the filter to obtain either a line or block
1N/Afrom the next filter in the chain or the actual source file if there
1N/Aaren't any other filters.
1N/A
1N/AThe function C<filter_read> takes two forms:
1N/A
1N/A $status = filter_read() ;
1N/A $status = filter_read($size) ;
1N/A
1N/AThe first form is used to request a I<line>, the second requests a
1N/AI<block>.
1N/A
1N/AIn line mode, C<filter_read> will append the next source line to the
1N/Aend of the C<$_> scalar.
1N/A
1N/AIn block mode, C<filter_read> will append a block of data which is <=
1N/AC<$size> to the end of the C<$_> scalar. It is important to emphasise
1N/Athe that C<filter_read> will not necessarily read a block which is
1N/AI<precisely> C<$size> bytes.
1N/A
1N/AIf you need to be able to read a block which has an exact size, you can
1N/Ause the function C<filter_read_exact>. It works identically to
1N/AC<filter_read> in block mode, except it will try to read a block which
1N/Ais exactly C<$size> bytes in length. The only circumstances when it
1N/Awill not return a block which is C<$size> bytes long is on EOF or
1N/Aerror.
1N/A
1N/AIt is I<very> important to check the value of C<$status> after I<every>
1N/Acall to C<filter_read> or C<filter_read_exact>.
1N/A
1N/A=item B<filter_del>
1N/A
1N/AThe function, C<filter_del>, is used to disable the current filter. It
1N/Adoes not affect the running of the filter. All it does is tell Perl not
1N/Ato call filter any more.
1N/A
1N/ASee L<Example 4: Using filter_del> for details.
1N/A
1N/A=back
1N/A
1N/A=head1 EXAMPLES
1N/A
1N/AHere are a few examples which illustrate the key concepts - as such
1N/Amost of them are of little practical use.
1N/A
1N/AThe C<examples> sub-directory has copies of all these filters
1N/Aimplemented both as I<method filters> and as I<closure filters>.
1N/A
1N/A=head2 Example 1: A simple filter.
1N/A
1N/ABelow is a I<method filter> which is hard-wired to replace all
1N/Aoccurrences of the string C<"Joe"> to C<"Jim">. Not particularly
1N/AUseful, but it is the first example and I wanted to keep it simple.
1N/A
1N/A package Joe2Jim ;
1N/A
1N/A use Filter::Util::Call ;
1N/A
1N/A sub import
1N/A {
1N/A my($type) = @_ ;
1N/A
1N/A filter_add(bless []) ;
1N/A }
1N/A
1N/A sub filter
1N/A {
1N/A my($self) = @_ ;
1N/A my($status) ;
1N/A
1N/A s/Joe/Jim/g
1N/A if ($status = filter_read()) > 0 ;
1N/A $status ;
1N/A }
1N/A
1N/A 1 ;
1N/A
1N/AHere is an example of using the filter:
1N/A
1N/A use Joe2Jim ;
1N/A print "Where is Joe?\n" ;
1N/A
1N/AAnd this is what the script above will print:
1N/A
1N/A Where is Jim?
1N/A
1N/A=head2 Example 2: Using the context
1N/A
1N/AThe previous example was not particularly useful. To make it more
1N/Ageneral purpose we will make use of the context data and allow any
1N/Aarbitrary I<from> and I<to> strings to be used. This time we will use a
1N/AI<closure filter>. To reflect its enhanced role, the filter is called
1N/AC<Subst>.
1N/A
1N/A package Subst ;
1N/A
1N/A use Filter::Util::Call ;
1N/A use Carp ;
1N/A
1N/A sub import
1N/A {
1N/A croak("usage: use Subst qw(from to)")
1N/A unless @_ == 3 ;
1N/A my ($self, $from, $to) = @_ ;
1N/A filter_add(
1N/A sub
1N/A {
1N/A my ($status) ;
1N/A s/$from/$to/
1N/A if ($status = filter_read()) > 0 ;
1N/A $status ;
1N/A })
1N/A }
1N/A 1 ;
1N/A
1N/Aand is used like this:
1N/A
1N/A use Subst qw(Joe Jim) ;
1N/A print "Where is Joe?\n" ;
1N/A
1N/A
1N/A=head2 Example 3: Using the context within the filter
1N/A
1N/AHere is a filter which a variation of the C<Joe2Jim> filter. As well as
1N/Asubstituting all occurrences of C<"Joe"> to C<"Jim"> it keeps a count
1N/Aof the number of substitutions made in the context object.
1N/A
1N/AOnce EOF is detected (C<$status> is zero) the filter will insert an
1N/Aextra line into the source stream. When this extra line is executed it
1N/Awill print a count of the number of substitutions actually made.
1N/ANote that C<$status> is set to C<1> in this case.
1N/A
1N/A package Count ;
1N/A
1N/A use Filter::Util::Call ;
1N/A
1N/A sub filter
1N/A {
1N/A my ($self) = @_ ;
1N/A my ($status) ;
1N/A
1N/A if (($status = filter_read()) > 0 ) {
1N/A s/Joe/Jim/g ;
1N/A ++ $$self ;
1N/A }
1N/A elsif ($$self >= 0) { # EOF
1N/A $_ = "print q[Made ${$self} substitutions\n]" ;
1N/A $status = 1 ;
1N/A $$self = -1 ;
1N/A }
1N/A
1N/A $status ;
1N/A }
1N/A
1N/A sub import
1N/A {
1N/A my ($self) = @_ ;
1N/A my ($count) = 0 ;
1N/A filter_add(\$count) ;
1N/A }
1N/A
1N/A 1 ;
1N/A
1N/AHere is a script which uses it:
1N/A
1N/A use Count ;
1N/A print "Hello Joe\n" ;
1N/A print "Where is Joe\n" ;
1N/A
1N/AOutputs:
1N/A
1N/A Hello Jim
1N/A Where is Jim
1N/A Made 2 substitutions
1N/A
1N/A=head2 Example 4: Using filter_del
1N/A
1N/AAnother variation on a theme. This time we will modify the C<Subst>
1N/Afilter to allow a starting and stopping pattern to be specified as well
1N/Aas the I<from> and I<to> patterns. If you know the I<vi> editor, it is
1N/Athe equivalent of this command:
1N/A
1N/A :/start/,/stop/s/from/to/
1N/A
1N/AWhen used as a filter we want to invoke it like this:
1N/A
1N/A use NewSubst qw(start stop from to) ;
1N/A
1N/AHere is the module.
1N/A
1N/A package NewSubst ;
1N/A
1N/A use Filter::Util::Call ;
1N/A use Carp ;
1N/A
1N/A sub import
1N/A {
1N/A my ($self, $start, $stop, $from, $to) = @_ ;
1N/A my ($found) = 0 ;
1N/A croak("usage: use Subst qw(start stop from to)")
1N/A unless @_ == 5 ;
1N/A
1N/A filter_add(
1N/A sub
1N/A {
1N/A my ($status) ;
1N/A
1N/A if (($status = filter_read()) > 0) {
1N/A
1N/A $found = 1
1N/A if $found == 0 and /$start/ ;
1N/A
1N/A if ($found) {
1N/A s/$from/$to/ ;
1N/A filter_del() if /$stop/ ;
1N/A }
1N/A
1N/A }
1N/A $status ;
1N/A } )
1N/A
1N/A }
1N/A
1N/A 1 ;
1N/A
1N/A=head1 Filter::Simple
1N/A
1N/AIf you intend using the Filter::Call functionality, I would strongly
1N/Arecommend that you check out Damian Conway's excellent Filter::Simple
1N/Amodule. Damian's module provides a much cleaner interface than
1N/AFilter::Util::Call. Although it doesn't allow the fine control that
1N/AFilter::Util::Call does, it should be adequate for the majority of
1N/Aapplications. It's available at
1N/A
1N/A http://www.cpan.org/modules/by-author/Damian_Conway/Filter-Simple.tar.gz
1N/A http://www.csse.monash.edu.au/~damian/CPAN/Filter-Simple.tar.gz
1N/A
1N/A=head1 AUTHOR
1N/A
1N/APaul Marquess
1N/A
1N/A=head1 DATE
1N/A
1N/A26th January 1996
1N/A
1N/A=cut
1N/A