This file is indexed.

/usr/share/perl5/String/BufferStack.pm is in libstring-bufferstack-perl 1.15-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
package String::BufferStack;

use strict;
use warnings;
use Carp;

our $VERSION; $VERSION = "1.15";

=head1 NAME

String::BufferStack - Nested buffers for templating systems

=head1 SYNOPSIS

  my $stack = String::BufferStack->new;
  $stack->push( filter => sub {return uc shift} );
  $stack->append("content");
  $stack->flush_output;

=head1 DESCRIPTION

C<String::BufferStack> provides a framework for storing nested
buffers.  By default, all of the buffers flow directly to the output
method, but individual levels of the stack can apply filters, or store
their output in a scalar reference.

=head1 METHODS

=head2 new PARAMHASH

Creates a new buffer stack and returns it.  Possible arguments include:

=over

=item prealoc

Preallocate this many bytes in the output buffer.  This can reduce
reallocations, and thus speed up appends.

=item out_method

The method to call when output trickles down to the bottom-most buffer
and is flushed via L<flush_output>.  The default C<out_method> prints
the content to C<STDOUT>.  This method will always be called with
non-undef, non-zero length content.

=item use_length

Calculate length of each buffer as it is built.  This imposes a
significant runtime cost, so should be avoided if at all possible.
Defaults to off.

=back

=cut

sub new {
    my $class = shift;
    my %args = @_;
    my $output = " "x($args{prealloc} || 0);
    $output = '';
    return bless {
        stack => [],
        top => undef,
        output => \$output,
        out_method => $args{out_method} || sub { print STDOUT @_ },
        pre_appends => {},
        use_length => $args{use_length},
    }, $class;
}

=head2 push PARAMHASH

Pushes a new frame onto the buffer stack.  By default, the output from
this new frame connects to the input of the previous frame.  There are
a number of possible options:

=over

=item buffer

A string reference, into which the output from this stack frame will
appear.  By default, this is the input buffer of the previous frame.

=item private

If a true value is passed for C<private>, it creates a private string
reference, and uses that as the buffer -- this is purely for
convenience.  That is, the following blocks are equivilent:

  my $buffer = "";
  $stack->push( buffer => \$buffer );
  # ...
  $stack->pop;
  print $buffer;

  $stack->push( private => 1 );
  # ...
  print $stack->pop;

=item pre_append

A callback, which will be called with a reference to the
C<String::BufferStack> object, and the arguments to append, whenever
this stack frame has anything appended to the input buffer, directly
or indirectly.

Within the context of the pre-append callback, L</append>,
L</direct_append>, and L</set_pre_append> function on the frame the
pre-append is attached to, not the topmost trame.  Using L</append>
within the pre-append callback is not suggested; use
L</direct_append> instead.  L</set_pre_append> can be used to alter or
remove the pre-append callback itself -- this is not uncommon, in
the case where the first append is the only one which needs be watched
for, for instance.

=item filter

A callback, used to process data which is appended to the stack frame.
By default, filters are lazy, being called only when a frame is
popped.  They can be forced at any time by calling L</flush_filters>,
however.

=back

=cut

sub push {
    my $self = shift;
    my $frame = {
        buffer => $self->{top} ? $self->{top}{pre_filter} : $self->{output},
        @_
    };
    my $filter = "";
    my $buffer = "";
    $frame->{buffer} = \$buffer if delete $frame->{private};
    $frame->{length} = (defined ${$frame->{buffer}}) ? CORE::length(${$frame->{buffer}}) : 0
        if $self->{use_length} or $frame->{use_length};
    $frame->{pre_filter} = $frame->{filter} ? \$filter : $frame->{buffer};
    $self->{top} = $frame;
    local $self->{local_frame} = $frame;
    $self->set_pre_append(delete $frame->{pre_append}) if defined $frame->{pre_append};
    CORE::push(@{$self->{stack}}, $frame);
}

=head2 depth

Returns the current depth of the stack.  This starts at 0, when no
frames have been pushed, and increases by one for each frame pushed.

=cut

sub depth {
    my $self = shift;
    return scalar @{$self->{stack}};
}

=head2 append STRING [, STRING, ...]

