File indexing completed on 2024-05-05 05:44:47
0001 #!/usr/bin/perl 0002 # 0003 # Code adapted from Pod::HtmlEasy for kio_perldoc. See CPAN for the real deal. 0004 # Integrated and crap^H^H^H^H unnecessary dependencies removed by Michael Pyne 0005 # <michael.pyne@kdemail.net> 0006 # 0007 # Copyright 2007, 2008 Michael Pyne. 0008 # Original source is licensed to be distributed under the same terms as Perl 0009 # itself. All changes by Michael Pyne retain this license. 0010 # 0011 # Based on Pod::HtmlEasy by M. P. Graciliano and Geoffrey Leach. 0012 # http://search.cpan.org/~gleach/Pod-HtmlEasy/ 0013 0014 ############################################################################# 0015 ## Name: TieHandler.pm 0016 ## Purpose: Pod::HtmlEasy::TieHandler 0017 ## Author: Graciliano M. P. 0018 ## Modified by: Geoffrey Leach 0019 ## Created: 2/14/2007 0020 ## Copyright: (c) 2004 Graciliano M. P. 0021 ## Licence: This program is free software; you can redistribute it and/or 0022 ## modify it under the same terms as Perl itself 0023 ############################################################################# 0024 0025 # The function of this package is to provide a print function that is 0026 # tied to a filehandle which is then passed as the output file to 0027 # Pod::Parser. Note that only PRINT() and CLOSE() are defined. 0028 # PRINT() accumulates output in an anon array, which is then referenced 0029 # by the defining function. 0030 0031 package Pod::HtmlEasy::TieHandler; 0032 0033 use strict; 0034 use warnings; 0035 0036 our $VERSION = 0.02; 0037 0038 sub TIEHANDLE { 0039 my $class = shift; 0040 my $scalar = shift; 0041 0042 return bless $scalar, $class; 0043 } 0044 0045 sub PRINT { 0046 my $this = shift; 0047 0048 push @{$this}, @_; 0049 return 1; 0050 } 0051 0052 sub FILENO { return 1; } 0053 sub CLOSE { return 1; } 0054 0055 ####### 0056 # END # 0057 ####### 0058 0059 1; 0060 0061 ############################################################################# 0062 ## Name: Parser.pm 0063 ## Purpose: Pod::HtmlEasy::Parser 0064 ## Author: Graciliano M. P. 0065 ## Modified by: Geoffrey Leach 0066 ## Created: 11/01/2004 0067 ## Updated: 2007-02-25 0068 ## Copyright: (c) 2004 Graciliano M. P. 0069 ## Licence: This program is free software; you can redistribute it and/or 0070 ## modify it under the same terms as Perl itself 0071 ############################################################################# 0072 0073 package Pod::HtmlEasy::Parser; 0074 0075 use base qw{ Pod::Parser }; 0076 0077 use Carp; 0078 use English qw{ -no_match_vars }; 0079 use feature "switch"; 0080 0081 use strict; 0082 use warnings; 0083 no warnings 'experimental::smartmatch'; 0084 0085 our $VERSION = 0.03; 0086 0087 our $EMPTY = q{}; 0088 our $NL = qq{\n}; 0089 our $NUL = qq{\0}; 0090 our $SPACE = q{ }; 0091 0092 # Set to 1 for URIs like /functions/foo to fixup links in evt_on_L 0093 our $fnPage = 0; 0094 0095 ######## 0096 # VARS # 0097 ######## 0098 0099 my $MAIL_RE = qr{ 0100 ( # grab all of this 0101 [\w-]+ # some word chars with '-' included foo 0102 \0? # possible NUL escape 0103 \@ # literal '@' @ 0104 [\w\\-]+ # another word bar 0105 (?: # non-grabbing pattern 0106 \. # literal '.' . 0107 [\w\-\.]+# that word stuff stuff 0108 \. # another literal '.' . 0109 [\w\-]+ # another word and 0110 | # or 0111 \. # literal '.' . 0112 [\w\-]+ # word nonsense 0113 | # or empty? 0114 ) # end of non-grab 0115 ) # end of grab 0116 }smx; # [6062] 0117 0118 # Treatment of embedded HTML-significant characters and embedded URIs. 0119 0120 # There are some characters (%html_entities below) which may in some 0121 # circumstances be interpreted by a browser, and you probably don't want that 0122 # Consequently, they are replaced by names defined by the W3C UNICODE spec, 0123 # http://www.w3.org/TR/MathML2/bycodes.html, bracketed by '&' and ';' 0124 # Thus, '>' becomes '<' This is handled by _encode_entities() 0125 # There's a "gotchya" in this process. As we are generating HTML, 0126 # the encoding needs to take place _before_ any HTML is generated. 0127 0128 # If the HTML appears garbled, and UNICODE entities appear where they 0129 # shouldn't, this encoding has happened to late at some point. 0130 0131 # This is all further complicated by the fact that the POD formatting 0132 # codes syntax uses some of the same characters, as in "L<...>", for example, 0133 # and we can't expand those first, because some of them generate 0134 # HTML. This is resolved by tagging the characters that we want 0135 # to distinguish from HTML with ASCII NUL ('\0', $NUL). Thus, '$lt;' becomes 0136 # '\0&' in _encode_entities(). Generated HTML is also handled 0137 # this way by _nul_escape(). After all processing of the POD formatting 0138 # codes are processed, this is reversed by _remove _nul_escapes(). 0139 0140 # Then there's the issue of embedded URIs. URIs are also generated 0141 # by the processing of L<...>, and can show up _inside L<...>, we 0142 # delay processing of embedded URIs until after all of the POD 0143 # formatting codes is complete. URIs that result from that processing 0144 # are tagged (you guessed it!) with a NUL character, but not preceeding 0145 # the generated URI, but after the first character. These NULs are removed 0146 # by _remove _nul_escapes() 0147 0148 my %html_entities = ( 0149 q{&} => q{amp}, 0150 q{>} => q{gt}, 0151 q{<} => q{lt}, 0152 q{"} => q{quot}, 0153 ); 0154 0155 my $HTML_ENTITIES_RE = '[' . join ('', keys %html_entities) . ']'; 0156 $HTML_ENTITIES_RE = qr{$HTML_ENTITIES_RE}; 0157 0158 ################# 0159 # _NUL_ESCAPE # 0160 ################# 0161 0162 # Escape HTML-significant characters with ASCII NUL to differentiate them 0163 # from the same characters that get converted to entity names 0164 0165 sub _nul_escape { 0166 my $txt_ref = shift; 0167 0168 ${$txt_ref} =~ s{($HTML_ENTITIES_RE)}{$NUL$1}gsm; 0169 return; 0170 } 0171 0172 ####################### 0173 # _REMOVE_NUL_ESCAPSE # 0174 ####################### 0175 0176 sub _remove_nul_escapes { 0177 my $txt_ref = shift; 0178 0179 ${$txt_ref} =~ s{$NUL}{}gsm; 0180 return; 0181 } 0182 0183 #################### 0184 # _ENCODE_ENTITIES # 0185 #################### 0186 0187 sub _encode_entities { 0188 my ( $txt_ref ) = @_; 0189 0190 return unless $$txt_ref; 0191 0192 foreach my $chr ( keys %html_entities ) { 0193 0194 my $re = qr{(?<!$NUL)$chr}; 0195 my $replacement = '&' . $html_entities{$chr} . ';'; 0196 ${$txt_ref} =~ s{$re}{$NUL$replacement}gsm; 0197 } 0198 0199 return; 0200 } 0201 0202 sub setFunctionPage { 0203 my $this = shift; 0204 our $fnPage = shift; 0205 } 0206 0207 ########### 0208 # COMMAND # 0209 ########### 0210 0211 # Overrides command() provided by base class in Pod::Parser 0212 sub command { 0213 my ( $parser, $command, $paragraph, $line_num, $pod ) = @_; 0214 0215 if ( defined $parser->{POD_HTMLEASY}->{VERBATIM_BUFFER} ) { 0216 _verbatim($parser); 0217 } # [6062] 0218 0219 my $expansion = $parser->interpolate( $paragraph, $line_num ); 0220 0221 $expansion =~ s{^\s*}{}gsm; # delete surrounding whitespace 0222 $expansion =~ s{\s*$}{}gsm; # delete surrounding whitespace 0223 0224 # Encoding puts in a NUL; we're finished with the text, so remove them 0225 _encode_entities( \$expansion ); 0226 _remove_nul_escapes( \$expansion ); 0227 0228 # Create the index tag 0229 # a_name has the text of the expansion _without_ anything between '<' and '>', 0230 # which amounts to the HTML formatting codes, which are not processed by 0231 # the name directive. 0232 my $a_name = $expansion; 0233 $a_name =~ s{<.*?>}{}gsm; 0234 0235 $a_name =~ /</g; 0236 my $pos = pos($a_name); 0237 my $start = $pos; 0238 my $count = 0; 0239 $count++ if defined $pos; 0240 0241 while(defined $pos and $count != 0) 0242 { 0243 my $match = $a_name =~ /\G[^<>]*([<>])/g; 0244 0245 last unless $match; 0246 $pos = pos($a_name); 0247 0248 $count++ if $1 eq '<'; 0249 $count-- if $1 eq '>'; 0250 } 0251 0252 if (defined $pos and defined $start) { 0253 $pos = $pos - $start + 1; 0254 $start = $start - 1; 0255 $a_name =~ s/^(.{$start}).{$pos}/$1/; 0256 } 0257 0258 my $html; 0259 given ($command) { 0260 when ("head1") { 0261 _add_tree_point( $parser, $expansion, 1 ); 0262 $html = $parser->{POD_HTMLEASY} 0263 ->{ON_HEAD1}( $parser->{POD_HTMLEASY}, $expansion, $a_name ); 0264 } 0265 when ("head2") { 0266 _add_tree_point( $parser, $expansion, 2 ); 0267 $html = $parser->{POD_HTMLEASY} 0268 ->{ON_HEAD2}( $parser->{POD_HTMLEASY}, $expansion, $a_name ); 0269 } 0270 when ("head3") { 0271 _add_tree_point( $parser, $expansion, 3 ); 0272 $html = $parser->{POD_HTMLEASY} 0273 ->{ON_HEAD3}( $parser->{POD_HTMLEASY}, $expansion, $a_name ); 0274 } 0275 when ("head4") { 0276 _add_tree_point( $parser, $expansion, 4 ); 0277 $html = $parser->{POD_HTMLEASY} 0278 ->{ON_HEAD4}( $parser->{POD_HTMLEASY}, $expansion, $a_name ); 0279 } 0280 when ("begin") { 0281 _add_tree_point( $parser, $expansion, 4 ); 0282 $html = $parser->{POD_HTMLEASY} 0283 ->{ON_BEGIN}( $parser->{POD_HTMLEASY}, $expansion, $a_name ); 0284 } 0285 when ("end") { 0286 $html = $parser->{POD_HTMLEASY} 0287 ->{ON_END}( $parser->{POD_HTMLEASY}, $expansion, $a_name ); 0288 } 0289 when ("over") { 0290 if ( $parser->{INDEX_ITEM} ) { 0291 $parser->{INDEX_ITEM_LEVEL}++; 0292 } 0293 $html = $parser->{POD_HTMLEASY} 0294 ->{ON_OVER}( $parser->{POD_HTMLEASY}, $expansion ); 0295 } 0296 when ("item") { 0297 if ( $parser->{INDEX_ITEM} ) { 0298 _add_tree_point( $parser, $expansion, 0299 ( 3 + ( $parser->{INDEX_ITEM_LEVEL} || 1 ) ) ); 0300 } 0301 $html = $parser->{POD_HTMLEASY} 0302 ->{ON_ITEM}( $parser->{POD_HTMLEASY}, $expansion, $a_name ); 0303 } 0304 when ("back") { 0305 if ( $parser->{INDEX_ITEM} ) { 0306 $parser->{INDEX_ITEM_LEVEL}--; 0307 } 0308 $html = $parser->{POD_HTMLEASY} 0309 ->{ON_BACK}( $parser->{POD_HTMLEASY}, $expansion ); 0310 } 0311 when ("for") { 0312 $html = $parser->{POD_HTMLEASY} 0313 ->{ON_FOR}( $parser->{POD_HTMLEASY}, $expansion, $a_name ); 0314 } 0315 when ("include") { 0316 my $file = $parser->{POD_HTMLEASY} 0317 ->{ON_INCLUDE}( $parser->{POD_HTMLEASY}, $expansion ); 0318 if ( -e $file 0319 && -r _ ) # _ is the last checked filehandle. 0320 { 0321 $parser->{POD_HTMLEASY}->parse_include($file); 0322 } 0323 } 0324 default { 0325 if ( defined $parser->{POD_HTMLEASY}->{qq{ON_\U$command\E}} ) { 0326 $html = $parser->{POD_HTMLEASY} 0327 ->{qq{ON_\U$command\E}}( $parser->{POD_HTMLEASY}, 0328 $expansion ); 0329 } 0330 elsif ( $command !~ /^(?:pod|cut)$/imx ) { 0331 $html = qq{<pre>=$command $expansion</pre>}; 0332 } 0333 else { $html = $EMPTY; } 0334 } 0335 }; 0336 0337 if ( $html ne $EMPTY ) { 0338 print { $parser->output_handle() } $html; 0339 } # [6062] 0340 0341 return; 0342 } 0343 0344 ############ 0345 # VERBATIM # 0346 ############ 0347 0348 # Overrides verbatim() provided by base class in Pod::Parser 0349 sub verbatim { 0350 my ( $parser, $paragraph, $line_num ) = @_; 0351 0352 if ( exists $parser->{POD_HTMLEASY}->{IN_BEGIN} ) { return; } 0353 $parser->{POD_HTMLEASY}->{VERBATIM_BUFFER} .= $paragraph; 0354 0355 return; 0356 } 0357 0358 sub _verbatim { 0359 my ($parser) = @_; 0360 0361 if ( exists $parser->{POD_HTMLEASY}->{IN_BEGIN} ) { return; } 0362 my $expansion = $parser->{POD_HTMLEASY}->{VERBATIM_BUFFER}; 0363 $parser->{POD_HTMLEASY}->{VERBATIM_BUFFER} = $EMPTY; 0364 0365 _encode_entities( \$expansion ); 0366 0367 my $html = $parser->{POD_HTMLEASY} 0368 ->{ON_VERBATIM}( $parser->{POD_HTMLEASY}, $expansion ); 0369 0370 # And remove any NUL escapes 0371 _remove_nul_escapes( \$html ); 0372 0373 if ( $html ne $EMPTY ) { 0374 print { $parser->output_handle() } $html; 0375 } # [6062] 0376 0377 return; 0378 } 0379 0380 ############# 0381 # TEXTBLOCK # 0382 ############# 0383 0384 # Overrides textblock() provided by base class in Pod::Parser 0385 sub textblock { 0386 my ( $parser, $paragraph, $line_num ) = @_; 0387 0388 if ( exists $parser->{POD_HTMLEASY}->{IN_BEGIN} ) { return; } 0389 if ( defined $parser->{POD_HTMLEASY}->{VERBATIM_BUFFER} ) { 0390 _verbatim($parser); 0391 } # [6062] 0392 0393 my $expansion = $parser->interpolate( $paragraph, $line_num ); 0394 0395 $expansion =~ s{^\s+}{}gsmx; 0396 $expansion =~ s{\s+$}{}gsmx; 0397 0398 # Encode HTML-specific characters before adding any HTML (eg <p>) 0399 _encode_entities( \$expansion ); 0400 0401 my $html = $parser->{POD_HTMLEASY} 0402 ->{ON_TEXTBLOCK}( $parser->{POD_HTMLEASY}, $expansion ); 0403 0404 # And remove any NUL escapes 0405 _remove_nul_escapes( \$html ); 0406 0407 if ( $html ne $EMPTY ) { print { $parser->output_handle() } $html; } 0408 0409 return; 0410 } 0411 0412 ##################### 0413 # INTERIOR_SEQUENCE # 0414 ##################### 0415 0416 # Overrides interior_sequence() provided by base class in Pod::Parser 0417 sub interior_sequence { 0418 my ( $parser, $seq_command, $seq_argument, $pod_seq ) = @_; 0419 0420 my $ret; 0421 0422 # If we're in the middle of a link then escaping now could break some of 0423 # the link uncracking code. 0424 _encode_entities(\$seq_argument) unless $seq_command eq 'L'; 0425 0426 # Not sure how these get in here but HTML doesn't support / (which is 0427 # simply forward slash 0428 $seq_argument =~ s///\//g; 0429 0430 if ($pod_seq->nested() and $pod_seq->nested()->cmd_name() eq 'L' 0431 and $seq_command ne 'E') 0432 { 0433 # Interpolating into a hyperlink, ignore formatting, unless we are 0434 # processing an escape code 0435 return $seq_argument; 0436 } 0437 0438 given ($seq_command) { 0439 when ("B") { 0440 $ret = $parser->{POD_HTMLEASY} 0441 ->{ON_B}( $parser->{POD_HTMLEASY}, $seq_argument ); 0442 } 0443 when ("C") { 0444 $ret = $parser->{POD_HTMLEASY} 0445 ->{ON_C}( $parser->{POD_HTMLEASY}, $seq_argument ); 0446 } 0447 when ("E") { 0448 $ret = $parser->{POD_HTMLEASY} 0449 ->{ON_E}( $parser->{POD_HTMLEASY}, $seq_argument ); 0450 } 0451 when ("F") { 0452 $ret = $parser->{POD_HTMLEASY} 0453 ->{ON_F}( $parser->{POD_HTMLEASY}, $seq_argument ); 0454 } 0455 when ("I") { 0456 $ret = $parser->{POD_HTMLEASY} 0457 ->{ON_I}( $parser->{POD_HTMLEASY}, $seq_argument ); 0458 } 0459 when ("L") { 0460 my ( $text, $name, $section, $type ) = _parselink($seq_argument); 0461 0462 # Held off on escaping these earlier, take care of it now. 0463 _encode_entities(\$text); 0464 _encode_entities(\$section) if $section; 0465 _encode_entities(\$name) if $name; 0466 0467 $ret = $parser->{POD_HTMLEASY}->{ON_L}( 0468 $parser->{POD_HTMLEASY}, 0469 $seq_argument, $text, $name, $section, $type, $fnPage, 0470 ); 0471 } 0472 when ("S") { 0473 $ret = $parser->{POD_HTMLEASY} 0474 ->{ON_S}( $parser->{POD_HTMLEASY}, $seq_argument ); 0475 } 0476 when ("Z") { 0477 $ret = $parser->{POD_HTMLEASY} 0478 ->{ON_Z}( $parser->{POD_HTMLEASY}, $seq_argument ); 0479 } 0480 default { 0481 if ( defined $parser->{POD_HTMLEASY}->{qq{ON_\U$seq_command\E}} ) 0482 { 0483 $ret = $parser->{POD_HTMLEASY} 0484 ->{qq{ON_\U$seq_command\E}}( $parser->{POD_HTMLEASY}, 0485 $seq_argument ); 0486 } 0487 else { 0488 $ret = qq{$seq_command<$seq_argument>}; 0489 } 0490 } 0491 } 0492 0493 # Escape HTML-significant characters to prevent them from being escaped 0494 # later. 0495 _nul_escape( \$ret ); 0496 0497 return $ret; 0498 } 0499 0500 ######################## 0501 # PREPROCESS_PARAGRAPH # 0502 ######################## 0503 0504 # Overrides preprocess_paragraph() provided by base class in Pod::Parser 0505 # NB: the text is _not altered. 0506 sub preprocess_paragraph { 0507 my $parser = shift; 0508 my ( $text, $line_num ) = @_; 0509 0510 if ( $parser->{POD_HTMLEASY}{INFO_COUNT} == 3 ) { 0511 return $text; 0512 } 0513 0514 if ( not exists $parser->{POD_HTMLEASY}{PACKAGE} ) { 0515 if ( $text =~ m{package}smx ) { 0516 my ($pack) = $text =~ m{(\w+(?:::\w+)*)}smx; 0517 if ( defined $pack ) { 0518 $parser->{POD_HTMLEASY}{PACKAGE} = $pack; 0519 $parser->{POD_HTMLEASY}{INFO_COUNT}++; 0520 } 0521 } 0522 } 0523 0524 if ( not exists $parser->{POD_HTMLEASY}{VERSION} ) { 0525 if ( $text =~ m{VERSION}smx ) { 0526 my ($ver) = $text =~ m{(\d)(?:\.\d*)?}smx; 0527 if ( defined $ver ) { 0528 $parser->{POD_HTMLEASY}{VERSION} = $ver; 0529 $parser->{POD_HTMLEASY}{INFO_COUNT}++; 0530 } 0531 } 0532 } 0533 0534 # This situation is created by evt_on_head1() 0535 if ( ( exists $parser->{POD_HTMLEASY}{TITLE} ) 0536 and ( not defined $parser->{POD_HTMLEASY}{TITLE} ) ) 0537 { 0538 my @lines = split m{\n}smx, $text; 0539 my $tmp_text = shift @lines; 0540 if ( not defined $tmp_text ) { return $text; } 0541 $tmp_text =~ s{^\s*}{}gsmx; # delete surrounding whitespace 0542 $tmp_text =~ s{\s*$}{}gsmx; # delete surrounding whitespace 0543 $parser->{POD_HTMLEASY}{TITLE} = $tmp_text; 0544 $parser->{POD_HTMLEASY}{INFO_COUNT}++; 0545 } 0546 0547 return $text; 0548 } 0549 0550 ################## 0551 # _PARSE_SECTION # 0552 ################## 0553 0554 # Parse a link that is not a URL to get the name and/or section 0555 # Algorithm may be found in perlpodspec. "About L<...> Codes" 0556 0557 sub _parse_section { 0558 my $link = shift; 0559 $link =~ s{^\s*}{}sm; # delete surrounding whitespace 0560 $link =~ s{\s*$}{}sm; # delete surrounding whitespace 0561 0562 # L<"FooBar"> is a the way to specify a section without a name. 0563 # However, L<Foo Bar> is possible, though deprecated. See below. 0564 if ($link =~ m/^"/) { 0565 $link =~ s{^"+\s*}{}sm; # strip the "s 0566 $link =~ s{\s*"+$}{}sm; 0567 return ( undef, $link ); 0568 } 0569 0570 # So now we have either a name by itself, or name/section 0571 my ( $name, $section ) = split m[\s*/\s*]sm, $link, 2; 0572 0573 # Trim leading and trailing whitespace and quotes from section 0574 if ($section) { 0575 $section =~ s{"}{}gsm; # quotes 0576 $section =~ s{^\s*}{}sm; # delete surrounding whitespace 0577 $section =~ s{\s*$}{}sm; # delete surrounding whitespace 0578 } # new leading/trailing 0579 0580 # Perlpodspec observes that and acceptable way to distinguish between L<name> and 0581 # L<section> is that if the link contains any whitespace, then it is a section. 0582 # The construct L<section> is deprecated. 0583 if ( $name && $name =~ m{\s}sm && !defined $section ) { 0584 $section = $name; 0585 $name = undef; 0586 } 0587 0588 return ( $name, $section ); 0589 } 0590 0591 ############### 0592 # _INFER_TEXT # 0593 ############### 0594 0595 # Infer the text content of a L<...> with no text| part (ie a text|-less link) 0596 # By definition (?) either name or section is nonempty, Algorithm from perlpodspec 0597 0598 sub _infer_text { 0599 my ( $name, $section ) = @_; 0600 0601 if ($name) { 0602 return $section 0603 ? "\"$section\" in $name" 0604 : $name; 0605 } 0606 0607 return $section; 0608 } 0609 0610 ############## 0611 # _PARSELINK # 0612 ############## 0613 0614 # Parse the content of L<...> and return 0615 # The text label 0616 # The name or URL 0617 # The section (if relevant) 0618 # The type of link discovered: url, man or pod 0619 0620 sub _parselink { 0621 my $link = shift; 0622 my $text; 0623 0624 # Squeeze out multiple spaces 0625 $link =~ s{\s+}{$SPACE}gsm; 0626 0627 if ( $link =~ m{\|}smx ) { 0628 0629 # Link is in the form "L<Foo|Foo::Bar>" 0630 ( $text, $link ) = split m{\|}sm, $link, 2; 0631 } 0632 0633 # Check for a generalized URL. The regex is defined in perlpodspec. 0634 # Quoting perlpodspec: "Authors wanting to link to a particular (absolute) URL, must do so 0635 # only with "L<scheme:...>" codes and must not attempt "L<Some Site Name|scheme:...>" 0636 # Consequently, although $text might be nonempty, we ignore it. 0637 if ($link =~ m{ 0638 \A # The beginning of the string 0639 \w+ # followed by some alphanumerics, which would be the protocol (or scheme) 0640 : # literal ":" 0641 [^:\s] # one char that is neither a ":" or whitespace 0642 \S* # maybe some non-whitespace 0643 \z # the end of the string 0644 }smx 0645 ) 0646 { 0647 return ( $link, $link, undef, q{url} ); 0648 } 0649 0650 # OK, we've eliminated URLs, so we must be dealing with something else 0651 0652 my ( $name, $section ) = _parse_section($link); 0653 if ( not defined $text ) { $text = _infer_text( $name, $section ); } 0654 0655 # A link with parenthesized non-whitespace is assumed to be a manpage reference 0656 # (per perlpodspec)) 0657 my $type = 0658 ( $name && $name =~ m{\(\S*\)}smx ) 0659 ? q{man} 0660 : q{pod}; 0661 0662 return ( $text, $name, $section, $type ); 0663 } 0664 0665 ################### 0666 # _ADD_TREE_POINT # 0667 ################### 0668 0669 sub _add_tree_point { 0670 my ( $parser, $name, $level ) = @_; 0671 $level ||= 1; 0672 0673 if ( $level == 1 ) { 0674 $parser->{POD_HTMLEASY}->{INDEX}{p} 0675 = $parser->{POD_HTMLEASY}->{INDEX}{tree}; 0676 } 0677 else { 0678 if ( exists $parser->{POD_HTMLEASY}->{INDEX}{p} ) { 0679 while ( $parser->{POD_HTMLEASY} 0680 ->{INDEX}{l}{ $parser->{POD_HTMLEASY}->{INDEX}{p} } 0681 > ( $level - 1 ) ) 0682 { 0683 last 0684 if !$parser->{POD_HTMLEASY} 0685 ->{INDEX}{b}{ $parser->{POD_HTMLEASY}->{INDEX}{p} }; 0686 $parser->{POD_HTMLEASY}->{INDEX}{p} = $parser->{POD_HTMLEASY} 0687 ->{INDEX}{b}{ $parser->{POD_HTMLEASY}->{INDEX}{p} }; 0688 } 0689 } 0690 } 0691 0692 my $array = []; 0693 0694 $parser->{POD_HTMLEASY}->{INDEX}{l}{$array} = $level; 0695 $parser->{POD_HTMLEASY}->{INDEX}{b}{$array} 0696 = $parser->{POD_HTMLEASY}->{INDEX}{p}; 0697 0698 push @{ $parser->{POD_HTMLEASY}->{INDEX}{p} }, $name, $array; 0699 $parser->{POD_HTMLEASY}->{INDEX}{p} = $array; 0700 0701 return; 0702 0703 } 0704 0705 ############# 0706 # BEGIN_POD # 0707 ############# 0708 0709 # Overrides begin_pod() provided by base class in Pod::Parser 0710 sub begin_pod { 0711 my ($parser) = @_; 0712 0713 if ( $parser->{POD_HTMLEASY_INCLUDE} ) { return; } 0714 0715 delete $parser->{POD_HTMLEASY}->{INDEX}; 0716 $parser->{POD_HTMLEASY}->{INDEX} = { tree => [] }; 0717 0718 return 1; 0719 } 0720 0721 ########### 0722 # END_POD # 0723 ########### 0724 0725 # Overrides end_pod() provided by base class in Pod::Parser 0726 sub end_pod { 0727 my ($parser) = @_; 0728 0729 if ( $parser->{POD_HTMLEASY_INCLUDE} ) { return; } 0730 0731 if ( defined $parser->{POD_HTMLEASY}->{VERBATIM_BUFFER} ) { 0732 _verbatim($parser); 0733 } 0734 0735 my $tree = $parser->{POD_HTMLEASY}->{INDEX}{tree}; 0736 0737 delete $parser->{POD_HTMLEASY}->{INDEX}; 0738 0739 $parser->{POD_HTMLEASY}->{INDEX} = $tree; 0740 0741 return 1; 0742 } 0743 0744 ########### 0745 # _ERRORS # 0746 ########### 0747 0748 sub _errors { 0749 my ( $parser, $error ) = @_; 0750 0751 carp "$error"; 0752 $error =~ s{^\s*\**\s*errors?:?\s*}{}ismx; 0753 $error =~ s{\s+$}{}smx; 0754 0755 my $html = $parser->{POD_HTMLEASY} 0756 ->{ON_ERROR}( $parser->{POD_HTMLEASY}, $error ); 0757 if ( $html ne $EMPTY ) { 0758 print { $parser->output_handle() } $html, $NL; 0759 } 0760 0761 return 1; 0762 } 0763 0764 ########### 0765 # DESTROY # 0766 ########### 0767 0768 sub DESTROY { } 0769 0770 ####### 0771 # END # 0772 ####### 0773 0774 1; 0775 0776 ############################################################################# 0777 ## Name: HtmlEasy.pm 0778 ## Purpose: Pod::HtmlEasy 0779 ## Author: Graciliano M. P. 0780 ## Modified by: Geoffrey Leach 0781 ## Created: 2004-01-11 0782 ## Updated: 2007-02-28 0783 ## Copyright: (c) 2004 Graciliano M. P. 0784 ## Licence: This program is free software; you can redistribute it and/or 0785 ## modify it under the same terms as Perl itself 0786 ############################################################################# 0787 0788 package Pod::HtmlEasy; 0789 use 5.008; 0790 0791 use Carp; 0792 use English qw{ -no_match_vars }; 0793 0794 use strict; 0795 use warnings; 0796 0797 our $VERSION = 0.09; # Also appears in "=head1 VERSION" in the POD below 0798 0799 our $EMPTY = q{}; 0800 our $NL = qq{\n}; 0801 our $NUL = qq{\0}; 0802 our $SPACE = q{ }; 0803 0804 ######## 0805 # VARS # 0806 ######## 0807 0808 my %BODY_DEF = ( 0809 bgcolor => '#FFFFFF', 0810 text => '#000000', 0811 link => '#000000', 0812 vlink => '#000066', 0813 alink => '#FF0000', 0814 ); 0815 0816 # This keeps track of valid options 0817 my %OPTS = ( 0818 basic_entities => 1, 0819 body => 1, 0820 common_entities => 1, 0821 css => 1, 0822 faq_page => 0, 0823 function_page => 0, 0824 index => 1, 0825 index_item => 1, 0826 no_css => 1, 0827 no_generator => 1, 0828 no_index => 1, 0829 only_content => 1, 0830 parserwarn => 1, 0831 title => 1, 0832 top => 1, 0833 ); 0834 0835 my $output_file; 0836 0837 ####### 0838 # CSS # 0839 ####### 0840 0841 my $CSS_DEF = q` 0842 /* 0843 ** HTML elements 0844 */ 0845 0846 body { 0847 margin: 10px; 0848 padding: 0; 0849 text-align: center; 0850 font-size: 0.8em; 0851 font-family: "Bitstream Vera Sans", "Lucida Grande", "Trebuchet MS", sans-serif; 0852 color: #535353; 0853 background: #ffffff; 0854 } 0855 0856 0857 /* 0858 ** HTML Tags 0859 */ 0860 0861 h1, h2, h3, h4 0862 { 0863 padding: 0; 0864 text-align: left; 0865 font-weight: bold; 0866 color: #f7800a; 0867 background: transparent; 0868 } 0869 0870 h1 { 0871 margin: 0 0 0.3em 0; 0872 font-size: 1.7em; 0873 } 0874 0875 h1.name + p { 0876 font-size: larger; 0877 font-style: oblique; 0878 } 0879 0880 h2, h3, h4 { 0881 margin: 1.3em 0 0 0.3em 0882 } 0883 0884 h2 { 0885 font-size: 1.5em; 0886 } 0887 0888 h3 { 0889 font-size: 1.4em; 0890 } 0891 0892 h4 { 0893 font-size: 1.3em; 0894 } 0895 0896 h5 { 0897 font-size: 1.2em; 0898 } 0899 0900 a:link { 0901 padding-bottom: 0; 0902 text-decoration: none; 0903 color: #0057ae; 0904 } 0905 0906 a:visited { 0907 padding-bottom: 0; 0908 text-decoration: none; 0909 color: #644A9B; 0910 } 0911 0912 0913 a[href]:hover { 0914 text-decoration: underline; 0915 } 0916 0917 hr { 0918 margin: 0.3em 1em 0.3em 1em; 0919 height: 1px; 0920 border: #bcbcbc dashed; 0921 border-width: 0 0 1px 0; 0922 } 0923 0924 pre { 0925 display: block; 0926 margin: 0.3em; 0927 padding: 0.3em; 0928 font-size: 1em; 0929 color: #000000; 0930 text-align: left; 0931 background: #f9f9f9; 0932 border: #2f6fab dashed; 0933 border-width: 1px; 0934 overflow: auto; 0935 line-height: 1.1em; 0936 } 0937 0938 input, textarea, select { 0939 margin: 0.2em; 0940 padding: 0.1em; 0941 color: #888888; 0942 background: #ffffff; 0943 border: 1px solid; 0944 } 0945 0946 blockquote { 0947 margin: 0.3em; 0948 padding-left: 2.5em; 0949 background: transparent; 0950 } 0951 0952 del { 0953 color: #800000; 0954 text-decoration: line-through; 0955 } 0956 0957 dt { 0958 font-weight: bold; 0959 font-size: 1.05em; 0960 color: #0057ae; 0961 } 0962 0963 dd { 0964 margin-left: 1em; 0965 } 0966 0967 p { 0968 margin-top: 0.5em; 0969 margin-bottom: 0.9em; 0970 text-align: justify; 0971 } 0972 fieldset { 0973 border: #cccccc 1px solid; 0974 } 0975 0976 li { 0977 text-align: left; 0978 } 0979 0980 fieldset { 0981 margin-bottom: 1em; 0982 padding: .5em; 0983 } 0984 0985 form { 0986 margin: 0; 0987 padding: 0; 0988 } 0989 0990 hr { 0991 height: 1px; 0992 border: #888888 1px solid; 0993 background: #888888; 0994 margin: 0.5em 0 0.5em 0 ; 0995 } 0996 0997 .toc a { 0998 text-decoration: none; 0999 } 1000 1001 .toc li { 1002 list-style-type: none; 1003 line-height: larger; 1004 } 1005 1006 img { 1007 border: 0; 1008 } 1009 1010 table { 1011 border-collapse: collapse; 1012 font-size: 1em; 1013 } 1014 1015 th { 1016 text-align: left; 1017 padding-right: 1em; 1018 border: #cccccc solid; 1019 border-width: 0 0 3px 0; 1020 } 1021 `; 1022 1023 ############### 1024 # DEFAULT_CSS # 1025 ############### 1026 1027 sub default_css { 1028 return $CSS_DEF; 1029 } 1030 1031 ####################### 1032 # _ORGANIZE_CALLBACKS # 1033 ####################### 1034 1035 sub _organize_callbacks { 1036 my $this = shift; 1037 1038 $this->{ON_B} = \&evt_on_B; 1039 $this->{ON_C} = \&evt_on_C; 1040 $this->{ON_E} = \&evt_on_E; 1041 $this->{ON_F} = \&evt_on_F; 1042 $this->{ON_I} = \&evt_on_I; 1043 $this->{ON_L} = \&evt_on_L; 1044 $this->{ON_S} = \&evt_on_S; 1045 $this->{ON_X} = \&evt_on_X; # [20078] 1046 $this->{ON_Z} = \&evt_on_Z; 1047 1048 $this->{ON_HEAD1} = \&evt_on_head1; 1049 $this->{ON_HEAD2} = \&evt_on_head2; 1050 $this->{ON_HEAD3} = \&evt_on_head3; 1051 $this->{ON_HEAD4} = \&evt_on_head4; 1052 1053 $this->{ON_VERBATIM} = \&evt_on_verbatim; 1054 $this->{ON_TEXTBLOCK} = \&evt_on_textblock; 1055 1056 $this->{ON_OVER} = \&evt_on_over; 1057 $this->{ON_ITEM} = \&evt_on_item; 1058 $this->{ON_BACK} = \&evt_on_back; 1059 1060 $this->{ON_FOR} = \&evt_on_for; 1061 $this->{ON_BEGIN} = \&evt_on_begin; 1062 $this->{ON_END} = \&evt_on_end; 1063 1064 $this->{ON_INDEX_NODE_START} = \&evt_on_index_node_start; 1065 $this->{ON_INDEX_NODE_END} = \&evt_on_index_node_end; 1066 1067 $this->{ON_INCLUDE} = \&evt_on_include; 1068 $this->{ON_URI} = \&evt_on_uri; 1069 1070 $this->{ON_ERROR} = \&evt_on_error; 1071 1072 return; 1073 } 1074 1075 ####### 1076 # NEW # 1077 ####### 1078 1079 sub new { 1080 my $this = shift; 1081 return $this if ref $this; 1082 my $class = $this || __PACKAGE__; 1083 $this = bless {}, $class; 1084 1085 my (%args) = @_; 1086 _organize_callbacks($this); 1087 1088 # Backwards compatibility 1089 if ( exists $args{on_verbatin} ) { 1090 $this->{ON_VERBATIM} = $args{on_verbatin}; 1091 } 1092 1093 foreach my $key ( keys %args ) { 1094 1095 # Add in any ON_ callbacks 1096 if ( $key =~ m{^on_(\w+)$}ismx ) { 1097 my $cmd = uc $1; 1098 $this->{qq{ON_$cmd}} = $args{$key}; 1099 } 1100 elsif ( $key =~ m{^(?:=(\w+)|(\w)<>)$}smx ) { 1101 my $cmd = uc $1 || $2; 1102 $this->{$cmd} = $args{$key}; 1103 } 1104 } 1105 1106 return $this; 1107 } 1108 1109 ############ 1110 # POD2HTML # 1111 ############ 1112 1113 sub pod2html { 1114 my $this = shift; 1115 my $file = shift; 1116 1117 # Assume a non-option second arg is a file name 1118 my $save = (exists $OPTS{ $_[0] } ? undef: shift) if defined $_[0]; 1119 my %args = @_; 1120 1121 # Check options for validity 1122 foreach my $key ( keys %args ) { 1123 if ( not exists $OPTS{$key} ) { 1124 carp qq{option $key is not supported}; 1125 } 1126 } 1127 1128 # No /x please 1129 if ( defined $save && $save =~ m{$NL}sm ) { 1130 1131 # Is this a M$ way of saying "nothing there"? 1132 $save = undef; 1133 } 1134 1135 # This will fall through to Pod::Parser::new 1136 # which is the base for Pod::HtmlEasy::Parser 1137 # and Pod::HtmlEasy::Parser does not implement new() 1138 my $parser = Pod::HtmlEasy::Parser->new(); 1139 1140 $parser->errorsub( sub { Pod::HtmlEasy::Parser::errors( $parser, @_ ); } 1141 ); 1142 1143 # Pod::Parser wiii complain about multiple blank lines in the input 1144 # which is moderately annoying 1145 if ( exists $args{parserwarn} ) { $parser->parseopts( -warnings => 1 ); } 1146 1147 # This allows us to search for non-POD stuff is preprocess_paragraph 1148 $parser->parseopts( -want_nonPODs => 1 ); 1149 1150 if (exists $args{'function_page'}) { $parser->setFunctionPage($args{'function_page'}); } 1151 1152 # This puts a subsection in the $parser hash that will record data 1153 # that is "local" to this code. Throughout, $parser will refer to 1154 # Pod::Parser and $this to Pod::HtmlEasy 1155 $parser->{POD_HTMLEASY} = $this; 1156 1157 if ( exists $args{index_item} ) { $parser->{INDEX_ITEM} = 1; } 1158 if ( exists $args{basic_entities} ) { 1159 carp q{"basic_entities" is deprecated.}; 1160 } 1161 if ( exists $args{common_entities} ) { 1162 carp q{"common_entities" is deprecated.}; 1163 } 1164 1165 # *HTML supplies a PRINT method that's used by the parser to do output 1166 # It gets accumulated into HTML, which is tied to $output. 1167 # You'll also see calls to print {$parser->output_handle()} ... 1168 # which accomplishes the same thing. When all is said and done, the output 1169 # of the parse winds up in $output declared below, and used in the construction 1170 # of @html. 1171 1172 my $output = []; 1173 local *HTML; 1174 tie *HTML => 'Pod::HtmlEasy::TieHandler', $output; 1175 my $html = \*HTML; 1176 $this->{TIEDOUTPUT} = $html; 1177 1178 my $title = $args{title}; 1179 if ( ref $file eq q{GLOB} ) { # $file is an open filehandle 1180 if ( not defined $title ) { $title = q{<DATA>}; } 1181 } 1182 else { 1183 if ( !-e $file ) { 1184 carp qq{No file $file}; 1185 return; 1186 } 1187 if ( not defined $title ) { $title = $file; } 1188 } 1189 1190 # Build the header to the HTML file 1191 my @html; 1192 push @html, 1193 qq{<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">$NL}; 1194 push @html, qq{<html><head>$NL}; 1195 push @html, 1196 qq{<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">$NL}; 1197 1198 if ( not exists $args{no_generator} ) { 1199 push @html, 1200 qq{<meta name="GENERATOR" content="kio_perldoc Pod::HtmlEasy/$VERSION Pod::Parser/$Pod::Parser::VERSION Perl/$] [$^O]">$NL}; 1201 } 1202 push @html, qq{<title>$title</title>$NL}; 1203 my $title_line_ref = \$html[-1]; 1204 push @html, _organize_css( \%args ); 1205 push @html, qq{</head>$NL}; 1206 if ( not exists $args{only_content} ) { 1207 push @html, _organize_body( \%args ); 1208 } 1209 1210 delete $this->{UPARROW}; 1211 delete $this->{UPARROW_FILE}; 1212 push @html, qq{<div id="header"><div id="header_top"><div><div>$NL}; 1213 push @html, qq{<img src="help:/kdoctools5-common/part_of_the_kde_family_horizontal_190.png" alt="Part of the KDE family"> $title - KDE Perldoc Viewer</div></div></div></div>}; 1214 push @html, q{<div class="pod">}; 1215 1216 if ( exists $args{top} ) { 1217 push @html, qq{$NL<a name='_top'></a>$NL}; 1218 if ( -e $args{top} ) { 1219 $this->{UPARROW_FILE} = $args{top}; 1220 } 1221 else { 1222 $this->{UPARROW} = $args{top}; 1223 } 1224 } 1225 1226 if ($args{'faq_page'}) { 1227 push @html, qq{$NL<p>The following FAQ results were found:</p>$NL}; 1228 } 1229 1230 # Avoid carry-over on multiple files 1231 delete $this->{IN_BEGIN}; 1232 delete $this->{PACKAGE}; 1233 delete $this->{TITLE}; 1234 delete $this->{VERSION}; 1235 $this->{INFO_COUNT} = 0; 1236 1237 # A filehandle as both args is not documented, but is supported 1238 # Everything that Pod::Parser prints winds up in $output 1239 $parser->parse_from_file( $file, $html ); 1240 1241 # If there's a head1 NAME, we've picked this up during processing 1242 if ( defined $this->{TITLE} && length $this->{TITLE} > 0 ) { 1243 ${$title_line_ref} = qq{<title>$this->{TITLE}</title>$NL}; 1244 } 1245 1246 # Note conflict here: user can specify an index, and no_index; no_index wins 1247 if ( not exists $args{index} ) { $args{index} = $this->build_index(); } 1248 if ( exists $args{no_index} ) { $args{index} = $EMPTY; } 1249 1250 if ( $args{'faq_page'} && not @{$output} ) { 1251 @{$output} = ("<b>None</b>"); 1252 } 1253 1254 my $kio_perldoc_version = $ENV{'KIO_PERLDOC_VERSION'} || "Unknown"; 1255 1256 push @html, qq{$args{index}$NL}; 1257 push @html, @{$output}; # The pod converted to HTML 1258 push @html, qq{</div><div id="footer"><div id="footer_text">Generated by kio_perldoc, version $kio_perldoc_version</div></div>}; 1259 push @html, qq{</body></html>$NL}; 1260 1261 delete $this->{TIEDOUTPUT}; 1262 close $html or carp q{Could not close html}; 1263 untie $html or carp q{Could not untie html}; 1264 1265 if ( defined $save ) { 1266 open my $out, q{>}, $save or croak qq{Unable to open $save - $!}; 1267 print {$out} @html; 1268 close $out; 1269 } 1270 1271 return wantarray ? @html : join $EMPTY, @html; 1272 } 1273 1274 ################# 1275 # PARSE_INCLUDE # 1276 ################# 1277 1278 sub parse_include { 1279 my $this = shift; 1280 my $file = shift; 1281 1282 my $parser = Pod::HtmlEasy::Parser->new(); 1283 $parser->errorsub( sub { Pod::HtmlEasy::Parser::errors( $parser, @_ ); } 1284 ); 1285 $parser->{POD_HTMLEASY} = $this; 1286 $parser->{POD_HTMLEASY_INCLUDE} = 1; 1287 1288 $parser->parse_from_file( $file, $this->{TIEDOUTPUT} ); 1289 1290 return 1; 1291 } 1292 1293 ############## 1294 # WALK_INDEX # 1295 ############## 1296 1297 sub walk_index { 1298 my ( $this, $tree, $on_open, $on_close, $output ) = @_; 1299 1300 my $i = 0; 1301 while ( $i < @{$tree} ) { 1302 my $nk = 1303 ref( ${$tree}[ $i + 1 ] ) eq q{ARRAY} 1304 ? @{ ${$tree}[ $i + 1 ] } 1305 : undef; 1306 $nk = $nk >= 1 ? 1 : undef; 1307 1308 my $a_name = ${$tree}[$i]; 1309 $a_name =~ s{<.*?>}{}gsmx; 1310 1311 #$a_name =~ s{&\w+;}{}gsmx; 1312 #$a_name =~ s{\W+}{-}gsmx; 1313 1314 if ($on_open) { 1315 my $ret = $on_open->( $this, ${$tree}[$i], $a_name, $nk ); 1316 if ( $output and defined $ret ) { 1317 ${$output} .= $ret; 1318 } # [6062] 1319 } 1320 1321 if ($nk) { 1322 walk_index( $this, ${$tree}[ $i + 1 ], 1323 $on_open, $on_close, $output ); 1324 } 1325 1326 if ($on_close) { 1327 my $ret = $on_close->( $this, ${$tree}[$i], $a_name, $nk ); 1328 if ( $output and defined $ret ) { 1329 ${$output} .= $ret; 1330 } # [6062] 1331 } 1332 $i += 2; 1333 } 1334 return; 1335 } 1336 1337 ############### 1338 # BUILD_INDEX # 1339 ############### 1340 1341 sub build_index { 1342 my $this = shift; 1343 1344 my $index = $EMPTY; # [6062] 1345 $this->walk_index( 1346 $this->{INDEX}, 1347 $this->{ON_INDEX_NODE_START}, 1348 $this->{ON_INDEX_NODE_END}, \$index 1349 ); 1350 1351 return qq{<div class="toc">$NL<ul>$NL$index</ul>$NL</div>$NL}; 1352 } 1353 1354 ################# 1355 # _ORGANIZE_BODY # 1356 ################# 1357 1358 sub _organize_body { 1359 my $args_ref = shift; 1360 1361 my ( $body, %body ); 1362 1363 $body = $EMPTY; 1364 if ( ref $args_ref->{body} eq q{HASH} ) { 1365 %body = %BODY_DEF; 1366 my %body_attr = %{ $args_ref->{body} }; 1367 foreach my $key ( keys %body_attr ) { 1368 $body{$key} = $body_attr{$key}; 1369 } 1370 } 1371 elsif ( !exists $args_ref->{body} ) { %body = %BODY_DEF; } 1372 1373 if (%body) { 1374 foreach my $key ( sort keys %body ) { 1375 if ( $body{$key} !~ m{\#}smx && defined $BODY_DEF{$key} ) { 1376 $body{$key} = qq{#$body{$key}}; 1377 } 1378 my $value = 1379 $body{$key} !~ m{"}smx 1380 ? qq{"$body{$key}"} 1381 : qq{'$body{$key}'}; 1382 $body .= qq{ $key=$value}; 1383 } 1384 } 1385 else { $body = $args_ref->{body}; } 1386 1387 return qq{<body $body>}; 1388 } 1389 1390 ################ 1391 # ORGANIZE_CSS # 1392 ################ 1393 1394 sub _organize_css { 1395 my $perldoc_css = $ENV{'KIO_PERLDOC_CSSLOCATION'}; 1396 chomp $perldoc_css; 1397 1398 return <<"EOL"; 1399 <link rel="stylesheet" href="help:/kdoctools5-common/kde-default.css" type="text/css"> 1400 <link rel="stylesheet" href="file://$perldoc_css" type="text/css"> 1401 <style> 1402 #header_top { 1403 background-image: url("help:/kdoctools5-common/top.jpg"); 1404 } 1405 #header_top div { 1406 background-image: url("help:/kdoctools5-common/top-left.jpg"); 1407 } 1408 #header_top div div { 1409 background-image: url("help:/kdoctools5-common/top-right.jpg"); 1410 } 1411 div.pod { 1412 margin-left: 5em; 1413 margin-right: 5em; 1414 } 1415 </style> 1416 EOL 1417 } 1418 1419 ################## 1420 # EVENT SUPPORT # 1421 ################## 1422 1423 sub do_title { 1424 my $this = shift; 1425 my ( $txt, $a_name ) = @_; 1426 1427 # This happens only on the _first_ head1 NAME 1428 if ( ( not exists $this->{TITLE} ) and ( $txt =~ m{\ANAME}smx ) ) { 1429 my ($title) = $txt =~ m{\ANAME\s+(.*)}smx; 1430 if ( defined $title ) { 1431 1432 # Oh, goody 1433 $title =~ s{^\s*}{}gsmx; # delete surrounding whitespace 1434 $title =~ s{\s*$}{}gsmx; # delete surrounding whitespace 1435 $this->{TITLE} = $title; 1436 } 1437 else { 1438 1439 # If we don't get anything off of NAME, it will be filled in by preprocess_paragraph() 1440 $this->{TITLE} = undef; 1441 } 1442 } 1443 return; 1444 } 1445 1446 ################## 1447 # DEFAULT EVENTS # 1448 ################## 1449 1450 sub evt_on_head1 { 1451 my $this = shift; 1452 my ( $txt, $a_name ) = @_; 1453 1454 if ( not defined $txt ) { $txt = $EMPTY; } 1455 1456 do_title( $this, $txt, $a_name ); 1457 1458 if ( exists $this->{UPARROW_FILE} ) { 1459 return "<h1><a href='#_top' 1460 title='click to go to top of document' 1461 name='$a_name'>$txt<img src='$this->{UPARROW_FILE}' 1462 alt=⇑></a></h1>$NL"; 1463 } 1464 elsif ( exists $this->{UPARROW} ) { 1465 return qq{<h1><a href='#_top' 1466 title='click to go to top of document' 1467 name='$a_name'>$txt&$this->{UPARROW};</a></h1>$NL}; 1468 } 1469 1470 my $style = ''; 1471 $style = 'class="name"' if $txt =~ m{\ANAME}; 1472 1473 return qq{<a name='$a_name'></a><h1 $style>$txt</h1>$NL}; 1474 } 1475 1476 sub evt_on_head2 { 1477 my $this = shift; 1478 my ( $txt, $a_name ) = @_; 1479 return qq{<a name='$a_name'></a><h2>$txt</h2>$NL$NL}; 1480 } 1481 1482 sub evt_on_head3 { 1483 my $this = shift; 1484 my ( $txt, $a_name ) = @_; 1485 return qq{<a name='$a_name'></a><h3>$txt</h3>$NL$NL}; 1486 } 1487 1488 sub evt_on_head4 { 1489 my $this = shift; 1490 my ( $txt, $a_name ) = @_; 1491 return qq{<a name='$a_name'></a><h4>$txt</h4>$NL$NL}; 1492 } 1493 1494 sub evt_on_begin { 1495 my $this = shift; 1496 my ( $txt, $a_name ) = @_; 1497 $this->{IN_BEGIN} = 1; 1498 return $EMPTY; 1499 } 1500 1501 sub evt_on_end { 1502 my $this = shift; 1503 my ( $txt, $a_name ) = @_; 1504 delete $this->{IN_BEGIN}; 1505 return $EMPTY; 1506 } 1507 1508 sub evt_on_L { 1509 my ($this, $L, $text, $page, $section, $type, $fnPage) = @_; 1510 1511 Pod::HtmlEasy::Parser::_encode_entities(\$page); 1512 1513 if($type eq 'pod') { 1514 $page = '' unless defined $page; 1515 1516 if($fnPage and not $page) { 1517 $page = "functions/"; 1518 $section = "" unless defined $section; 1519 } 1520 else { 1521 $section = defined $section ? "#$section" : ""; 1522 } 1523 1524 # Keep later escaping functions from incorrectly messing this up. 1525 $section =~ s/^(.)/$1$NUL/; 1526 1527 # The browser knows what to do for simple links in the same page, 1528 # and knows how to do it better than we do. 1529 return "<a href=\"$section\">$text</a>" unless $page; 1530 1531 $page =~ s/^(.)/$1$NUL/; 1532 return "<a href=\"perldoc:$page$section\">$text</a>"; 1533 } 1534 elsif($type eq 'man') { 1535 return "<a href=\"man:/$page\">$text</a>"; 1536 } 1537 elsif($type eq 'url') { 1538 # Keep later escaping functions from incorrectly messing this up. 1539 $page =~ s/^(.)/$1$NUL/; 1540 $text =~ s/^(.)/$1$NUL/; 1541 1542 return "<a href=\"$page\" target=\"_blank\">$text</a>"; 1543 } 1544 } 1545 1546 sub evt_on_B { 1547 my $this = shift; 1548 my $txt = shift; 1549 return qq{<b>$txt</b>}; 1550 } 1551 1552 sub evt_on_I { 1553 my $this = shift; 1554 my $txt = shift; 1555 return qq{<i>$txt</i>}; 1556 } 1557 1558 sub evt_on_C { 1559 my $this = shift; 1560 my $txt = shift; 1561 1562 # Who would put IMG tags in this? 1563 return $EMPTY if $txt =~ m{<IMG}i; 1564 return "<tt>$txt</tt>"; 1565 } 1566 1567 sub evt_on_E { 1568 my $this = shift; 1569 my $txt = shift; 1570 1571 # Hey guess what, not all &foo; entities are part of HTML! So don't go 1572 # throwing them out without checking. 1573 return "/" if $txt eq '/'; 1574 1575 $txt =~ s{^&}{}smx; 1576 $txt =~ s{;$}{}smx; 1577 if ( $txt =~ m{^\d+$}smx ) { $txt = qq{#$txt}; } 1578 return qq{$NUL&$txt;}; 1579 } 1580 1581 sub evt_on_F { 1582 my $this = shift; 1583 my $txt = shift; 1584 1585 # Some pod encoders put hyperlinks in F<>?? 1586 return qq{<a href="$txt">$txt</a>} if $txt =~ m'^http://'; 1587 return qq{<b><i>$txt</i></b>}; 1588 } 1589 1590 sub evt_on_S { 1591 my $this = shift; 1592 my $txt = shift; 1593 $txt =~ s{$SPACE}{ }gs; 1594 return $txt; 1595 } 1596 1597 sub evt_on_X { return $EMPTY; } # [20078] 1598 1599 sub evt_on_Z { return $EMPTY; } 1600 1601 sub evt_on_verbatim { 1602 my $this = shift; 1603 my $txt = shift; 1604 1605 return if exists $this->{IN_BEGIN}; 1606 1607 # Multiple empty lines are parsed as verbatim text by Pod::Parser 1608 # And will show up as empty <pre> blocks, which is mucho messy 1609 { 1610 local $RS = $EMPTY; 1611 chomp $txt; 1612 } 1613 1614 if ( not length $txt ) { return $EMPTY; } 1615 return qq{<pre>$txt</pre>$NL}; 1616 } 1617 1618 sub evt_on_textblock { 1619 my $this = shift; 1620 my $txt = shift; 1621 return if exists $this->{IN_BEGIN}; 1622 return qq{<p>$txt</p>$NL}; 1623 } 1624 1625 sub evt_on_over { 1626 my $this = shift; 1627 my $level = shift; 1628 return qq{<ul>$NL}; 1629 } 1630 1631 sub evt_on_item { 1632 my $this = shift; 1633 my ( $txt, $a_name ) = @_; 1634 1635 # POD has no list item tag, so most authors simulate it, breaking the HTML. 1636 # So, strip out most bullet characters. 1637 $txt =~ s/^\s*[\*oO\+\-\.](?!\S)//; 1638 1639 # If POD authors are going so far as to number the list, it's already too 1640 # late to fix it by using <ol> tag, but we can change the CSS style. 1641 my $style = ''; 1642 if ($txt =~ m/^\d+\.?/) { 1643 $style = qq{ style="list-style-type:decimal;"}; 1644 $txt =~ s/^\d+\.?\s*//; 1645 } 1646 1647 return qq{<li$style>$NL} if $txt =~ /^\s*$/; 1648 return qq{<li$style><a name='$a_name'></a><b>$txt</b></li>$NL}; 1649 } 1650 1651 sub evt_on_back { 1652 my $this = shift; 1653 return qq{</ul>$NL}; 1654 } 1655 1656 sub evt_on_for { return $EMPTY; } 1657 1658 sub evt_on_error { 1659 my $this = shift; 1660 my $txt = shift; 1661 return qq{<!-- POD_ERROR: $txt -->}; 1662 } 1663 1664 sub evt_on_include { 1665 my $this = shift; 1666 my $file = shift; 1667 return $file; 1668 } 1669 1670 sub evt_on_uri { 1671 my $this = shift; 1672 my $uri = shift; 1673 my $target = 1674 $uri !~ m{^(?:mailto|telnet|ssh|irc):}ismx 1675 ? q{ target='_blank'} 1676 : $EMPTY; # [6062] 1677 my $txt = $uri; 1678 $txt =~ s{^mailto:}{}ismx; 1679 return qq{<a href='$uri'$target>$txt</a>}; 1680 } 1681 1682 sub evt_on_index_node_start { 1683 my $this = shift; 1684 my ( $txt, $a_name, $has_children ) = @_; 1685 1686 my $ret = qq{<li><a href='#$a_name'>$txt</a>$NL}; 1687 if ($has_children) { 1688 $ret .= qq{$NL<ul>$NL}; 1689 } 1690 return $ret; 1691 } 1692 1693 sub evt_on_index_node_end { 1694 my $this = shift; 1695 my ( $txt, $a_name, $has_children ) = @_; 1696 1697 my $ret = $has_children ? q{</ul>} : undef; 1698 return $ret; 1699 } 1700 1701 ############## 1702 # PM_VERSION # 1703 ############## 1704 1705 sub pm_version { 1706 my $this = ref( $_[0] ) ? shift: undef; 1707 if ( not defined $this ) { 1708 carp q{pm_version must be referenced through Pod::HtmlEasy}; 1709 return; 1710 } 1711 1712 return $this->{VERSION}; 1713 } 1714 1715 ############## 1716 # PM_PACKAGE # 1717 ############## 1718 1719 sub pm_package { 1720 my $this = ref( $_[0] ) ? shift: undef; 1721 if ( not defined $this ) { 1722 carp q{pm_package must be referenced through Pod::HtmlEasy}; 1723 return; 1724 } 1725 1726 return $this->{PACKAGE}; 1727 } 1728 1729 ########### 1730 # PM_NAME # 1731 ########### 1732 1733 sub pm_name { 1734 my $this = ref( $_[0] ) ? shift: undef; 1735 if ( not defined $this ) { 1736 carp q{pm_name must be referenced through Pod::HtmlEasy}; 1737 return; 1738 } 1739 return $this->{TITLE}; 1740 } 1741 1742 ########################### 1743 # PM_PACKAGE_VERSION_NAME # 1744 ########################### 1745 1746 sub pm_package_version_name { 1747 my $this = ref( $_[0] ) ? shift: undef; 1748 if ( not defined $this ) { 1749 carp 1750 q{pm_package_version_name must be referenced through Pod::HtmlEasy}; 1751 return; 1752 } 1753 1754 return ( $this->pm_package(), $this->pm_version(), $this->pm_name() ); 1755 } 1756 1757 ####### 1758 # END # 1759 ####### 1760 1761 1; 1762 1763 package main; 1764 1765 # Pass argv to perldoc, which we will redirect the output of perldoc to this 1766 # process. This syntax only works in Perl 5.8 and higher, but that's OK, the 1767 # rest of the code also requires Perl 5.8. 1768 open my $perlDocInput, "-|", qw/perldoc -u -T/, @ARGV 1769 or die "Unable to open pipe: $!"; 1770 1771 my $usingFunctionPage = 0; 1772 if(exists $ARGV[0] and $ARGV[0] eq '-f') 1773 { 1774 # Looking for a function, rewrite some URLs that refer to other functions 1775 # on the same page. 1776 $usingFunctionPage = 1; 1777 } 1778 1779 my $podhtml = Pod::HtmlEasy->new(); 1780 1781 print $podhtml->pod2html($perlDocInput, 1782 'function_page'=>$usingFunctionPage, 1783 'faq_page' => exists $ARGV[0] && $ARGV[0] eq '-q', 1784 title=>"$ARGV[-1]"), "\n";