This file is indexed.

/usr/share/perl5/PPI/HTML.pm is in libppi-html-perl 1.08-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
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
package PPI::HTML;

=pod

=head1 NAME

PPI::HTML - Generate syntax-hightlighted HTML for Perl using PPI

=head1 SYNOPSIS

  use PPI;
  use PPI::HTML;
  
  # Load your Perl file
  my $Document = PPI::Document->load( 'script.pl' );
  
  # Create a reusable syntax highlighter
  my $Highlight = PPI::HTML->new( line_numbers => 1 );
  
  # Spit out the HTML
  print $Highlight->html( $Document );

=head1 DESCRIPTION

PPI::HTML converts Perl documents into syntax highlighted HTML pages.

=head1 HISTORY

PPI::HTML is the successor to the now-redundant PPI::Format::HTML.

While early on it was thought that the same formatting code might be able
to be used for a variety of different types of things (ANSI and HTML for
example) later developments with the here-doc code and the need for
independantly written serializers meant that this idea had to be discarded.

In addition, the old module only made use of the Tokenizer, and had a
pretty shit API to boot.

=head2 API Overview

The new module is much cleaner. Simply create an object with the options
you want, pass L<PPI::Document> objects to the C<html> method,
and you get strings of HTML that you can do whatever you want with.

=head1 METHODS

=cut

use 5.005;
use strict;
use CSS::Tiny           ();
use PPI::Document       ();
use PPI::HTML::Fragment ();
use Params::Util '_HASH', '_INSTANCE';

use vars qw{$VERSION};
BEGIN {
	$VERSION = '1.08';
}





#####################################################################
# Constructor and Accessors

=pod

=head2 new %args

The C<new> constructor takes a simple set of key/value pairs to define
the formatting options for the HTML.

=over

=item page

Is the C<page> option is enabled, the generator will wrap the generated
HTML fragment in a basic but complete page.

=item line_numbers

At the present time, the only option available. If set to true, line
numbers are added to the output.

=item colors | colours

For cases where you don't want to use an external stylesheet, you
can provide C<colors> as a hash reference where the keys are CSS classes
(generally matching the token name) and the values are colours.

This allows basic colouring without the need for a whole stylesheet.

=item css

The C<css> option lets you provide a custom L<CSS::Tiny> object containing
any CSS you want to apply to the page (if you are using page mode).

If both the C<colors> and C<css> options are used, the colour CSS entries
will overwrite anything contained in the L<CSS::Tiny> object. The object
will also be cloned if it to be modified, to prevent destroying any CSS
objects passed in.

=back

Returns a new L<PPI::HTML> object

=cut

sub new {
	my $class = ref $_[0] ? ref shift : shift;
	my %args  = @_;

	# Create the basic object
	my $self = bless {
		line_numbers => !! $args{line_numbers},
		page         => !! $args{page},
		# colors     => undef,
		# css        => undef,
		}, $class;

	# Manually specify the class colours and custom CSS
	$args{colors}   = delete $args{colours} if $args{colours};
	$self->{colors} = $args{colors}         if _HASH($args{colors});
	$self->{css}    = $args{css}            if _INSTANCE($args{css}, 'CSS::Tiny');

	$self;
}

=pod

=head2 css

The C<css> accessor returns the L<CSS::Tiny> object originally provided
to the constructor.

=cut

sub css { $_[0]->{css} }





#####################################################################
# Main Methods

=pod

=head2 html $Document | $file | \$source

The main method for the class, the C<html> method takes a single
L<PPI::Document> object, or anything that can be turned into a
L<PPI::Document> via its C<new> method, and returns a string of HTML
formatted based on the arguments given to the C<PPI::HTML> constructor.

Returns a string, or C<undef> on error.

=cut

sub html {
	my $self     = shift;
	my $Document = $self->_Document(shift) or return undef;

	# Build the basic set of fragments
	$self->_build_fragments($Document) or return undef;

	# Interleave the line numbers
	$self->_build_line_numbers or return undef;

	# Optimise
	$self->_optimize_fragments or return undef;

	# Merge and stringify the fragments
	$self->_build_html or return undef;

	# Return the final HTML
	delete $self->{html};
}