Appends the given strings to the input side of the topmost buffer.
This will call all pre-append hooks attached to it, as well.  Note
that if the frame has a filter, the filter will not immediately run,
but will be delayed until the frame is L</pop>'d, or L</flush_filters>
is called.

When called with no frames on the stack, appends the stringins
directly to the L</output_buffer>.

=cut

sub append {
    my $self = shift;
    my $frame = $self->{local_frame} || $self->{top};
    if ($frame) {
        my $ref = $frame->{pre_filter};
        if (exists $self->{pre_appends}{$frame->{buffer}} and not $frame->{filter}) {
            # This is an append to the output buffer, signal all pre_append hooks for it
            for my $frame (@{$self->{pre_appends}{$frame->{buffer}}}) {
                die unless $frame->{pre_append};
                local $self->{local_frame} = $frame;
                $frame->{pre_append}->($self, @_);
            }
        }
        for (@_) {
            $$ref .= $_ if defined;
        }
    } else {
        my $ref = $self->{output};
        for (@_) {
            $$ref .= $_ if defined;
        }
    }
}

=head2 direct_append STRING [, STRING, ...]

Similar to L</append>, but appends the strings to the output side of
the frame, skipping pre-append callbacks and filters.

When called with no frames on the stack, appends the strings
directly to the L</output_buffer>.

=cut

sub direct_append {
    my $self = shift;
    my $frame = $self->{local_frame} || $self->{top};
    my $ref = $frame ? $frame->{buffer} : $self->{output};
    for (@_) {
        $$ref .= $_ if defined;
    }
}

=head2 pop

Removes the topmost frame on the stack, flushing the topmost filters
in the process.  Returns the output buffer of the frame -- note that
this may not contain only strings appended in the current frame, but
also those from before, as a speed optimization.  That is:

   $stack->append("one");
   $stack->push;
   $stack->append(" two");
   $stack->pop;   # returns "one two"

This operation is a no-op if there are no frames on the stack.

=cut

sub pop {
    my $self = shift;
    return unless $self->{top};
    $self->filter;
    my $frame = CORE::pop(@{$self->{stack}});
    local $self->{local_frame} = $frame;
    $self->set_pre_append(undef);
    $self->{top} = @{$self->{stack}} ? $self->{stack}[-1] : undef;
    return ${$frame->{buffer}};
}

=head2 set_pre_append CALLBACK

Alters the pre-append callback on the topmost frame.  The callback
will be called before text is appended to the input buffer of the
frame, and will be passed the C<String::BufferStack> and the arguments
to L</append>.

=cut

sub set_pre_append {
    my $self = shift;
    my $hook = shift;
    my $frame = $self->{local_frame} || $self->{top};
    return unless $frame;
    if ($hook and not $frame->{pre_append}) {
        CORE::push(@{$self->{pre_appends}{$frame->{buffer}}}, $frame);
    } elsif (not $hook and $frame->{pre_append}) {
        $self->{pre_appends}{ $frame->{buffer} }
            = [ grep { $_ ne $frame } @{ $self->{pre_appends}{ $frame->{buffer} } } ];
        delete $self->{pre_appends}{ $frame->{buffer} }
            unless @{ $self->{pre_appends}{ $frame->{buffer} } };
    }
    $frame->{pre_append} = $hook;
}

=head2 set_filter FILTER

Alters the filter on the topmost frame.  Doing this flushes the
filters on the topmost frame.

=cut

sub set_filter {
    my $self = shift;
    my $filter = shift;
    return unless $self->{top};
    $self->filter;
    if (defined $self->{top}{filter} and not defined $filter) {
        # Removing a filter, flush, then in = out
        $self->{top}{pre_filter} = $self->{top}{buffer};
    } elsif (not defined $self->{top}{filter} and defined $filter) {
        # Adding a filter, add a pre_filter stage
        my $pre_filter = "";
        $self->{top}{pre_filter} = \$pre_filter;
    }
    $self->{top}{filter} = $filter;
}

=head2 filter

Filters the topmost stack frame, if it has outstanding unfiltered
data.  This will propagate content to lower frames, possibly calling
their pre-append hooks.

=cut

