File Coverage

blib/lib/Perl/Tidy/HtmlWriter.pm
Criterion Covered Total %
statement 401 849 47.2
branch 72 352 20.4
condition 11 75 14.6
subroutine 37 50 74.0
pod 0 24 0.0
total 521 1350 38.5


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