File Coverage

blib/lib/Perl/Tidy/HtmlWriter.pm
Criterion Covered Total %
statement 417 863 48.3
branch 71 350 20.2
condition 11 75 14.6
subroutine 36 49 73.4
pod 0 24 0.0
total 535 1361 39.3


line stmt bran cond sub pod time code
1             #####################################################################
2             #
3             # The Perl::Tidy::HtmlWriter class writes a copy of the input stream in html
4             #
5             #####################################################################
6              
7             package Perl::Tidy::HtmlWriter;
8 44     44   266 use strict;
  44         77  
  44         1552  
9 44     44   185 use warnings;
  44         68  
  44         3268  
10             our $VERSION = '20260204';
11              
12 44     44   219 use Carp;
  44         73  
  44         3309  
13 44     44   193 use English qw( -no_match_vars );
  44         68  
  44         287  
14 44     44   13634 use File::Basename;
  44         79  
  44         3357  
15 44     44   19648 use Encode ();
  44         603039  
  44         1757  
16              
17 44     44   292 use constant EMPTY_STRING => q{};
  44         68  
  44         5073  
18 44     44   1170 use constant SPACE => q{ };
  44         281  
  44         5749  
19              
20             { #<<< A non-indenting brace to contain all lexical variables
21              
22             # List of hash keys to prevent -duk from listing them.
23             my @unique_hash_keys_uu = qw(use-pod-formatter);
24              
25             # class variables
26             my (
27              
28             # INITIALIZER: BEGIN block
29             $missing_html_entities,
30              
31             # INITIALIZER: sub load_pod_formatter
32             $loaded_pod_formatter,
33              
34             # INITIALIZER: BEGIN block
35             %short_to_long_names,
36             %token_short_names,
37              
38             # INITIALIZER: sub check_options
39             $rOpts,
40             $rOpts_html_entities,
41             $css_linkname,
42             %html_bold,
43             %html_color,
44             %html_italic,
45             $log_message,
46              
47             );
48              
49             # replace unsafe characters with HTML entity representation if HTML::Entities
50             # is available
51             #{ eval "use HTML::Entities"; $missing_html_entities = $@; }
52              
53             BEGIN {
54              
55 44     44   135 $missing_html_entities = EMPTY_STRING;
56 44 50       159 if ( !eval { require HTML::Entities; 1 } ) {
  44         19645  
  44         258354  
57 0 0       0 $missing_html_entities = $EVAL_ERROR ? $EVAL_ERROR : 1;
58             }
59              
60             } ## end BEGIN
61              
62             sub AUTOLOAD {
63              
64             # Catch any undefined sub calls so that we are sure to get
65             # some diagnostic information. This sub should never be called
66             # except for a programming error.
67 0     0   0 our $AUTOLOAD;
68 0 0       0 return if ( $AUTOLOAD =~ /\bDESTROY$/ );
69 0         0 my ( $pkg, $fname, $lno ) = caller();
70 0         0 my $my_package = __PACKAGE__;
71 0         0 print {*STDERR} <<EOM;
  0         0  
72             ======================================================================
73             Error detected in package '$my_package', version $VERSION
74             Received unexpected AUTOLOAD call for sub '$AUTOLOAD'
75             Called from package: '$pkg'
76             Called from File '$fname' at line '$lno'
77             This error is probably due to a recent programming change
78             ======================================================================
79             EOM
80 0         0 exit 1;
81             } ## end sub AUTOLOAD
82              
83       0     sub DESTROY {
84              
85             # required to avoid call to AUTOLOAD in some versions of perl
86             }
87              
88             sub new {
89              
90 1     1 0 5 my ( $class, @arglist ) = @_;
91 1 50       3 if ( @arglist % 2 ) { croak "Odd number of items in arg hash list\n" }
  0         0  
92              
93 1         9 my %defaults = (
94             input_file => undef,
95             html_file => undef,
96             extension => undef,
97             html_toc_extension => undef,
98             html_src_extension => undef,
99             is_encoded_data => undef,
100             is_pure_ascii_data => undef,
101             logger_object => undef,
102             );
103 1         6 my %args = ( %defaults, @arglist );
104              
105 1         2 my $input_file = $args{input_file};
106 1         2 my $html_file = $args{html_file};
107 1         2 my $extension = $args{extension};
108 1         15 my $html_toc_extension = $args{html_toc_extension};
109 1         3 my $html_src_extension = $args{html_src_extension};
110 1         3 my $is_encoded_data = $args{is_encoded_data};
111 1         2 my $is_pure_ascii_data = $args{is_pure_ascii_data};
112 1         2 my $logger_object = $args{logger_object};
113              
114 1         5 my $html_fh = Perl::Tidy::streamhandle( $html_file, 'w' );
115 1 50       3 if ( !$html_fh ) {
116 0         0 Perl::Tidy::Warn("can't open html file '$html_file'\n");
117 0         0 return;
118             }
119 1         2 my $html_file_opened = 1;
120              
121 1 50 33     8 if ( !$input_file || $input_file eq '-' || ref($input_file) ) {
      33        
122 0         0 $input_file = "NONAME";
123             }
124              
125             # write the table of contents to a string
126 1         2 my $toc_string;
127 1         3 my $html_toc_fh = Perl::Tidy::IOScalar->new( \$toc_string, 'w' );
128              
129 1         2 my $html_pre_fh;
130             my @pre_string_stack;
131 1 50       11 if ( $rOpts->{'html-pre-only'} ) {
132              
133             # pre section goes directly to the output stream
134 0         0 $html_pre_fh = $html_fh;
135 0         0 $html_pre_fh->print(<<"PRE_END");
136             <pre>
137             PRE_END
138             }
139             else {
140              
141             # pre section go out to a temporary string
142 1         2 my $pre_string;
143 1         3 $html_pre_fh = Perl::Tidy::IOScalar->new( \$pre_string, 'w' );
144 1         2 push @pre_string_stack, \$pre_string;
145             }
146              
147             # Output any log message created by sub check_options
148 1 50 33     5 if ( $log_message && $logger_object ) {
149 1         4 $logger_object->write_logfile_entry($log_message);
150 1         2 $log_message = EMPTY_STRING;
151             }
152              
153             # pod text gets diverted if the 'pod2html' is used and possible
154 1         2 my $pod_string;
155             my $html_pod_fh;
156 1 50       5 if ( $rOpts->{'pod2html'} ) {
157 1         4 $html_pod_fh = Perl::Tidy::IOScalar->new( \$pod_string, 'w' );
158             }
159              
160 1         3 my $toc_filename;
161             my $src_filename;
162 1 50       9 if ( $rOpts->{'frames'} ) {
163 0 0       0 if ( !$extension ) {
164 0         0 Perl::Tidy::Warn(
165             "cannot use frames without a specified output extension; ignoring -frm\n"
166             );
167 0         0 undef $rOpts->{'frames'};
168             }
169             else {
170 0         0 $toc_filename = $input_file . $html_toc_extension . $extension;
171 0         0 $src_filename = $input_file . $html_src_extension . $extension;
172             }
173             }
174              
175             # ----------------------------------------------------------
176             # Output is now directed as follows:
177             # html_toc_fh <-- table of contents items
178             # html_pre_fh <-- the <pre> section of formatted code, except:
179             # html_pod_fh <-- pod goes here with the pod2html option
180             # ----------------------------------------------------------
181              
182 1         2 my $title = $rOpts->{'title'};
183 1 50       3 if ( !$title ) {
184 1         32 ( $title, my $path_uu ) = fileparse($input_file);
185             }
186 1         3 my $toc_item_count = 0;
187 1         3 my $in_toc_package = EMPTY_STRING;
188 1         1 my $last_level = 0;
189 1         24 return bless {
190             _input_file => $input_file, # name of input file
191             _title => $title, # title, unescaped
192             _html_file => $html_file, # name of .html output file
193             _toc_filename => $toc_filename, # for frames option
194             _src_filename => $src_filename, # for frames option
195             _html_file_opened => $html_file_opened, # a flag
196             _html_fh => $html_fh, # the output stream
197             _html_pre_fh => $html_pre_fh, # pre section goes here
198             _rpre_string_stack => \@pre_string_stack, # stack of pre sections
199             _html_pod_fh => $html_pod_fh, # pod goes here if pod2html
200             _rpod_string => \$pod_string, # string holding pod
201             _pod_cut_count => 0, # how many =cut's?
202             _html_toc_fh => $html_toc_fh, # fh for table of contents
203             _rtoc_string => \$toc_string, # string holding toc
204             _rtoc_item_count => \$toc_item_count, # how many toc items
205             _rin_toc_package => \$in_toc_package, # package name
206             _rtoc_name_count => {}, # hash to track unique names
207             _rpackage_stack => [], # stack to check for package
208             # name changes
209             _rlast_level => \$last_level, # brace indentation level
210              
211             _is_encoded_data => $is_encoded_data, # true for utf-8 source
212             _is_pure_ascii_data => $is_pure_ascii_data,
213             }, $class;
214             } ## end sub new
215              
216             sub add_toc_item {
217              
218             # Add an item to the html table of contents.
219             # This is called even if no table of contents is written,
220             # because we still want to put the anchors in the <pre> text.
221             # We are given an anchor name and its type; types are:
222             # 'package', 'sub', '__END__', '__DATA__', 'EOF'
223             # There must be an 'EOF' call at the end to wrap things up.
224 1     1 0 3 my ( $self, $name, $type ) = @_;
225 1         1 my $html_toc_fh = $self->{_html_toc_fh};
226 1         2 my $html_pre_fh = $self->{_html_pre_fh};
227 1         2 my $rtoc_name_count = $self->{_rtoc_name_count};
228 1         3 my $rtoc_item_count = $self->{_rtoc_item_count};
229 1         1 my $rlast_level = $self->{_rlast_level};
230 1         19 my $rin_toc_package = $self->{_rin_toc_package};
231 1         3 my $rpackage_stack = $self->{_rpackage_stack};
232              
233             # packages contain sublists of subs, so to avoid errors all package
234             # items are written and finished with the following routines
235             my $end_package_list = sub {
236 0 0   0   0 if ( ${$rin_toc_package} ) {
  0         0  
237 0         0 $html_toc_fh->print("</ul>\n</li>\n");
238 0         0 ${$rin_toc_package} = EMPTY_STRING;
  0         0  
239             }
240 0         0 return;
241 1         3 }; ## end $end_package_list = sub
242              
243             my $start_package_list = sub {
244 0     0   0 my ( $unique_name, $package ) = @_;
245 0 0       0 if ( ${$rin_toc_package} ) { $end_package_list->() }
  0         0  
  0         0  
246 0         0 $html_toc_fh->print(<<EOM);
247             <li><a href=\"#$unique_name\">package $package</a>
248             <ul>
249             EOM
250 0         0 ${$rin_toc_package} = $package;
  0         0  
251 0         0 return;
252 1         4 }; ## end $start_package_list = sub
253              
254             # start the table of contents on the first item
255 1 50       1 if ( !${$rtoc_item_count} ) {
  1         3  
256              
257             # but just quit if we hit EOF without any other entries
258             # in this case, there will be no toc
259 1 50       10 return if ( $type eq 'EOF' );
260 0         0 $html_toc_fh->print(<<"TOC_END");
261             <!-- BEGIN CODE INDEX --><a name="code-index"></a>
262             <ul>
263             TOC_END
264             }
265 0         0 ${$rtoc_item_count}++;
  0         0  
266              
267             # make a unique anchor name for this location:
268             # - packages get a 'package-' prefix
269             # - subs use their names
270 0         0 my $unique_name = $name;
271 0 0       0 if ( $type eq 'package' ) { $unique_name = "package-$name" }
  0         0  
272              
273             # append '-1', '-2', etc if necessary to make unique; this will
274             # be unique because subs and packages cannot have a '-'
275 0 0       0 if ( my $count = $rtoc_name_count->{ lc($unique_name) }++ ) {
276 0         0 $unique_name .= "-$count";
277             }
278              
279             # - all names get terminal '-' if pod2html is used, to avoid
280             # conflicts with anchor names created by pod2html
281 0 0       0 if ( $rOpts->{'pod2html'} ) { $unique_name .= '-' }
  0         0  
282              
283             # start/stop lists of subs
284 0 0       0 if ( $type eq 'sub' ) {
285 0         0 my $package = $rpackage_stack->[ ${$rlast_level} ];
  0         0  
286 0 0       0 if ( !$package ) { $package = 'main' }
  0         0  
287              
288             # if we're already in a package/sub list, be sure its the right
289             # package or else close it
290 0 0 0     0 if ( ${$rin_toc_package} && ${$rin_toc_package} ne $package ) {
  0         0  
  0         0  
291 0         0 $end_package_list->();
292             }
293              
294             # start a package/sub list if necessary
295 0 0       0 if ( !${$rin_toc_package} ) {
  0         0  
296 0         0 $start_package_list->( $unique_name, $package );
297             }
298             }
299              
300             # now write an entry in the toc for this item
301 0 0       0 if ( $type eq 'package' ) {
    0          
302 0         0 $start_package_list->( $unique_name, $name );
303             }
304             elsif ( $type eq 'sub' ) {
305 0         0 $html_toc_fh->print("<li><a href=\"#$unique_name\">$name</a></li>\n");
306             }
307             else {
308 0         0 $end_package_list->();
309 0         0 $html_toc_fh->print("<li><a href=\"#$unique_name\">$name</a></li>\n");
310             }
311              
312             # write the anchor in the <pre> section
313 0         0 $html_pre_fh->print("<a name=\"$unique_name\"></a>");
314              
315             # end the table of contents, if any, on the end of file
316 0 0       0 if ( $type eq 'EOF' ) {
317 0         0 $html_toc_fh->print(<<"TOC_END");
318             </ul>
319             <!-- END CODE INDEX -->
320             TOC_END
321             }
322 0         0 return;
323             } ## end sub add_toc_item
324              
325             BEGIN {
326              
327             # This is the official list of tokens which may be identified by the
328             # user. Long names are used as getopt keys. Short names are
329             # convenient short abbreviations for specifying input. Short names
330             # somewhat resemble token type characters, but are often different
331             # because they may only be alphanumeric, to allow command line
332             # input. Also, note that because of case insensitivity of html,
333             # this table must be in a single case only (I've chosen to use all
334             # lower case).
335             # When adding NEW_TOKENS: update this hash table
336             # short names => long names
337 44     44   485 %short_to_long_names = (
338             'n' => 'numeric',
339             'p' => 'paren',
340             'q' => 'quote',
341             's' => 'structure',
342             'c' => 'comment',
343             'v' => 'v-string',
344             'cm' => 'comma',
345             'w' => 'bareword',
346             'co' => 'colon',
347             'pu' => 'punctuation',
348             'i' => 'identifier',
349             'j' => 'label',
350             'h' => 'here-doc-target',
351             'hh' => 'here-doc-text',
352             'k' => 'keyword',
353             'sc' => 'semicolon',
354             'm' => 'subroutine',
355             'pd' => 'pod-text',
356             );
357              
358             # Now we have to map actual token types into one of the above short
359             # names; any token types not mapped will get 'punctuation'
360             # properties.
361              
362             # The values of this hash table correspond to the keys of the
363             # previous hash table.
364             # The keys of this hash table are token types and can be seen
365             # by running with --dump-token-types (-dtt).
366              
367             # When adding NEW_TOKENS: update this hash table
368             # $type => $short_name
369             # c250: changed 'M' to 'S'
370 44         455 %token_short_names = (
371             '#' => 'c',
372             'n' => 'n',
373             'v' => 'v',
374             'k' => 'k',
375             'F' => 'k',
376             'Q' => 'q',
377             'q' => 'q',
378             'J' => 'j',
379             'j' => 'j',
380             'h' => 'h',
381             'H' => 'hh',
382             'w' => 'w',
383             ',' => 'cm',
384             '=>' => 'cm',
385             ';' => 'sc',
386             ':' => 'co',
387             'f' => 'sc',
388             '(' => 'p',
389             ')' => 'p',
390             'S' => 'm',
391             'pd' => 'pd',
392             'A' => 'co',
393             );
394              
395             # These token types will all be called identifiers for now
396             # Fix for c250: added new type 'P', formerly 'i'
397             # ( but package statements will eventually be split into 'k' and 'i')
398 44         143 my @identifier = qw< i t U C Y Z G P :: CORE::>;
399 44         368 $token_short_names{$_} = 'i' for @identifier;
400              
401             # These token types will be called 'structure'
402 44         101 my @structure = qw< { } >;
403 44         23636 $token_short_names{$_} = 's' for @structure;
404              
405             # OLD NOTES: save for reference
406             # Any of these could be added later if it would be useful.
407             # For now, they will by default become punctuation
408             # my @list = qw< L R [ ] >;
409             # @token_long_names{@list} = ('non-structure') x scalar(@list);
410             #
411             # my @list = qw"
412             # / /= * *= ** **= + += - -= % %= = ++ -- << <<= >> >>= pp p m mm
413             # ";
414             # @token_long_names{@list} = ('math') x scalar(@list);
415             #
416             # my @list = qw" & &= ~ ~= ^ ^= | |= ";
417             # @token_long_names{@list} = ('bit') x scalar(@list);
418             #
419             # my @list = qw" == != < > <= <=> ";
420             # @token_long_names{@list} = ('numerical-comparison') x scalar(@list);
421             #
422             # my @list = qw" && || ! &&= ||= //= ";
423             # @token_long_names{@list} = ('logical') x scalar(@list);
424             #
425             # my @list = qw" . .= =~ !~ x x= ";
426             # @token_long_names{@list} = ('string-operators') x scalar(@list);
427             #
428             # # Incomplete..
429             # my @list = qw" .. -> <> ... \ ? ";
430             # @token_long_names{@list} = ('misc-operators') x scalar(@list);
431              
432             } ## end BEGIN
433              
434             sub make_getopt_long_names {
435 645     645 0 1729 my ( $class, $rgetopt_names ) = @_;
436 645         5722 foreach my $short_name ( keys %short_to_long_names ) {
437 11610         15380 my $long_name = $short_to_long_names{$short_name};
438 11610         11177 push @{$rgetopt_names}, "html-color-$long_name=s";
  11610         16680  
439 11610         12106 push @{$rgetopt_names}, "html-italic-$long_name!";
  11610         16793  
440 11610         11748 push @{$rgetopt_names}, "html-bold-$long_name!";
  11610         18306  
441             }
442 645         1776 push @{$rgetopt_names}, "html-color-background=s";
  645         1346  
443 645         1054 push @{$rgetopt_names}, "html-linked-style-sheet=s";
  645         1159  
444 645         988 push @{$rgetopt_names}, "nohtml-style-sheets";
  645         1129  
445 645         878 push @{$rgetopt_names}, "html-pre-only";
  645         1113  
446 645         971 push @{$rgetopt_names}, "html-line-numbers";
  645         1123  
447 645         974 push @{$rgetopt_names}, "html-entities!";
  645         1183  
448 645         997 push @{$rgetopt_names}, "stylesheet";
  645         1158  
449 645         853 push @{$rgetopt_names}, "html-table-of-contents!";
  645         1150  
450 645         928 push @{$rgetopt_names}, "pod2html!";
  645         1151  
451 645         1008 push @{$rgetopt_names}, "frames!";
  645         1079  
452 645         958 push @{$rgetopt_names}, "html-toc-extension=s";
  645         1173  
453 645         897 push @{$rgetopt_names}, "html-src-extension=s";
  645         1192  
454              
455             # Pod::Html parameters:
456 645         929 push @{$rgetopt_names}, "cachedir=s";
  645         1134  
457 645         881 push @{$rgetopt_names}, "htmlroot=s";
  645         1051  
458 645         964 push @{$rgetopt_names}, "libpods=s";
  645         1072  
459 645         964 push @{$rgetopt_names}, "podpath=s";
  645         1214  
460 645         942 push @{$rgetopt_names}, "podroot=s";
  645         1202  
461 645         922 push @{$rgetopt_names}, "title=s";
  645         1132  
462              
463             # Pod::Html parameters with leading 'pod' which will be removed
464             # before the call to Pod::Html
465 645         933 push @{$rgetopt_names}, "podbacklink!";
  645         1193  
466 645         1016 push @{$rgetopt_names}, "podquiet!";
  645         1183  
467 645         1075 push @{$rgetopt_names}, "podverbose!";
  645         1168  
468 645         960 push @{$rgetopt_names}, "podrecurse!";
  645         1118  
469 645         926 push @{$rgetopt_names}, "podflush";
  645         1063  
470 645         920 push @{$rgetopt_names}, "podheader!";
  645         1107  
471 645         1030 push @{$rgetopt_names}, "podindex!";
  645         1107  
472 645         1811 return;
473             } ## end sub make_getopt_long_names
474              
475             sub make_abbreviated_names {
476              
477             # We're appending things like this to the expansion list:
478             # 'hcc' => [qw(html-color-comment)],
479             # 'hck' => [qw(html-color-keyword)],
480             # etc
481 645     645 0 2194 my ( $class, $rexpansion ) = @_;
482              
483             # abbreviations for color/bold/italic properties
484 645         3624 foreach my $short_name ( keys %short_to_long_names ) {
485 11610         14289 my $long_name = $short_to_long_names{$short_name};
486 11610         17273 ${$rexpansion}{"hc$short_name"} = ["html-color-$long_name"];
  11610         18483  
487 11610         17411 ${$rexpansion}{"hb$short_name"} = ["html-bold-$long_name"];
  11610         18017  
488 11610         16815 ${$rexpansion}{"hi$short_name"} = ["html-italic-$long_name"];
  11610         17766  
489 11610         16771 ${$rexpansion}{"nhb$short_name"} = ["nohtml-bold-$long_name"];
  11610         17529  
490 11610         16896 ${$rexpansion}{"nhi$short_name"} = ["nohtml-italic-$long_name"];
  11610         20569  
491             }
492              
493             # abbreviations for all other html options
494 645         2130 ${$rexpansion}{"hcbg"} = ["html-color-background"];
  645         1574  
495 645         1395 ${$rexpansion}{"pre"} = ["html-pre-only"];
  645         1411  
496 645         1249 ${$rexpansion}{"toc"} = ["html-table-of-contents"];
  645         1314  
497 645         1283 ${$rexpansion}{"ntoc"} = ["nohtml-table-of-contents"];
  645         1401  
498 645         1260 ${$rexpansion}{"nnn"} = ["html-line-numbers"];
  645         1387  
499 645         1332 ${$rexpansion}{"hent"} = ["html-entities"];
  645         1420  
500 645         1278 ${$rexpansion}{"nhent"} = ["nohtml-entities"];
  645         1517  
501 645         1251 ${$rexpansion}{"css"} = ["html-linked-style-sheet"];
  645         1275  
502 645         1237 ${$rexpansion}{"nss"} = ["nohtml-style-sheets"];
  645         1264  
503 645         1309 ${$rexpansion}{"ss"} = ["stylesheet"];
  645         1431  
504 645         1469 ${$rexpansion}{"pod"} = ["pod2html"];
  645         1514  
505 645         1402 ${$rexpansion}{"npod"} = ["nopod2html"];
  645         1345  
506 645         1309 ${$rexpansion}{"frm"} = ["frames"];
  645         1330  
507 645         1194 ${$rexpansion}{"nfrm"} = ["noframes"];
  645         1203  
508 645         1223 ${$rexpansion}{"text"} = ["html-toc-extension"];
  645         16339  
509 645         1548 ${$rexpansion}{"sext"} = ["html-src-extension"];
  645         12752  
510 645         2513 return;
511             } ## end sub make_abbreviated_names
512              
513             sub check_options {
514              
515             # This will be called once after options have been parsed
516             # Note that we are defining the package variable $rOpts here:
517 1     1 0 4 ( my $class, $rOpts ) = @_;
518              
519             # X11 color names for default settings that seemed to look ok
520             # (these color names are only used for programming clarity; the hex
521             # numbers are actually written)
522             ## use constant SaddleBrown => "#8B4513";
523 44     44   337 use constant ForestGreen => "#228B22";
  44         83  
  44         3632  
524 44     44   270 use constant magenta4 => "#8B008B";
  44         66  
  44         1870  
525 44     44   183 use constant IndianRed3 => "#CD5555";
  44         63  
  44         1503  
526 44     44   171 use constant DeepSkyBlue4 => "#00688B";
  44         65  
  44         1630  
527 44     44   178 use constant MediumOrchid3 => "#B452CD";
  44         65  
  44         1492  
528 44     44   170 use constant black => "#000000";
  44         91  
  44         1685  
529 44     44   172 use constant white => "#FFFFFF";
  44         86  
  44         1321  
530 44     44   140 use constant red => "#FF0000";
  44         65  
  44         117787  
531              
532             # set default color, bold, italic properties
533             # anything not listed here will be given the default (punctuation) color --
534             # these types currently not listed and get default: ws pu s sc cm co p
535             # When adding NEW_TOKENS: add an entry here if you don't want defaults
536              
537             # set_default_properties( $short_name, default_color, bold?, italic? );
538 1         39 set_default_properties( 'c', ForestGreen, 0, 0 );
539 1         2 set_default_properties( 'pd', ForestGreen, 0, 1 );
540 1         2 set_default_properties( 'k', magenta4, 1, 0 ); # was SaddleBrown
541 1         3 set_default_properties( 'q', IndianRed3, 0, 0 );
542 1         3 set_default_properties( 'hh', IndianRed3, 0, 1 );
543 1         3 set_default_properties( 'h', IndianRed3, 1, 0 );
544 1         3 set_default_properties( 'i', DeepSkyBlue4, 0, 0 );
545 1         3 set_default_properties( 'w', black, 0, 0 );
546 1         4 set_default_properties( 'n', MediumOrchid3, 0, 0 );
547 1         4 set_default_properties( 'v', MediumOrchid3, 0, 0 );
548 1         3 set_default_properties( 'j', IndianRed3, 1, 0 );
549 1         2 set_default_properties( 'm', red, 1, 0 );
550              
551 1         3 set_default_color( 'html-color-background', white );
552 1         2 set_default_color( 'html-color-punctuation', black );
553              
554             # setup property lookup tables for tokens based on their short names
555             # every token type has a short name, and will use these tables
556             # to do the html markup
557 1         5 foreach my $short_name ( keys %short_to_long_names ) {
558 18         18 my $long_name = $short_to_long_names{$short_name};
559 18         26 $html_color{$short_name} = $rOpts->{"html-color-$long_name"};
560 18         22 $html_bold{$short_name} = $rOpts->{"html-bold-$long_name"};
561 18         30 $html_italic{$short_name} = $rOpts->{"html-italic-$long_name"};
562             }
563              
564             # write style sheet to STDOUT and die if requested
565 1 50       4 if ( defined( $rOpts->{'stylesheet'} ) ) {
566 0         0 write_style_sheet_file('-');
567 0         0 Perl::Tidy::Exit(0);
568             }
569              
570             # make sure user gives a file name after -css
571 1         3 $css_linkname = EMPTY_STRING;
572 1 50       4 if ( defined( $rOpts->{'html-linked-style-sheet'} ) ) {
573 0         0 $css_linkname = $rOpts->{'html-linked-style-sheet'};
574 0 0       0 if ( $css_linkname =~ /^-/ ) {
575 0         0 Perl::Tidy::Die("You must specify a valid filename after -css\n");
576             }
577             }
578              
579             # check for conflict
580 1 0 33     4 if ( $css_linkname && $rOpts->{'nohtml-style-sheets'} ) {
581 0         0 $rOpts->{'nohtml-style-sheets'} = 0;
582 0         0 Perl::Tidy::Warn(
583             "You can't specify both -css and -nss; -nss ignored\n");
584             }
585              
586             # write a style sheet file if necessary
587 1 50       2 if ($css_linkname) {
588              
589             # if the selected filename exists, don't write, because user may
590             # have done some work by hand to create it; use backup name instead
591             # Also, this will avoid a potential disaster in which the user
592             # forgets to specify the style sheet, like this:
593             # perltidy -html -css myfile1.pl myfile2.pl
594             # This would cause myfile1.pl to parsed as the style sheet by GetOpts
595 0 0       0 if ( !-e $css_linkname ) {
596 0         0 write_style_sheet_file($css_linkname);
597             }
598             }
599 1         2 $rOpts_html_entities = $rOpts->{'html-entities'};
600              
601 1 50       3 if ( $rOpts->{'pod2html'} ) {
602 1 50       3 if ( $rOpts->{'html-pre-only'} ) {
603 0         0 undef $rOpts->{'pod2html'};
604             }
605             else {
606 1         3 load_pod_formatter();
607 1 50       3 if ( !$loaded_pod_formatter ) {
608 0         0 undef $rOpts->{'pod2html'};
609             }
610             }
611             }
612              
613 1         6 return;
614             } ## end sub check_options
615              
616             sub load_pod_formatter {
617              
618             # Load a Pod to Html formatter
619             # Define global variables:
620             # $loaded_pod_formatter
621             # = name of pod formatter found, or
622             # = empty string if not found
623             # $log_message = log message to write for first file
624              
625             # Global variables:
626 1     1 0 2 $log_message = EMPTY_STRING;
627 1         1 $loaded_pod_formatter = EMPTY_STRING;
628              
629 1 50       5 return if ( !$rOpts->{'pod2html'} );
630              
631             # Built-in search order is higher values to lower values
632 1         5 my %formatters = (
633             'Pod::Simple::XHTML' => 3,
634             'Pod::Simple::HTML' => 1,
635             'Pod::Html' => 2,
636             );
637              
638             # Start search with any user-selected formatter
639 1         2 my $use_pod_formatter = $rOpts->{'use-pod-formatter'};
640 1 50       3 if ($use_pod_formatter) {
641 0         0 my @q = keys %formatters;
642 0         0 my %ok = map { $_ => 1 } @q;
  0         0  
643 0 0       0 if ( !$ok{$use_pod_formatter} ) {
644 0         0 my $str = join ', ', @q;
645 0         0 Perl::Tidy::Die(<<EOM);
646             --use-pod-formatter='$use_pod_formatter' not recognized; expecting one of:
647             $str
648             EOM
649             }
650 0         0 $formatters{$use_pod_formatter} = 1 + keys %formatters;
651             }
652              
653 1         7 my @sorted = sort { $formatters{$b} <=> $formatters{$a} } keys %formatters;
  3         7  
654              
655 1         2 foreach my $formatter (@sorted) {
656 1 50       4 if ( $formatter eq 'Pod::Simple::XHTML' ) {
657 1 50       2 if ( !eval { require Pod::Simple::XHTML; 1 } ) {
  1         800  
  1         35127  
658 0         0 $log_message .= <<EOM;
659             Unable to load $formatter
660             EOM
661 0         0 next;
662             }
663             else {
664 1         3 $loaded_pod_formatter = $formatter;
665 1         5 $log_message .= <<EOM;
666             Loaded $formatter
667             EOM
668 1         3 last;
669             }
670             }
671 0 0       0 if ( $formatter eq 'Pod::Simple::HTML' ) {
672 0 0       0 if ( !eval { require Pod::Simple::HTML; 1 } ) {
  0         0  
  0         0  
673 0         0 $log_message .= <<EOM;
674             Unable to load $formatter
675             EOM
676 0         0 next;
677             }
678             else {
679 0         0 $loaded_pod_formatter = $formatter;
680 0         0 $log_message .= <<EOM;
681             Loaded $formatter
682             EOM
683 0         0 last;
684             }
685             }
686 0 0       0 if ( $formatter eq 'Pod::Html' ) {
687 0 0       0 if ( !eval { require Pod::Html; 1 } ) {
  0         0  
  0         0  
688 0         0 $log_message .= <<EOM;
689             Unable to load $formatter
690             EOM
691 0         0 next;
692             }
693             else {
694 0         0 $loaded_pod_formatter = $formatter;
695 0         0 $log_message .= <<EOM;
696             Loaded $formatter
697             EOM
698 0         0 last;
699             }
700             }
701             }
702              
703 1 50       4 if ( !$loaded_pod_formatter ) {
704 0         0 $log_message .= <<EOM;
705             unable to find a pod formatter; cannot use pod2html\n-npod disables this message
706             EOM
707             }
708              
709 1         5 return;
710             } ## end sub load_pod_formatter
711              
712             sub write_style_sheet_file {
713              
714 0     0 0 0 my $filename = shift;
715 0         0 my $fh = IO::File->new("> $filename");
716 0 0       0 if ( !$fh ) {
717 0         0 Perl::Tidy::Die("can't open $filename: $OS_ERROR\n");
718             }
719 0         0 write_style_sheet_data($fh);
720 0 0 0     0 if ( $fh->can('close') && $filename ne '-' && !ref($filename) ) {
      0        
721 0 0       0 $fh->close()
722             or
723             Perl::Tidy::Warn("can't close style sheet '$filename' : $OS_ERROR\n");
724             }
725 0         0 return;
726             } ## end sub write_style_sheet_file
727              
728             sub write_style_sheet_data {
729              
730             # write the style sheet data to an open file handle
731 1     1 0 2 my $fh = shift;
732              
733 1         2 my $bg_color = $rOpts->{'html-color-background'};
734 1         4 my $text_color = $rOpts->{'html-color-punctuation'};
735              
736             # pre-bgcolor is new, and may not be defined
737 1         1 my $pre_bg_color = $rOpts->{'html-pre-color-background'};
738 1 50       3 $pre_bg_color = $bg_color unless ($pre_bg_color);
739              
740 1         4 $fh->print(<<"EOM");
741             /* default style sheet generated by perltidy */
742             body {background: $bg_color; color: $text_color}
743             pre { color: $text_color;
744             background: $pre_bg_color;
745             font-family: courier;
746             }
747              
748             EOM
749              
750 1         13 foreach my $short_name ( sort keys %short_to_long_names ) {
751 18         25 my $long_name = $short_to_long_names{$short_name};
752              
753 18         13 my $abbrev = '.' . $short_name;
754 18 100       25 if ( length($short_name) == 1 ) { $abbrev .= SPACE } # for alignment
  12         10  
755 18         27 my $color = $html_color{$short_name};
756 18 100       28 if ( !defined($color) ) { $color = $text_color }
  5         5  
757 18         30 $fh->print("$abbrev \{ color: $color;");
758              
759 18 100       31 if ( $html_bold{$short_name} ) {
760 4         6 $fh->print(" font-weight:bold;");
761             }
762              
763 18 100       25 if ( $html_italic{$short_name} ) {
764 2         4 $fh->print(" font-style:italic;");
765             }
766 18         25 $fh->print("} /* $long_name */\n");
767             }
768 1         16 return;
769             } ## end sub write_style_sheet_data
770              
771             sub set_default_color {
772              
773             # make sure that options hash $rOpts->{$key} contains a valid color
774 14     14 0 19 my ( $key, $color ) = @_;
775 14 50       21 if ( $rOpts->{$key} ) { $color = $rOpts->{$key} }
  0         0  
776 14         16 $rOpts->{$key} = check_RGB($color);
777 14         15 return;
778             } ## end sub set_default_color
779              
780             sub check_RGB {
781              
782             # if color is a 6 digit hex RGB value, prepend a #, otherwise
783             # assume that it is a valid ascii color name
784 14     14 0 16 my ($color) = @_;
785 14 50       19 if ( $color =~ /^[0-9a-fA-F]{6,6}$/ ) { $color = "#$color" }
  0         0  
786 14         26 return $color;
787             } ## end sub check_RGB
788              
789             sub set_default_properties {
790 12     12 0 21 my ( $short_name, $color, $bold, $italic ) = @_;
791              
792 12         27 set_default_color( "html-color-$short_to_long_names{$short_name}", $color );
793 12         11 my $key;
794 12         14 $key = "html-bold-$short_to_long_names{$short_name}";
795 12 50       44 $rOpts->{$key} = defined( $rOpts->{$key} ) ? $rOpts->{$key} : $bold;
796 12         14 $key = "html-italic-$short_to_long_names{$short_name}";
797 12 50       22 $rOpts->{$key} = defined( $rOpts->{$key} ) ? $rOpts->{$key} : $italic;
798 12         13 return;
799             } ## end sub set_default_properties
800              
801             sub pod_to_html {
802              
803             # Convert the pod to html
804             # then merge the perltidy code sections into it.
805             # return 1 if success, 0 otherwise
806 1     1 0 5 my ( $self, $pod_string, $css_string, $toc_string, $rpre_string_stack ) =
807             @_;
808 1         3 my $title = $self->{_title};
809 1         2 my $is_encoded_data = $self->{_is_encoded_data};
810 1         2 my $is_pure_ascii_data = $self->{_is_pure_ascii_data};
811 1         2 my $success_flag = 0;
812              
813             # don't try to use pod2html if no pod
814 1 50       9 if ( !$pod_string ) {
815 1         3 return $success_flag;
816             }
817              
818 0         0 my $rhtml_string;
819 0 0       0 if ( $loaded_pod_formatter eq 'Pod::Simple::XHTML' ) {
    0          
    0          
820 0         0 my $psx = Pod::Simple::XHTML->new;
821 0         0 $rhtml_string = $self->pod_to_html_simple( $pod_string, $psx );
822             }
823             elsif ( $loaded_pod_formatter eq 'Pod::Simple::HTML' ) {
824 0         0 my $psx = Pod::Simple::HTML->new;
825 0         0 $rhtml_string = $self->pod_to_html_simple( $pod_string, $psx );
826             }
827             elsif ( $loaded_pod_formatter eq 'Pod::Html' ) {
828 0         0 $rhtml_string = $self->pod_to_html_old($pod_string);
829             }
830             else {
831             # Looks like a pod formatter could not be loaded
832 0         0 return $success_flag;
833             }
834              
835 0 0       0 if ( !$rhtml_string ) {
836 0         0 return $success_flag;
837             }
838              
839 0         0 my $html_fh = $self->{_html_fh};
840 0         0 my @toc;
841             my $in_toc;
842 0         0 my $ul_level = 0;
843 0         0 my $no_print;
844              
845             # This routine will write the html selectively and store the toc
846             my $html_print = sub {
847 0     0   0 foreach my $line (@_) {
848 0 0       0 $html_fh->print($line) unless ($no_print);
849 0 0       0 if ($in_toc) { push @toc, $line }
  0         0  
850             }
851 0         0 return;
852 0         0 }; ## end $html_print = sub
853              
854             # loop over lines of html output from pod2html and merge in
855             # the necessary perltidy html sections
856 0         0 my ( $saw_body, $saw_index, $saw_body_end );
857              
858 0         0 my $timestamp = EMPTY_STRING;
859 0 0       0 if ( $rOpts->{'timestamp'} ) {
860 0         0 my $date = localtime;
861 0         0 $timestamp = "on $date";
862             }
863              
864 0         0 my @html_lines = split /^/, ${$rhtml_string};
  0         0  
865 0         0 my $saw_charset;
866             my $want_charset;
867 0 0 0     0 if ( $is_encoded_data || $is_pure_ascii_data ) {
868 0         0 $want_charset = 'utf-8';
869             }
870             else {
871 0         0 $want_charset = 'ISO-8859-1';
872             }
873 0         0 foreach my $line (@html_lines) {
874              
875 0 0 0     0 if ( $line =~ /^\s*<html>\s*$/i ) {
    0 0        
    0 0        
    0 0        
    0 0        
    0          
    0          
    0          
    0          
    0          
876 0         0 $html_print->("<!-- Generated by perltidy $timestamp -->\n");
877 0         0 $html_print->($line);
878             }
879              
880             # Fix the charset if necessary
881             elsif ( !$saw_charset && $line =~ /^\s*<meta.*charset=([\w\-]+)/i ) {
882 0         0 $saw_charset = $1;
883 0 0       0 if ( uc($saw_charset) ne uc($want_charset) ) {
884 0         0 $line =~ s/$saw_charset/$want_charset/;
885             }
886 0         0 $html_print->($line);
887             }
888              
889             # Copy the perltidy css, if any, after <body> tag
890             elsif ( $line =~ /^\s*<body.*>\s*$/i ) {
891 0         0 $saw_body = 1;
892 0 0       0 $html_print->($css_string) if ($css_string);
893 0         0 $html_print->($line);
894              
895             # add a top anchor and heading
896 0         0 $html_print->("<a name=\"-top-\"></a>\n");
897 0         0 $title = escape_html($title);
898 0         0 $html_print->("<h1>$title</h1>\n");
899             }
900              
901             # check for start of index, old pod2html
902             # before Pod::Html VERSION 1.15_02 it is delimited by comments as:
903             # <!-- INDEX BEGIN -->
904             # <ul>
905             # ...
906             # </ul>
907             # <!-- INDEX END -->
908             #
909             elsif ( $line =~ /^\s*<!-- INDEX BEGIN -->\s*$/i ) {
910 0         0 $in_toc = 'INDEX';
911              
912             # when frames are used, an extra table of contents in the
913             # contents panel is confusing, so don't print it
914             $no_print = $rOpts->{'frames'}
915 0   0     0 || !$rOpts->{'html-table-of-contents'};
916 0 0       0 $html_print->("<h2>Doc Index:</h2>\n") if ( $rOpts->{'frames'} );
917 0         0 $html_print->($line);
918             }
919              
920             # check for start of index, new pod2html
921             # After Pod::Html VERSION 1.15_02 it is delimited as:
922             # <ul id="index">
923             # ...
924             # </ul>
925             elsif ( $line =~ /^\s*<ul\s+id="index">/i ) {
926 0         0 $in_toc = 'UL';
927 0         0 $ul_level = 1;
928              
929             # when frames are used, an extra table of contents in the
930             # contents panel is confusing, so don't print it
931             $no_print = $rOpts->{'frames'}
932 0   0     0 || !$rOpts->{'html-table-of-contents'};
933 0 0       0 $html_print->("<h2>Doc Index:</h2>\n") if ( $rOpts->{'frames'} );
934 0         0 $html_print->($line);
935             }
936              
937             # Check for end of index, old pod2html
938             elsif ( $line =~ /^\s*<!-- INDEX END -->\s*$/i ) {
939 0         0 $saw_index = 1;
940 0         0 $html_print->($line);
941              
942             # Copy the perltidy toc, if any, after the Pod::Html toc
943 0 0       0 if ($toc_string) {
944 0 0       0 $html_print->("<hr />\n") if ( $rOpts->{'frames'} );
945 0         0 $html_print->("<h2>Code Index:</h2>\n");
946 0         0 my @toc_st = split /^/, $toc_string;
947 0         0 $html_print->(@toc_st);
948             }
949 0         0 $in_toc = EMPTY_STRING;
950 0         0 $no_print = 0;
951             }
952              
953             # must track <ul> depth level for new pod2html
954             elsif ( $line =~ /\s*<ul>\s*$/i && $in_toc && $in_toc eq 'UL' ) {
955 0         0 $ul_level++;
956 0         0 $html_print->($line);
957             }
958              
959             # Check for end of index, for new pod2html
960             elsif ( $line =~ /\s*<\/ul>/i && $in_toc && $in_toc eq 'UL' ) {
961 0         0 $ul_level--;
962 0         0 $html_print->($line);
963              
964             # Copy the perltidy toc, if any, after the Pod::Html toc
965 0 0       0 if ( $ul_level <= 0 ) {
966 0         0 $saw_index = 1;
967 0 0       0 if ($toc_string) {
968 0 0       0 $html_print->("<hr />\n") if ( $rOpts->{'frames'} );
969 0         0 $html_print->("<h2>Code Index:</h2>\n");
970 0         0 my @toc_st = split /^/, $toc_string;
971 0         0 $html_print->(@toc_st);
972             }
973 0         0 $in_toc = EMPTY_STRING;
974 0         0 $ul_level = 0;
975 0         0 $no_print = 0;
976             }
977             }
978              
979             # Copy one perltidy section after each marker
980             elsif ( $line =~ /^(.*)<!-- pERLTIDY sECTION -->(.*)$/ ) {
981 0         0 $line = $2;
982 0 0       0 $html_print->($1) if ($1);
983              
984             # Intermingle code and pod sections if we saw multiple =cut's.
985 0 0       0 if ( $self->{_pod_cut_count} > 1 ) {
986 0         0 my $rpre_string = shift @{$rpre_string_stack};
  0         0  
987 0 0       0 if ( ${$rpre_string} ) {
  0         0  
988 0         0 $html_print->('<pre>');
989 0         0 $html_print->( ${$rpre_string} );
  0         0  
990 0         0 $html_print->('</pre>');
991             }
992             else {
993              
994             # shouldn't happen: we stored a string before writing
995             # each marker.
996 0         0 Perl::Tidy::Warn(
997             "Problem merging html stream with pod2html; order may be wrong\n"
998             );
999             }
1000 0         0 $html_print->($line);
1001             }
1002              
1003             # If didn't see multiple =cut lines, we'll put the pod out first
1004             # and then the code, because it's less confusing.
1005             else {
1006              
1007             # since we are not intermixing code and pod, we don't need
1008             # or want any <hr> lines which separated pod and code
1009 0 0       0 $html_print->($line) unless ( $line =~ /^\s*<hr>\s*$/i );
1010             }
1011             }
1012              
1013             # Copy any remaining code section before the </body> tag
1014             elsif ( $line =~ /^\s*<\/body>/i ) {
1015 0         0 $saw_body_end = 1;
1016 0 0       0 if ( @{$rpre_string_stack} ) {
  0         0  
1017 0 0       0 if ( $self->{_pod_cut_count} <= 1 ) {
1018 0         0 $html_print->('<hr />');
1019             }
1020 0         0 while ( @{$rpre_string_stack} ) {
  0         0  
1021 0         0 my $rpre_string = shift @{$rpre_string_stack};
  0         0  
1022 0         0 $html_print->('<pre>');
1023 0         0 $html_print->( ${$rpre_string} );
  0         0  
1024 0         0 $html_print->('</pre>');
1025             } ## end while ( @{$rpre_string_stack...})
1026             }
1027 0         0 $html_print->($line);
1028             }
1029             else {
1030 0         0 $html_print->($line);
1031             }
1032             } ## end while ( defined( my $line...))
1033              
1034 0         0 $success_flag = 1;
1035 0 0       0 if ( !$saw_body ) {
1036 0         0 Perl::Tidy::Warn("Did not see <body> in pod2html output\n");
1037 0         0 $success_flag = 0;
1038             }
1039 0 0       0 if ( !$saw_body_end ) {
1040 0         0 Perl::Tidy::Warn("Did not see </body> in pod2html output\n");
1041 0         0 $success_flag = 0;
1042             }
1043              
1044             # Added check on $in_toc to handle small files without an index at all
1045 0 0 0     0 if ( !$saw_index && defined($in_toc) ) {
1046 0         0 Perl::Tidy::Warn("Did not find INDEX END in pod2html output\n");
1047 0         0 $success_flag = 0;
1048             }
1049              
1050 0 0       0 if ( $html_fh->can('close') ) {
1051 0         0 $html_fh->close();
1052             }
1053              
1054 0 0 0     0 if ( $success_flag && $rOpts->{'frames'} ) {
1055 0         0 $self->make_frame( \@toc );
1056             }
1057 0         0 return $success_flag;
1058             } ## end sub pod_to_html
1059              
1060             sub pod_to_html_old {
1061              
1062 0     0 0 0 my ( $self, $pod_string ) = @_;
1063              
1064             # Use Pod::Html to process pod text
1065             # Given:
1066             # $pod_string = string with pod to process
1067             # Return:
1068             # $rhtml_string = ref to string with pod as html, or
1069             # undef if error
1070              
1071 0         0 my $is_encoded_data = $self->{_is_encoded_data};
1072 0         0 my $is_pure_ascii_data = $self->{_is_pure_ascii_data};
1073              
1074             # Make a temporary named file for data transfer to and from Pod::Html.
1075             # NOTE: For perl perl-5.10 and later, the default will use one of the
1076             # Pod::Simple formatters instead. These formatters do not require temp
1077             # files. So this routine will not normally be used, unless specifically
1078             # requested with the -ups flag, or if running on perl-5.8.x. (c539).
1079 44     44   34362 use File::Temp qw();
  44         713478  
  44         156907  
1080 0         0 my ( $fh_tmp, $tmpfile ) = File::Temp::tempfile( UNLINK => 1 );
1081 0 0       0 if ( !$fh_tmp ) {
1082 0         0 Perl::Tidy::Warn(
1083             "unable to open temporary file $tmpfile; cannot use pod2html\n");
1084 0         0 return;
1085             }
1086              
1087 0 0       0 if ($is_encoded_data) { binmode $fh_tmp, ":raw:encoding(UTF-8)" }
  0         0  
1088 0         0 else { binmode $fh_tmp }
1089              
1090 0         0 my $pod_is_pure_ascii_data = !( $pod_string =~ /[^[:ascii:]]/ );
1091              
1092             # Pod::Html wants to see =encoding if not pure ascii
1093 0 0       0 if ($pod_is_pure_ascii_data) {
    0          
    0          
1094              
1095             # no '=encoding' needed for pure ascii pod text
1096             }
1097             elsif ($is_encoded_data) {
1098 0         0 $pod_string = "\n=encoding UTF-8\n\n$pod_string";
1099             }
1100             elsif ( !$is_pure_ascii_data ) {
1101 0         0 $pod_string = "\n=encoding CP1252\n\n$pod_string";
1102             }
1103             else {
1104             ## no '=encoding' needed for pure ascii
1105             }
1106              
1107             # write the pod text to the temporary file
1108 0         0 $fh_tmp->print($pod_string);
1109              
1110 0 0       0 if ( !$fh_tmp->close() ) {
1111 0         0 Perl::Tidy::Warn(
1112             "unable to close temporary file $tmpfile; cannot use pod2html\n");
1113 0         0 return;
1114             }
1115              
1116             # Hand off the pod to pod2html.
1117             # Note that we can use the same temporary filename for input and output
1118             # because of the way pod2html works.
1119             {
1120 0         0 my $title = $self->{_title};
  0         0  
1121 0         0 my @args;
1122 0         0 push @args, "--infile=$tmpfile", "--outfile=$tmpfile", "--title=$title";
1123              
1124             # Flags with string args:
1125             # "cachedir=s", "htmlroot=s", "libpods=s", "podpath=s", "podroot=s"
1126             # Note: -css=s is handled by perltidy itself
1127             # Note: backlink=s was incorrectly in this list up to v20250912:
1128             # backlink can now be input as 'podbacklink', below
1129 0         0 foreach my $kw (qw( cachedir htmlroot libpods podpath podroot )) {
1130 0 0       0 if ( $rOpts->{$kw} ) { push @args, "--$kw=$rOpts->{$kw}" }
  0         0  
1131             }
1132              
1133             # Toggle switches; these have extra leading 'pod'
1134             # "header!", "index!", "recurse!", "quiet!", "verbose!", "backlink!'
1135             # See note above regarding the change for backlink.
1136 0         0 foreach my $kw (
1137             qw( podheader podindex podrecurse podquiet podverbose podbacklink ))
1138             {
1139 0         0 my $kwd = $kw; # allows us to strip 'pod'
1140 0 0       0 if ( $rOpts->{$kw} ) { $kwd =~ s/^pod//; push @args, "--$kwd" }
  0 0       0  
  0         0  
1141             elsif ( defined( $rOpts->{$kw} ) ) {
1142 0         0 $kwd =~ s/^pod//;
1143 0         0 push @args, "--no$kwd";
1144             }
1145             else {
1146             # user did not set this keyword
1147             }
1148             }
1149              
1150             # "flush",
1151 0         0 my $kw = 'podflush';
1152 0 0       0 if ( $rOpts->{$kw} ) { $kw =~ s/^pod//; push @args, "--$kw" }
  0         0  
  0         0  
1153              
1154             # Must clean up if pod2html dies (it can);
1155             # Be careful not to overwrite callers __DIE__ routine
1156             local $SIG{__DIE__} = sub {
1157 0 0   0   0 unlink($tmpfile) if ( -e $tmpfile );
1158 0         0 Perl::Tidy::Die( $_[0] );
1159 0         0 };
1160              
1161 0         0 Pod::Html::pod2html(@args);
1162             }
1163              
1164 0         0 my $rhtml_string;
1165 0 0       0 if ( open( my $fh, '<', $tmpfile ) ) {
1166 0         0 local $INPUT_RECORD_SEPARATOR = undef;
1167 0 0       0 if ($is_encoded_data) { binmode $fh, ":raw:encoding(UTF-8)"; }
  0         0  
1168 0         0 else { binmode $fh }
1169 0         0 my $buf = <$fh>;
1170 0         0 $rhtml_string = \$buf;
1171 0 0       0 $fh->close() or Warn("Cannot close $tmpfile\n");
1172             }
1173             else {
1174             # this error shouldn't happen ... we just used this filename
1175 0         0 Perl::Tidy::Warn(
1176             "unable to open temporary file $tmpfile; cannot use Pod::Html\n");
1177 0         0 return;
1178             }
1179 0 0       0 if ( -e $tmpfile ) {
1180 0 0       0 if ( !unlink($tmpfile) ) {
1181 0         0 Perl::Tidy::Warn(
1182             "couldn't unlink temporary file $tmpfile: $OS_ERROR\n");
1183 0         0 return;
1184             }
1185             }
1186 0         0 return $rhtml_string;
1187             } ## end sub pod_to_html_old
1188              
1189             sub pod_to_html_simple {
1190              
1191 0     0 0 0 my ( $self, $pod_string, $psx ) = @_;
1192              
1193             # Use Pod::Simple::HTML or Pod::Simple::XHTML to process pod text
1194             # Given:
1195             # $pod_string = string with pod to process
1196             # $psx = either Pod::Simple::HTML->new or Pod::Simple::XHTML->new
1197             # Return:
1198             # $rhtml_string = ref to string with pod as html, or
1199             # undef if error
1200 0         0 my $is_pure_ascii_data = $self->{_is_pure_ascii_data};
1201 0         0 my $is_encoded_data = $self->{_is_encoded_data};
1202 0         0 my $html_string;
1203              
1204             # make an index if possible
1205 0 0       0 $psx->index(1)
1206             if ( $psx->can('index') );
1207              
1208             # pass characters if possible, otherwise pass octets
1209 0         0 my $pass_octets;
1210 0 0       0 if ( !$is_pure_ascii_data ) {
1211              
1212             # Tell parser to expect characters, not octets, and ignore =encoding if
1213             # not a pure ascii file, if possible.
1214 0 0       0 if ( $psx->can('parse_characters') ) {
1215 0         0 $psx->parse_characters(1);
1216             }
1217              
1218             # Otherwise, add =encoding and pass octets
1219             else {
1220 0 0       0 if ($is_encoded_data) {
1221 0         0 $pass_octets = 1;
1222 0         0 $pod_string = "\n=encoding UTF-8\n\n$pod_string";
1223 0         0 $pod_string = Encode::encode( 'UTF-8', $pod_string );
1224             }
1225             else {
1226 0         0 $pod_string = "\n=encoding CP1252\n\n$pod_string";
1227             }
1228             }
1229             }
1230              
1231 0         0 $psx->output_string( \$html_string );
1232 0         0 $psx->parse_string_document($pod_string);
1233              
1234 0 0       0 if ($pass_octets) {
1235 0         0 $html_string = Encode::decode( 'UTF-8', $html_string );
1236             }
1237 0         0 return \$html_string;
1238             } ## end sub pod_to_html_simple
1239              
1240             sub make_frame {
1241              
1242             # Make a frame with table of contents in the left panel
1243             # and the text in the right panel.
1244             # On entry:
1245             # $html_filename contains the no-frames html output
1246             # $rtoc is a reference to an array with the table of contents
1247 0     0 0 0 my ( $self, $rtoc ) = @_;
1248 0         0 my $html_filename = $self->{_html_file};
1249 0         0 my $toc_filename = $self->{_toc_filename};
1250 0         0 my $src_filename = $self->{_src_filename};
1251 0         0 my $title = $self->{_title};
1252 0         0 $title = escape_html($title);
1253              
1254             # FUTURE input parameter:
1255 0         0 my $top_basename = EMPTY_STRING;
1256              
1257             # We need to produce 3 html files:
1258             # 1. - the table of contents
1259             # 2. - the contents (source code) itself
1260             # 3. - the frame which contains them
1261              
1262             # get basenames for relative links
1263 0         0 my ( $toc_basename, $toc_path_uu ) = fileparse($toc_filename);
1264 0         0 my ( $src_basename, $src_path_uu ) = fileparse($src_filename);
1265              
1266             # 1. Make the table of contents panel, with appropriate changes
1267             # to the anchor names
1268 0         0 my $src_frame_name = 'SRC';
1269 0         0 my $first_anchor_uu = write_toc_html(
1270             {
1271             title => $title,
1272             toc_filename => $toc_filename,
1273             src_basename => $src_basename,
1274             rtoc => $rtoc,
1275             src_frame_name => $src_frame_name,
1276             }
1277             );
1278              
1279             # 2. The current .html filename is renamed to be the contents panel
1280 0 0       0 rename( $html_filename, $src_filename )
1281             or Perl::Tidy::Die(
1282             "Cannot rename $html_filename to $src_filename: $OS_ERROR\n");
1283              
1284             # 3. Then use the original html filename for the frame
1285 0         0 write_frame_html(
1286             {
1287             title => $title,
1288             frame_filename => $html_filename,
1289             top_basename => $top_basename,
1290             toc_basename => $toc_basename,
1291             src_basename => $src_basename,
1292             src_frame_name => $src_frame_name,
1293             }
1294             );
1295 0         0 return;
1296             } ## end sub make_frame
1297              
1298             sub write_toc_html {
1299              
1300             # write a separate html table of contents file for frames
1301 0     0 0 0 my ($rarg_hash) = @_;
1302              
1303 0         0 my $title = $rarg_hash->{title};
1304 0         0 my $toc_filename = $rarg_hash->{toc_filename};
1305 0         0 my $src_basename = $rarg_hash->{src_basename};
1306 0         0 my $rtoc = $rarg_hash->{rtoc};
1307 0         0 my $src_frame_name = $rarg_hash->{src_frame_name};
1308              
1309 0 0       0 my $fh = IO::File->new( $toc_filename, 'w' )
1310             or Perl::Tidy::Die("Cannot open $toc_filename: $OS_ERROR\n");
1311 0         0 $fh->print(<<EOM);
1312             <html>
1313             <head>
1314             <title>$title</title>
1315             </head>
1316             <body>
1317             <h1><a href=\"$src_basename#-top-" target="$src_frame_name">$title</a></h1>
1318             EOM
1319              
1320 0         0 my $first_anchor_uu =
1321             change_anchor_names( $rtoc, $src_basename, "$src_frame_name" );
1322 0         0 $fh->print( join EMPTY_STRING, @{$rtoc} );
  0         0  
1323              
1324 0         0 $fh->print(<<EOM);
1325             </body>
1326             </html>
1327             EOM
1328              
1329 0         0 return;
1330             } ## end sub write_toc_html
1331              
1332             sub write_frame_html {
1333              
1334             # write an html file to be the table of contents frame
1335              
1336 0     0 0 0 my ($rarg_hash) = @_;
1337              
1338 0         0 my $title = $rarg_hash->{title};
1339 0         0 my $frame_filename = $rarg_hash->{frame_filename};
1340 0         0 my $top_basename = $rarg_hash->{top_basename};
1341 0         0 my $toc_basename = $rarg_hash->{toc_basename};
1342 0         0 my $src_basename = $rarg_hash->{src_basename};
1343 0         0 my $src_frame_name = $rarg_hash->{src_frame_name};
1344              
1345 0 0       0 my $fh = IO::File->new( $frame_filename, 'w' )
1346             or Perl::Tidy::Die("Cannot open $toc_basename: $OS_ERROR\n");
1347              
1348 0         0 $fh->print(<<EOM);
1349             <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
1350             "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
1351             <?xml version="1.0" encoding="iso-8859-1" ?>
1352             <html xmlns="http://www.w3.org/1999/xhtml">
1353             <head>
1354             <title>$title</title>
1355             </head>
1356             EOM
1357              
1358             # two left panels, one right, if master index file
1359 0 0       0 if ($top_basename) {
1360 0         0 $fh->print(<<EOM);
1361             <frameset cols="20%,80%">
1362             <frameset rows="30%,70%">
1363             <frame src = "$top_basename" />
1364             <frame src = "$toc_basename" />
1365             </frameset>
1366             EOM
1367             }
1368              
1369             # one left panels, one right, if no master index file
1370             else {
1371 0         0 $fh->print(<<EOM);
1372             <frameset cols="20%,*">
1373             <frame src = "$toc_basename" />
1374             EOM
1375             }
1376 0         0 $fh->print(<<EOM);
1377             <frame src = "$src_basename" name = "$src_frame_name" />
1378             <noframes>
1379             <body>
1380             <p>If you see this message, you are using a non-frame-capable web client.</p>
1381             <p>This document contains:</p>
1382             <ul>
1383             <li><a href="$toc_basename">A table of contents</a></li>
1384             <li><a href="$src_basename">The source code</a></li>
1385             </ul>
1386             </body>
1387             </noframes>
1388             </frameset>
1389             </html>
1390             EOM
1391 0         0 return;
1392             } ## end sub write_frame_html
1393              
1394             sub change_anchor_names {
1395              
1396             # add a filename and target to anchors
1397             # also return the first anchor
1398 0     0 0 0 my ( $rlines, $filename, $target ) = @_;
1399 0         0 my $first_anchor;
1400 0         0 foreach my $line ( @{$rlines} ) {
  0         0  
1401              
1402             # We're looking for lines like this:
1403             # <LI><A HREF="#synopsis">SYNOPSIS</A></LI>
1404             # ---- - -------- -----------------
1405             # $1 $4 $5
1406 0 0       0 if ( $line =~ /^(.*)<a(.*)href\s*=\s*"([^#]*)#([^"]+)"[^>]*>(.*)$/i ) {
1407 0         0 my $pre = $1;
1408 0         0 my $name = $4;
1409 0         0 my $post = $5;
1410 0         0 my $href = "$filename#$name";
1411 0         0 $line = "$pre<a href=\"$href\" target=\"$target\">$post\n";
1412 0 0       0 if ( !$first_anchor ) { $first_anchor = $href }
  0         0  
1413             }
1414             }
1415 0         0 return $first_anchor;
1416             } ## end sub change_anchor_names
1417              
1418             sub close_html_file {
1419 1     1 0 2 my ($self) = @_;
1420              
1421             # Finish writing an html output file and close it
1422              
1423 1 50       4 return unless ( $self->{_html_file_opened} );
1424              
1425 1         2 my $html_fh = $self->{_html_fh};
1426 1         3 my $rtoc_string = $self->{_rtoc_string};
1427              
1428             # There are 3 basic paths to html output...
1429              
1430             # ---------------------------------
1431             # Path 1: finish up if in -pre mode
1432             # ---------------------------------
1433 1 50       3 if ( $rOpts->{'html-pre-only'} ) {
1434 0         0 $html_fh->print(<<"PRE_END");
1435             </pre>
1436             PRE_END
1437 0 0       0 $html_fh->close()
1438             if ( $html_fh->can('close') );
1439 0         0 return;
1440             }
1441              
1442             # Finish the index
1443 1         4 $self->add_toc_item( 'EOF', 'EOF' );
1444              
1445 1         1 my $rpre_string_stack = $self->{_rpre_string_stack};
1446              
1447             # Patch to darken the <pre> background color in case of pod2html and
1448             # interleaved code/documentation. Otherwise, the distinction
1449             # between code and documentation is blurred.
1450 1 50 33     8 if ( $rOpts->{pod2html}
      33        
1451             && $self->{_pod_cut_count} >= 1
1452             && $rOpts->{'html-color-background'} eq '#FFFFFF' )
1453             {
1454 0         0 $rOpts->{'html-pre-color-background'} = '#F0F0F0';
1455             }
1456              
1457             # put the css or its link into a string, if used
1458 1         2 my $css_string;
1459 1         4 my $fh_css = Perl::Tidy::IOScalar->new( \$css_string, 'w' );
1460              
1461             # use css linked to another file,
1462 1 50       5 if ( $rOpts->{'html-linked-style-sheet'} ) {
    50          
1463 0         0 $fh_css->print(
1464             qq(<link rel="stylesheet" href="$css_linkname" type="text/css" />));
1465             }
1466              
1467             # or no css,
1468             elsif ( $rOpts->{'nohtml-style-sheets'} ) {
1469              
1470             }
1471              
1472             # or use css embedded in this file
1473             else {
1474 1         3 $fh_css->print(<<'ENDCSS');
1475             <style type="text/css">
1476             <!--
1477             ENDCSS
1478 1         4 write_style_sheet_data($fh_css);
1479 1         3 $fh_css->print(<<"ENDCSS");
1480             -->
1481             </style>
1482             ENDCSS
1483             }
1484              
1485             # -----------------------------------------------------------
1486             # path 2: use pod2html if requested
1487             # If we fail for some reason, continue on to path 3
1488             # -----------------------------------------------------------
1489 1 50       3 if ( $rOpts->{'pod2html'} ) {
1490 1         2 my $rpod_string = $self->{_rpod_string};
1491             my $success = $self->pod_to_html(
1492 1         2 ${$rpod_string}, $css_string,
1493 1         2 ${$rtoc_string}, $rpre_string_stack
  1         19  
1494             );
1495 1 50       3 return if ($success);
1496             }
1497              
1498             # --------------------------------------------------
1499             # path 3: write code in html, with pod only in italics
1500             # --------------------------------------------------
1501 1         2 my $input_file = $self->{_input_file};
1502 1         7 my $title = escape_html($input_file);
1503 1         1 my $timestamp = EMPTY_STRING;
1504 1 50       4 if ( $rOpts->{'timestamp'} ) {
1505 0         0 my $date = localtime;
1506 0         0 $timestamp = "on $date";
1507             }
1508 1         4 $html_fh->print(<<"HTML_START");
1509             <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
1510             "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
1511             <!-- Generated by perltidy $timestamp -->
1512             <html xmlns="http://www.w3.org/1999/xhtml">
1513             <head>
1514             <title>$title</title>
1515             HTML_START
1516              
1517             # output the css, if used
1518 1 50       2 if ($css_string) {
1519 1         3 $html_fh->print($css_string);
1520 1         2 $html_fh->print(<<"ENDCSS");
1521             </head>
1522             <body>
1523             ENDCSS
1524             }
1525             else {
1526              
1527 0         0 $html_fh->print(<<"HTML_START");
1528             </head>
1529             <body bgcolor=\"$rOpts->{'html-color-background'}\" text=\"$rOpts->{'html-color-punctuation'}\">
1530             HTML_START
1531             }
1532              
1533 1         2 $html_fh->print("<a name=\"-top-\"></a>\n");
1534 1         3 $html_fh->print(<<"EOM");
1535             <h1>$title</h1>
1536             EOM
1537              
1538             # copy the table of contents
1539 1 0 33     1 if ( ${$rtoc_string}
  1   33     4  
1540             && !$rOpts->{'frames'}
1541             && $rOpts->{'html-table-of-contents'} )
1542             {
1543 0         0 $html_fh->print( ${$rtoc_string} );
  0         0  
1544             }
1545              
1546             # copy the pre section(s)
1547 1         2 my $fname_comment = $input_file;
1548 1         2 $fname_comment =~ s/--+/-/g; # protect HTML comment tags
1549 1         3 $html_fh->print(<<"END_PRE");
1550             <hr />
1551             <!-- contents of filename: $fname_comment -->
1552             <pre>
1553             END_PRE
1554              
1555 1         1 foreach my $rpre_string ( @{$rpre_string_stack} ) {
  1         3  
1556 1         1 $html_fh->print( ${$rpre_string} );
  1         9  
1557             }
1558              
1559             # and finish the html page
1560 1         2 $html_fh->print(<<"HTML_END");
1561             </pre>
1562             </body>
1563             </html>
1564             HTML_END
1565 1 50       9 $html_fh->close()
1566             if ( $html_fh->can('close') );
1567              
1568 1 50       4 if ( $rOpts->{'frames'} ) {
1569 0         0 my @toc = split /^/, ${$rtoc_string};
  0         0  
1570 0         0 $self->make_frame( \@toc );
1571             }
1572 1         3 return;
1573             } ## end sub close_html_file
1574              
1575             sub markup_tokens {
1576 2     2 0 4 my ( $self, $rtokens, $rtoken_type, $rlevels ) = @_;
1577              
1578             # Loop to add html markup to all tokens
1579              
1580 2         2 my ( @colored_tokens, $type, $token, $level );
1581 2         4 my $rlast_level = $self->{_rlast_level};
1582 2         3 my $rpackage_stack = $self->{_rpackage_stack};
1583              
1584 2         4 foreach my $j ( 0 .. @{$rtoken_type} - 1 ) {
  2         5  
1585 46         53 $type = $rtoken_type->[$j];
1586 46         47 $token = $rtokens->[$j];
1587 46         50 $level = $rlevels->[$j];
1588 46 50       51 $level = 0 if ( $level < 0 );
1589              
1590             #-------------------------------------------------------
1591             # Update the package stack. The package stack is needed to keep
1592             # the toc correct because some packages may be declared within
1593             # blocks and go out of scope when we leave the block.
1594             #-------------------------------------------------------
1595 46 100       53 if ( $level > ${$rlast_level} ) {
  46 100       54  
1596 3 100       8 if ( !$rpackage_stack->[ $level - 1 ] ) {
1597 1         2 $rpackage_stack->[ $level - 1 ] = 'main';
1598             }
1599 3         4 $rpackage_stack->[$level] = $rpackage_stack->[ $level - 1 ];
1600             }
1601 43         52 elsif ( $level < ${$rlast_level} ) {
1602 3         5 my $package = $rpackage_stack->[$level];
1603 3 50       7 if ( !$package ) { $package = 'main' }
  0         0  
1604              
1605             # if we change packages due to a nesting change, we
1606             # have to make an entry in the toc
1607 3 50       6 if ( $package ne $rpackage_stack->[ $level + 1 ] ) {
1608 0         0 $self->add_toc_item( $package, 'package' );
1609             }
1610             }
1611             else {
1612             ## level unchanged
1613             }
1614 46         43 ${$rlast_level} = $level;
  46         59  
1615              
1616             #-------------------------------------------------------
1617             # Intercept a sub name here; split it
1618             # into keyword 'sub' and sub name; and add an
1619             # entry in the toc
1620             # Fix for c250: switch from 'i' to 'S'
1621             #-------------------------------------------------------
1622 46 50 33     90 if ( $type eq 'S' && $token =~ /^(\w+\s+)(\w.*)$/ ) {
1623 0         0 $token = $self->markup_html_element( $1, 'k' );
1624 0         0 push @colored_tokens, $token;
1625 0         0 $token = $2;
1626 0         0 $type = 'S';
1627              
1628             # but don't include sub declarations in the toc;
1629             # these will have leading token types 'i;'
1630 0         0 my $signature = join EMPTY_STRING, @{$rtoken_type};
  0         0  
1631 0 0       0 if ( $signature !~ /^i;/ ) {
1632 0         0 my $subname = $token;
1633 0         0 $subname =~ s/[\s\(].*$//; # remove any attributes and prototype
1634 0         0 $self->add_toc_item( $subname, 'sub' );
1635             }
1636             }
1637              
1638             #-------------------------------------------------------
1639             # Intercept a package name here; split it
1640             # into keyword 'package' and name; add to the toc,
1641             # and update the package stack
1642             #-------------------------------------------------------
1643             # Fix for c250: switch from 'i' to 'P' and allow 'class' or 'package'
1644 46 50 33     55 if ( $type eq 'P' && $token =~ /^(\w+\s+)(\w.*)$/ ) {
1645 0         0 $token = $self->markup_html_element( $1, 'k' );
1646 0         0 push @colored_tokens, $token;
1647 0         0 $token = $2;
1648 0         0 $type = 'i';
1649 0         0 $self->add_toc_item( "$token", 'package' );
1650 0         0 $rpackage_stack->[$level] = $token;
1651             }
1652              
1653 46         52 $token = $self->markup_html_element( $token, $type );
1654 46         58 push @colored_tokens, $token;
1655             }
1656 2         5 return ( \@colored_tokens );
1657             } ## end sub markup_tokens
1658              
1659             sub markup_html_element {
1660 46     46 0 56 my ( $self, $token, $type ) = @_;
1661              
1662             # Add html markup to a single token
1663             # Given:
1664             # $token = the token text
1665             # $type = the token type
1666              
1667 46 100       64 return $token if ( $type eq 'b' ); # skip a blank token
1668 25 50       47 return $token if ( $token =~ /^\s*$/ ); # skip a blank line
1669 25         28 $token = escape_html($token);
1670              
1671             # get the short abbreviation for this token type
1672 25         40 my $short_name = $token_short_names{$type};
1673 25 100       30 if ( !defined($short_name) ) {
1674 4         5 $short_name = "pu"; # punctuation is default
1675             }
1676              
1677             # handle style sheets..
1678 25 50       31 if ( !$rOpts->{'nohtml-style-sheets'} ) {
1679 25 100       35 if ( $short_name ne 'pu' ) {
1680 21         27 $token = qq(<span class="$short_name">) . $token . "</span>";
1681             }
1682             }
1683              
1684             # handle no style sheets..
1685             else {
1686 0         0 my $color = $html_color{$short_name};
1687              
1688 0 0 0     0 if ( $color && ( $color ne $rOpts->{'html-color-punctuation'} ) ) {
1689 0         0 $token = qq(<font color="$color">) . $token . "</font>";
1690             }
1691 0 0       0 if ( $html_italic{$short_name} ) { $token = "<i>$token</i>" }
  0         0  
1692 0 0       0 if ( $html_bold{$short_name} ) { $token = "<b>$token</b>" }
  0         0  
1693             }
1694 25         36 return $token;
1695             } ## end sub markup_html_element
1696              
1697             sub escape_html {
1698              
1699 26     26 0 28 my $token = shift;
1700 26 50 33     49 if ( $missing_html_entities || !$rOpts_html_entities ) {
1701 0         0 $token =~ s/\&/&amp;/g;
1702 0         0 $token =~ s/\</&lt;/g;
1703 0         0 $token =~ s/\>/&gt;/g;
1704 0         0 $token =~ s/\"/&quot;/g;
1705             }
1706             else {
1707 26         40 HTML::Entities::encode_entities($token);
1708             }
1709 26         322 return $token;
1710             } ## end sub escape_html
1711              
1712             sub finish_formatting {
1713              
1714             # Called after last line to do the actual html formatting.
1715 1     1 0 3 my ( $self, $rtokenization_info_uu ) = @_;
1716              
1717             # Given:
1718             # $rtokenization_info, a hash with error info
1719              
1720             # Go ahead and try to format as html in all cases, even if there
1721             # are syntax errors.
1722 1         5 $self->close_html_file();
1723 1         3 return;
1724             } ## end sub finish_formatting
1725              
1726             sub write_line {
1727              
1728 2     2 0 4 my ( $self, $line_of_tokens ) = @_;
1729              
1730             # Given:
1731             # $line_of_tokens = a tokenized line from the input stream
1732             # Markup the line as html and output it
1733              
1734 2 50       6 return unless ( $self->{_html_file_opened} );
1735 2         5 my $html_pre_fh = $self->{_html_pre_fh};
1736 2         3 my $line_type = $line_of_tokens->{_line_type};
1737 2         3 my $input_line = $line_of_tokens->{_line_text};
1738 2         18 my $line_number = $line_of_tokens->{_line_number};
1739 2         5 chomp $input_line;
1740              
1741             # markup line of code..
1742 2         3 my $html_line;
1743 2 50       4 if ( $line_type eq 'CODE' ) {
1744 2         4 my $rtoken_type = $line_of_tokens->{_rtoken_type};
1745 2         3 my $rtokens = $line_of_tokens->{_rtokens};
1746 2         3 my $rlevels = $line_of_tokens->{_rlevels};
1747              
1748 2 50       9 if ( $input_line =~ /(^\s*)/ ) {
1749 2         4 $html_line = $1;
1750             }
1751             else {
1752 0         0 $html_line = EMPTY_STRING;
1753             }
1754 2         9 my ($rcolored_tokens) =
1755             $self->markup_tokens( $rtokens, $rtoken_type, $rlevels );
1756 2         3 $html_line .= join EMPTY_STRING, @{$rcolored_tokens};
  2         7  
1757             }
1758              
1759             # markup line of non-code..
1760             else {
1761 0         0 my $line_character;
1762 0 0       0 if ( $line_type eq 'HERE' ) { $line_character = 'H' }
  0 0       0  
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
1763 0         0 elsif ( $line_type eq 'HERE_END' ) { $line_character = 'h' }
1764 0         0 elsif ( $line_type eq 'FORMAT' ) { $line_character = 'H' }
1765 0         0 elsif ( $line_type eq 'FORMAT_END' ) { $line_character = 'h' }
1766 0         0 elsif ( $line_type eq 'SKIP' ) { $line_character = 'H' }
1767 0         0 elsif ( $line_type eq 'SKIP_END' ) { $line_character = 'h' }
1768 0         0 elsif ( $line_type eq 'SYSTEM' ) { $line_character = 'c' }
1769             elsif ( $line_type eq 'END_START' ) {
1770 0         0 $line_character = 'k';
1771 0         0 $self->add_toc_item( '__END__', '__END__' );
1772             }
1773             elsif ( $line_type eq 'DATA_START' ) {
1774 0         0 $line_character = 'k';
1775 0         0 $self->add_toc_item( '__DATA__', '__DATA__' );
1776             }
1777             elsif ( $line_type =~ /^POD/ ) {
1778              
1779             # fix for c250: changed 'P' to 'pd' here and in %token_short_names
1780             # to allow use of 'P' as new package token type
1781 0         0 $line_character = 'pd';
1782 0 0       0 if ( $rOpts->{'pod2html'} ) {
1783 0         0 my $html_pod_fh = $self->{_html_pod_fh};
1784 0 0       0 if ( $line_type eq 'POD_START' ) {
1785              
1786 0         0 my $rpre_string_stack = $self->{_rpre_string_stack};
1787 0         0 my $rpre_string = $rpre_string_stack->[-1];
1788              
1789             # if we have written any non-blank lines to the
1790             # current pre section, start writing to a new output
1791             # string
1792 0 0       0 if ( ${$rpre_string} =~ /\S/ ) {
  0         0  
1793 0         0 my $pre_string;
1794 0         0 $html_pre_fh =
1795             Perl::Tidy::IOScalar->new( \$pre_string, 'w' );
1796 0         0 $self->{_html_pre_fh} = $html_pre_fh;
1797 0         0 push @{$rpre_string_stack}, \$pre_string;
  0         0  
1798              
1799             # leave a marker in the pod stream so we know
1800             # where to put the pre section we just
1801             # finished.
1802 0         0 my $for_html = '=for html'; # don't confuse pod utils
1803 0         0 $html_pod_fh->print(<<EOM);
1804              
1805             $for_html
1806             <!-- pERLTIDY sECTION -->
1807              
1808             EOM
1809             }
1810              
1811             # otherwise, just clear the current string and start
1812             # over
1813             else {
1814 0         0 ${$rpre_string} = EMPTY_STRING;
  0         0  
1815 0         0 $html_pod_fh->print("\n");
1816             }
1817             }
1818 0         0 $html_pod_fh->print( $input_line . "\n" );
1819 0 0       0 if ( $line_type eq 'POD_END' ) {
1820 0         0 $self->{_pod_cut_count}++;
1821 0         0 $html_pod_fh->print("\n");
1822             }
1823 0         0 return;
1824             }
1825             }
1826 0         0 else { $line_character = 'Q' }
1827 0         0 $html_line = $self->markup_html_element( $input_line, $line_character );
1828             }
1829              
1830             # add the line number if requested
1831 2 50       8 if ( $rOpts->{'html-line-numbers'} ) {
1832 0 0       0 my $extra_space =
    0          
    0          
1833             ( $line_number < 10 ) ? SPACE x 3
1834             : ( $line_number < 100 ) ? SPACE x 2
1835             : ( $line_number < 1000 ) ? SPACE
1836             : EMPTY_STRING;
1837 0         0 $html_line = $extra_space . $line_number . SPACE . $html_line;
1838             }
1839              
1840             # write the line
1841 2         11 $html_pre_fh->print("$html_line\n");
1842 2         25 return;
1843             } ## end sub write_line
1844              
1845             } ## end package Perl::Tidy::HtmlWriter
1846             1;