File Coverage

blib/lib/Pod/SAX.pm
Criterion Covered Total %
statement 235 312 75.3
branch 86 134 64.1
condition 10 27 37.0
subroutine 26 35 74.2
pod n/a
total 357 508 70.2


line stmt bran cond sub pod time code
1             # $Id: SAX.pm,v 1.25 2003/01/29 18:01:08 matt Exp $
2              
3             package Pod::SAX;
4              
5             $VERSION = '0.14';
6 12     12   112079 use XML::SAX::Base;
  12         380605  
  12         575  
7             @ISA = qw(XML::SAX::Base);
8              
9 12     12   193 use strict;
  12         28  
  12         597  
10 12     12   21098 use XML::SAX::DocumentLocator;
  12         6666  
  12         2768  
11              
12             sub _parse_bytestream {
13 2     2   1513 my ($self, $fh) = @_;
14 2         52 my $parser = Pod::SAX::Parser->new();
15 2         9 $parser->set_parent($self);
16 2         112 $parser->parse_from_filehandle($fh, undef);
17             }
18              
19             sub _parse_characterstream {
20 0     0   0 my ($self, $fh) = @_;
21 0         0 die "parse_characterstream not supported";
22             }
23              
24             sub _parse_string {
25 7     7   6217 my ($self, $str) = @_;
26 7         220 my $parser = Pod::SAX::Parser->new();
27 7         57 $parser->set_parent($self);
28 7         52 my $strobj = Pod::SAX::StringIO->new($str);
29 7         504 $parser->parse_from_filehandle($strobj, undef);
30             }
31              
32             sub _parse_systemid {
33 2     2   1404 my ($self, $sysid) = @_;
34 2         64 my $parser = Pod::SAX::Parser->new();
35 2         12 $parser->set_parent($self);
36 2         338 $parser->parse_from_file($sysid, undef);
37             }
38              
39             package Pod::SAX::Parser;
40              
41 12     12   83 use Pod::Parser;
  12         21  
  12         756  
42 12     12   61 use vars qw(@ISA %HTML_Escapes);
  12         23  
  12         83805  
