File Coverage

blib/lib/Pod/MultiLang/Html.pm
Criterion Covered Total %
statement 488 772 63.2
branch 168 396 42.4
condition 43 119 36.1
subroutine 37 43 86.0
pod 18 18 100.0
total 754 1348 55.9


line stmt bran cond sub pod time code
1             ## ----------------------------------------------------------------------------
2             # Pod::MultiLang::Html
3             # -----------------------------------------------------------------------------
4             # Mastering programed by YAMASHINA Hio
5             #
6             # Copyright 2003 YMIRLINK,Inc.
7             # -----------------------------------------------------------------------------
8             # $Id: /perl/Pod-MultiLang/lib/Pod/MultiLang/Html.pm 578 2007-12-14T05:15:38.051888Z hio $
9             # -----------------------------------------------------------------------------
10             package Pod::MultiLang::Html;
11 6     6   155724 use strict;
  6         16  
  6         273  
12 6     6   34 use vars qw($VERSION);
  6         11  
  6         330  
13             BEGIN{
14 6     6   99 $VERSION = '0.03';
15             }
16              
17 6     6   7081 use File::Spec::Functions;
  6         5229  
  6         642  
18 6     6   6388 use Hash::Util qw(lock_keys);
  6         17028  
  6         45  
19 6     6   692 use Cwd;
  6         13  
  6         416  
20 6     6   6279 use UNIVERSAL qw(isa can);
  6         78  
  6         36  
21 6     6   5023 use List::Util qw(first);
  6         13  
  6         718  
22 6     6   5239 use Pod::ParseLink;
  6         5005  
  6         311  
23              
24 6     6   4175 use Pod::MultiLang;
  6         21  
  6         301  
25 6     6   2192 use Pod::MultiLang::Dict;
  6         15  
  6         122  
26             our @ISA = qw(Pod::MultiLang);
27              
28             use constant
29             {
30 6         1008 PARA_VERBATIM => 1,
31             PARA_TEXTBLOCK => 2,
32             PARA_HEAD => 3,
33             PARA_OVER => 4,
34             PARA_BACK => 5,
35             PARA_ITEM => 6,
36             PARA_BEGIN => 7,
37             PARA_END => 8,
38             PARA_FOR => 9,
39             PARA_ENCODING => 10,
40             PARA_POD => 11,
41             PARA_CUT => 12,
42 6     6   347 };
  6         8  
43             use constant
44             {
45 6         531 PARAINFO_TYPE => 0,
46             PARAINFO_PARAOBJ => 1,
47             # =head
48             PARAINFO_CONTENT => 2,
49             PARAINFO_ID => 3,
50             PARAINFO_HEADSIZE => 4,
51             # =over,item,back
52             PARAINFO_LISTTYPE => 2,
53             #PARAINFO_ID => 3,
54 6     6   28 };
  6         11  
55             use constant
56             {
57 6         349 DEFAULT_LANG => 'en',
58 6     6   30 };
  6         10  
59             use constant
60             {
61 6         56144 VERBOSE_NONE => 0,
62             VERBOSE_ERROR => 10,
63             VERBOSE_NOLINK => 20,
64             VERBOSE_WARN => 30,
65             VERBOSE_DEFAULT => 50,
66             VERBOSE_FINDLINK => 90,
67             VERBOSE_VERBOSE => 80,
68             VERBOSE_DEBUG => 95,
69             VERBOSE_FULL => 100,
70 6     6   31 };
  6         95  
