const I32 gimme = GIMME_V;
int filter_has_file = 0;
PerlIO *tryrsfp = NULL;
+ SV *filter_cache = NULL;
SV *filter_state = NULL;
SV *filter_sub = NULL;
SV *hook_sv = NULL;
SP -= count - 1;
arg = SP[i++];
+ if (SvROK(arg) && (SvTYPE(SvRV(arg)) <= SVt_PVLV)
+ && !isGV_with_GP(SvRV(arg))) {
+ filter_cache = SvRV(arg);
+ SvREFCNT_inc_void_NN(filter_cache);
+
+ if (i < count) {
+ arg = SP[i++];
+ }
+ }
+
if (SvROK(arg) && SvTYPE(SvRV(arg)) == SVt_PVGV) {
arg = SvRV(arg);
}
filter_state = SP[i];
SvREFCNT_inc_simple_void(filter_state);
}
+ }
- if (!tryrsfp) {
- tryrsfp = PerlIO_open(BIT_BUCKET,
- PERL_SCRIPT_MODE);
- }
+ if (!tryrsfp && (filter_cache || filter_sub)) {
+ tryrsfp = PerlIO_open(BIT_BUCKET,
+ PERL_SCRIPT_MODE);
}
SP--;
}
}
filter_has_file = 0;
+ if (filter_cache) {
+ SvREFCNT_dec(filter_cache);
+ filter_cache = NULL;
+ }
if (filter_state) {
SvREFCNT_dec(filter_state);
filter_state = NULL;
SAVESPTR(PL_compiling.cop_io);
PL_compiling.cop_io = NULL;
- if (filter_sub) {
+ if (filter_sub || filter_cache) {
SV * const datasv = filter_add(S_run_user_filter, NULL);
IoLINES(datasv) = filter_has_file;
IoTOP_GV(datasv) = (GV *)filter_state;
IoBOTTOM_GV(datasv) = (GV *)filter_sub;
+ IoFMT_GV(datasv) = (GV *)filter_cache;
}
/* switch to eval mode */
SV * const filter_state = (SV *)IoTOP_GV(datasv);
SV * const filter_sub = (SV *)IoBOTTOM_GV(datasv);
int status = 0;
- /* Filter API says that the filter appends to the contents of the buffer.
- Usually the buffer is "", so the details don't matter. But if it's not,
- then clearly what it contains is already filtered by this filter, so we
- don't want to pass it in a second time.
- I'm going to use a mortal in case the upstream filter croaks. */
SV *upstream;
STRLEN got_len;
const char *got_p;
const char *prune_from = NULL;
+ bool read_from_cache = FALSE;
/* I was having segfault trouble under Linux 2.2.5 after a
parse error occured. (Had to hack around it with a test
maxlen -= cache_len;
}
SvOK_off(cache);
+ read_from_cache = TRUE;
}
}
+ /* Filter API says that the filter appends to the contents of the buffer.
+ Usually the buffer is "", so the details don't matter. But if it's not,
+ then clearly what it contains is already filtered by this filter, so we
+ don't want to pass it in a second time.
+ I'm going to use a mortal in case the upstream filter croaks. */
upstream = ((SvOK(buf_sv) && sv_len(buf_sv)) || SvGMAGICAL(buf_sv))
? sv_newmortal() : buf_sv;
SvUPGRADE(upstream, SVt_PV);
status = FILTER_READ(idx+1, upstream, 0);
}
- assert(filter_sub);
- if (status >= 0) {
+ if (filter_sub && status >= 0) {
dSP;
int count;
status = 1;
}
- if (upstream != buf_sv) {
+ /* If they are at EOF but buf_sv has something in it, then they may never
+ have touched the SV upstream, so it may be undefined. If we naively
+ concatenate it then we get a warning about use of uninitialised value.
+ */
+ if (upstream != buf_sv && (SvOK(upstream) || SvGMAGICAL(upstream))) {
sv_catsv(buf_sv, upstream);
}
}
filter_del(S_run_user_filter);
}
+ if (status == 0 && read_from_cache) {
+ /* If we read some data from the cache (and by getting here it implies
+ that we emptied the cache) then we aren't yet at EOF, and mustn't
+ report that to our caller. */
+ return 1;
+ }
return status;
}
use strict;
use Filter::Util::Call;
-plan(tests => 128);
+plan(tests => 141);
unshift @INC, sub {
no warnings 'uninitialized';
# Check that the array dereferencing works ready for the more complex tests:
do [\&generator] or die;
-do [sub {
- my $param = $_[1];
- is (ref $param, 'ARRAY', "Got our parameter");
- $_ = shift @$param;
- return defined $_ ? 1 : 0;
- }, ["pass('Can return generators which take state');\n",
- "pass('And return multiple lines');\n",
- ]] or die;
+sub generator_with_state {
+ my $param = $_[1];
+ is (ref $param, 'ARRAY', "Got our parameter");
+ $_ = shift @$param;
+ return defined $_ ? 1 : 0;
+}
+
+do [\&generator_with_state,
+ ["pass('Can return generators which take state');\n",
+ "pass('And return multiple lines');\n",
+ ]] or die;
open $fh, "<", \'fail("File handles and filters work from \@INC");';
EOC
do [$fh, sub {$_ .= $_ . $_; return;}] or die;
+
+do \"pass\n(\n'Scalar references are treated as initial file contents'\n)\n"
+or die;
+
+open $fh, "<", \"ss('The file is concatentated');";
+
+do [\'pa', $fh] or die;
+
+open $fh, "<", \"ff('Gur svygre vf bayl eha ba gur svyr');";
+
+do [\'pa', $fh, sub {tr/A-Za-z/N-ZA-Mn-za-m/; return;}] or die;
+
+open $fh, "<", \"SS('State also works');";
+
+do [\'pa', $fh, sub {s/($_[1])/lc $1/ge; return;}, "S"] or die;
+
+@lines = ('ss', '(', "'you can use a generator'", ')');
+
+do [\'pa', \&generator] or die;
+
+do [\'pa', \&generator_with_state,
+ ["ss('And generators which take state');\n",
+ "pass('And return multiple lines');\n",
+ ]] or die;