1898184e3Ssthenrequire 5.006; 2898184e3Ssthenpackage Pod::Perldoc::ToMan; 3898184e3Ssthenuse strict; 4898184e3Ssthenuse warnings; 5898184e3Ssthenuse parent qw(Pod::Perldoc::BaseTo); 6898184e3Ssthen 7898184e3Ssthenuse vars qw($VERSION); 89f11ffb7Safresh1$VERSION = '3.28'; 9898184e3Ssthen 10898184e3Ssthenuse File::Spec::Functions qw(catfile); 11898184e3Ssthenuse Pod::Man 2.18; 12898184e3Ssthen# This class is unlike ToText.pm et al, because we're NOT paging thru 13898184e3Ssthen# the output in our particular format -- we make the output and 14898184e3Ssthen# then we run nroff (or whatever) on it, and then page thru the 15898184e3Ssthen# (plaintext) output of THAT! 16898184e3Ssthen 17898184e3Ssthensub SUCCESS () { 1 } 18898184e3Ssthensub FAILED () { 0 } 19898184e3Ssthen 20898184e3Ssthensub is_pageable { 1 } 21898184e3Ssthensub write_with_binmode { 0 } 22898184e3Ssthensub output_extension { 'txt' } 23898184e3Ssthen 24898184e3Ssthensub __filter_nroff { shift->_perldoc_elem('__filter_nroff' , @_) } 25898184e3Ssthensub __nroffer { shift->_perldoc_elem('__nroffer' , @_) } 26898184e3Ssthensub __bindir { shift->_perldoc_elem('__bindir' , @_) } 27898184e3Ssthensub __pod2man { shift->_perldoc_elem('__pod2man' , @_) } 28898184e3Ssthensub __output_file { shift->_perldoc_elem('__output_file' , @_) } 29898184e3Ssthen 30898184e3Ssthensub center { shift->_perldoc_elem('center' , @_) } 31898184e3Ssthensub date { shift->_perldoc_elem('date' , @_) } 32898184e3Ssthensub fixed { shift->_perldoc_elem('fixed' , @_) } 33898184e3Ssthensub fixedbold { shift->_perldoc_elem('fixedbold' , @_) } 34898184e3Ssthensub fixeditalic { shift->_perldoc_elem('fixeditalic' , @_) } 35898184e3Ssthensub fixedbolditalic { shift->_perldoc_elem('fixedbolditalic', @_) } 36898184e3Ssthensub name { shift->_perldoc_elem('name' , @_) } 37898184e3Ssthensub quotes { shift->_perldoc_elem('quotes' , @_) } 38898184e3Ssthensub release { shift->_perldoc_elem('release' , @_) } 39898184e3Ssthensub section { shift->_perldoc_elem('section' , @_) } 40898184e3Ssthen 41898184e3Ssthensub new { 42898184e3Ssthen my( $either ) = shift; 43898184e3Ssthen my $self = bless {}, ref($either) || $either; 44898184e3Ssthen $self->init( @_ ); 45898184e3Ssthen return $self; 46898184e3Ssthen } 47898184e3Ssthen 48898184e3Ssthensub init { 49898184e3Ssthen my( $self, @args ) = @_; 50898184e3Ssthen 51898184e3Ssthen unless( $self->__nroffer ) { 52898184e3Ssthen my $roffer = $self->_find_roffer( $self->_roffer_candidates ); 53898184e3Ssthen $self->debug( "Using $roffer\n" ); 54898184e3Ssthen $self->__nroffer( $roffer ); 55898184e3Ssthen } 56898184e3Ssthen else { 57898184e3Ssthen $self->debug( "__nroffer is " . $self->__nroffer() . "\n" ); 58898184e3Ssthen } 59898184e3Ssthen 60898184e3Ssthen $self->_check_nroffer; 61898184e3Ssthen } 62898184e3Ssthen 63898184e3Ssthensub _roffer_candidates { 64898184e3Ssthen my( $self ) = @_; 65898184e3Ssthen 669f11ffb7Safresh1 if( $self->is_openbsd || $self->is_freebsd || $self->is_bitrig ) { qw( mandoc groff nroff ) } 67898184e3Ssthen else { qw( groff nroff mandoc ) } 68898184e3Ssthen } 69898184e3Ssthen 70898184e3Ssthensub _find_roffer { 71898184e3Ssthen my( $self, @candidates ) = @_; 72898184e3Ssthen 73898184e3Ssthen my @found = (); 74898184e3Ssthen foreach my $candidate ( @candidates ) { 75898184e3Ssthen push @found, $self->_find_executable_in_path( $candidate ); 76898184e3Ssthen } 77898184e3Ssthen 78898184e3Ssthen return wantarray ? @found : $found[0]; 79898184e3Ssthen } 80898184e3Ssthen 81898184e3Ssthensub _check_nroffer { 82898184e3Ssthen return 1; 83898184e3Ssthen # where is it in the PATH? 84898184e3Ssthen 85898184e3Ssthen # is it executable? 86898184e3Ssthen 87898184e3Ssthen # what is its real name? 88898184e3Ssthen 89898184e3Ssthen # what is its version? 90898184e3Ssthen 91898184e3Ssthen # does it support the flags we need? 92898184e3Ssthen 93898184e3Ssthen # is it good enough for us? 94898184e3Ssthen } 95898184e3Ssthen 96898184e3Ssthensub _get_stty { `stty -a` } 97898184e3Ssthen 98898184e3Ssthensub _get_columns_from_stty { 99898184e3Ssthen my $output = $_[0]->_get_stty; 100898184e3Ssthen 101898184e3Ssthen if( $output =~ /\bcolumns\s+(\d+)/ ) { return $1 } 102898184e3Ssthen elsif( $output =~ /;\s*(\d+)\s+columns;/ ) { return $1 } 103898184e3Ssthen else { return 0 } 104898184e3Ssthen } 105898184e3Ssthen 106898184e3Ssthensub _get_columns_from_manwidth { 107898184e3Ssthen my( $self ) = @_; 108898184e3Ssthen 109898184e3Ssthen return 0 unless defined $ENV{MANWIDTH}; 110898184e3Ssthen 111898184e3Ssthen unless( $ENV{MANWIDTH} =~ m/\A\d+\z/ ) { 112898184e3Ssthen $self->warn( "Ignoring non-numeric MANWIDTH ($ENV{MANWIDTH})\n" ); 113898184e3Ssthen return 0; 114898184e3Ssthen } 115898184e3Ssthen 116898184e3Ssthen if( $ENV{MANWIDTH} == 0 ) { 117898184e3Ssthen $self->warn( "Ignoring MANWIDTH of 0. Really? Why even run the program? :)\n" ); 118898184e3Ssthen return 0; 119898184e3Ssthen } 120898184e3Ssthen 121898184e3Ssthen if( $ENV{MANWIDTH} =~ m/\A(\d+)\z/ ) { return $1 } 122898184e3Ssthen 123898184e3Ssthen return 0; 124898184e3Ssthen } 125898184e3Ssthen 126898184e3Ssthensub _get_default_width { 127898184e3Ssthen 73 128898184e3Ssthen } 129898184e3Ssthen 130898184e3Ssthensub _get_columns { 131898184e3Ssthen $_[0]->_get_columns_from_manwidth || 132898184e3Ssthen $_[0]->_get_columns_from_stty || 133898184e3Ssthen $_[0]->_get_default_width; 134898184e3Ssthen } 135898184e3Ssthen 136898184e3Ssthensub _get_podman_switches { 137898184e3Ssthen my( $self ) = @_; 138898184e3Ssthen 139e5157e49Safresh1 my @switches = map { $_, $self->{$_} } grep !m/^_/s, keys %$self; 140898184e3Ssthen 141af9ddab1Sschwarze # There needs to be a cleaner way to handle setting 142af9ddab1Sschwarze # the UTF-8 flag, but for now, comment out this 143af9ddab1Sschwarze # line because it often does the wrong thing. 144af9ddab1Sschwarze # 145af9ddab1Sschwarze # See RT #77465 146af9ddab1Sschwarze # 147*fac98b93Safresh1 # Then again, do *not* comment it out on OpenBSD: 148*fac98b93Safresh1 # mandoc handles UTF-8 input just fine. 149*fac98b93Safresh1 push @switches, 'utf8' => 1; 150af9ddab1Sschwarze 151898184e3Ssthen $self->debug( "Pod::Man switches are [@switches]\n" ); 152898184e3Ssthen 153898184e3Ssthen return @switches; 154898184e3Ssthen } 155898184e3Ssthen 156898184e3Ssthensub _parse_with_pod_man { 157898184e3Ssthen my( $self, $file ) = @_; 158898184e3Ssthen 159898184e3Ssthen #->output_fh and ->output_string from Pod::Simple aren't 160898184e3Ssthen # working, apparently, so there's this ugly hack: 161898184e3Ssthen local *STDOUT; 162898184e3Ssthen open STDOUT, '>', $self->{_text_ref}; 163898184e3Ssthen my $parser = Pod::Man->new( $self->_get_podman_switches ); 164898184e3Ssthen $self->debug( "Parsing $file\n" ); 165898184e3Ssthen $parser->parse_from_file( $file ); 166898184e3Ssthen $self->debug( "Done parsing $file\n" ); 167898184e3Ssthen close STDOUT; 168898184e3Ssthen 169898184e3Ssthen $self->die( "No output from Pod::Man!\n" ) 170898184e3Ssthen unless length $self->{_text_ref}; 171898184e3Ssthen 172898184e3Ssthen $self->_save_pod_man_output if $self->debugging; 173898184e3Ssthen 174898184e3Ssthen return SUCCESS; 175898184e3Ssthen } 176898184e3Ssthen 177898184e3Ssthensub _save_pod_man_output { 178898184e3Ssthen my( $self, $fh ) = @_; 179898184e3Ssthen 180898184e3Ssthen $fh = do { 181898184e3Ssthen my $file = "podman.out.$$.txt"; 182898184e3Ssthen $self->debug( "Writing $file with Pod::Man output\n" ); 183898184e3Ssthen open my $fh2, '>', $file; 184898184e3Ssthen $fh2; 185898184e3Ssthen } unless $fh; 186898184e3Ssthen 187898184e3Ssthen print { $fh } ${ $self->{_text_ref} }; 188898184e3Ssthen } 189898184e3Ssthen 190898184e3Ssthensub _have_groff_with_utf8 { 191898184e3Ssthen my( $self ) = @_; 192898184e3Ssthen 193898184e3Ssthen return 0 unless $self->_is_groff; 194898184e3Ssthen my $roffer = $self->__nroffer; 195898184e3Ssthen 196898184e3Ssthen my $minimum_groff_version = '1.20.1'; 197898184e3Ssthen 198898184e3Ssthen my $version_string = `$roffer -v`; 199898184e3Ssthen my( $version ) = $version_string =~ /\(?groff\)? version (\d+\.\d+(?:\.\d+)?)/; 200898184e3Ssthen $self->debug( "Found groff $version\n" ); 201898184e3Ssthen 202898184e3Ssthen # is a string comparison good enough? 203898184e3Ssthen if( $version lt $minimum_groff_version ) { 204898184e3Ssthen $self->warn( 205898184e3Ssthen "You have an old groff." . 206898184e3Ssthen " Update to version $minimum_groff_version for good Unicode support.\n" . 207898184e3Ssthen "If you don't upgrade, wide characters may come out oddly.\n" 208898184e3Ssthen ); 209898184e3Ssthen } 210898184e3Ssthen 211898184e3Ssthen $version ge $minimum_groff_version; 212898184e3Ssthen } 213898184e3Ssthen 214898184e3Ssthensub _collect_nroff_switches { 215898184e3Ssthen my( $self ) = shift; 216898184e3Ssthen 217e5157e49Safresh1 my @render_switches = ('-man', $self->_get_device_switches); 218898184e3Ssthen 219898184e3Ssthen # Thanks to Brendan O'Dea for contributing the following block 220e5157e49Safresh1 if( $self->_is_roff and -t STDOUT and my ($cols) = $self->_get_columns ) { 221898184e3Ssthen my $c = $cols * 39 / 40; 222898184e3Ssthen $cols = $c > $cols - 2 ? $c : $cols -2; 223898184e3Ssthen push @render_switches, '-rLL=' . (int $c) . 'n' if $cols > 80; 224898184e3Ssthen } 225898184e3Ssthen 226*fac98b93Safresh1 if( $self->_is_mandoc ) { 227*fac98b93Safresh1 push @render_switches, '-Owidth=' . $self->_get_columns; 228*fac98b93Safresh1 } 229*fac98b93Safresh1 230898184e3Ssthen # I hear persistent reports that adding a -c switch to $render 231898184e3Ssthen # solves many people's problems. But I also hear that some mans 232898184e3Ssthen # don't have a -c switch, so that unconditionally adding it here 233898184e3Ssthen # would presumably be a Bad Thing -- sburke@cpan.org 234898184e3Ssthen push @render_switches, '-c' if( $self->_is_roff and $self->is_cygwin ); 235898184e3Ssthen 236898184e3Ssthen return @render_switches; 237898184e3Ssthen } 238898184e3Ssthen 239898184e3Ssthensub _get_device_switches { 240898184e3Ssthen my( $self ) = @_; 241898184e3Ssthen 242898184e3Ssthen if( $self->_is_nroff ) { qw() } 243898184e3Ssthen elsif( $self->_have_groff_with_utf8 ) { qw(-Kutf8 -Tutf8) } 244898184e3Ssthen elsif( $self->_is_ebcdic ) { qw(-Tcp1047) } 245898184e3Ssthen elsif( $self->_is_mandoc ) { qw() } 246898184e3Ssthen else { qw(-Tlatin1) } 247898184e3Ssthen } 248898184e3Ssthen 249898184e3Ssthensub _is_roff { 250898184e3Ssthen my( $self ) = @_; 251898184e3Ssthen 252898184e3Ssthen $self->_is_nroff or $self->_is_groff; 253898184e3Ssthen } 254898184e3Ssthen 255898184e3Ssthensub _is_nroff { 256898184e3Ssthen my( $self ) = @_; 257898184e3Ssthen 258898184e3Ssthen $self->__nroffer =~ /\bnroff\b/; 259898184e3Ssthen } 260898184e3Ssthen 261898184e3Ssthensub _is_groff { 262898184e3Ssthen my( $self ) = @_; 263898184e3Ssthen 264898184e3Ssthen $self->__nroffer =~ /\bgroff\b/; 265898184e3Ssthen } 266898184e3Ssthen 267898184e3Ssthensub _is_mandoc { 268898184e3Ssthen my ( $self ) = @_; 269898184e3Ssthen 270898184e3Ssthen $self->__nroffer =~ /\bmandoc\b/; 271898184e3Ssthen } 272898184e3Ssthen 273898184e3Ssthensub _is_ebcdic { 274898184e3Ssthen my( $self ) = @_; 275898184e3Ssthen 276898184e3Ssthen return 0; 277898184e3Ssthen } 278898184e3Ssthen 279898184e3Ssthensub _filter_through_nroff { 280898184e3Ssthen my( $self ) = shift; 281898184e3Ssthen $self->debug( "Filtering through " . $self->__nroffer() . "\n" ); 282898184e3Ssthen 283898184e3Ssthen # Maybe someone set rendering switches as part of the opt_n value 284898184e3Ssthen # Deal with that here. 285898184e3Ssthen 286e9ce3842Safresh1 my ($render, $switches) = $self->__nroffer() =~ /\A([\/a-zA-Z0-9_\.-]+)\b(.+)?\z/; 287898184e3Ssthen 288898184e3Ssthen $self->die("no nroffer!?") unless $render; 289898184e3Ssthen my @render_switches = $self->_collect_nroff_switches; 290898184e3Ssthen 291898184e3Ssthen if ( $switches ) { 292898184e3Ssthen # Eliminate whitespace 293898184e3Ssthen $switches =~ s/\s//g; 294898184e3Ssthen 295e5157e49Safresh1 # Then separate the switches with a zero-width positive 296898184e3Ssthen # lookahead on the dash. 297898184e3Ssthen # 298898184e3Ssthen # See: 299898184e3Ssthen # http://www.effectiveperlprogramming.com/blog/1411 300898184e3Ssthen # for a good discussion of this technique 301898184e3Ssthen 302898184e3Ssthen push @render_switches, split(/(?=-)/, $switches); 303898184e3Ssthen } 304898184e3Ssthen 305898184e3Ssthen $self->debug( "render is $render\n" ); 306898184e3Ssthen $self->debug( "render options are @render_switches\n" ); 307898184e3Ssthen 308898184e3Ssthen require Symbol; 309898184e3Ssthen require IPC::Open3; 310898184e3Ssthen require IO::Handle; 311898184e3Ssthen 312898184e3Ssthen my $pid = IPC::Open3::open3( 313898184e3Ssthen my $writer, 314898184e3Ssthen my $reader, 315898184e3Ssthen my $err = Symbol::gensym(), 316898184e3Ssthen $render, 317898184e3Ssthen @render_switches 318898184e3Ssthen ); 319898184e3Ssthen 320898184e3Ssthen $reader->autoflush(1); 321898184e3Ssthen 322898184e3Ssthen use IO::Select; 323898184e3Ssthen my $selector = IO::Select->new( $reader ); 324898184e3Ssthen 325898184e3Ssthen $self->debug( "Writing to pipe to $render\n" ); 326898184e3Ssthen 327898184e3Ssthen my $offset = 0; 328898184e3Ssthen my $chunk_size = 4096; 329898184e3Ssthen my $length = length( ${ $self->{_text_ref} } ); 330898184e3Ssthen my $chunks = $length / $chunk_size; 331898184e3Ssthen my $done; 332898184e3Ssthen my $buffer; 333898184e3Ssthen while( $offset <= $length ) { 334898184e3Ssthen $self->debug( "Writing chunk $chunks\n" ); $chunks++; 335898184e3Ssthen syswrite $writer, ${ $self->{_text_ref} }, $chunk_size, $offset 336898184e3Ssthen or $self->die( $! ); 337898184e3Ssthen $offset += $chunk_size; 338898184e3Ssthen $self->debug( "Checking read\n" ); 339898184e3Ssthen READ: { 340898184e3Ssthen last READ unless $selector->can_read( 0.01 ); 341898184e3Ssthen $self->debug( "Reading\n" ); 342898184e3Ssthen my $bytes = sysread $reader, $buffer, 4096; 343898184e3Ssthen $self->debug( "Read $bytes bytes\n" ); 344898184e3Ssthen $done .= $buffer; 345898184e3Ssthen $self->debug( sprintf "Output is %d bytes\n", 346898184e3Ssthen length $done 347898184e3Ssthen ); 348898184e3Ssthen next READ; 349898184e3Ssthen } 350898184e3Ssthen } 351898184e3Ssthen close $writer; 352898184e3Ssthen $self->debug( "Done writing\n" ); 353898184e3Ssthen 354898184e3Ssthen # read any leftovers 355898184e3Ssthen $done .= do { local $/; <$reader> }; 356898184e3Ssthen $self->debug( sprintf "Done reading. Output is %d bytes\n", 357898184e3Ssthen length $done 358898184e3Ssthen ); 359898184e3Ssthen 360*fac98b93Safresh1 # wait for it to exit 361*fac98b93Safresh1 waitpid( $pid, 0 ); 362*fac98b93Safresh1 363898184e3Ssthen if( $? ) { 364898184e3Ssthen $self->warn( "Error from pipe to $render!\n" ); 365898184e3Ssthen $self->debug( 'Error: ' . do { local $/; <$err> } ); 366898184e3Ssthen } 367898184e3Ssthen 368898184e3Ssthen 369898184e3Ssthen close $reader; 370898184e3Ssthen if( my $err = $? ) { 371898184e3Ssthen $self->debug( 372898184e3Ssthen "Nonzero exit ($?) while running `$render @render_switches`.\n" . 373898184e3Ssthen "Falling back to Pod::Perldoc::ToPod\n" 374898184e3Ssthen ); 375898184e3Ssthen return $self->_fallback_to_pod( @_ ); 376898184e3Ssthen } 377898184e3Ssthen 378898184e3Ssthen $self->debug( "Output:\n----\n$done\n----\n" ); 379898184e3Ssthen 380898184e3Ssthen ${ $self->{_text_ref} } = $done; 381898184e3Ssthen 382898184e3Ssthen return length ${ $self->{_text_ref} } ? SUCCESS : FAILED; 383898184e3Ssthen } 384898184e3Ssthen 385898184e3Ssthensub parse_from_file { 386898184e3Ssthen my( $self, $file, $outfh) = @_; 387898184e3Ssthen 388898184e3Ssthen # We have a pipeline of filters each affecting the reference 389898184e3Ssthen # in $self->{_text_ref} 390898184e3Ssthen $self->{_text_ref} = \my $output; 391898184e3Ssthen 392898184e3Ssthen $self->_parse_with_pod_man( $file ); 393898184e3Ssthen # so far, nroff is an external command so we ensure it worked 394898184e3Ssthen my $result = $self->_filter_through_nroff; 395898184e3Ssthen return $self->_fallback_to_pod( @_ ) unless $result == SUCCESS; 396898184e3Ssthen 397898184e3Ssthen $self->_post_nroff_processing; 398898184e3Ssthen 399898184e3Ssthen print { $outfh } $output or 400898184e3Ssthen $self->die( "Can't print to $$self{__output_file}: $!" ); 401898184e3Ssthen 402898184e3Ssthen return; 403898184e3Ssthen } 404898184e3Ssthen 405898184e3Ssthensub _fallback_to_pod { 406898184e3Ssthen my( $self, @args ) = @_; 407898184e3Ssthen $self->warn( "Falling back to Pod because there was a problem!\n" ); 408898184e3Ssthen require Pod::Perldoc::ToPod; 409898184e3Ssthen return Pod::Perldoc::ToPod->new->parse_from_file(@_); 410898184e3Ssthen } 411898184e3Ssthen 412898184e3Ssthen# maybe there's a user setting we should check? 413898184e3Ssthensub _get_tab_width { 4 } 414898184e3Ssthen 415898184e3Ssthensub _expand_tabs { 416898184e3Ssthen my( $self ) = @_; 417898184e3Ssthen 418898184e3Ssthen my $tab_width = ' ' x $self->_get_tab_width; 419898184e3Ssthen 420898184e3Ssthen ${ $self->{_text_ref} } =~ s/\t/$tab_width/g; 421898184e3Ssthen } 422898184e3Ssthen 423898184e3Ssthensub _post_nroff_processing { 424898184e3Ssthen my( $self ) = @_; 425898184e3Ssthen 426898184e3Ssthen if( $self->is_hpux ) { 427898184e3Ssthen $self->debug( "On HP-UX, I'm going to expand tabs for you\n" ); 428898184e3Ssthen # this used to be a pipe to `col -x` for HP-UX 429898184e3Ssthen $self->_expand_tabs; 430898184e3Ssthen } 431898184e3Ssthen 432898184e3Ssthen if( $self->{'__filter_nroff'} ) { 433898184e3Ssthen $self->debug( "filter_nroff is set, so filtering\n" ); 434898184e3Ssthen $self->_remove_nroff_header; 435898184e3Ssthen $self->_remove_nroff_footer; 436898184e3Ssthen } 437898184e3Ssthen else { 438898184e3Ssthen $self->debug( "filter_nroff is not set, so not filtering\n" ); 439898184e3Ssthen } 440898184e3Ssthen 441898184e3Ssthen $self->_handle_unicode; 442898184e3Ssthen 443898184e3Ssthen return 1; 444898184e3Ssthen } 445898184e3Ssthen 446898184e3Ssthen# I don't think this does anything since there aren't two consecutive 447898184e3Ssthen# newlines in the Pod::Man output 448898184e3Ssthensub _remove_nroff_header { 449898184e3Ssthen my( $self ) = @_; 450898184e3Ssthen $self->debug( "_remove_nroff_header is still a stub!\n" ); 451898184e3Ssthen return 1; 452898184e3Ssthen 453898184e3Ssthen# my @data = split /\n{2,}/, shift; 454898184e3Ssthen# shift @data while @data and $data[0] !~ /\S/; # Go to header 455898184e3Ssthen# shift @data if @data and $data[0] =~ /Contributed\s+Perl/; # Skip header 456898184e3Ssthen } 457898184e3Ssthen 458898184e3Ssthen# I don't think this does anything since there aren't two consecutive 459898184e3Ssthen# newlines in the Pod::Man output 460898184e3Ssthensub _remove_nroff_footer { 461898184e3Ssthen my( $self ) = @_; 462898184e3Ssthen $self->debug( "_remove_nroff_footer is still a stub!\n" ); 463898184e3Ssthen return 1; 464898184e3Ssthen ${ $self->{_text_ref} } =~ s/\n\n+.*\w.*\Z//m; 465898184e3Ssthen 466898184e3Ssthen# my @data = split /\n{2,}/, shift; 467898184e3Ssthen# pop @data if @data and $data[-1] =~ /^\w/; # Skip footer, like 468898184e3Ssthen # 28/Jan/99 perl 5.005, patch 53 1 469898184e3Ssthen } 470898184e3Ssthen 471898184e3Ssthensub _unicode_already_handled { 472898184e3Ssthen my( $self ) = @_; 473898184e3Ssthen 474898184e3Ssthen $self->_have_groff_with_utf8 || 475898184e3Ssthen 1 # so, we don't have a case that needs _handle_unicode 476898184e3Ssthen ; 477898184e3Ssthen } 478898184e3Ssthen 479898184e3Ssthensub _handle_unicode { 480898184e3Ssthen# this is the job of preconv 481898184e3Ssthen# we don't need this with groff 1.20 and later. 482898184e3Ssthen my( $self ) = @_; 483898184e3Ssthen 484898184e3Ssthen return 1 if $self->_unicode_already_handled; 485898184e3Ssthen 486898184e3Ssthen require Encode; 487898184e3Ssthen 488898184e3Ssthen # it's UTF-8 here, but we need character data 489898184e3Ssthen my $text = Encode::decode( 'UTF-8', ${ $self->{_text_ref} } ) ; 490898184e3Ssthen 491898184e3Ssthen# http://www.mail-archive.com/groff@gnu.org/msg01378.html 492898184e3Ssthen# http://linux.die.net/man/7/groff_char 493898184e3Ssthen# http://www.gnu.org/software/groff/manual/html_node/Using-Symbols.html 494898184e3Ssthen# http://lists.gnu.org/archive/html/groff/2011-05/msg00007.html 495898184e3Ssthen# http://www.simplicidade.org/notes/archives/2009/05/fixing_the_pod.html 496898184e3Ssthen# http://lists.freebsd.org/pipermail/freebsd-questions/2011-July/232239.html 497898184e3Ssthen $text =~ s/(\P{ASCII})/ 498898184e3Ssthen sprintf '\\[u%04X]', ord $1 499898184e3Ssthen /eg; 500898184e3Ssthen 501898184e3Ssthen # should we encode? 502898184e3Ssthen ${ $self->{_text_ref} } = $text; 503898184e3Ssthen } 504898184e3Ssthen 505898184e3Ssthen1; 506898184e3Ssthen 507898184e3Ssthen__END__ 508898184e3Ssthen 509898184e3Ssthen=head1 NAME 510898184e3Ssthen 511898184e3SsthenPod::Perldoc::ToMan - let Perldoc render Pod as man pages 512898184e3Ssthen 513898184e3Ssthen=head1 SYNOPSIS 514898184e3Ssthen 515898184e3Ssthen perldoc -o man Some::Modulename 516898184e3Ssthen 517898184e3Ssthen=head1 DESCRIPTION 518898184e3Ssthen 519898184e3SsthenThis is a "plug-in" class that allows Perldoc to use 520898184e3SsthenPod::Man and C<groff> for reading Pod pages. 521898184e3Ssthen 522898184e3SsthenThe following options are supported: center, date, fixed, fixedbold, 523898184e3Ssthenfixeditalic, fixedbolditalic, quotes, release, section 524898184e3Ssthen 525898184e3Ssthen(Those options are explained in L<Pod::Man>.) 526898184e3Ssthen 527898184e3SsthenFor example: 528898184e3Ssthen 529898184e3Ssthen perldoc -o man -w center:Pod Some::Modulename 530898184e3Ssthen 531898184e3Ssthen=head1 CAVEAT 532898184e3Ssthen 533898184e3SsthenThis module may change to use a different pod-to-nroff formatter class 534898184e3Ssthenin the future, and this may change what options are supported. 535898184e3Ssthen 536898184e3Ssthen=head1 SEE ALSO 537898184e3Ssthen 538898184e3SsthenL<Pod::Man>, L<Pod::Perldoc>, L<Pod::Perldoc::ToNroff> 539898184e3Ssthen 540898184e3Ssthen=head1 COPYRIGHT AND DISCLAIMERS 541898184e3Ssthen 542898184e3SsthenCopyright (c) 2011 brian d foy. All rights reserved. 543898184e3Ssthen 544898184e3SsthenCopyright (c) 2002,3,4 Sean M. Burke. All rights reserved. 545898184e3Ssthen 546898184e3SsthenThis library is free software; you can redistribute it and/or modify it 547898184e3Ssthenunder the same terms as Perl itself. 548898184e3Ssthen 549898184e3SsthenThis program is distributed in the hope that it will be useful, but 550898184e3Ssthenwithout any warranty; without even the implied warranty of 551898184e3Ssthenmerchantability or fitness for a particular purpose. 552898184e3Ssthen 553898184e3Ssthen=head1 AUTHOR 554898184e3Ssthen 555898184e3SsthenCurrent maintainer: Mark Allen C<< <mallen@cpan.org> >> 556898184e3Ssthen 557898184e3SsthenPast contributions from: 558898184e3Ssthenbrian d foy C<< <bdfoy@cpan.org> >> 559898184e3SsthenAdriano R. Ferreira C<< <ferreira@cpan.org> >>, 560898184e3SsthenSean M. Burke C<< <sburke@cpan.org> >> 561898184e3Ssthen 562898184e3Ssthen=cut 563898184e3Ssthen 564