71              
72             our $VERBOSE_DEFAULT = VERBOSE_DEFAULT;
73              
74             sub verbmsg
75             {
76 4     4 1 7 my ($parser,$level) = @_;
77 4 50       23 if( $parser->{_verbose}>=$level )
78             {
79 0         0 my $verbout = $parser->{_verbout};
80 0         0 print $verbout @_[2..$#_];
81             }
82             }
83              
84             # -----------------------------------------------------------------------------
85             # makelink
86             # L<> から を作成
87             #
88             sub makelink
89             {
90 4     4 1 10 my ($parser,$lang,$text,$target,$sec,$sec_anchor) = @_;
91 4   66     31 $sec_anchor ||= $sec;
92 4 50       12 defined($target) or $target = '';
93            
94 4         5 my $link_info;
95              
96 4 50       122 if( exists($parser->{linkcache}{$target}) )
    50          
    50          
97             {
98 0         0 $link_info = $parser->{linkcache}{$target};
99             }elsif( $target eq '' )
100             {
101 0         0 $link_info = {
102             base => '',
103             path => '',
104             href => '',
105             };
106 0         0 $parser->{linkcache}{''} = $link_info;
107             }elsif( $target =~ /\(\d+\w?\)$/ )
108             {
109             # 多分man. 適当に^^;
110             #
111 0         0 $link_info = {
112             base => "man:",
113             path => "$target",
114             href => undef,
115             };
116 0         0 $parser->{linkcache}{$target} = $link_info;
117             }else
118             {
119             # Pkg/Class.html
120             # Pkg/Pkg-Class.html
121             # Pkg-Class.html
122             # Pkg/Pkg-Class-[\d\.]+.html
123             # Pkg-Class-[\d\.]+.html
124 4         27 (my $file1 = $target.'.html') =~ s,::,/,g;
125 4         18 (my $file3 = $target.'.html') =~ s,::,-,g;
126 4         30 (my $dir = $file1)=~s,[^/]*$,,;
127 4 50       469 my $file2 = $dir ne '' ? $dir.$file3 : undef;
128 4         7 my $found;
129 4   33     16 my $verbout = $parser->{_verbose}>=VERBOSE_FINDLINK && $parser->{_verbout};
130 4         7 foreach my $poddir(@{$parser->{opt_poddir}})
  4         28  
131             {
132 0         0 $found = $poddir.$file1;
133 0 0       0 -f $found and last;
134 0 0       0 $parser->{_verbose}>=VERBOSE_FINDLINK and $parser->verbmsg(VERBOSE_FINDLINK,"[$target] ==> x [$found]\n");
135 0 0       0 if( defined($file2) )
136             {
137 0         0 $found = $poddir.$file2;
138 0 0       0 -f $found and last;
139 0 0       0 $parser->{_verbose}>=VERBOSE_FINDLINK and $parser->verbmsg(VERBOSE_FINDLINK,"[$target] ==> x [$found]\n");
140             }
141 0         0 $found = $poddir.$file3;
142 0 0       0 -f $found and last;
143 0 0       0 $parser->{_verbose}>=VERBOSE_FINDLINK and $parser->verbmsg(VERBOSE_FINDLINK,"[$target] ==> x [$found]\n");
144 0         0 undef $found;
145             }
146 4 50       12 if( $found )
147             {
148 0         0 $link_info = {
149             base => $parser->{out_topdir},
150             path => $found,
151             href => undef,
152             };
153 0 0       0 $parser->{linkcache}{$target} = $link_info,
154             $parser->{_verbose}>=VERBOSE_FINDLINK and $parser->verbmsg(VERBOSE_FINDLINK,"[$target] ==> [$found]\n");
155             }else
156             {
157             # not found.
158             #
159 4         13 my $missing_base;
160 4 50 33     40 if( defined($parser->{opt_missing_poddir}) && $target=~/^perl\w*$/ )
    50 33        
    100          
161             {
162 0         0 $missing_base = $parser->{opt_missing_poddir};
163             }elsif( defined($parser->{opt_missing_pragmadir}) && $target =~ /^[a-z]/ )
164             {
165 0         0 $missing_base = $parser->{opt_missing_pragmadir};
166             }elsif( defined($parser->{opt_missing_dir}) )
167             {
168 2         5 $missing_base = $parser->{opt_missing_dir};
169             }else
170             {
171 2         6 $missing_base = $parser->{out_topdir};
172             }
173 4         20 my $href = $missing_base . $parser->escapeUrl($file1);
174 4         46 $link_info = {
175             base => $missing_base,
176             path => $file1,
177             href => $href,
178             };
179 4         65 $parser->{linkcache}{$target} = $link_info,
180             $parser->verbmsg(VERBOSE_NOLINK,"[$target] not found ==> $href\n");
181             }
182             }
183              
184 4 50       14 if( !defined($link_info->{href}) )
185             {
186 0         0 my $base = $link_info->{base};
187 0         0 my $path = $link_info->{path};
188 0         0 $link_info->{href} = $base . $parser->escapeUrl($path);
189             }
190              
191 4         8 my $link_to = $link_info->{href};
192 4 100       13 if( $sec_anchor )
193             {
194 1         169 $link_to .= '#' . $parser->makelinkanchor($sec_anchor);
195             }
196            
197 4 50 33     16 if( !defined($text)||$text eq '' )
198             {
199 4         64 $text = $parser->makelinktext(@_[1..$#_]);
200             }
201             #print STDERR "($lang,$text,$target,$sec) ==> [$link_to]\n";
202 4         201 $text = $parser->escapeHtml($text);
203 4         11 $link_to = $parser->escapeHtml($link_to);
204 4         19 qq($text);
205             }
206              
207             # -----------------------------------------------------------------------------
208             # $parser->_map_head_word($ptree)
209             # head のテキストに基本訳を付ける
210             #
211             sub _map_head_word
212             {
213 87     87   306 my ($parser,$ptree) = @_;
214 87 100       1854 ref($ptree) or $ptree = Pod::Paragraph->new(-text=>$ptree);
215            
216 87         772 my $text = $ptree->text();
217 87         326 $text =~ s/^\s+//;
218 87         449 $text =~ s/\s+$//;
219            
220 87         1163 my @text = Pod::MultiLang::Dict->find_word($parser->{langs},$text);
221 87         172 my $num_found = grep{defined($_)}@text;
  98         277  
222 87 100       555 if( $num_found==0 )
223             {
224 76         717 return $ptree;
225             }
226 11 50       118 if( $num_found==1 )
227             {
228 11         13 my $i = 0;
229 11         23 foreach(@text)
230             {
231 22 50 66     169 if( defined($_) && $parser->{langs}[$i] && $parser->{langs}[$i]eq'en' )
      66        
232             {
233             # default only.
234 0         0 return $ptree;
235             }
236 22         55 ++$i;
237             }
238             }
239 11         21 my $i=0;
240 11         17 my $result = $text;
241 11         21 foreach(@text)
242             {
243 22 100       49 if( defined($_) )
244             {
245 11         37 $result .= "\nJ<$parser->{langs}[$i];$_>";
246             }
247 22         38 ++$i;
248             }
249 11         57 $ptree->text($result);
250 11         63 $ptree;
251             }
252              
253             # -----------------------------------------------------------------------------
254             # new
255             # コンストラクタ
256             # poddir => []
257             # Pkg/Class.html
258             # Pkg/Pkg-Class.html
259             # Pkg/Pkg-Class-[\d\.]+.html
260             # Pkg-Class.html
261             # Pkg-Class-[\d\.]+.html
262             # あたりかなぁ。。?
263             #
264             sub new
265             {
266 43     43 1 77616 my $pkg = shift;
267 43 50       2560 ref($pkg) and $pkg = ref($pkg);
268 43 100 66     776 my %arg = @_&&ref($_[0])eq'HASH'?%{$_[0]}:@_;
  38         320  
269            
270             # SUPER クラスを使ってインスタンスを生成.
271             #
272 43 100       112 my @passarg = map{exists($arg{$_})?($_=>$arg{$_}):()}qw(langs);
  43         216  
273 43         430 my $parser = $pkg->SUPER::new(@passarg);
274            
275             # 見出し変換辞書のロード
276             #
277 43 100       234 exists($arg{langs}) and Pod::MultiLang::Dict->load_dict($arg{langs});
278            
279             # 設定を記録
280             #
281 43   50     627 $parser->{opt_poddir} = $arg{poddir}||[];
282 43         194 $parser->{opt_css} = $arg{css};
283 43         114 $parser->{opt_made} = $arg{made};
284 43         108 $parser->{opt_missing_poddir} = $arg{missing_poddir};
285 43         94 $parser->{opt_missing_pragmadir} = $arg{missing_pragmadir};
286 43         104 $parser->{opt_missing_dir} = $arg{missing_dir};
287 43         140 $parser->{opt_use_index} = 1;
288 43   50     426 $parser->{opt_default_lang} = $arg{default_lang} || DEFAULT_LANG;
289 43   100     291 $parser->{_in_charset} = $arg{in_charset} || 'utf-8';
290 43   100     1367 $parser->{_out_charset} = $arg{out_charset} || 'utf-8';
291 43         104 $parser->{_langstack} = undef;
292 43         142 $parser->{linkcache} = {};
293            
294 43         776 @$parser{qw(_verbose _verbout
295             langs _expandlangs _default_lang _fetchlangs
296             _linkwords _linkwords_keys
297             _langstack _neststack _skipblock _iseqstack
298             paras heads items
299             _cssprefix
300             out_outfile out_outdir out_topdir out_css out_made
301             _outhtml_heading_toc
302             _outhtml_heading_index
303             _outhtml_plain_title
304             _outhtml_block_title
305             )} = ();
306 43         302 @$parser{qw( _INFILE _OUTFILE _PARSEOPTS _CUTTING
307             _INPUT _OUTPUT _CALLBACKS _TOP_STREAM _ERRORSUB
308             _INPUT_STREAMS
309             )} = ();
310             #_SELECTED_SECTIONS
311             #lock_keys(%$parser);
312            
313             # ディレクトリは末尾/付きに正規化
314 43         81 foreach(@{$parser->{opt_poddir}},@$parser{qw(opt_missing_poddir opt_missing_pragmadir opt_missing_dir)})
  43         150  
315             {
316 129 100 100     416 defined($_) && !m/\/$/ and $_.='/';
317             }
318 43         354 $parser;
319             }
320              
321             # -----------------------------------------------------------------------------
322             # begin_pod
323             # 初期化
324             #
325             sub begin_pod
326             {
327 43     43 1 8746 my ($parser) = @_;
328 43         147 &Pod::MultiLang::begin_pod;
329            
330 43         118 $parser->{_verbose} = $VERBOSE_DEFAULT;
331 43         86 $parser->{_verbout} = \*STDERR;
332 43         78 $parser->{_expandlangs} = undef;
333 43         118 $parser->{_default_lang} = $parser->{opt_default_lang};
334 43         74 $parser->{_fetchlangs} = undef;
335 43         87 $parser->{_linkwords} = undef;
336 43         59 $parser->{_linkwords_keys} = undef;
337 43         103 $parser->{_langstack} = [undef];
338 43         135 $parser->{_cssprefix} = 'pod_';
339            
340 43         424 my $outfile = $parser->output_file();
341 43 50       400 file_name_is_absolute($outfile) or $outfile = File::Spec->rel2abs($outfile);
342 43         4781 my $outdir = (File::Spec->splitpath($outfile))[1];
343 43         113 my $css = $parser->{opt_css};
344 43 50 33     175 if( $css && !file_name_is_absolute($css) )
345             {
346 0         0 $css = File::Spec->abs2rel(File::Spec->rel2abs($css),$outdir);
347             }
348 43         95 my $made = $parser->{opt_made};
349 43         240 $parser->{out_outfile} = $outfile;
350 43         84 $parser->{out_outdir} = $outdir;
351 43   50     423599 $parser->{out_topdir} = File::Spec->abs2rel(cwd(),$outdir)||'.';
352 43         596 $parser->{out_css} = $css;
353 43         155 $parser->{out_made} = $made;
354            
355             # ディレクトリは末尾/付きに正規化
356 43         209 foreach(@$parser{qw(out_topdir out_outdir)})
357             {
358 86 100 66     2692 defined($_) && !m/\/$/ and $_.='/';
359             }
360            
361 43 50       6110 if( $parser->{_verbose}>=VERBOSE_FULL )
362             {
363 0         0 my $out = $$parser{_verbout};
364 0         0 print $out $parser->input_file()."\n";
365 0         0 print $out "scan...\n";
366             }
367             }
368              
369             # -----------------------------------------------------------------------------
370             # interior_sequence
371             # 装飾符号の展開
372             #
373             sub interior_sequence
374             {
375 12     12 1 26 my ($parser, $seq_command, $seq_argument) = @_;
376             ## Expand an interior sequence; sample actions might be:
377 12 50       104 if( $seq_command eq 'I' )
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
378             {
379 0         0 return qq($seq_argument);
380             }elsif( $seq_command eq 'B' )
381             {
382 0         0 return qq($seq_argument);
383             }elsif( $seq_command eq 'C' )
384             {
385 0         0 return qq($seq_argument);
386             }elsif( $seq_command eq 'L' )
387             {
388 0         0 $parser->resolveLink($seq_argument);
389             }elsif( $seq_command eq 'E' )
390             {
391 12         77 return $parser->resolvePodEscape($seq_argument);
392             }elsif( $seq_command eq 'F' )
393             {
394 0         0 return qq($seq_argument);
395             }elsif( $seq_command eq 'S' )
396             {
397 0         0 return qq($seq_argument);
398             }elsif( $seq_command eq 'X' )
399             {
400 0         0 return '';
401             }elsif( $seq_command eq 'Z' )
402             {
403 0         0 return '';
404             }elsif( $seq_command eq 'J' )
405             {
406 0         0 my ($lang,$text) = $parser->parseLang($seq_argument);
407 0 0       0 if( $parser->{_expandlangs} )
408             {
409 0 0       0 if( !grep{$lang eq $_}@{$parser->{_expandlangs}} )
  0         0  
  0         0  
410             {
411 0         0 return '';
412             }
413 0 0       0 grep{$lang eq $_}@{$parser->{_fetchlangs}} or push(@{$parser->{_fetchlangs}},$lang);
  0         0  
  0         0  
  0         0  
414             }
415 0         0 return qq($text);
416             }
417             }
418              
419             # -----------------------------------------------------------------------------
420             # plainize
421             # ptreeを単純テキストに.
422             #
423             sub plainize
424             {
425 4     4 1 7 my ($parser,$ptree) = @_;
426 4 100       45 if( $ptree->isa('Pod::InteriorSequence') )
427             {
428 2         10 $ptree = $ptree->parse_tree();
429             }
430 4 100       38 if( $ptree->isa('Pod::ParseTree') )
431             {
432 3         6 my $text = '';
433 3         16 foreach($ptree->children())
434             {
435 3 50       11 $text .= ref($_) ? $parser->plainize($_) : $_;
436             }
437 3         22 return $text;
438             }
439 1 50       6 if( $ptree->isa('Pod::Paragraph') )
440             {
441 1         5 my $text = $ptree->text();
442 1         23 $text =~ s/^(.+?)(J<)/J<< $parser->{_default_lang}; $1 >>$2/s;
443 1         295 return $parser->parse_text( { -expand_seq => \&_plainize_iseq,
444             -expand_ptree => \&plainize,
445             },
446             $text,
447             ($ptree->file_line())[1],
448             );
449             }
450 0         0 die "unknown type [$ptree]";
451             }
452              
453             # -----------------------------------------------------------------------------
454             # _plainize_iseq
455             # 装飾符号を単純テキストに.
456             #
457             sub _plainize_iseq
458             {
459 2     2   5 my ($parser, $iseq) = @_;
460 2         16 my $cmd = $iseq->cmd_name();
461 2 50 33     69 if( $cmd eq 'I' || $cmd eq 'B' || $cmd eq 'C' || $cmd eq 'F' || $cmd eq 'S' )
    50 33        
    50 33        
    50 33        
    50 33        
462             {
463 0         0 return $parser->plainize($iseq);
464             }elsif( $cmd eq 'X' || $cmd eq 'Z' )
465             {
466 0         0 return '';
467             }elsif( $cmd eq 'E' )
468             {
469 0         0 return $parser->resolvePodEscape($parser->plainize($iseq->parse_tree()));
470             }elsif( $cmd eq 'L' )
471             {
472 0         0 return '_';
473             }elsif( $cmd eq 'J' )
474             {
475 2         12 my $text = $parser->plainize($iseq);
476 2         14 (my $lang,$text) = $parser->parseLang($text);
477 2 50       4 if( grep{$_ eq 'en'}@{$parser->{langs}} )
  4 0       22  
  2         5  
478             {
479             # if langs contains en, use en.
480 2 100       268 return $lang eq 'en' ? $text : '';
481             }elsif( $lang eq $parser->{langs}[0] )
482             {
483             # no en, use first lang.
484 0         0 return $text;
485             }else
486             {
487 0         0 return '';
488             }
489             }
490 0         0 '';
491             }
492              
493             # -----------------------------------------------------------------------------
494             # buildhtml
495             # paraobj からhtmlを生成
496             #
497             sub buildhtml
498             {
499 130     130 1 214 my ($parser,$paraobj) = @_;
500            
501 130         181 my $ptree;
502 130 50       665 if( isa($paraobj,'Pod::Paragraph') )
503             {
504 130         22854 $ptree = $parser->parse_text($paraobj->text(),($paraobj->file_line())[1]);
505             }else
506             {
507 0         0 $ptree = $paraobj;
508             }
509            
510             # [langs..,,no-lang];
511 130         858 my @list = $parser->_buildhtml_parse($ptree);
512 130         193 my @html;
513 130         208 for( my $i=0; $i<=$#{$parser->{langs}}; ++$i )
  276         1006  
514             {
515 146 100       667 if( defined($list[$i]) )
    100          
516             {
517 12         38 my $cls = "$parser->{_cssprefix}lang_$parser->{langs}[$i]";
518 12         85 my $text = $list[$i];
519 12         45 push(@html,qq($list[$i]));
520             }elsif( $parser->{langs}[$i]eq$parser->{_default_lang} )
521             {
522 130 100       207 if( grep{defined}@list[0..$#{$parser->{langs}}] )
  146         482  
  130         332  
523             {
524 12         37 my $cls = "$parser->{_cssprefix}lang_$parser->{langs}[$i]";
525 12         48 push(@html,qq($list[-1]));
526             }else
527             {
528 118         455 my $cls = "$parser->{_cssprefix}lang";
529 118         472 push(@html,qq($list[-1]));
530             }
531             }
532             }
533              
534 130         356 my $ret = join("\n",@html);
535 130 50       338 if( $ret eq '' )
536             {
537 0 0 0     0 if( defined($list[-1]) && $list[-1] ne '' )
538             {
539 0         0 $ret = $list[-1];
540             }else
541             {
542 0         0 foreach (@list,'{empty}')
543             {
544 0 0       0 defined($_) and $ret = $_,last;
545             }
546             }
547             }
548 130         2898 $ret;
549             }
550 0 0   0   0 sub _a2s{ join('-',map{defined($_)?"[$_]":'{undef}'}@_) }
  0         0  
551              
552             sub _find_lang_index
553             {
554 158     158   467 my ($this,$lang) = @_;
555 158         289 for( my $i=0; $i<=$#{$this->{langs}}; ++$i )
  190         745  
556             {
557 190 100       623 if( $this->{langs}[$i] eq $lang )
558             {
559 158         1240 return $i;
560             }
561             }
562 0         0 undef;
563             }
564             # -----------------------------------------------------------------------------
565             # _buildhtml_parse
566             # 言語毎に分解.
567             #
568             sub _buildhtml_parse
569             {
570 158     158   359 my ($parser,$ptree,$inlang) = @_;
571 158         233 my @ret = ((undef)x@{$parser->{langs}},'');
  158         655  
572 158   100     530 my $idx_default_lang = $parser->_find_lang_index($parser->{_default_lang})||0;
573            
574 158 50       867 if( can($ptree,'parse_tree') )
575             {
576 158         654 $ptree = $ptree->parse_tree();
577             }
578 158 0       1454 my @children = can($ptree,'children')?$ptree->children():isa($ptree,'ARRAY')?@$ptree:die "unknown object : $ptree";
    50          
579             #print STDERR "in: @{[scalar@children]} ",_a2s(@children),"\n";
580 158         356 foreach (@children)
581             {
582 190 100       595 if( !ref($_) )
583             {
584             # plain text.
585 160         690 my $text = $parser->escapeHtml($_);
586 160         455 $ret[-1] .= $text;
587 160         461 next;
588             }
589 30 100       218 if( $_->cmd_name() eq 'L' )
590             {
591             # link iseq.
592             #print STDERR "link iseq\n";
593 4         55 my $link = $_->raw_text();
594 4         40 $link =~ s/^L\<+\s*//;
595 4         40 $link =~ s/\s*\>+$//;
596 4         66 my ($text, undef, $name, $section, $type) = parselink($link);
597 4 50 66     315 if( !$section && $name =~ / / )
598             {
599 0         0 $section = $name;
600 0         0 $name = '';
601             }
602 4 50       16 if( $link !~ /J\
603             {
604 4         5 my $link;
605 4 50       19 if( $type eq 'man' )
    50          
606             {
607 0         0 $link = $parser->escapeHtml($name);
608             }elsif( $type eq 'url' )
609             {
610 0         0 my $url = $parser->escapeHtml($name);
611 0         0 my $text = $parser->escapeHtml($name);
612 0         0 $link = qq($text);
613             }else
614             {
615 4   33     48 my $lang = $parser->{_langstack}[-1]||$parser->{_default_lang};
616 4         19 $link =$parser->makelink($lang,$text,$name,$section);
617             }
618 4 50       14 if( defined($ret[-1]) )
619             {
620 4         8 $ret[-1] .= $link;
621             }else
622             {
623 0         0 $ret[-1] = $link;
624             }
625 4         14 next;
626             }
627 0         0 my $line = ($_->file_line())[1];
628 0         0 foreach($text, $name, $section)
629             {
630 0 0       0 if( !defined($_) )
631             {
632 0         0 $_ = [(undef)x$#ret];
633 0         0 next;
634             }
635 0         0 my $ptree = $parser->parse_text($_,$line);
636 0         0 my @child = $parser->_buildhtml_parse($ptree);
637             # default_lang が未定義だったら, 言語指定なし部分を充てる.
638             # (全部未定義なら必要ない)
639 0 0 0     0 if( defined($idx_default_lang)
  0   0     0  
640             && !defined($child[$idx_default_lang])
641 0         0 && grep{defined($_)}@child[0..$#{$parser->{langs}}] )
642             {
643 0         0 $child[$idx_default_lang] = $child[-1];
644             }
645 0         0 foreach(grep{defined($_)}@child)
  0         0  
646             {
647 0         0 s/^\s+//;
648 0         0 s/\s+$//;
649             }
650 0         0 $_ = \@child;
651             }
652             # 装飾符号の展開.
653 0         0 my $cmd_name = $_->cmd_name();
654 0   0     0 my $sec_anchor = $$section[-1]||$$section[$idx_default_lang]||'';
655 0   0     0 my $lang = $parser->{_langstack}[-1]||$parser->{_default_lang};
656 0         0 my $i = $parser->_find_lang_index($lang);
657 0 0       0 defined($i) or $i = $idx_default_lang;
658             {
659              
660 0   0     0 my $text = $$text[$i]||$$text[$idx_default_lang]||'';
  0         0  
661 0   0     0 my $name = $$name[$i]||$$name[$idx_default_lang]||'';
662 0   0     0 my $section = $$section[$i]||$$section[$idx_default_lang]||'';
663 0   0     0 my $lang = $parser->{langs}[$i]||$parser->{_default_lang};
664 0         0 my $link;
665 0 0       0 if( $type eq 'man' )
    0          
666             {
667 0         0 $link = $parser->escapeHtml($name);
668             }elsif( $type eq 'url' )
669             {
670 0         0 my $url = $parser->escapeHtml($name);
671 0         0 my $text = $parser->escapeHtml($name);
672 0         0 $link = qq($text);
673             }else
674             {
675 0         0 $link =$parser->makelink($lang,$text,$name,$section,$sec_anchor);
676             }
677 0 0       0 if( defined($ret[-1]) )
678             {
679 0         0 $ret[-1] .= $link;
680             }else
681             {
682 0         0 $ret[-1] = $link;
683             }
684             }
685 0         0 next;
686             } # if cmd_name eq 'L'
687 26 100       143 if( $_->cmd_name() ne 'J' )
688             {
689             # normal iseq.
690             #print STDERR "normal iseq\n";
691 12         234 my @child = $parser->_buildhtml_parse($_->parse_tree());
692             #print STDERR" child : $#child "._a2s(@child)."\n";
693             # default_lang が未定義だったら, 言語指定なし部分を充てる.
694 12         32 for( my $i=0; $i<=$#{$parser->{langs}}; ++$i )
  12         45  
695             {
696 12 50       52 if( $parser->{langs}[$i] eq $parser->{_default_lang} )
697             {
698 12 50 33     91 !defined($child[$i]) &&grep{defined}@child[0..$#{$parser->{langs}}] and $child[$i] = $child[-1];
  12         64  
  12         38  
699             #print STDERR " fallback [$child[-1]] ==> [$parser->{_default_lang}#$i]\n";
700 12         34 last;
701             }
702             }
703             # 装飾符号の展開.
704 12         65 my $cmd_name = $_->cmd_name();
705 12         52 for( my $i=0; $i<=$#child; ++$i )
706             {
707 24 100       127 if( !defined($child[$i]) )
708             {
709 12         31 next;
710             }
711 12         160 $child[$i] = $parser->interior_sequence($cmd_name,$child[$i]);
712 12 50       39 if( defined($ret[$i]) )
713             {
714 12         46 $ret[$i] .= $child[$i];
715             }else
716             {
717 0         0 $ret[$i] = $child[$i];
718             }
719             }
720 12         67 next;
721             } # if cmd_name ne 'J'
722            
723             # lang iseq.
724 14         150 my $iseq = $_;
725 14   50     104 my $first = ($iseq->parse_tree()->children())[0] || '';
726 14 50       32 push(@{$parser->{_langstack}},$first=~/^\s*(\w+)\s*[\/;]/?$1:$parser->{_langstack}[-1]);
  14         107  
727 14         150 my @child = $parser->_buildhtml_parse($iseq->parse_tree());
728 14         23 pop(@{$parser->{_langstack}});
  14         29  
729 14         69 $child[-1] =~ s,^\s*(\w+)\s*[/;]\s*,,;
730 14         36 my $lang = $1;
731 14 50       34 if( !defined($lang) )
732             {
733 0         0 $parser->verbmsg(VERBOSE_ERROR,"no lang in J<>, use default-lang [$parser->{_default_lang}] at ".$iseq->file_line()."\n");
734 0         0 $lang = $parser->{_default_lang};
735             }
736 14         42 for( my $i=0; $i<=$#{$parser->{langs}}; ++$i )
  14         45  
737             {
738 14 50       40 $parser->{langs}[$i] ne $lang and next;
739 14         29 $ret[$i] .= $child[-1];
740 14         51 last;
741             }
742             #print STDERR " iseq: $#ret ",_a2s(@ret),"\n";
743             }
744 158 50       867 $ret[-1]=~/\S/ or $ret[-1]='';
745             #print "out: @{[scalar@ret]} ",_a2s(@ret),"\n";
746 158         962 @ret;
747             }
748              
749             # -----------------------------------------------------------------------------
750             # _parse_iseq_J
751             # ($lang,$text) = $parser->_parse_iseq_J($iseq);
752             #
753             sub _parse_iseq_J
754             {
755 0     0   0 my ($parser,$iseq) = @_;
756 0         0 my @children = $iseq->parse_tree->children();
757 0         0 for( my $i=0; $i<@children; ++$i )
758             {
759 0 0       0 ref($children[$i]) and next;
760 0 0       0 my ($lang_last,$text_head) = split('/',$_,2)
761             or next;
762            
763 0         0 my $lang = [@children[0..$i-1],$lang_last];
764 0         0 my $text = [$text_head,@children[$i+1..$#children]];
765 0         0 my ($file,$line) = $iseq->file_line();
766 0         0 my $text_line = $line + $parser->_countnewline(@$lang);
767 0         0 my $lang_iseq = Pod::InteriorSequence->new( -name => '',
768             -file => $file,
769             -line => $line,
770             -ldelim => '',
771             -rdelim => '',
772             -ptree => Pod::ParseTree->new($lang),
773             );
774 0         0 my $text_iseq = Pod::InteriorSequence->new( -name => '',
775             -file => $file,
776             -line => $text_line,
777             -ldelim => '',
778             -rdelim => '',
779             -ptree => Pod::ParseTree->new($text),
780             );
781 0         0 return ($lang_iseq,$text_iseq);
782             }
783 0         0 (undef,$iseq);
784             }
785              
786             # -----------------------------------------------------------------------------
787             # _countnewline
788             #
789             sub _countnewline
790             {
791 0     0   0 my $line=0;
792 0         0 foreach my $t (@_[1..$#_])
793             {
794 0         0 $line += $t =~ tr/\n/\n/;
795             }
796 0         0 $line;
797             }
798              
799             # -----------------------------------------------------------------------------
800             # buildtitle
801             # タイトルを作成. ヘッダ用と本文用.
802             #
803             sub buildtitle
804             {
805 1     1 1 2 my ($parser,$paraobj) = @_;
806            
807             # [langs..,,no-lang];
808 1         108 my @list = $parser->_buildhtml_parse($parser->parse_text($paraobj->text()));
809 1         22 my $plain_title;
810 1         2 for( my $i=0; $i<=$#{$parser->{langs}}; ++$i )
  1         4  
811             {
812 1 50       4 if( defined($list[$i]) )
    0          
813             {
814 1         1 $plain_title = $list[$i];
815 1         2 last;
816             }elsif( $parser->{langs}[$i]eq$parser->{_default_lang} )
817             {
818 0         0 $plain_title = $list[-1];
819 0         0 last;
820             }
821             }
822 1 50       4 if( !defined($plain_title) )
823             {
824 0 0       0 $plain_title = defined($list[-1]) ? $list[-1] : 'untitled';
825             }
826 1         3 $plain_title =~ s/<.*?>//g;
827 1         6 $plain_title =~ s/^\s+//;
828 1         4 $plain_title =~ s/\s+$//;
829            
830 1         8 for( my $i=0; $i<=$#{$parser->{langs}}; ++$i )
  2         7  
831             {
832 2 100       8 if( $parser->{langs}[$i]eq$parser->{_default_lang} )
    50          
833             {
834 1 50       3 if( !defined($list[$i]) )
835             {
836 1 50       3 if( grep{defined}@list[0..$#{$parser->{langs}}] )
  2         7  
  1         8  
837             {
838 1         4 my $cls = "$parser->{_cssprefix}lang_$parser->{langs}[$i]";
839 1         4 $list[$i] = qq($list[-1]);
840             }else
841             {
842 0         0 $list[$i] = $list[-1];
843             }
844             }else
845             {
846 0         0 my $cls = "$parser->{_cssprefix}lang_$parser->{langs}[$i]";
847 0         0 $list[$i] = qq($list[$i]);
848             }
849 1         3 last;
850             }elsif( defined($list[$i]) )
851             {
852 1         5 my $cls = "$parser->{_cssprefix}lang_$parser->{langs}[$i]";
853 1         5 $list[$i] = qq($list[$i]);
854             }
855             }
856 1         2 my $html = join("
\n",grep{defined}@list[0..$#{$parser->{langs}}]);
  2         5  
  1         3  
857 1 50       5 if( $html eq '' )
858             {
859 0 0       0 my $txt = defined($list[-1]) ? $list[-1] : 'untitled';
860 0         0 my $cls = "$parser->{_cssprefix}lang_default";
861 0         0 $html = qq($txt);
862             }
863 1         2 my $cls = "$parser->{_cssprefix}title_block";
864 1         4 my $block_title = qq(
\n$html\n
\n\n);
865 1         8 ($plain_title,$block_title);
866             }
867              
868             # -----------------------------------------------------------------------------
869             # $parser->makelinkanchor($text)
870             # $parser->makelinkanchor($paraobj)
871             # アンカーキーの生成. のxxxの部分.
872             #
873             sub makelinkanchor
874             {
875 2     2 1 15 my ($parser,$paraobj) = @_;
876 2 100       26 my $id = ref($paraobj) ? $parser->plainize($paraobj) : $paraobj;
877 2         18 $id =~ s/^\s+//;
878 2         10 $id =~ s/\s+$//;
879 2         5 $id =~ s/\s+/_/g;
880 2         12 $id =~ s/([^\a-zA-Z0-9\-\_\.])/join('',map{sprintf('X%02x',$_)}unpack("C*",$1))/ge;
  0         0  
  0         0  
881 2 50       29 $id=~/^[a-zA-Z]/ or $id = 'X'.$id;
882 2         9 $id;
883             }
884              
885             # -----------------------------------------------------------------------------
886             # addindex
887             # adding to index.
888             #
889             sub addindex
890             {
891 1     1 1 7 my ($parser,$hash,$ids,$id,$paraobj) = @_;
892            
893             # make id unique.
894             #
895 1 50       6 if( grep{$_ eq $id} @$ids )
  0         0  
896             {
897 0         0 for(my$i=0;;++$i)
898             {
899 0         0 my $add = sprintf('_%02d',$i);
900 0         0 my $newkey = $id.$add;
901 0 0       0 !grep{$_ eq $newkey}@$ids and $id=$newkey,last;
  0         0  
902             }
903             }
904 1         3 push(@$ids,$id);
905            
906             # [langs..,,no-lang];
907             #
908 1         114 my @list = $parser->_buildhtml_parse($parser->parse_text($paraobj->text()));
909 1         26 my $i;
910 1         3 foreach(@list)
911             {
912 3 100       9 defined($_) or next;
913 2         8 s/<.*?>//g;
914 2         5 s/\s+/ /g;
915 2         4 s/^ //;
916 2         6 s/ $//;
917 2 50       5 if( $_ eq '' )
918             {
919             #my $src = $paraobj->text();
920             #my $lang = $i<$#list ? $parser->{langs}[$i] : 'default';
921             #defined($src) or $src = "{undef}";
922             #defined($lang) or $lang = "{undef}";
923             #$parser->verbmsg(VERBOSE_WARN,"src:[$src] lang:[$lang] is empty.\n");
924 0         0 next;
925             }
926 2         8 $hash->{$_} = $id;
927 2         4 ++$i;
928             }
929 1         4 return $id;
930             }
931              
932             # -----------------------------------------------------------------------------
933             # end_pod
934             # at end of parsing pod.
935             # build html and output it.
936             #
937             sub end_pod
938             {
939 43     43 1 95 my $parser = shift;
940 43         104 my ($command, $paragraph, $line_num) = @_;
941 43         552 $parser->SUPER::end_pod(@_);
942            
943 43 50       148 if( !@{$parser->{paras}} )
  43         292  
944             {
945 0         0 warn "input has no paragraphs";
946             }
947            
948 43         517 $parser->rebuild();
949 43         200 $parser->output_html();
950             }
951              
952             # -----------------------------------------------------------------------------
953             # rebuild
954             # build infomations needed for html.
955             #
956             sub rebuild
957             {
958 43     43 1 169 my ($parser, $command, $paragraph, $line_num) = @_;
959            
960 43 50       177 if( $parser->{_verbose}>=VERBOSE_FULL )
961             {
962 0         0 my $out = $$parser{_verbout};
963 0         0 print $out "scan done, rebuild...\n";
964             }
965            
966 43         492 my %link_keys;
967             my @link_ids;
968 43         429 delete $parser->{_linkwords};
969 43         243 delete $parser->{_linkwords_keys};
970            
971             # build indices from "head"s.
972             #
973 43         99 foreach (@{$parser->{heads}})
  43         160  
974             {
975 1         3 my ($paraobj) = $$_[PARAINFO_PARAOBJ];
976            
977 1 50       25 if( $paraobj->text() !~ /[^\w\s&]/ )
978             {
979 1         5 $paraobj = $parser->_map_head_word($paraobj);
980 1         2 $$_[PARAINFO_PARAOBJ] = $paraobj;
981             }
982            
983 1         9 my $id = $parser->makelinkanchor($paraobj);
984 1         6 $id = $parser->addindex(\%link_keys,\@link_ids,$id,$paraobj);
985 1         6 my $html = $parser->buildhtml($paraobj);
986            
987 1         19 my ($headsize) = $paraobj->cmd_name()=~/(\d)/;
988 1         10 @$_[PARAINFO_CONTENT,PARAINFO_ID,PARAINFO_HEADSIZE] = ($html,$id,$headsize);
989             }
990            
991             # build indices from "item"s too.
992             #
993 43         91 foreach (@{$parser->{items}})
  43         204  
994             {
995 0         0 my ($paraobj,$listtype) = @$_[PARAINFO_PARAOBJ,PARAINFO_LISTTYPE];
996            
997 0 0       0 $listtype ne 'dl' and next;
998            
999 0 0       0 if( $paraobj->text() !~ /[^\w\s&]/ )
1000             {
1001 0         0 $paraobj = $parser->_map_head_word($paraobj);
1002 0         0 $$_[PARAINFO_PARAOBJ] = $paraobj;
1003             }
1004            
1005 0         0 my $id = $parser->makelinkanchor($paraobj);
1006 0         0 $id = $parser->addindex(\%link_keys,\@link_ids,$id,$paraobj);
1007            
1008 0         0 $$_[PARAINFO_ID] = $id;
1009             }
1010            
1011             # find title block.
1012             #
1013 43         170 my $plain_title;
1014             my $block_title;
1015             {
1016             # title is next of paragraph "=head NAME"
1017             #
1018 43         74 for( my $pos=0; $pos<@{$parser->{paras}}-1; ++$pos )
  43         115  
  85         308  
1019             {
1020 43         206 my $para = $parser->{paras}[$pos];
1021             # TODO: ID が NAME だったり 名前 だったり..
1022 43 50 33     256 $para->[PARAINFO_TYPE]==PARA_HEAD && ($para->[PARAINFO_ID] =~ /^NAME/ || $para->[PARAINFO_ID] =~ /^Xe5X90X8dXe5X89X8d/ || $para->[PARAINFO_ID] eq 'X')
      66        
1023             or next;
1024            
1025             # found "=head NAME"
1026             # title is next of it.
1027             #
1028 1         3 $para = $parser->{paras}[$pos+1];
1029            
1030 1         5 ($plain_title,$block_title) = $parser->buildtitle($para->[PARAINFO_PARAOBJ]);
1031 1         2 last;
1032             }
1033             # if no title..
1034             #
1035 43 100       142 if( !defined($plain_title) )
1036             {
1037 42         277 $plain_title = 'untitled';
1038             }
1039 43 100       156 if( !defined($block_title) )
1040             {
1041 42         214 my $cls = "$parser->{_cssprefix}title_block";
1042 42         380 $block_title = qq(
\n$plain_title\n
\n\n);
1043             }
1044             }
1045            
1046 43         630 $parser->{_outhtml_heading_toc} = $parser->buildhtml($parser->_map_head_word('TABLE OF CONTENTS'));
1047 43         461 $parser->{_outhtml_heading_index} = $parser->buildhtml($parser->_map_head_word('INDEX'));
1048 43         509 $parser->{_outhtml_plain_title} = $plain_title;
1049 43         118 $parser->{_outhtml_block_title} = $block_title;
1050            
1051             # set link words.
1052             #
1053 43         364 $parser->{_linkwords} = \%link_keys;
1054             }
1055              
1056             # -----------------------------------------------------------------------------
1057             # output_html
1058             # htmlを出力
1059             #
1060             sub output_html
1061             {
1062 43     43 1 101 my ($parser, $command, $paragraph, $line_num) = @_;
1063            
1064 43         480 my $out_fh = $parser->output_handle();
1065            
1066 43 50       162 if( $parser->{_verbose}>=VERBOSE_FULL )
1067             {
1068 0         0 $parser->vermbsg(VERBOSE_FULL,"ok, output...\n");
1069             }
1070            
1071             #binmode($out_fh,":encoding($parser->{_out_charset})");
1072             #print defined($out_fh)?"[$out_fh]\n":"{undef}\n";
1073 43         1930 binmode($out_fh,":bytes");
1074            
1075 43         267 my $plain_title = $parser->{_outhtml_plain_title};
1076 43         96 my $block_title = $parser->{_outhtml_block_title};
1077 43         79 my $made = $parser->{out_made};
1078 43         184 my $charset = $parser->{_out_charset};
1079 43         80 my $css = $parser->{out_css};
1080 43         187 my $xmllang = "ja-JP";
1081 43 50       145 defined($plain_title) or $plain_title = 'untitled';
1082 43         113 my $cls = "$parser->{_cssprefix}title_block";
1083 43 50       141 defined($block_title) or $block_title = qq(
\n$plain_title
\n\n);
1084 43 100       4591 if( $parser->{_in_charset} ne $parser->{_out_charset} )
1085             {
1086 20         104 foreach($plain_title,$block_title,$made,$charset,$css)
1087             {
1088 100 100       456 defined($_) or next;
1089 60         351 $_ = $parser->_from_to($_);
1090             }
1091             }
1092            
1093             # 出力開始
1094             #
1095 43         657 print $out_fh qq(\n);
1096 43         741 print $out_fh qq(\n);
1097 43         601 print $out_fh qq(\n);
1098 43         443 print $out_fh qq(\n);
1099 43         717 print $out_fh qq( \n);
1100 43 50       521 if( defined($css) )
1101             {
1102 0         0 print $out_fh qq( \n);
1103 0         0 print $out_fh qq( \n);
1104             }
1105             #print $out_fh qq( \n);
1106 43         169 print $out_fh qq( $plain_title\n);
1107 43 50       744 if( defined($made) )
1108             {
1109 0         0 print $out_fh qq( \n);
1110             }
1111 43         126 print $out_fh qq( \n);
1112 43         738 print $out_fh qq( \n);
1113 43         409 print $out_fh qq(\n);
1114 43         434 print $out_fh qq(\n);
1115 43         487 print $out_fh qq(\n);
1116            
1117 43         358 print $out_fh $block_title;
1118            
1119             # table of contents
1120             #
1121 43 100       373 if( @{$parser->{heads}} )
  43         168  
1122             {
1123 1         11 my $heading = $parser->_from_to($parser->{_outhtml_heading_toc},'toc.heading');
1124 1         4 print $out_fh qq(\n);
1125 1         11 print $out_fh qq(
\n);
1126 1         10 print $out_fh qq(

\n$heading\n

\n);
1127 1         9 print $out_fh qq(
    \n);
1128 1         7 my $curlevel = 0;
1129 1         10 foreach (@{$parser->{heads}})
  1         3  
1130             {
1131 1         3 my ($text,$id,$headsize) = @$_[PARAINFO_CONTENT,
1132             PARAINFO_ID, PARAINFO_HEADSIZE];
1133 1         4 $text = $parser->_from_to($text,$_->[PARAINFO_PARAOBJ]);
1134 1 50       4 if( !$curlevel )
    0          
    0          
1135             {
1136             # 最初の1個.
1137 1         1 $curlevel = 1;
1138             }elsif( $curlevel==$headsize )
1139             {
1140             # 同じレベル.
1141 0         0 print $out_fh qq(\n);
1142             }elsif( $curlevel<$headsize )
1143             {
1144             # レベル増加.
1145 0         0 print $out_fh qq(
    \n);
1146 0         0 ++$curlevel;
1147 0         0 print $out_fh qq(
  • *\n
      \n)x($headsize-$curlevel);
  • 1148 0         0 $curlevel=$headsize;
    1149             }else
    1150             {
    1151             # レベル減少.
    1152 0         0 print $out_fh qq(\n).(qq(\n\n)x($curlevel-$headsize));
    1153 0         0 $curlevel = $headsize;
    1154             }
    1155 1         8 print $out_fh qq(
  • \n$text\n);
  • 1156             }
    1157 1         15 print $out_fh qq(\n\n)x$curlevel;
    1158 1         8 print $out_fh qq(\n);
    1159 1         15 print $out_fh qq(\n);
    1160 1         8 print $out_fh qq(\n);
    1161             }
    1162            
    1163             # 本文の出力.
    1164 43         235 my $in_item = 0;
    1165 43         75 my $first_item = 1;
    1166 43         86 my @verbpack;
    1167             my @blockstack;
    1168 6     6   88 use constant {STK_PARAOBJ=>0,STK_BEHAVIOR=>1,};
      6         15  
      6         731  
    1169 6     6   33 use constant {BHV_NONE=>'none',BHV_NORMAL=>'normal',BHV_VERBATIM=>'verbatim',BHV_IGNORE=>'ignore'};
      6         18  
      6         23190  
    1170 43         295 print $out_fh qq(\n);
    1171 43         451 foreach (@{$parser->{paras}})
      43         156  
    1172             {
    1173 86         468 my ($paratype,$paraobj) = @$_[PARAINFO_TYPE,PARAINFO_PARAOBJ];
    1174 86         190 $parser->{_iseqstack} = [];
    1175            
    1176             # ignore 状態の確認
    1177             #
    1178 86 50       396 if( grep{$_->[STK_BEHAVIOR]eq BHV_IGNORE}@blockstack )
      0         0  
    1179             {
    1180             #print $out_fh " in ignore ...\n";
    1181 0 0 0     0 if( $paratype==PARA_END
    1182             && $_->[PARAINFO_CONTENT] eq $blockstack[-1]->[STK_PARAOBJ][PARAINFO_CONTENT] )
    1183             {
    1184 0         0 my $fin = pop(@blockstack);
    1185 0         0 my $mode = $_->[PARAINFO_CONTENT];
    1186 0         0 my $outtext = "\n";
    1187 0         0 print $out_fh $parser->_from_to($outtext);
    1188             }
    1189 0         0 next;
    1190             }
    1191            
    1192             # 連続する verbose の連結処理.
    1193             #
    1194 86 0 0 0   823 my $blk = first{(ref($_)||'')eq'ARRAY'&&$$_[STK_BEHAVIOR]ne BHV_IGNORE}reverse @blockstack;
      0         0  
    1195 86 50 33     1527 if( $paratype==PARA_VERBATIM || ($paratype!=PARA_END&&$blk&&$blk->[STK_BEHAVIOR]eq BHV_VERBATIM) )
        50 33        
          33        
    1196             {
    1197 0         0 my $text = $parser->escapeHtml($paraobj->text());
    1198 0         0 $text = $parser->_from_to($text);
    1199 0 0       0 $text !~ /^\n*$/ and push(@verbpack,$text);
    1200 0         0 next;
    1201             }elsif( @verbpack )
    1202             {
    1203 0         0 my $text = join('',@verbpack);
    1204 0         0 $text =~ s/\s*$//;
    1205 0 0       0 if( $text !~ /^\n*$/ )
    1206             {
    1207 0         0 $text =~ s/\n+$/\n/;
    1208 0         0 my $outtext = qq(
    $text
    \n\n);
    1209 0         0 print $out_fh $outtext;
    1210             }
    1211 0         0 @verbpack = ();
    1212             }
    1213            
    1214             # 普通に出力処理.
    1215             # $outtext には _from_to 済みのテキストを追加.
    1216             #
    1217 86         271 my $outtext;
    1218 86 100       717 if( $paratype==PARA_TEXTBLOCK )
        100          
        50          
        50          
        50          
        50          
        50          
        50          
        50          
        50          
        0          
    1219             {
    1220 43         203 my $text = $parser->buildhtml($paraobj);
    1221 43         1119 $text = $parser->_from_to($text);
    1222 43 50       556 $text =~ /^\s*$/ and next;
    1223 43         134 $outtext = "

    \n$text\n

    \n\n";
    1224             }elsif( $paratype==PARA_HEAD )
    1225             {
    1226 1         9 $outtext = '';
    1227 1 50       4 if( @blockstack )
    1228             {
    1229 0         0 foreach(@blockstack)
    1230             {
    1231 0 0       0 if( ref($_)eq'ARRAY' )
    1232             {
    1233 0 0       0 if( $_->[PARAINFO_TYPE]==PARA_OVER )
    1234             {
    1235 0         0 my ($type) = $_->[PARAINFO_LISTTYPE];
    1236 0 0       0 $type eq 'dl' and $outtext .= "";
    1237 0         0 $outtext .= " \n\n";
    1238             }
    1239             }else
    1240             {
    1241 0         0 my $type = $_;
    1242 0 0       0 $type eq 'dl' and $outtext .= "";
    1243 0         0 $outtext .= " \n\n";
    1244             }
    1245             }
    1246 0         0 $#blockstack = -1;
    1247 0         0 $first_item = 1;
    1248             }
    1249 1         3 my ($text,$id,$headsize) = @$_[PARAINFO_CONTENT,PARAINFO_ID,PARAINFO_HEADSIZE];
    1250 1         3 my $tag = "h$headsize";
    1251 1         4 $text = $parser->_from_to($text);
    1252 1 50       7 $headsize==1 and $outtext .= qq(\n
    \n);
    1253 1         4 $outtext .= qq(<$tag>\n$text\n\n);
    1254             }elsif( $paratype==PARA_OVER )
    1255             {
    1256 0         0 my ($type) = $_->[PARAINFO_LISTTYPE];
    1257 0         0 $outtext = '';
    1258 0 0       0 if( defined($type) )
    1259             {
    1260 0         0 $outtext .= "<$type>\n";
    1261             }else
    1262             {
    1263 0         0 warn "over type unknown, using ul";
    1264 0         0 $type = 'ul';
    1265 0         0 $outtext .= "\n";
    1266 0         0 $outtext .= "<$type>\n";
    1267             }
    1268 0         0 $first_item = 1;
    1269 0         0 my @stk;
    1270 0         0 @stk[STK_PARAOBJ,STK_BEHAVIOR] = ($_,BHV_NORMAL);
    1271 0         0 push(@blockstack,\@stk);
    1272             }elsif( $paratype==PARA_BACK )
    1273             {
    1274 0         0 my ($type) = @$_[PARAINFO_LISTTYPE];
    1275 0         0 $outtext = '';
    1276 0 0       0 if( $in_item )
    1277             {
    1278 0 0       0 $outtext = $type eq 'dl' ? "\n" : "\n";
    1279 0         0 --$in_item;
    1280             }
    1281 0         0 $outtext .= "\n\n";
    1282 0         0 pop(@blockstack);
    1283             }elsif( $paratype==PARA_ITEM )
    1284             {
    1285 0         0 my ($type,$id) = @$_[PARAINFO_LISTTYPE,PARAINFO_ID];
    1286 0         0 $outtext = '';
    1287 0 0       0 if( !@blockstack )
    1288             {
    1289 0         0 push(@blockstack,$type);
    1290 0         0 $outtext = qq(<$type> \n);
    1291             }
    1292 0 0 0     0 if( $type eq 'ul' || $type eq 'ol' )
        0          
    1293             {
    1294 0 0       0 $first_item or $outtext .= "\n";
    1295 0         0 $outtext .= qq(
  • \n);
  • 1296             }elsif( $type eq 'dl' )
    1297             {
    1298 0         0 my $bak = delete $parser->{_linkwords};
    1299 0         0 my $item = $parser->buildhtml($paraobj);
    1300 0         0 $parser->{_linkwords} = $bak;
    1301 0         0 $item =~ s/^\s+//;
    1302 0         0 $item =~ s/\s+$//;
    1303 0         0 $item = $parser->_from_to($item);
    1304 0 0       0 $first_item or $outtext .= "\n";
    1305 0         0 $outtext .= qq(
    $item
    \n);
    1306 0         0 $outtext .= qq(
    \n);
    1307             }else
    1308             {
    1309 0         0 $parser->vermsg(VERBOSE_ERROR,"unknown list type [$type]");
    1310             }
    1311 0 0       0 $first_item and undef($first_item),++$in_item;
    1312             }elsif( $paratype==PARA_BEGIN )
    1313             {
    1314 0         0 my @stk;
    1315 0         0 @stk[STK_PARAOBJ,STK_BEHAVIOR] = ($_,BHV_IGNORE);
    1316 0         0 push(@blockstack,\@stk);
    1317 0         0 my $mode = $_->[PARAINFO_CONTENT];
    1318 0 0       0 if( $mode eq 'html' )
        0          
    1319             {
    1320 0         0 $outtext .= "\n";
    1321 0         0 $stk[STK_BEHAVIOR] = BHV_NORMAL;
    1322             }elsif( $mode eq 'text' )
    1323             {
    1324 0         0 $outtext .= "\n";
    1325 0         0 $stk[STK_BEHAVIOR] = BHV_VERBATIM;
    1326             }else
    1327             {
    1328 0         0 $outtext .= "\n";
    1329             }
    1330             }elsif( $paratype==PARA_END )
    1331             {
    1332 0         0 my $fin = pop(@blockstack);
    1333 0         0 my $mode = $_->[PARAINFO_CONTENT];
    1334 0         0 $outtext .= "\n";
    1335             }elsif( $paratype==PARA_FOR )
    1336             {
    1337             }elsif( $paratype==PARA_ENCODING )
    1338             {
    1339 0         0 my $text = $_->[PARAINFO_CONTENT];
    1340 0         0 my $cmd = $paraobj->cmd_name();
    1341 0         0 $text = $parser->_from_to($text);
    1342 0         0 $text =~ s/\n(\s*\n)+/\n/g;
    1343 0         0 $outtext = "\n";
    1344             }elsif( $paratype==PARA_POD )
    1345             {
    1346             }elsif( $paratype==PARA_CUT )
    1347             {
    1348             }else
    1349             {
    1350 0         0 $parser->verbmsg(VERBOSE_ERROR,"what\'s got?? [$paratype]");
    1351 0         0 next;
    1352             }
    1353 86 100       396 if( defined($outtext) )
    1354             {
    1355             # $outtext は _from_to 済み.
    1356 44         445 print $out_fh $outtext;
    1357             }
    1358             }
    1359 43 50       695 if( @verbpack )
    1360             {
    1361 0         0 my $text = join('',@verbpack);
    1362 0 0       0 if( $text !~ /^\n*$/ )
    1363             {
    1364 0         0 my $outtext = qq(
    $text
    \n\n);
    1365 0         0 $outtext = $parser->_from_to($outtext);
    1366 0         0 print $out_fh $outtext;
    1367             }
    1368             }
    1369 43         482 print $out_fh qq(\n);
    1370 43         480 print $out_fh qq(\n);
    1371            
    1372 43         545 print $out_fh $block_title;
    1373            
    1374             # 索引
    1375             #
    1376             {
    1377 43         679 my $heading = $parser->_from_to($parser->{_outhtml_heading_index});
      43         1386  
    1378 43         232 print $out_fh qq(\n);
    1379 43         450 print $out_fh qq(
    \n);
    1380 43         442 print $out_fh qq(

    $heading

    \n);
    1381 43         583 print $out_fh qq(
    \n);
    1382 43         456 print $out_fh qq(
      \n);
    1383 43         352 foreach(sort keys %{$parser->{_linkwords}})
      43         305  
    1384             {
    1385             #my ($text,$id) = ($parser->escapeHtml($_),$parser->{_linkwords}{$_});
    1386 2         12 my ($text,$id) = ($_,$parser->{_linkwords}{$_});
    1387 2         6 $text = $parser->_from_to($text);
    1388 2         8 print $out_fh qq(
  • $text
  • \n);
    1389             }
    1390 43         485 print $out_fh qq(\n);
    1391 43         437 print $out_fh qq(\n);
    1392 43         411 print $out_fh qq(\n);
    1393 43         410 print $out_fh qq(\n);
    1394            
    1395 43         366 print $out_fh $block_title;
    1396             }
    1397            
    1398 43         1622 print $out_fh qq(\n);
    1399 43         534 print $out_fh qq(\n);
    1400             }
    1401              
    1402             # =============================================================================
    1403             # ユーティリティ関数群
    1404             # =============================================================================
    1405              
    1406             # -----------------------------------------------------------------------------
    1407             # $text = $this->escapeHtml($text);
    1408             # html に埋め込めれる用にエスケープ
    1409             #
    1410             sub escapeHtml
    1411             {
    1412 168     168 1 542 my @list = @_[1..$#_];
    1413 168 50       575 wantarray or @list = shift @list;
    1414 168         304 foreach(@list)
    1415             {
    1416 168 50       679 defined($_) or next;
    1417 168 50       685 s/([&<>\"])/$1 eq '&' ? '&'
      2 50       28  
        50          
    1418             : $1 eq '<' ? '<'
    1419             : $1 eq '>' ? '>'
    1420             : '"' /ge;
    1421             }
    1422 168 50       846 @list!=1?@list:$list[0];
    1423             }
    1424              
    1425             # -----------------------------------------------------------------------------
    1426             # $text = $this->unescapeHtml($text);
    1427             # escapeHtml によって実体参照に変換された文字を通常の文字に戻す.
    1428             #
    1429             sub unescapeHtml
    1430             {
    1431 0     0 1 0 my @list = @_[1..$#_];
    1432 0 0       0 wantarray or @list = shift @list;
    1433 0         0 foreach(@list)
    1434             {
    1435 0 0       0 s/&(lt|gt|amp|quot);/$1 eq 'amp' ? '&'
      0 0       0  
        0          
    1436             : $1 eq 'lt' ? '<'
    1437             : $1 eq 'gt' ? '>'
    1438             : '"' /ge;
    1439             }
    1440 0 0       0 @list!=1?@list:$list[0];
    1441             }
    1442              
    1443             # -----------------------------------------------------------------------------
    1444             # $text = $this->escapeUrl($text);
    1445             # url に埋め込めれる用にエスケープ
    1446             #
    1447             sub escapeUrl
    1448             {
    1449 4     4 1 16 my @list = @_[1..$#_];
    1450 4 50       17 wantarray or @list = $list[0];
    1451 4         9 foreach(@list)
    1452             {
    1453 4         18 s/([^a-zA-Z0-9\-\_\.\!\~\*\'\(\)\/])/sprintf('%%%02x',unpack("C",$1))/eg;
      0         0  
    1454             }
    1455 4 50       21 @list!=1?@list:$list[0];
    1456             }
    1457              
    1458             # -----------------------------------------------------------------------------
    1459             # $text = $this->resolvePodEscape($text);
    1460             # E<> の中身を html な実体参照に変換.
    1461             #
    1462             sub resolvePodEscape
    1463             {
    1464 12     12 1 43 my @list = @_[1..$#_];
    1465 12 50       43 wantarray or @list = shift @list;
    1466 12         26 foreach(@list)
    1467             {
    1468 12 100       186 if( $_ eq 'lt' )
        100          
        100          
        100          
        100          
        100          
        100          
    1469             {
    1470 1         5 $_ = '<';
    1471             }elsif( $_ eq 'gt' )
    1472             {
    1473 1         11 $_ = '>';
    1474             }elsif( $_ eq 'verbar' )
    1475             {
    1476 1         10 $_ = '|';
    1477             }elsif( $_ eq 'sol' )
    1478             {
    1479 1         13 $_ = '/';
    1480             }elsif( $_ =~ /^0x([0-9a-fA-F]+)$/ )
    1481             {
    1482 2         17 $_ = "&#x$1;";
    1483             }elsif( $_ =~ /^0([0-7]+)$/ )
    1484             {
    1485 2         33 $_ = "&#".oct($1).";";
    1486             }elsif( $_ =~ /^\d+$/ )
    1487             {
    1488 2         22 $_ = "&#$_;";
    1489             }else
    1490             {
    1491 2         13 $_ = "&$_;";
    1492             }
    1493             }
    1494 12 50       63 wantarray?@list:$list[0];
    1495             }
    1496             # -----------------------------------------------------------------------------
    1497             # $text = $parser->resolveLink($text);
    1498             #
    1499             sub resolveLink
    1500             {
    1501 0     0 1   my ($parser,@list) = @_;
    1502 0 0         @list = $parser->unescapeHtml(wantarray?@list:shift @list);
    1503 0           foreach(@list)
    1504             {
    1505 0 0         if( /^\w+:[^:]/ )
    1506             {
    1507 0           my $link_to = $parser->escapeHtml($_);
    1508 0           $_ = qq($_);
    1509             }else
    1510             {
    1511 0           my ($text,$target,$sec);
    1512 0 0         if( /^"(.*)"$/ )
    1513             {
    1514 0           ($text,$target,$sec) = ('','',$1);
    1515             }else
    1516             {
    1517 0 0         $text = s/^([^\/\|]*)\|// ? $1 : '';
    1518 0 0         $target = s/^([^\/\|]*)\/?// ? $1 : '';
    1519 0           ($sec = $_) =~ s/^\"(.*)\"$/$1/;
    1520             }
    1521 0   0       my $lang = $parser->{_expandlangs}[0]||$parser->{_defaultlang} || DEFAULT_LANG;
    1522 0           return $parser->makelink($lang,$text,$target,$sec);
    1523             }
    1524             }
    1525 0 0         wantarray?@list:$list[0];
    1526             }
    1527              
    1528             1;
    1529             __END__