# Create the basic list of fragments
sub _build_fragments {
	my ($self, $Document) = @_;

	# Convert the list of tokens to a list of fragments
	$self->{fragments}      = [];
	$self->{heredoc_buffer} = undef;
	foreach my $Token ( $Document->tokens ) {
		# Find the Fragments for the token
		my @fragments = ();
		if ( _INSTANCE($Token, 'PPI::Token::HereDoc') ) {
			@fragments = $self->_heredoc_fragments($Token) or return undef;
		} else {
			@fragments = $self->_simple_fragments($Token) or return undef;
		}

		# Add the fragments
		foreach my $Fragment ( @fragments ) {
			$self->_add_fragment( $Fragment ) or return undef;
		}
	}

	# Are there any trailing heredoc lines to add?
	if ( $self->{heredoc_buffer} ) {
		# Unless the last line ends in a newline, add one
		unless ( $self->{fragments}->[-1]->ends_line ) {
			my $Fragment = PPI::HTML::Fragment->new( "\n" ) or return undef;
			push @{$self->{fragments}}, $Fragment;
		}

		# Add the remaining buffer lines
		push @{$self->{fragments}}, @{$self->{heredoc_buffer}};
	}

	# We don't need the heredoc buffer any more
	delete $self->{heredoc_buffer};

	1;
}

sub _simple_fragments {
	my ($self, $Token) = @_;

	# Split the token content into strings
	my @strings = grep { defined $_ and length $_ } split /(?<=\n)/, $Token->content;

	# Convert each string to a fragment
	my @fragments = ();
	my $css_class = $self->_css_class( $Token );
	foreach my $string ( @strings ) {
		my $Fragment = PPI::HTML::Fragment->new( $string, $css_class ) or return ();
		push @fragments, $Fragment;
	}

	@fragments;
}

sub _heredoc_fragments {
	my ($self, $Token) = @_;

	# First, create the heredoc content lines and add them
	# to the buffer
	foreach my $line ( $Token->heredoc ) {
		$self->_add_heredoc( $line,
			'heredoc_content' ) or return ();
	}

	# Add the terminator line
	$self->_add_heredoc( $Token->terminator . "\n",
		'heredoc_terminator' ) or return ();

	# Return a single fragment for the main content part
	my $Fragment = PPI::HTML::Fragment->new( $Token->content,
		$self->_css_class( $Token ) ) or return ();

	$Fragment;
}

sub _build_line_numbers {
	my $self = shift;
	return 1 unless $self->{line_numbers};

	# Find the width of the highest line number, so that
	# we can pad the line numbers
	my $max     = 1 + scalar map { $_->ends_line } @{$self->{fragments}};
	my $width   = length("$max");
	my $pattern = "\%${width}s: ";

	# Iterate over the existing array, and insert new line
	# fragments after each newline.
	my $line = 1;
	my @fragments = map {
		$_->ends_line
			? ($_, $self->_line_fragment( sprintf($pattern, ++$line) ))
			: ($_)
		} @{$self->{fragments}};

	# Add the fragment for line 1 to the beginning
	unshift @fragments, $self->_line_fragment( sprintf($pattern, 1) );

	$self->{fragments} = \@fragments;

	1;
}

sub _build_html {
	my $self = shift;

	# Iterate over the loop, stringifying and merging
	my $html = '';
	foreach my $Fragment ( @{$self->{fragments}} ) {
		$html .= $Fragment->html;
	}

	# Page wrap if needed
	if ( $self->{page} ) {
		my $css = $self->_css_html;

		$html = <<END_HTML;
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN">
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
  <meta name="robots" content="noarchive">
$css
</head>
<body bgcolor="#FFFFFF" text="#000000"><pre>$html</pre></body>
</html>
END_HTML
	}

	# Replace the fragments array with the HTML
	$self->{html} = $html;
	delete $self->{fragments};

	1;
}

sub _optimize_fragments {
	my $self = shift;

	# Iterate through and do the simplest optimisation layer,
	# when is joining identical adjacent fragments.
	my $current = $self->{fragments};
	my @fragments = ( shift @$current );
	foreach my $Fragment ( @$current ) {
		if ( $Fragment->css and $fragments[-1]->css and $Fragment->css eq $fragments[-1]->css ) {
			$fragments[-1]->concat( $Fragment->string );
		} else {
			push @fragments, $Fragment;
		}
	}

	# Remove the class from all whitespace
	foreach my $Fragment ( @fragments ) {
		my $css = $Fragment->css or next;
		$Fragment->clear if $css eq 'whitespace';
	}

	# If we know what classes are coloured, strip the style
	# from everything that doesn't have a colour.
	if ( $self->{colors} ) {
		my $colors = $self->{colors};
		foreach my $Fragment ( @fragments ) {
			my $css = $Fragment->css or next;
			next if $colors->{$css};
			$Fragment->clear;
		}
	}

	# Overwrite the fragments list
	$self->{fragments} = \@fragments;

	1;
}