sub filter {
    my $self = shift;
    my $frame = shift || $self->{top};
    return unless $frame and $frame->{filter} and CORE::length(${$frame->{pre_filter}});

    # We remove the input before we shell out to the filter, so we
    # don't get into infinite loops.
    my $input = ${$frame->{pre_filter}};
    ${$frame->{pre_filter}} = '';
    my $output = $frame->{filter}->($input);
    if (exists $self->{pre_appends}{$frame->{buffer}}) {
        for my $frame (@{$self->{pre_appends}{$frame->{buffer}}}) {
            local $self->{local_frame} = $frame;
            $frame->{pre_append}->($self, $output);
        }
    }
    ${$frame->{buffer}} .= $output;
}

=head2 flush

If there are no frames on the stack, calls L</flush_output>.
Otherwise, calls L</flush_filters>.

=cut

sub flush {
    my $self = shift;
    # Flushing with no stack flushes the output
    return $self->flush_output unless $self->depth;
    # Otherwise it just flushes the filters
    $self->flush_filters;
}

=head2 flush_filters

Flushes all filters.  This does not flush output from the output
buffer; see L</flush_output>.

=cut

sub flush_filters {
    my $self = shift;
    # Push content through filters -- reverse so the top one is first
    for my $frame (reverse @{$self->{stack}}) {
        $self->filter($frame);
    }
}

=head2 buffer

Returns the contents of the output buffer of the topmost frame; if
there are no frames, returns the output buffer.

=cut

sub buffer {
    my $self = shift;
    return $self->{top} ? ${$self->{top}{buffer}} : ${$self->{output}};
}

=head2 buffer_ref

Returns a reference to the output buffer of the topmost frame; if
there are no frames, returns a reference to the output buffer.  Note
that adjusting this skips pre-append and filter hooks.

=cut

sub buffer_ref {
    my $self = shift;
    return $self->{top} ? $self->{top}{buffer} : $self->{output};
}

=head2 length

If C<use_length> was enabled in the buffer stack's constructor,
returns the number of characters appended to the current frame; if
there are no frames, returns the length of the output buffer.

If C<use_length> was not enabled, warns and returns 0.

=cut

sub length {
    my $self = shift;
    carp("String::BufferStack object didn't enable use_length") and return 0
        unless $self->{use_length} or ($self->{top} and $self->{top}{use_length});
    return $self->{top} ? CORE::length(${$self->{top}{buffer}}) - $self->{top}{length} : CORE::length(${$self->{output}});
}


=head2 flush_output

Flushes all filters using L</flush_filters>, then flushes output from
the output buffer, using the configured L</out_method>.

=cut

sub flush_output {
    my $self = shift;
    $self->flush_filters;

    # Look at what we have at the end
    return unless CORE::length(${$self->{output}});
    $self->{out_method}->(${$self->{output}});
    ${$self->{output}} = "";
    return "";
}

=head2 output_buffer

Returns the pending output buffer, which sits below all existing
frames.

=cut

sub output_buffer {
    my $self = shift;
    return ${$self->{output}};
}

=head2 output_buffer_ref

Returns a reference to the pending output buffer, allowing you to
modify it.

=cut

sub output_buffer_ref {
    my $self = shift;
    return $self->{output};
}

=head2 clear

Clears I<all> buffers in the stack, including the output buffer.

=cut

sub clear {
    my $self = shift;
    ${$self->{output}} = "";
    ${$_->{pre_filter}} = ${$_->{buffer}} = "" for @{$self->{stack}};
    return "";
}

=head2 clear_top

Clears the topmost buffer in the stack; if there are no frames on the
stack, clears the output buffer.

=cut

sub clear_top {
    my $self = shift;
    if ($self->{top}) {
        ${$self->{top}{pre_filter}} = ${$self->{top}{buffer}} = "";
    } else {
        ${$self->{output}} = "";
    }
    return "";
}

=head2 out_method [CALLBACK]

Gets or sets the output method callback, which is given content from
the pending output buffer, which sits below all frames.

=cut

sub out_method {
    my $self = shift;
    $self->{out_method} = shift if @_;
    return $self->{out_method};
}

=head1 SEE ALSO

Many concepts were originally taken from L<HTML::Mason>'s internal
buffer stack.

=head1 AUTHORS

Alex Vandiver C<< alexmv@bestpractical.com >>

=head1 LICENSE

Copyright 2008-2009, Best Practical Solutions.

This package is distributed under the same terms as Perl itself.

=cut


1;