File Coverage

blib/lib/Pod/Checker.pm
Criterion Covered Total %
statement 261 261 100.0
branch 79 88 89.7
condition 52 76 68.4
subroutine 73 73 100.0
pod 61 61 100.0
total 526 559 94.1


line stmt bran cond sub pod time code
1             #############################################################################
2             # Pod/Checker.pm -- check pod documents for syntax errors
3             #
4             # Copyright (C) 1994-2000 by Bradford Appleton. All rights reserved.
5             # This is free software; you can redistribute it and/or modify it under the
6             # same terms as Perl itself.
7             #############################################################################
8              
9             package Pod::Checker;
10 5     5   91220 use strict;
  5         33  
  5         130  
11 5     5   21 use warnings;
  5         7  
  5         514  
12              
13             our $VERSION = '1.75'; ## Current version of this package
14              
15             =head1 NAME
16              
17             Pod::Checker - check pod documents for syntax errors
18              
19             =head1 SYNOPSIS
20              
21             use Pod::Checker;
22              
23             $syntax_okay = podchecker($filepath, $outputpath, %options);
24              
25             my $checker = Pod::Checker->new(%options);
26             $checker->parse_from_file($filepath, \*STDERR);
27              
28             =head1 OPTIONS/ARGUMENTS
29              
30             C<$filepath> is the input POD to read and C<$outputpath> is
31             where to write POD syntax error messages. Either argument may be a scalar
32             indicating a file-path, or else a reference to an open filehandle.
33             If unspecified, the input-file it defaults to C<\*STDIN>, and
34             the output-file defaults to C<\*STDERR>.
35              
36             =head2 podchecker()
37              
38             This function can take a hash of options:
39              
40             =over 4
41              
42             =item B<-warnings> =E I
43              
44             Turn warnings on/off. I is usually 1 for on, but higher values
45             trigger additional warnings. See L<"Warnings">.
46              
47             =item B<-quiet> =E I
48              
49             If C is true, do not print any errors/warnings.
50              
51             =back
52              
53             =head1 DESCRIPTION
54              
55             B will perform syntax checking of Perl5 POD format documentation.
56              
57             Curious/ambitious users are welcome to propose additional features they wish
58             to see in B and B and verify that the checks are
59             consistent with L.
60              
61             The following checks are currently performed:
62              
63             =over 4
64              
65             =item *
66              
67             Unknown '=xxxx' commands, unknown 'XE...E' interior-sequences,
68             and unterminated interior sequences.
69              
70             =item *
71              
72             Check for proper balancing of C<=begin> and C<=end>. The contents of such
73             a block are generally ignored, i.e. no syntax checks are performed.
74              
75             =item *
76              
77             Check for proper nesting and balancing of C<=over>, C<=item> and C<=back>.
78              
79             =item *
80              
81             Check for same nested interior-sequences (e.g.
82             C...LE...E...E>).
83              
84             =item *
85              
86             Check for malformed or non-existing entities C...E>.
87              
88             =item *
89              
90             Check for correct syntax of hyperlinks C...E>. See L
91             for details.
92              
93             =item *
94              
95             Check for unresolved document-internal links. This check may also reveal
96             misspelled links that seem to be internal links but should be links
97             to something else.
98              
99             =back
100              
101             =head1 DIAGNOSTICS
102              
103             =head2 Errors
104              
105             =over 4
106              
107             =item * empty =headn
108              
109             A heading (C<=head1> or C<=head2>) without any text? That ain't no
110             heading!
111              
112             =item * =over on line I without closing =back
113              
114             =item * You forgot a '=back' before '=headI'
115              
116             =item * =over is the last thing in the document?!
117              
118             The C<=over> command does not have a corresponding C<=back> before the
119             next heading (C<=head1> or C<=head2>) or the end of the file.
120              
121             =item * '=item' outside of any '=over'
122              
123             =item * =back without =over
124              
125             An C<=item> or C<=back> command has been found outside a
126             C<=over>/C<=back> block.
127              
128             =item * Can't have a 0 in =over I
129              
130             You need to indent a strictly positive number of spaces, not 0.
131              
132             =item * =over should be: '=over' or '=over positive_number'
133              
134             Either have an argumentless =over, or have its argument a strictly positive number.
135              
136             =item * =begin I without matching =end I
137              
138             A C<=begin> command was found that has no matching =end command.
139              
140             =item * =begin without a target?
141              
142             A C<=begin> command was found that is not followed by the formatter
143             specification.
144              
145             =item * =end I without matching =begin.
146              
147             A standalone C<=end> command was found.
148              
149             =item * '=end' without a target?
150              
151             '=end' directives need to have a target, just like =begin directives.
152              
153             =item * '=end I' is invalid.
154              
155             I needs to be one word
156              
157             =item * =end I doesn't match =begin I
158              
159             I needs to match =begin's I.
160              
161             =item * =for without a target?
162              
163             There is no specification of the formatter after the C<=for> command.
164              
165             =item * unresolved internal link I
166              
167             The given link to I does not have a matching node in the current
168             POD. This also happened when a single word node name is not enclosed in
169             C<"">.
170              
171             =item * Unknown directive: I
172              
173             An invalid POD command has been found. Valid are C<=head1>, C<=head2>,
174             C<=head3>, C<=head4>, C<=over>, C<=item>, C<=back>, C<=begin>, C<=end>,
175             C<=for>, C<=pod>, C<=cut>
176              
177             =item * Deleting unknown formatting code I
178              
179             An invalid markup command has been encountered. Valid are:
180             CE>, CE>, CE>, CE>,
181             CE>, CE>, CE>, CE>,
182             CE>
183              
184             =item * Unterminated IEE sequence
185              
186             An unclosed formatting code
187              
188             =item * An EE...E surrounding strange content
189              
190             The I found cannot be interpreted as a character entity.
191              
192             =item * An empty EEE
193              
194             =item * An empty C<< LEE >>
195              
196             =item * An empty XEE
197              
198             There needs to be content inside E, L, and X formatting codes.
199              
200             =item * Spurious text after =pod / =cut
201              
202             The commands C<=pod> and C<=cut> do not take any arguments.
203              
204             =item * =back doesn't take any parameters, but you said =back I
205              
206             The C<=back> command does not take any arguments.
207              
208             =item * =pod directives shouldn't be over one line long! Ignoring all I lines of content
209              
210             Self explanatory
211              
212             =item * =cut found outside a pod block.
213              
214             A '=cut' directive found in the middle of non-POD
215              
216             =item * Invalid =encoding syntax: I
217              
218             Syntax error in =encoding directive
219              
220             =back
221              
222             =head2 Warnings
223              
224             These may not necessarily cause trouble, but indicate mediocre style.
225              
226             =over 4
227              
228             =item * nested commands IE...IE...E...E
229              
230             Two nested identical markup commands have been found. Generally this
231             does not make sense.
232              
233             =item * multiple occurrences (I) of link target I
234              
235             The POD file has some C<=item> and/or C<=head> commands that have
236             the same text. Potential hyperlinks to such a text cannot be unique then.
237             This warning is printed only with warning level greater than one.
238              
239             =item * line containing nothing but whitespace in paragraph
240              
241             There is some whitespace on a seemingly empty line. POD is very sensitive
242             to such things, so this is flagged. B users switch on the B
243             option to avoid this problem.
244              
245             =item * =item has no contents
246              
247             There is a list C<=item> that has no text contents. You probably want to delete
248             empty items.
249              
250             =item * You can't have =items (as at line I) unless the first thing after the =over is an =item
251              
252             A list introduced by C<=over> starts with a text or verbatim paragraph,
253             but continues with C<=item>s. Move the non-item paragraph out of the
254             C<=over>/C<=back> block.
255              
256             =item * Expected '=item I'
257              
258             =item * Expected '=item *'
259              
260             =item * Possible =item type mismatch: 'I' found leading a supposed definition =item
261              
262             A list started with e.g. a bullet-like C<=item> and continued with a
263             numbered one. This is obviously inconsistent. For most translators the
264             type of the I C<=item> determines the type of the list.
265              
266             =item * You have '=item x' instead of the expected '=item I'
267              
268             Erroneous numbering of =item numbers; they need to ascend consecutively.
269              
270             =item * Unknown E content in EEIE
271              
272             A character entity was found that does not belong to the standard
273             ISO set or the POD specials C and C. I
274             only appears if a character entity was found that does not have a Unicode
275             character. This should be fixed to adhere to the original warning.>
276              
277             =item * empty =over/=back block
278              
279             The list opened with C<=over> does not contain anything.
280              
281             =item * empty section in previous paragraph
282              
283             The previous section (introduced by a C<=head> command) does not contain
284             any valid content. This usually indicates that something is missing. Note: A
285             C<=head1> followed immediately by C<=head2> does not trigger this warning.
286              
287             =item * Verbatim paragraph in NAME section
288              
289             The NAME section (C<=head1 NAME>) should consist of a single paragraph
290             with the script/module name, followed by a dash `-' and a very short
291             description of what the thing is good for.
292              
293             =item * =headI without preceding higher level
294              
295             For example if there is a C<=head2> in the POD file prior to a
296             C<=head1>.
297              
298             =item * A non-empty ZEE
299              
300             The CE> sequence is supposed to be empty. Caveat: this issue is
301             detected in L and will be flagged as an I by any client
302             code; any contents of C...E> will be disregarded, anyway.
303              
304             =back
305              
306             =head2 Hyperlinks
307              
308             There are some warnings with respect to malformed hyperlinks:
309              
310             =over 4
311              
312             =item * ignoring leading/trailing whitespace in link
313              
314             There is whitespace at the beginning or the end of the contents of
315             LE...E.
316              
317             =item * alternative text/node '%s' contains non-escaped | or /
318              
319             The characters C<|> and C are special in the LE...E context.
320             Although the hyperlink parser does its best to determine which "/" is
321             text and which is a delimiter in case of doubt, one ought to escape
322             these literal characters like this:
323              
324             / E
325             | E
326              
327             =back
328              
329             Note that the line number of the error/warning may refer to the line number of
330             the start of the paragraph in which the error/warning exists, not the line
331             number that the error/warning is on. This bug is present in errors/warnings
332             related to formatting codes. I
333              
334             =head1 RETURN VALUE
335              
336             B returns the number of POD syntax errors found or -1 if
337             there were no POD commands at all found in the file.
338              
339             =head1 EXAMPLES
340              
341             See L
342              
343             =head1 SCRIPTS
344              
345             The B script that comes with this distribution is a lean wrapper
346             around this module. See the online manual with
347              
348             podchecker -help
349             podchecker -man
350              
351             =head1 INTERFACE
352              
353             While checking, this module collects document properties, e.g. the nodes
354             for hyperlinks (C<=headX>, C<=item>) and index entries (CE>).
355             POD translators can use this feature to syntax-check and get the nodes in
356             a first pass before actually starting to convert. This is expensive in terms
357             of execution time, but allows for very robust conversions.
358              
359             Since v1.24 the B module uses only the B
360             method to print errors and warnings. The summary output (e.g.
361             "Pod syntax OK") has been dropped from the module and has been included in
362             B (the script). This allows users of B to
363             control completely the output behavior. Users of B (the script)
364             get the well-known behavior.
365              
366             v1.45 inherits from L as opposed to all previous versions
367             inheriting from Pod::Parser. Do B use Pod::Simple's interface when
368             using Pod::Checker unless it is documented somewhere on this page. I
369             repeat, DO B USE POD::SIMPLE'S INTERFACE.
370              
371             The following list documents the overrides to Pod::Simple, primarily to
372             make L happy:
373              
374             =over 4
375              
376             =item end_B
377              
378             =item end_C
379              
380             =item end_Document
381              
382             =item end_F
383              
384             =item end_I
385              
386             =item end_L
387              
388             =item end_Para
389              
390             =item end_S
391              
392             =item end_X
393              
394             =item end_fcode
395              
396             =item end_for
397              
398             =item end_head
399              
400             =item end_head1
401              
402             =item end_head2
403              
404             =item end_head3
405              
406             =item end_head4
407              
408             =item end_item
409              
410             =item end_item_bullet
411              
412             =item end_item_number
413              
414             =item end_item_text
415              
416             =item handle_pod_and_cut
417              
418             =item handle_text
419              
420             =item handle_whiteline
421              
422             =item hyperlink
423              
424             =item scream
425              
426             =item start_B
427              
428             =item start_C
429              
430             =item start_Data
431              
432             =item start_F
433              
434             =item start_I
435              
436             =item start_L
437              
438             =item start_Para
439              
440             =item start_S
441              
442             =item start_Verbatim
443              
444             =item start_X
445              
446             =item start_fcode
447              
448             =item start_for
449              
450             =item start_head
451              
452             =item start_head1
453              
454             =item start_head2
455              
456             =item start_head3
457              
458             =item start_head4
459              
460             =item start_item_bullet
461              
462             =item start_item_number
463              
464             =item start_item_text
465              
466             =item start_over
467              
468             =item start_over_block
469              
470             =item start_over_bullet
471              
472             =item start_over_empty
473              
474             =item start_over_number
475              
476             =item start_over_text
477              
478             =item whine
479              
480             =back
481              
482             =cut
483              
484             #############################################################################
485              
486             #use diagnostics;
487 5     5   30 use Carp qw(croak);
  5         7  
  5         270  
488 5     5   26 use Exporter 'import';
  5         8  
  5         149  
489 5     5   22 use base qw/Pod::Simple::Methody/;
  5         8  
  5         2084  
490              
491             our @EXPORT = qw(&podchecker);
492              
493             ##---------------------------------
494             ## Function definitions begin here
495             ##---------------------------------
496              
497             sub podchecker {
498 3     3 1 764 my ($infile, $outfile, %options) = @_;
499 3         7 local $_;
500              
501             ## Set defaults
502 3   50     11 $infile ||= \*STDIN;
503 3   50     9 $outfile ||= \*STDERR;
504              
505             ## Now create a pod checker
506 3         25 my $checker = Pod::Checker->new(%options);
507              
508             ## Now check the pod document for errors
509 3         22 $checker->parse_from_file($infile, $outfile);
510              
511             ## Return the number of errors found
512 3         131 return $checker->num_errors();
513             }
514              
515              
516             ##---------------------------------------------------------------------------
517              
518             ##-------------------------------
519             ## Method definitions begin here
520             ##-------------------------------
521              
522             ##################################
523              
524             =over 4
525              
526             =item Cnew( %options )>
527              
528             Return a reference to a new Pod::Checker object that inherits from
529             Pod::Simple and is used for calling the required methods later. The
530             following options are recognized:
531              
532             C<-warnings =E num>
533             Print warnings if C is true. The higher the value of C,
534             the more warnings are printed. Currently there are only levels 1 and 2.
535              
536             C<-quiet =E num>
537             If C is true, do not print any errors/warnings. This is useful
538             when Pod::Checker is used to munge POD code into plain text from within
539             POD formatters.
540              
541             =cut
542              
543             sub new {
544 5     5 1 1336 my $new = shift->SUPER::new(@_);
545 5   50     285 $new->{'output_fh'} ||= *STDERR{IO};
546              
547             # Set options
548 5         14 my %opts = @_;
549             $new->{'-warnings'} = defined $opts{'-warnings'} ?
550 5 100       21 $opts{'-warnings'} : 1; # default on
551 5   100     26 $new->{'-quiet'} = $opts{'-quiet'} || 0; # default off
552              
553             # Initialize number of errors/warnings
554 5         16 $new->{'_NUM_ERRORS'} = 0;
555 5         9 $new->{'_NUM_WARNINGS'} = 0;
556              
557             # 'current' also means 'most recent' in the follow comments
558 5         11 $new->{'_thispara'} = ''; # current POD paragraph
559 5         20 $new->{'_line'} = 0; # current line number
560 5         8 $new->{'_head_num'} = 0; # current =head level (set to 0 to make
561             # logic easier down the road)
562 5         13 $new->{'_cmds_since_head'} = 0; # num of POD directives since prev. =headN
563 5         12 $new->{'_nodes'} = []; # stack for =head/=item nodes
564 5         10 $new->{'_fcode_stack'} = []; # stack for nested formatting codes
565 5         15 $new->{'_fcode_pos'} = []; # stack for position in paragraph of fcodes
566 5         36 $new->{'_begin_stack'} = []; # stack for =begins: [line #, target]
567 5         12 $new->{'_links'} = []; # stack for hyperlinks to external entities
568 5         9 $new->{'_internal_links'} = []; # set of linked-to internal sections
569 5         12 $new->{'_index'} = []; # stack for text in X<>s
570              
571 5         35 $new->accept_targets('*'); # check all =begin/=for blocks
572 5         146 $new->cut_handler( \&handle_pod_and_cut ); # warn if text after =cut
573 5         44 $new->pod_handler( \&handle_pod_and_cut ); # warn if text after =pod
574 5         43 $new->whiteline_handler( \&handle_whiteline ); # warn if whiteline
575 5         61 $new->parse_empty_lists(1); # warn if they are empty
576              
577 5         43 return $new;
578             }
579              
580             ##################################
581              
582             =item C<$checker-Epoderror( @args )>
583              
584             =item C<$checker-Epoderror( {%opts}, @args )>
585              
586             Internal method for printing errors and warnings. If no options are given,
587             simply prints "@_". The following options are recognized and used to form
588             the output:
589              
590             -msg
591              
592             A message to print prior to C<@args>.
593              
594             -line
595              
596             The line number the error occurred in.
597              
598             -file
599              
600             The file (name) the error occurred in. Defaults to the name of the current
601             file being processed.
602              
603             -severity
604              
605             The error level, should be 'WARNING' or 'ERROR'.
606              
607             =cut
608              
609             # Invoked as $self->poderror( @args ), or $self->poderror( {%opts}, @args )
610             sub poderror {
611 83     83 1 105 my $self = shift;
612 83 100       128 my %opts = (ref $_[0]) ? %{shift()} : ();
  82         280  
613              
614             ## Retrieve options
615 83   100     281 chomp( my $msg = ($opts{'-msg'} || '')."@_" );
616 83 100       187 my $line = (exists $opts{'-line'}) ? " at line $opts{'-line'}" : '';
617             my $file = ' in file ' . ((exists $opts{'-file'})
618 83 50       203 ? $opts{'-file'}
    50          
619             : ((defined $self->source_filename)
620             ? $self->source_filename
621             : "???"));
622 83 100       771 unless (exists $opts{'-severity'}) {
623             ## See if can find severity in message prefix
624 1 50       8 $opts{'-severity'} = $1 if ( $msg =~ s/^\**\s*([A-Z]{3,}):\s+// );
625             }
626 83 50       149 my $severity = (exists $opts{'-severity'}) ? "*** $opts{-severity}: " : '';
627              
628             ## Increment error count and print message "
629             ++($self->{'_NUM_ERRORS'})
630 83 100 66     307 if(!%opts || ($opts{-severity} && $opts{'-severity'} eq 'ERROR'));
      66        
631             ++($self->{'_NUM_WARNINGS'})
632 83 100 66     307 if(!%opts || ($opts{-severity} && $opts{'-severity'} eq 'WARNING'));
      66        
633 83 100       344 unless($self->{'-quiet'}) {
634 82   50     121 my $out_fh = $self->{'output_fh'} || \*STDERR;
635             print $out_fh ($severity, $msg, $line, $file, "\n")
636 82 50 33     365 if($self->{'-warnings'} || !%opts || $opts{'-severity'} ne 'WARNING');
      33        
637             }
638             }
639              
640             ##################################
641              
642             =item C<$checker-Enum_errors()>
643              
644             Set (if argument specified) and retrieve the number of errors found.
645              
646             =cut
647              
648             sub num_errors {
649 4 50   4 1 340 return (@_ > 1) ? ($_[0]->{'_NUM_ERRORS'} = $_[1]) : $_[0]->{'_NUM_ERRORS'};
650             }
651              
652             ##################################
653              
654             =item C<$checker-Enum_warnings()>
655              
656             Set (if argument specified) and retrieve the number of warnings found.
657              
658             =cut
659              
660             sub num_warnings {
661             return (@_ > 1) ? ($_[0]->{'_NUM_WARNINGS'} = $_[1]) :
662 1 50   1 1 39 $_[0]->{'_NUM_WARNINGS'};
663             }
664              
665             ##################################
666              
667             =item C<$checker-Ename()>
668              
669             Set (if argument specified) and retrieve the canonical name of POD as
670             found in the C<=head1 NAME> section.
671              
672             =cut
673              
674             sub name {
675             return (@_ > 1 && $_[1]) ?
676 1 50 33 1 1 297 ($_[0]->{'_pod_name'} = $_[1]) : $_[0]->{'_pod_name'};
677             }
678              
679             ##################################
680              
681             =item C<$checker-Enode()>
682              
683             Add (if argument specified) and retrieve the nodes (as defined by C<=headX>
684             and C<=item>) of the current POD. The nodes are returned in the order of
685             their occurrence. They consist of plain text, each piece of whitespace is
686             collapsed to a single blank.
687              
688             =cut
689              
690             sub node {
691 186     186 1 322 my ($self,$text) = @_;
692 186 100       316 if(defined $text) {
693 181         400 $text =~ s/\s+$//s; # strip trailing whitespace
694 181         466 $text =~ s/\s+/ /gs; # collapse whitespace
695             # add node, order important!
696 181         225 push(@{$self->{'_nodes'}}, $text);
  181         365  
697             # keep also a uniqueness counter
698 181 100       807 $self->{'_unique_nodes'}->{$text}++ if($text !~ /^\s*$/s);
699 181         325 return $text;
700             }
701 5         10 @{$self->{'_nodes'}};
  5         53  
702             }
703              
704             ##################################
705              
706             =item C<$checker-Eidx()>
707              
708             Add (if argument specified) and retrieve the index entries (as defined by
709             CE>) of the current POD. They consist of plain text, each piece
710             of whitespace is collapsed to a single blank.
711              
712             =cut
713              
714             # set/return index entries of current POD
715             sub idx {
716 11     11 1 23 my ($self,$text) = @_;
717 11 100       40 if(defined $text) {
718 6         15 $text =~ s/\s+$//s; # strip trailing whitespace
719 6         11 $text =~ s/\s+/ /gs; # collapse whitespace
720             # add node, order important!
721 6         7 push(@{$self->{'_index'}}, $text);
  6         12  
722             # keep also a uniqueness counter
723 6 100       33 $self->{'_unique_nodes'}->{$text}++ if($text !~ /^\s*$/s);
724 6         18 return $text;
725             }
726 5         8 @{$self->{'_index'}};
  5         67  
727             }
728              
729             ##################################
730              
731             # add a hyperlink to the list of those of the current POD; returns current
732             # list after the addition has been done
733             sub hyperlink {
734 45     45 1 61 my $self = shift;
735 45         51 push(@{$self->{'_links'}}, $_[0]);
  45         91  
736 45         79 return $_[0];
737             }
738              
739             =item C<$checker-Ehyperlinks()>
740              
741             Retrieve an array containing the hyperlinks to things outside
742             the current POD (as defined by CE>).
743              
744             Each is an instance of a class with the following methods:
745              
746             =cut
747              
748             sub hyperlinks {
749 1     1 1 2 @{shift->{'_links'}};
  1         6  
750             }
751              
752             ##################################
753              
754             # override Pod::Simple's whine() and scream() to use poderror()
755              
756             # Note:
757             # Ignore $self->{'no_whining'} b/c $self->{'quiet'} takes care of it in poderror
758             # Don't bother incrementing $self->{'errors_seen'} -- it's not used
759             # Don't bother pushing to $self->{'errata'} b/c poderror() outputs immediately
760             # We don't need to set $self->no_errata_section(1) b/c of these overrides
761              
762              
763             sub whine {
764 45     45 1 20357 my ($self, $line, $complaint) = @_;
765              
766 45         53 my $severity = 'ERROR';
767              
768 45         45 if (0) {
769             # XXX: Let's standardize what's a warning and what's an error. Let's not
770             # move stuff up and down the severity tree. -- rjbs, 2013-04-12
771             # Convert errors in Pod::Simple that are warnings in Pod::Checker
772             # XXX Do differently so the $complaint can be reworded without this breaking
773             $severity = 'WARNING' if
774             $complaint =~ /^Expected '=item .+?'$/ ||
775             $complaint =~ /^You can't have =items \(as at line .+?\) unless the first thing after the =over is an =item$/ ||
776             $complaint =~ /^You have '=item .+?' instead of the expected '=item .+?'$/;
777             }
778              
779             # rt.cpan.org #98326 - errors about Z<> ("non-empty")
780 45 100       100 $severity = 'WARNING' if $complaint =~ /\bZ\<\>/;
781              
782 45         145 $self->poderror({ -line => $line,
783             -severity => $severity,
784             -msg => $complaint });
785              
786 45         115 return 1; # assume everything is peachy keen
787             }
788              
789             sub scream {
790 1     1 1 1382 my ($self, $line, $complaint) = @_;
791              
792 1         4 $self->poderror({ -line => $line,
793             -severity => 'ERROR', # consider making severity 'FATAL'
794             -msg => $complaint });
795              
796 1         4 return 1;
797             }
798              
799              
800             ##################################
801              
802             # Some helper subroutines
803              
804             sub _init_event { # assignments done at the start of most events
805 378     378   577 $_[0]{'_thispara'} = '';
806 378         514 $_[0]{'_line'} = $_[1]{'start_line'};
807 378         551 $_[0]{'_cmds_since_head'}++;
808             }
809              
810             sub _check_fcode {
811 255     255   372 my ($self, $inner, $outers) = @_;
812             # Check for an fcode inside another of the same fcode
813             # XXX line number is the line of the start of the paragraph that the warning
814             # is in, not the line that the warning is on. Fix this
815              
816             # Later versions of Pod::Simple forbid nested L<>'s
817 255 100 66     628 return if $inner eq 'L' && $Pod::Simple::VERSION ge '3.33';
818              
819 189 100       405 if (grep { $_ eq $inner } @$outers) {
  76         118  
820 7         30 $self->poderror({ -line => $self->{'_line'},
821             -severity => 'WARNING',
822             -msg => "nested commands $inner<...$inner<...>...>"});
823             }
824             }
825              
826             ##################################
827              
828 736     736 1 7151 sub handle_text { $_[0]{'_thispara'} .= $_[1] }
829              
830             # whiteline is a seemingly blank line that matches /[^\S\r\n]/
831             sub handle_whiteline {
832 2     2 1 187 my ($line, $line_n, $self) = @_;
833 2         7 $self->poderror({
834             -line => $line_n,
835             -severity => 'WARNING',
836             -msg => 'line containing nothing but whitespace in paragraph'});
837             }
838              
839             ######## Directives
840             sub handle_pod_and_cut {
841 21     21 1 487 my ($line, $line_n, $self) = @_;
842 21         39 $self->{'_cmds_since_head'}++;
843 21 100       73 if ($line =~ /=(pod|cut)\s+\S/) {
844 2         12 $self->poderror({ -line => $line_n,
845             -severity => 'ERROR',
846             -msg => "Spurious text after =$1"});
847             }
848             }
849              
850 162     162 1 59712 sub start_Para { shift->_init_event(@_); }
851             sub end_Para {
852 162     162 1 1132 my $self = shift;
853             # Get the NAME of the pod document
854 162 100 100     539 if ($self->{'_head_num'} == 1 && $self->{'_head_text'} eq 'NAME') {
855 12 100       56 if ($self->{'_thispara'} =~ /^\s*(\S+?)\s*[,-]/) {
856 5 100       23 $self->{'_pod_name'} = $1 unless defined $self->{'_pod_name'};
857             }
858             }
859             }
860              
861             sub start_Verbatim {
862 10     10 1 2717 my $self = shift;
863 10         27 $self->_init_event(@_);
864              
865 10 100 100     49 if ($self->{'_head_num'} == 1 && $self->{'_head_text'} eq 'NAME') {
866 1         5 $self->poderror({ -line => $self->{'_line'},
867             -severity => 'WARNING',
868             -msg => 'Verbatim paragraph in NAME section' });
869             }
870             }
871             # Don't need an end_Verbatim
872              
873             # Do I need to do anything else with this?
874 1     1 1 134 sub start_Data { shift->_init_event() }
875              
876 19     19 1 5488 sub start_head1 { shift->start_head(1, @_) }
877 22     22 1 5620 sub start_head2 { shift->start_head(2, @_) }
878 2     2 1 504 sub start_head3 { shift->start_head(3, @_) }
879 1     1 1 146 sub start_head4 { shift->start_head(4, @_) }
880             sub start_head {
881 44     44 1 75 my $self = shift;
882 44         62 my $h = shift;
883 44         107 $self->_init_event(@_);
884 44         72 my $prev_h = $self->{'_head_num'};
885 44         65 $self->{'_head_num'} = $h;
886 44         96 $self->{"_count_head$h"}++;
887              
888 44 100 100     171 if ($h > 1 && !$self->{'_count_head'.($h-1)}) {
889 1         16 $self->poderror({ -line => $self->{'_line'},
890             -severity => 'WARNING',
891             -msg => "=head$h without preceding higher level"});
892             }
893              
894             # If this is the first =head of the doc, $prev_h is 0, thus less than $h
895 44 100 100     202 if ($self->{'_cmds_since_head'} == 1 && $prev_h >= $h) {
896 5         18 $self->poderror({ -line => $self->{'_line'},
897             -severity => 'WARNING',
898             -msg => 'empty section in previous paragraph'});
899             }
900             }
901              
902 19     19 1 185 sub end_head1 { shift->end_head(@_) }
903 22     22 1 192 sub end_head2 { shift->end_head(@_) }
904 2     2 1 35 sub end_head3 { shift->end_head(@_) }
905 1     1 1 10 sub end_head4 { shift->end_head(@_) }
906             sub end_head {
907 44     44 1 82 my $self = shift;
908 44         88 my $arg = $self->{'_thispara'};
909 44         113 $arg =~ s/\s+$//;
910 44         68 $self->{'_head_text'} = $arg;
911 44         54 $self->{'_cmds_since_head'} = 0;
912 44         59 my $h = $self->{'_head_num'};
913 44         107 $self->node($arg); # remember this node
914 44 100       106 if ($arg eq '') {
915 1         8 $self->poderror({ -line => $self->{'_line'},
916             -severity => 'ERROR',
917             -msg => "empty =head$h" });
918             }
919             }
920              
921 6     6 1 1454 sub start_over_bullet { shift->start_over(@_, 'bullet') }
922 1     1 1 199 sub start_over_number { shift->start_over(@_, 'number') }
923 8     8 1 2678 sub start_over_text { shift->start_over(@_, 'definition') }
924 4     4 1 433 sub start_over_block { shift->start_over(@_, 'block') }
925             sub start_over_empty {
926 1     1 1 105 my $self = shift;
927 1         5 $self->start_over(@_, 'empty');
928 1         12 $self->poderror({ -line => $self->{'_line'},
929             -severity => 'WARNING',
930             -msg => 'empty =over/=back block' });
931             }
932             sub start_over {
933 20     20 1 31 my $self = shift;
934 20         30 my $type = pop;
935 20         37 $self->_init_event(@_);
936             }
937              
938 58     58 1 24898 sub start_item_bullet { shift->_init_event(@_) }
939 4     4 1 444 sub start_item_number { shift->_init_event(@_) }
940 75     75 1 31910 sub start_item_text { shift->_init_event(@_) }
941 58     58 1 440 sub end_item_bullet { shift->end_item('bullet') }
942 4     4 1 31 sub end_item_number { shift->end_item('number') }
943 75     75 1 575 sub end_item_text { shift->end_item('definition') }
944             sub end_item {
945 137     137 1 163 my $self = shift;
946 137         153 my $type = shift;
947             # If there is verbatim text in this item, it will show up as part of
948             # 'paras', and not part of '_thispara'. If the first para after this is a
949             # verbatim one, it actually will be (part of) the contents for this item.
950 137 100 33     307 if ( $self->{'_thispara'} eq ''
      66        
951             && ( ! @{$self->{'paras'}}
952             || $self->{'paras'}[0][0] !~ /Verbatim/i))
953             {
954 1         8 $self->poderror({ -line => $self->{'_line'},
955             -severity => 'WARNING',
956             -msg => '=item has no contents' });
957             }
958              
959 137         264 $self->node($self->{'_thispara'}); # remember this node
960             }
961              
962             sub start_for { # =for and =begin directives
963 4     4 1 788 my ($self, $flags) = @_;
964 4         11 $self->_init_event($flags);
965 4         5 push @{$self->{'_begin_stack'}}, [$self->{'_line'}, $flags->{'target'}];
  4         14  
966             }
967              
968             sub end_for {
969 4     4 1 318 my ($self, $flags) = @_;
970 4         4 my ($line, $target) = @{pop @{$self->{'_begin_stack'}}};
  4         5  
  4         11  
971 4 100       12 if ($flags->{'fake-closer'}) { # meaning Pod::Simple generated this =end
972 2         9 $self->poderror({ -line => $line,
973             -severity => 'ERROR',
974             -msg => "=begin $target without matching =end $target"
975             });
976             }
977             }
978              
979             sub end_Document {
980             # Some final error checks
981 5     5 1 391 my $self = shift;
982              
983             # no POD found here
984 5 50 0     63 $self->num_errors(-1) && return unless $self->content_seen;
985              
986 5         42 my %nodes;
987 5         20 for ($self->node()) {
988 181         331 $nodes{$_} = 1;
989 181 100       379 if(/^(\S+)\s+\S/) {
990             # we have more than one word. Use the first as a node, too.
991             # This is used heavily in perlfunc.pod
992 87   100     233 $nodes{$1} ||= 2; # derived node
993             }
994             }
995 5         35 for ($self->idx()) {
996 6         8 $nodes{$_} = 3; # index node
997             }
998              
999             # XXX update unresolved internal link POD -- single word not enclosed in ""?
1000             # I don't know what I was thinking when I made the above TODO, and I don't
1001             # know what it means...
1002              
1003 5         14 for my $link (@{ $self->{'_internal_links'} }) {
  5         16  
1004 20         31 my ($name, $line) = @$link;
1005 20 100       44 unless ( $nodes{$name} ) {
1006 8         25 $self->poderror({ -line => $line,
1007             -severity => 'ERROR',
1008             -msg => "unresolved internal link '$name'"});
1009             }
1010             }
1011              
1012             # check the internal nodes for uniqueness. This pertains to
1013             # =headX, =item and X<...>
1014 5 100       24 if ($self->{'-warnings'} > 1 ) {
1015 3         6 for my $node (sort keys %{ $self->{'_unique_nodes'} }) {
  3         80  
1016 174         175 my $count = $self->{'_unique_nodes'}{$node};
1017 174 100       263 if ($count > 1) { # not unique
1018 3         13 $self->poderror({
1019             -line => '-',
1020             -severity => 'WARNING',
1021             -msg => "multiple occurrences ($count) of link target ".
1022             "'$node'"});
1023             }
1024             }
1025             }
1026             }
1027              
1028             ######## Formatting codes
1029              
1030 21     21 1 296 sub start_B { shift->start_fcode('B') }
1031 110     110 1 1395 sub start_C { shift->start_fcode('C') }
1032 2     2 1 28 sub start_F { shift->start_fcode('F') }
1033 48     48 1 604 sub start_I { shift->start_fcode('I') }
1034 2     2 1 26 sub start_S { shift->start_fcode('S') }
1035             sub start_fcode {
1036 255     255 1 374 my ($self, $fcode) = @_;
1037 255         267 unshift @{$self->{'_fcode_stack'}}, $fcode;
  255         536  
1038             }
1039              
1040 21     21 1 164 sub end_B { shift->end_fcode() }
1041 110     110 1 850 sub end_C { shift->end_fcode() }
1042 2     2 1 20 sub end_F { shift->end_fcode() }
1043 48     48 1 367 sub end_I { shift->end_fcode() }
1044 2     2 1 22 sub end_S { shift->end_fcode() }
1045             sub end_fcode {
1046 255     255 1 292 my $self = shift;
1047 255         454 $self->_check_fcode(shift @{$self->{'_fcode_stack'}}, # current fcode removed
1048 255         269 $self->{'_fcode_stack'}); # previous fcodes
1049             }
1050              
1051             sub start_L {
1052 66     66 1 838 my ($self, $flags) = @_;
1053 66         143 $self->start_fcode('L');
1054              
1055 66         156 my $link = Pod::Checker::Hyperlink->new($flags, $self);
1056 66 100       117 if ($link) {
1057 65 100 100     114 if ( $link->type eq 'pod'
      100        
      100        
1058             && $link->node
1059             # It's an internal-to-this-page link if no page is given, or
1060             # if the given one is to our NAME.
1061             && (! $link->page || ( $self->{'_pod_name'}
1062             && $link->page eq $self->{'_pod_name'})))
1063             {
1064 20         32 push @{ $self->{'_internal_links'} }, [ $link->{'-raw_node'}, $link->line ];
  20         50  
1065             }
1066             else {
1067 45         84 $self->hyperlink($link);
1068             }
1069             }
1070             }
1071              
1072             sub end_L {
1073 66     66 1 489 my $self = shift;
1074 66         116 $self->end_fcode();
1075             }
1076              
1077             sub start_X {
1078 6     6 1 76 my $self = shift;
1079 6         13 $self->start_fcode('X');
1080             # keep track of where X<> starts in the paragraph
1081             # (this is a stack so nested X<>s are handled correctly)
1082 6         9 push @{$self->{'_fcode_pos'}}, length $self->{'_thispara'};
  6         13  
1083             }
1084             sub end_X {
1085 6     6 1 46 my $self = shift;
1086             # extract contents of X<> and replace with ''
1087 6         7 my $start = pop @{$self->{'_fcode_pos'}}; # start at the beginning of X<>
  6         10  
1088 6         11 my $end = length($self->{'_thispara'}) - $start; # end at end of X<>
1089 6         13 my $x = substr($self->{'_thispara'}, $start, $end, '');
1090 6 100       15 if ($x eq "") {
1091 1         8 $self->poderror({ -line => $self->{'_line'},
1092             -severity => 'ERROR',
1093             -msg => "An empty X<>" });
1094             }
1095 6         15 $self->idx($x); # remember this node
1096 6         14 $self->end_fcode();
1097             }
1098              
1099             package Pod::Checker::Hyperlink;
1100              
1101             # This class is used to represent L<> link structures, so that the individual
1102             # elements are easily accessible. It is based on code in Pod::Hyperlink
1103              
1104             sub new {
1105 66     66   96 my ($class,
1106             $simple_link, # The link structure returned by Pod::Simple
1107             $caller # The caller class
1108             ) = @_;
1109              
1110 66         83 my $self = +{};
1111 66         91 bless $self, $class;
1112              
1113 66   33     282 $self->{'-line'} ||= $caller->{'_line'};
1114 66   33     219 $self->{'-type'} ||= $simple_link->{'type'};
1115             # preserve raw link text for additional checks
1116 66 100       177 $self->{'-raw-link-text'} = (exists $simple_link->{'raw'})
1117             ? "$simple_link->{'raw'}"
1118             : "";
1119             # Force stringification of page and node. (This expands any E<>.)
1120 66 100       179 $self->{'-page'} = exists $simple_link->{'to'} ? "$simple_link->{'to'}" : "";
1121 66 100       690 $self->{'-node'} = exists $simple_link->{'section'} ? "$simple_link->{'section'}" : "";
1122              
1123             # Save the unmodified node text, as the .t files are expecting the message
1124             # for internal link failures to include it (hence this preserves backward
1125             # compatibility).
1126 66         675 $self->{'-raw_node'} = $self->{'-node'};
1127              
1128             # Remove leading/trailing white space. Pod::Simple already warns about
1129             # these, so if the only error is this, and the link is otherwise correct,
1130             # only the Pod::Simple warning will be output, avoiding unnecessary
1131             # confusion.
1132 66         184 $self->{'-page'} =~ s/ ^ \s+ //x;
1133 66         118 $self->{'-page'} =~ s/ \s+ $ //x;
1134              
1135 66         110 $self->{'-node'} =~ s/ ^ \s+ //x;
1136 66         108 $self->{'-node'} =~ s/ \s+ $ //x;
1137              
1138             # Pod::Simple warns about L<> and L< >, but not L
1139 66 100 100     165 if ($self->{'-page'} eq "" && $self->{'-node'} eq "") {
1140 1         5 $caller->poderror({ -line => $caller->{'_line'},
1141             -severity => 'WARNING',
1142             -msg => 'empty link'});
1143 1         4 return;
1144             }
1145              
1146 65         100 return $self;
1147             }
1148              
1149             =item line()
1150              
1151             Returns the approximate line number in which the link was encountered
1152              
1153             =cut
1154              
1155             sub line {
1156 46     46   10470 return $_[0]->{-line};
1157             }
1158              
1159             =item type()
1160              
1161             Returns the type of the link; one of:
1162             C<"url"> for things like
1163             C, C<"man"> for man pages, or C<"pod">.
1164              
1165             =cut
1166              
1167             sub type {
1168 91     91   280 return $_[0]->{-type};
1169             }
1170              
1171             =item page()
1172              
1173             Returns the linked-to page or url.
1174              
1175             =cut
1176              
1177             sub page {
1178 87     87   278 return $_[0]->{-page};
1179             }
1180              
1181             =item node()
1182              
1183             Returns the anchor or node within the linked-to page, or an empty string
1184             (C<"">) if none appears in the link.
1185              
1186             =back
1187              
1188             =cut
1189              
1190             sub node {
1191 83     83   271 return $_[0]->{-node};
1192             }
1193              
1194             =head1 AUTHOR
1195              
1196             Please report bugs using L.
1197              
1198             Brad Appleton Ebradapp@enteract.comE (initial version),
1199             Marek Rouchal Emarekr@cpan.orgE,
1200             Marc Green Emarcgreen@cpan.orgE (port to Pod::Simple)
1201             Ricardo Signes Erjbs@cpan.orgE (more porting to Pod::Simple)
1202             Karl Williamson Ekhw@cpan.orgE (more porting to Pod::Simple)
1203              
1204             Based on code for B written by
1205             Tom Christiansen Etchrist@mox.perl.comE
1206              
1207             =cut
1208              
1209             1