# For a set of colors, generate the relevant CSS
sub _css_html {
	my $self = shift;

	# Create and fill a CSS object
	my $css = $self->{css}
		? $self->{css}->clone
		: CSS::Tiny->new;
	foreach my $key ( sort keys %{$self->{colors}} ) {
		$css->{".$key"}->{color} = $self->{colors}->{$key};
	}

	keys %$css ? $css->html : '';
}





#####################################################################
# Support Methods

# Create a Document from anything we can
sub _Document {
	my $class = shift;
	_INSTANCE( $_[0], 'PPI::Document' )
		? $_[0]                        # Already a Document
		: PPI::Document->new( @_ ); # Make a Document
}

# Create a Fragment from anything we can
sub _Fragment {
	my $class = shift;
	_INSTANCE( $_[0], 'PPI::HTML::Fragment' )
		? $_[0] 
		: PPI::HTML::Fragment->new( @_ );
}

sub _add_fragment {
	my $self     = shift;
	my $Fragment = $self->_Fragment(@_) or return undef;

	# Add the fragment itself
	push @{$self->{fragments}}, $Fragment;

	# If the fragment ends a line, add
	# anything that is in the heredoc buffer.
	if ( $self->{heredoc_buffer} and $Fragment->ends_line ) {
		push @{$self->{fragments}}, @{$self->{heredoc_buffer}};
		$self->{heredoc_buffer} = undef;
	}

	1;
}

sub _add_heredoc {
	my $self     = shift;
	my $Fragment = $self->_Fragment(@_) or return undef;
	$self->{heredoc_buffer} ||= [];
	push @{$self->{heredoc_buffer}}, $Fragment;
	1;
}

sub _line_fragment {
	my ($self, $line) = @_;
	PPI::HTML::Fragment->new( $line, 'line_number' );
}

sub _css_class {
	my ($self, $Token) = @_;
	if ( $Token->isa('PPI::Token::Word') ) {
		# There are some words we can be very confident are
		# being used as keywords
		my $content = $Token->content;

		unless ( $Token->snext_sibling and $Token->snext_sibling->content eq '=>' ) {
			if ( $content eq 'sub' ) {
				return 'keyword';
			} elsif ( $content eq 'return' ) {
				return 'keyword';
			} elsif ( $content eq 'undef' ) {
				return 'core';
			} elsif ( $content eq 'shift' ) {
				return 'core';
			} elsif ( $content eq 'defined' ) {
				return 'core';
			}
		}

		my $parent = $Token->parent;
		if ( $parent->isa('PPI::Statement::Include') ) {
			if ( $content =~ /^(?:use|no)$/ ) {
				return 'keyword';
			}
			if ( $content eq $parent->pragma ) {
				return 'pragma';
			}
		} elsif ( $parent->isa('PPI::Statement::Variable') ) {
			if ( $content =~ /^(?:my|local|our)$/ ) {
				return 'keyword';
			}
		} elsif ( $parent->isa('PPI::Statement::Compound') ) {
			if ( $content =~ /^(?:if|else|elsif|unless|for|foreach|while|my)$/ ) {
				return 'keyword';
			}
		} elsif ( $parent->isa('PPI::Statement::Given') ) {
			if ( $content eq 'given' ) {
				return 'keyword';
			}
		} elsif ( $parent->isa('PPI::Statement::When') ) {
			if ( $content =~ /^(?:when|default)$/ ) {
				return 'keyword';
			}
		} elsif ( $parent->isa('PPI::Statement::Package') ) {
			if ( $content eq 'package' ) {
				return 'keyword';
			}
		} elsif ( $parent->isa('PPI::Statement::Scheduled') ) {
			return 'keyword';
		}
	}

	# Normal colouring
	my $css = lc ref $Token;
	$css =~ s/^.+:://;
	$css;
}

1;

=pod

=head1 SUPPORT

Bugs should always be submitted via the CPAN bug tracker

L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=PPI-HTML>

For other issues, contact the maintainer

=head1 AUTHOR

Adam Kennedy E<lt>adamk@cpan.orgE<gt>

Funding provided by The Perl Foundation

=head1 SEE ALSO

L<http://ali.as/>, L<PPI>

=head1 COPYRIGHT

Copyright 2005 - 2009 Adam Kennedy.

This program is free software; you can redistribute
it and/or modify it under the same terms as Perl itself.

The full text of the license can be found in the
LICENSE file included with this module.

=cut