43             @ISA = qw(Pod::Parser);
44              
45             %HTML_Escapes = (
46             'amp' => '&', # ampersand
47             'lt' => '<', # left chevron, less-than
48             'gt' => '>', # right chevron, greater-than
49             'quot' => '"', # double quote
50             'sol' => '/', # slash
51             'verbar' => '|', # vertical bar
52              
53             "Aacute" => "\xC3\x81", # capital A, acute accent
54             "aacute" => "\xC3\xA1", # small a, acute accent
55             "Acirc" => "\xC3\x82", # capital A, circumflex accent
56             "acirc" => "\xC3\xA2", # small a, circumflex accent
57             "AElig" => "\xC3\x86", # capital AE diphthong (ligature)
58             "aelig" => "\xC3\xA6", # small ae diphthong (ligature)
59             "Agrave" => "\xC3\x80", # capital A, grave accent
60             "agrave" => "\xC3\xA0", # small a, grave accent
61             "Aring" => "\xC3\x85", # capital A, ring
62             "aring" => "\xC3\xA5", # small a, ring
63             "Atilde" => "\xC3\x83", # capital A, tilde
64             "atilde" => "\xC3\xA3", # small a, tilde
65             "Auml" => "\xC3\x84", # capital A, dieresis or umlaut mark
66             "auml" => "\xC3\xA4", # small a, dieresis or umlaut mark
67             "Ccedil" => "\xC3\x87", # capital C, cedilla
68             "ccedil" => "\xC3\xA", # small c, cedilla
69             "Eacute" => "\xC3\x89", # capital E, acute accent
70             "eacute" => "\xC3\xA9", # small e, acute accent
71             "Ecirc" => "\xC3\x8A", # capital E, circumflex accent
72             "ecirc" => "\xC3\xAA", # small e, circumflex accent
73             "Egrave" => "\xC3\x88", # capital E, grave accent
74             "egrave" => "\xC3\xA8", # small e, grave accent
75             "ETH" => "\xC3\x90", # capital Eth, Icelandic
76             "eth" => "\xC3\xB0", # small eth, Icelandic
77             "Euml" => "\xC3\x8B", # capital E, dieresis or umlaut mark
78             "euml" => "\xC3\xAB", # small e, dieresis or umlaut mark
79             "Iacute" => "\xC3\x8D", # capital I, acute accent
80             "iacute" => "\xC3\xAD", # small i, acute accent
81             "Icirc" => "\xC3\x8E", # capital I, circumflex accent
82             "icirc" => "\xC3\xAE", # small i, circumflex accent
83             "Igrave" => "\xC3\x8D", # capital I, grave accent
84             "igrave" => "\xC3\xAD", # small i, grave accent
85             "Iuml" => "\xC3\x8F", # capital I, dieresis or umlaut mark
86             "iuml" => "\xC3\xAF", # small i, dieresis or umlaut mark
87             "Ntilde" => "\xC3\x91", # capital N, tilde
88             "ntilde" => "\xC3\xB1", # small n, tilde
89             "Oacute" => "\xC3\x93", # capital O, acute accent
90             "oacute" => "\xC3\xB3", # small o, acute accent
91             "Ocirc" => "\xC3\x94", # capital O, circumflex accent
92             "ocirc" => "\xC3\xB4", # small o, circumflex accent
93             "Ograve" => "\xC3\x92", # capital O, grave accent
94             "ograve" => "\xC3\xB2", # small o, grave accent
95             "Oslash" => "\xC3\x98", # capital O, slash
96             "oslash" => "\xC3\xB8", # small o, slash
97             "Otilde" => "\xC3\x95", # capital O, tilde
98             "otilde" => "\xC3\xB5", # small o, tilde
99             "Ouml" => "\xC3\x96", # capital O, dieresis or umlaut mark
100             "ouml" => "\xC3\xB6", # small o, dieresis or umlaut mark
101             "szlig" => "\xC3\x9F", # small sharp s, German (sz ligature)
102             "THORN" => "\xC3\x9E", # capital THORN, Icelandic
103             "thorn" => "\xC3\xBE", # small thorn, Icelandic
104             "Uacute" => "\xC3\x9A", # capital U, acute accent
105             "uacute" => "\xC3\xBA", # small u, acute accent
106             "Ucirc" => "\xC3\x9B", # capital U, circumflex accent
107             "ucirc" => "\xC3\xBB", # small u, circumflex accent
108             "Ugrave" => "\xC3\x99", # capital U, grave accent
109             "ugrave" => "\xC3\xB9", # small u, grave accent
110             "Uuml" => "\xC3\x9C", # capital U, dieresis or umlaut mark
111             "uuml" => "\xC3\xBC", # small u, dieresis or umlaut mark
112             "Yacute" => "\xC3\x9D", # capital Y, acute accent
113             "yacute" => "\xC3\xBD", # small y, acute accent
114             "yuml" => "\xC3\xBF", # small y, dieresis or umlaut mark
115              
116             "lchevron" => "\xC2\xAB", # left chevron (double less than)
117             "rchevron" => "\xC2\xBB", # right chevron (double greater than)
118             );
119              
120             sub sex {
121 0     0   0 require Data::Dumper;$Data::Dumper::Indent=1;warn(Data::Dumper::Dumper(@_));
  0         0  
  0         0  
122             }
123              
124             sub set_parent {
125 11     11   28 my $self = shift;
126 11         136 $self->{parent} = shift;
127             }
128              
129             sub parent {
130 1215     1215   2150 my $self = shift;
131 1215         6010 return $self->{parent};
132             }
133              
134             sub begin_pod {
135 11     11   26 my $self = shift;
136 11         47 my $sysid = $self->parent->{ParserOptions}->{Source}{SystemId};
137             $self->parent->set_document_locator(
138             XML::SAX::DocumentLocator->new(
139 0     0   0 sub { "" },
140 0     0   0 sub { $sysid },
141 0     0   0 sub { $self->{line_number} },
142 0     0   0 sub { 0 },
143 11         55 ),
144             );
145 11         1599 $self->parent->start_document({});
146 11         10939 $self->parent->start_element(_element('pod'));
147 11         1513 $self->parent->characters({Data => "\n"});
148 11         531 $self->parent->comment({Data => " Pod::SAX v$Pod::SAX::VERSION, using POD::Parser v$Pod::Parser::VERSION "});
149 11         2961 $self->parent->characters({Data => "\n"});
150             }
151              
152             sub end_pod {
153 11     11   269 my $self = shift;
154 11 50       54 if ($self->{in_verbatim}) {
155 0         0 $self->parent->end_element(_element('verbatim', 1));
156 0         0 $self->parent->characters({Data => "\n"});
157             }
158 11         74 while ($self->{in_list}) {
159 1         5 $self->close_list();
160             }
161 11         35 $self->parent->end_element(_element('pod', 1));
162 11         951 $self->parent->end_document({});
163             }
164              
165             sub open_list {
166 14     14   32 my $self = shift;
167 14         19 my ($list_type) = @_;
168 14         38 $self->{list_type}[$self->{in_list}] = $list_type;
169 14         32 $self->parent->characters({Data => (" " x $self->{in_list})});
170 14         149 my $el = _element($list_type);
171 14         45 _add_attrib($el, indent_width => $self->{indent});
172 14         31 $self->parent->start_element($el);
173 14         1567 $self->parent->characters({Data => "\n"});
174 14         130 $self->{open_lists}--;
175 14         62 return;
176             }
177              
178             sub close_list {
179 15     15   19 my $self = shift;
180            
181 15 100       39 if ($self->{in_item}) {
182 14         30 $self->parent->end_element(_element('listitem', 1));
183 14         1595 $self->parent->characters({Data => "\n"});
184 14         285 $self->{in_item}--;
185             }
186            
187 15         34 my $list_type = $self->{list_type}[$self->{in_list}];
188 15         29 $self->{list_type}[$self->{in_list}] = undef;
189 15         34 $self->parent->characters({Data => (" " x $self->{in_list})});
190 15         132 $self->{in_list}--;
191 15         31 $self->parent->end_element(_element($list_type, 1));
192 15         1459 $self->parent->characters({Data => "\n"});
193 15         140 return;
194             }
195              
196             sub command {
197 114     114   5871 my ($self, $command, $paragraph, $line_num) = @_;
198             ## Interpret the command and its text; sample actions might be:
199 114         182 $self->{line_number} = $line_num;
200 114         597 $paragraph =~ s/\s*$//;
201 114         320 $paragraph =~ s/^\s*//;
202            
203 114 50       344 if ($self->{in_verbatim}) {
204 0         0 $self->parent->end_element(_element('verbatim', 1));
205 0         0 $self->parent->characters({Data => "\n"});
206 0         0 $self->{in_verbatim} = 0;
207             }
208            
209 114 100 33     837 if ($command eq 'over') {
    100          
    100          
    50          
    50          
    50          
210 15         28 $self->{in_list}++;
211 15         20 $self->{open_lists}++;
212 15 100       49 my $indent = ($paragraph ? $paragraph + 0 : 4);
213 15         23 $self->{indent} = $indent;
214 15         154 return;
215             }
216             elsif ($command eq 'back') {
217 14 50       38 if ($self->{in_list}) {
218 14         38 $self->close_list();
219             }
220             else {
221 0         0 throw XML::SAX::Exception::Parse (
222             Message => "=back without =over",
223             LineNumber => $self->{line_number},
224             ColumnNumber => 0,
225             );
226             }
227 14         134 return;
228             }
229             elsif ($command eq 'item') {
230 29 50       83 if (!$self->{in_list}) {
231 0         0 throw XML::SAX::Exception::Parse (
232             Message => "=item without =over",
233             LineNumber => $self->{line_number},
234             ColumnNumber => 0,
235             );
236             }
237 29 100       66 if ($self->{open_lists}) {
238             # determine list type, and open list tag
239 14         19 my $list_type = 'itemizedlist';
240 14 100       43 $paragraph =~ s|^\s* \* \s*||x and $list_type = 'itemizedlist';
241 14 100       51 $paragraph =~ s|^\s* \d+\.? \s*||x and $list_type = 'orderedlist';
242 14         41 $self->open_list($list_type);
243             }
244             else {
245 15 100       53 if ($self->{list_type}[$self->{in_list}] eq 'itemizedlist') {
    50          
246 12         37 $paragraph =~ s|^\s* \* \s*||x;
247             }
248             elsif ($self->{list_type}[$self->{in_list}] eq 'orderedlist') {
249 3         13 $paragraph =~ s|^\s* \d+\.? \s*||x;
250             }
251            
252 15 50       41 if ($self->{in_item}) {
253             # close the last one
254 15         31 $self->parent->end_element(_element('listitem', 1));
255 15         1614 $self->parent->characters({Data => "\n"});
256 15         139 $self->{in_item}--;
257             }
258             }
259            
260 29         59 $self->parent->characters({Data => " ".(" " x $self->{in_list})});
261            
262 29         268 $self->parent->start_element(_element('listitem'));
263 29 100       3047 if ($paragraph) {
264 26         1405 $self->parse_text({ -expand_ptree => 'expand_ptree' }, $paragraph, $line_num);
265 26         913 $self->parent->characters({Data => "\n"});
266             }
267 29         263 $self->{in_item}++;
268 29         396 return;
269             }
270             elsif ($command eq 'begin' || $command eq 'for') {
271 0 0       0 if ($self->{open_lists}) {
272             # non =item command while in =over section - must be indented
273 0         0 my $list_type = 'indent';
274 0         0 $self->open_list($list_type);
275             }
276            
277 0         0 my $el = _element('markup');
278 0         0 $paragraph =~ s/^(\S*)\s*//;
279 0         0 my $type = $1;
280 0         0 my $process_paragraphs = 0;
281 0 0       0 if ($type =~ /^:(.*)$/) {
282 0         0 $process_paragraphs = 1;
283 0         0 $type = $1;
284             }
285 0         0 _add_attrib($el, type => $type);
286 0         0 _add_attrib($el, ordinary_paragraph => $process_paragraphs);
287 0         0 $self->parent->start_element($el);
288 0 0       0 if ($process_paragraphs) {
289 0         0 $self->parse_text({ -expand_ptree => 'expand_ptree' }, $paragraph, $line_num);
290             }
291             else {
292 0         0 $self->parent->characters({Data => $paragraph});
293             }
294 0 0       0 $self->parent->end_element(_element('markup', 1)) if $command eq 'for';
295 0 0       0 $self->{in_begin_section} = 1 if $command eq 'begin';
296 0         0 return;
297             }
298             elsif ($command eq 'end') {
299 0 0       0 if ($self->{open_lists}) {
300             # non =item command while in =over section - must be indented
301 0         0 my $list_type = 'indent';
302 0         0 $self->open_list($list_type);
303             }
304            
305 0 0       0 if ($self->{in_begin_section}) {
306 0         0 $self->parent->end_element(_element('markup'));
307 0         0 $self->{in_begin_section} = 0;
308             }
309             else {
310 0         0 throw XML::SAX::Exception::Parse (
311             Message => "=end without =begin",
312             LineNumber => $self->{line_number},
313             ColumnNumber => 0,
314             );
315             }
316 0         0 return;
317             }
318             elsif ($self->{in_list}) {
319 0         0 throw XML::SAX::Exception::Parse (
320             Message => "=$command inside =over/=end block is not allowed",
321             LineNumber => $self->{line_number},
322             ColumnNumber => 0,
323             );
324             }
325            
326 56 100       156 if ($command eq 'pod') {
327 1         15 return;
328             }
329            
330 55         134 $self->parent->start_element(_element($command));
331 55         8575 $self->parse_text({ -expand_ptree => 'expand_ptree' }, $paragraph, $line_num);
332 55         1604 $self->parent->end_element(_element($command, 1));
333 55         7740 $self->parent->characters({Data => "\n"});
334             }
335              
336             sub verbatim {
337 29     29   1228 my ($self, $paragraph, $line_num) = @_;
338 29         50 $self->{line_number} = $line_num;
339            
340 29         38 my $text = $paragraph;
341 29         118 $text =~ s/\n\z//;
342            
343 29 50       77 if ($self->{open_lists}) {
344             # non =item command while in =over section - must be indented
345 0         0 $self->open_list('indent');
346             }
347            
348 29 100       156 return unless $paragraph =~ /\S/;
349            
350 26         33 my $last_verbatim = 0;
351 26 100       89 if ($text =~ /\n\z/) {
352 20         37 $last_verbatim = 1;
353             }
354            
355 26 100       89 $self->parent->start_element(_element('verbatim')) unless $self->{in_verbatim};
356 26 100       1866 $self->parent->characters({Data => "\n\n"}) if $self->{in_verbatim};
357 26         138 $self->{in_verbatim} = 1;
358            
359 26 50       108 if ($paragraph =~ /^(\s+)/) {
360             # get all indents
361 26         295 my @indents = ($paragraph =~ m/^([ \t]+)/mg);
362             # and take the shortest one
363 47         77 my $indent = (
364 55         74 sort { length($a) <=> length($b) }
365 26         54 map { s/\t/ /g; $_ } # expand tabs
  55         142  
366             @indents)[0];
367              
368 26         296 $paragraph =~ s/\s*$//;
369 26 50       63 return unless length $paragraph;
370             # warn("stripping: '$indent'\n");
371 26         187 $paragraph =~ s/^$indent//mg; # un-indent
372 26         65 $self->parent->characters({Data => $paragraph});
373             }
374            
375 26 100       524 if ($last_verbatim) {
376 20         58 $self->parent->end_element(_element('verbatim', 1));
377 20         2590 $self->parent->characters({Data => "\n"});
378 20         1151 $self->{in_verbatim} = 0;
379             }
380             }
381              
382             sub textblock {
383 96     96   2921 my ($self, $paragraph, $line_num) = @_;
384 96         215 $self->{line_number} = $line_num;
385              
386 96 100       259 if ($self->{open_lists}) {
387             # non =item command while in =over section - must be indented
388 1         3 my $list_type = 'indent';
389 1         3 $self->{list_type}[$self->{in_list}] = $list_type;
390 1         4 $self->parent->characters({Data => (" " x $self->{in_list})});
391 1         11 my $el = _element($list_type);
392 1         4 _add_attrib($el, indent_width => $self->{indent});
393 1         3 $self->parent->start_element($el);
394 1         108 $self->parent->characters({Data => "\n"});
395 1         12 $self->{open_lists}--;
396             }
397 96 50       229 if ($self->{in_verbatim}) {
398 0         0 $self->parent->end_element(_element('verbatim', 1));
399 0         0 $self->parent->characters({Data => "\n"});
400 0         0 $self->{in_verbatim} = 0;
401             }
402            
403            
404 96         380 $paragraph =~ s/^\s*//;
405 96         1559 $paragraph =~ s/\s*$//;
406            
407 96         236 $self->parent->start_element(_element('para'));
408 96         17190 $self->parse_text({ -expand_ptree => 'expand_ptree' }, $paragraph, $line_num);
409 96         4384 $self->parent->end_element(_element('para', 1));
410 96         10327 $self->parent->characters({Data => "\n"});
411             }
412              
413             sub expand_ptree {
414 216     216   347 my ($self, $ptree) = @_;
415 216         1106 foreach my $node ($ptree->children) {
416             # warn("Expand_ptree($node)\n");
417 300 100       4079 if (ref($node)) {
418 54         140 $self->expand_seq($node);
419             }
420             else {
421 246         664 $self->parent->characters({Data => $node});
422             }
423             }
424             }
425              
426             # Copied from Pod::Tree::Node
427             sub SplitTarget
428             {
429 0     0   0 my $text = shift;
430 0         0 my($page, $section);
431            
432 0 0       0 if ($text =~ /^"(.*)"$/s) # L<"sec">;
433             {
434 0         0 $page = '';
435 0         0 $section = $1;
436             }
437             else # all other cases
438             {
439 0         0 ($page, $section) = split m(/), $text, 2;
440            
441             # to quiet -w
442 0 0       0 defined $page or $page = '';
443 0 0       0 defined $section or $section = '';
444            
445 0         0 $page =~ s/\s*\(\d\)$//; # ls (1) -> ls
446 0         0 $section =~ s( ^" | "$ )()xg; # lose the quotes
447            
448             # L
(without quotes)
449 0 0 0     0 if ($page !~ /^[\w.-]+(::[\w.-]+)*$/ and $section eq '')
450             {
451 0         0 $section = $page;
452 0         0 $page = '';
453             }
454             }
455            
456 0         0 $section =~ s( \s*\n\s* )( )xg; # close line breaks
457 0         0 $section =~ s( ^\s+ | \s+$ )()xg; # clip leading and trailing WS
458            
459 0         0 ($page, $section)
460             }
461              
462             sub expand_seq {
463 54     54   126 my ($self, $sequence) = @_;
464            
465 54         208 my $name = $sequence->cmd_name;
466 54         294 my ($filename, $line_number) = $sequence->file_line();
467 54         91 $self->{line_number} = $line_number;
468            
469             # warn("seq $name\n");
470            
471 54 100       167 if ($name eq 'L') {
    100          
    50          
472             # link
473            
474 22         234 my $link = $sequence->raw_text;
475 22         113 $link =~ s/^L<(.*)>$/$1/;
476 22         61 $link =~ s/^<+\s(.*)\s>+$/$1/;
477 22         62 my ($text, $inferred, $name, $section, $type) = $self->parselink($link);
478 22 100       59 $text = '' unless defined $text;
479 22 50       53 $inferred = '' unless defined $inferred;
480 22 50       118 $name = '' unless defined $name;
481 22 100       92 $section = '' unless defined $section;
482 22 50       45 $type = '' unless defined $type;
483              
484             # warn("Link L<$link> parsed into: '$text', '$inferred', '$name', '$section', '$type'\n");
485            
486 22 100       46 if ($type eq 'url') {
487 4         12 my $start = _element("xlink");
488 4         22 _add_attrib($start, href => $name);
489            
490 4         12 $self->parent->start_element($start);
491 4         478 $self->parse_text({ -expand_ptree => 'expand_ptree' }, $inferred, $line_number);
492 4         80 $self->parent->end_element(_element('xlink', 1));
493             }
494             else {
495 18         59 my $start = _element("link");
496 18         43 _add_attrib($start, page => $name);
497 18         35 _add_attrib($start, section => $section);
498 18         33 _add_attrib($start, type => $type);
499            
500 18         38 $self->parent->start_element($start);
501 18         3491 $self->parse_text({ -expand_ptree => 'expand_ptree' }, $inferred, $line_number);
502 18         6894 $self->parent->end_element(_element('link', 1));
503             }
504             }
505             elsif ($name eq 'E') {
506 15         105 my $text = join('', $sequence->parse_tree->children);
507 15         24 my $char;
508 15 100       45 if ($text =~ /^\d+$/) {
509 1         7 $char = chr($text);
510             }
511             else {
512 14         32 $char = $HTML_Escapes{$text};
513             }
514             # warn("doing E<$text> = $char\n");
515            
516 15         45 $self->parent->characters({Data => $char});
517             }
518             elsif ($name eq 'S') {
519 0         0 my $spaces = join('', $sequence->parse_tree->children);
520 0         0 $self->parent->characters({Data => "\160" x length($spaces)});
521             }
522             else {
523 17         42 $self->parent->start_element(_element($name));
524 17         2347 $self->expand_ptree($sequence->parse_tree);
525 17         219 $self->parent->end_element(_element($name, 1));
526             }
527             }
528              
529             sub expand_text {
530 0     0   0 my ($self, $text, $ptree_node) = @_;
531 0         0 $self->parent->characters({Data => $text});
532             }
533              
534             sub _element {
535 530     530   830 my ($name, $end) = @_;
536             return {
537 530 100       4416 Name => $name,
538             LocalName => $name,
539             $end ? () : (Attributes => {}),
540             NamespaceURI => '',
541             Prefix => '',
542             };
543             }
544              
545             sub _add_attrib {
546 73     73   102 my ($el, $name, $value) = @_;
547            
548 73         392 $el->{Attributes}{"{}$name"} =
549             {
550             Name => $name,
551             LocalName => $name,
552             Prefix => "",
553             NamespaceURI => "",
554             Value => $value,
555             };
556             }
557              
558             # Next three functions copied from Pod::ParseLink
559              
560             # Parse the name and section portion of a link into a name and section.
561             sub _parse_section {
562 18     18   26 my ($link) = @_;
563 18         36 $link =~ s/^\s+//;
564 18         29 $link =~ s/\s+$//;
565            
566             # If the whole link is enclosed in quotes, interpret it all as a section
567             # even if it contains a slash.
568 18 50       50 return (undef, $1) if ($link =~ /^"\s*(.*?)\s*"$/);
569            
570             # Split into page and section on slash, and then clean up quoting in the
571             # section. If there is no section and the name contains spaces, also
572             # guess that it's an old section link.
573 18         44 my ($page, $section) = split (/\s*\/\s*/, $link, 2);
574 18 100       48 $section =~ s/^"\s*(.*?)\s*"$/$1/ if $section;
575 18 50 33     131 if ($page && $page =~ / / && !defined ($section)) {
      33        
576 0         0 $section = $page;
577 0         0 $page = undef;
578             } else {
579 18 50       38 $page = undef unless $page;
580 18 100       36 $section = undef unless $section;
581             }
582 18         44 return ($page, $section);
583             }
584              
585             # Infer link text from the page and section.
586             sub _infer_text {
587 6     6   7 my ($page, $section) = @_;
588 6         8 my $inferred;
589 6 100 66     43 if ($page && !$section) {
    50 33        
    50 33        
590 5         8 $inferred = $page;
591             } elsif (!$page && $section) {
592 0         0 $inferred = '"' . $section . '"';
593             } elsif ($page && $section) {
594 1         3 $inferred = '"' . $section . '" in ' . $page;
595             }
596 6         24 return $inferred;
597             }
598              
599             # Given the contents of an L<> formatting code, parse it into the link text,
600             # the possibly inferred link text, the name or URL, the section, and the type
601             # of link (pod, man, or url).
602             sub parselink {
603 22     22   34 my ($self, $link) = @_;
604 22         63 $link =~ s/\s+/ /g;
605             # my $real_text = $self->parse_text({ -expand_ptree => 'expand_link' }, $link, 0);
606 22 100       68 if ($link =~ /\A\w+:[^:\s]\S*\Z/) {
607 3         12 return (undef, $link, $link, undef, 'url');
608             }
609             else {
610 19         27 my $text;
611 19 100       66 if ($link =~ /\|/) {
612 13         45 ($text, $link) = split (/\|/, $link, 2);
613             }
614 19 100       63 if ($link =~ /\A(\w+):[^:\s]\S*\Z/) {
615 1         2 my $scheme = $1;
616 1 50       6 die "Invalid URL scheme: $scheme" unless $scheme =~ /^(https?|ftp|mailto|news|nntp|snews)$/;
617 1         4 return (undef, $text, $link, $text, 'url');
618             }
619 18         41 my ($name, $section) = _parse_section ($link);
620 18   66     56 my $inferred = $text || _infer_text ($name, $section);
621 18 50 33     92 my $type = ($name && $name =~ /\(\S*\)/) ? 'man' : 'pod';
622 18         68 return ($text, $inferred, $name, $section, $type);
623             }
624             }
625              
626             # Unused right now...
627             sub expand_link {
628 0     0   0 my ($self, $ptree) = @_;
629 0         0 my $text = '';
630 0         0 foreach my $node ($ptree->children) {
631             # warn("Expand_ptree($node)\n");
632 0 0       0 if (ref($node)) {
633 0         0 $self->expand_seq($node);
634             }
635             else {
636 0         0 $self->parent->characters({Data => $node});
637             }
638             }
639             }
640              
641             package Pod::SAX::StringIO;
642              
643             sub new {
644 7     7   19 my $class = shift;
645 7         15 my ($string) = @_;
646 7         30 $string =~ s/\r//g;
647 7         152 my @lines = split(/^/, $string);
648 7         41 return bless \@lines, $class;
649             }
650              
651             sub getline {
652 287     287   2361 my $self = shift;
653 287         7545 return shift @$self;
654             }
655              
656             1;
657             __END__