File Coverage

blib/lib/Pod/Checker.pm
Criterion Covered Total %
statement 260 260 100.0
branch 77 86 89.5
condition 52 76 68.4
subroutine 73 73 100.0
pod 61 61 100.0
total 523 556 94.0


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   112736 use strict;
  5         31  
  5         152  
11 5     5   25 use warnings;
  5         10  
  5         685  
12              
13             our $VERSION = '1.74'; ## 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   40 use Carp qw(croak);
  5         11  
  5         285  
488 5     5   41 use Exporter 'import';
  5         49  
  5         194  
489 5     5   30 use base qw/Pod::Simple::Methody/;
  5         8  
  5         2652  
490              
491             our @EXPORT = qw(&podchecker);
492              
493             ##---------------------------------
494             ## Function definitions begin here
495             ##---------------------------------
496              
497             sub podchecker {
498 3     3 1 784 my ($infile, $outfile, %options) = @_;
499 3         8 local $_;
500              
501             ## Set defaults
502 3   50     14 $infile ||= \*STDIN;
503 3   50     19 $outfile ||= \*STDERR;
504              
505             ## Now create a pod checker
506 3         28 my $checker = Pod::Checker->new(%options);
507              
508             ## Now check the pod document for errors
509 3         24 $checker->parse_from_file($infile, $outfile);
510              
511             ## Return the number of errors found
512 3         126 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 1610 my $new = shift->SUPER::new(@_);
545 5   50     420 $new->{'output_fh'} ||= *STDERR{IO};
546              
547             # Set options
548 5         16 my %opts = @_;
549             $new->{'-warnings'} = defined $opts{'-warnings'} ?
550 5 100       27 $opts{'-warnings'} : 1; # default on
551 5   100     30 $new->{'-quiet'} = $opts{'-quiet'} || 0; # default off
552              
553             # Initialize number of errors/warnings
554 5         16 $new->{'_NUM_ERRORS'} = 0;
555 5         13 $new->{'_NUM_WARNINGS'} = 0;
556              
557             # 'current' also means 'most recent' in the follow comments
558 5         24 $new->{'_thispara'} = ''; # current POD paragraph
559 5         11 $new->{'_line'} = 0; # current line number
560 5         14 $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         13 $new->{'_nodes'} = []; # stack for =head/=item nodes
564 5         12 $new->{'_fcode_stack'} = []; # stack for nested formatting codes
565 5         16 $new->{'_fcode_pos'} = []; # stack for position in paragraph of fcodes
566 5         36 $new->{'_begin_stack'} = []; # stack for =begins: [line #, target]
567 5         15 $new->{'_links'} = []; # stack for hyperlinks to external entities
568 5         12 $new->{'_internal_links'} = []; # set of linked-to internal sections
569 5         12 $new->{'_index'} = []; # stack for text in X<>s
570              
571 5         38 $new->accept_targets('*'); # check all =begin/=for blocks
572 5         171 $new->cut_handler( \&handle_pod_and_cut ); # warn if text after =cut
573 5         55 $new->pod_handler( \&handle_pod_and_cut ); # warn if text after =pod
574 5         51 $new->whiteline_handler( \&handle_whiteline ); # warn if whiteline
575 5         70 $new->parse_empty_lists(1); # warn if they are empty
576              
577 5         56 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 125 my $self = shift;
612 83 100       172 my %opts = (ref $_[0]) ? %{shift()} : ();
  82         288  
613              
614             ## Retrieve options
615 83   100     332 chomp( my $msg = ($opts{'-msg'} || '')."@_" );
616 83 100       230 my $line = (exists $opts{'-line'}) ? " at line $opts{'-line'}" : '';
617             my $file = ' in file ' . ((exists $opts{'-file'})
618 83 50       284 ? $opts{'-file'}
    50          
619             : ((defined $self->source_filename)
620             ? $self->source_filename
621             : "???"));
622 83 100       930 unless (exists $opts{'-severity'}) {
623             ## See if can find severity in message prefix
624 1 50       10 $opts{'-severity'} = $1 if ( $msg =~ s/^\**\s*([A-Z]{3,}):\s+// );
625             }
626 83 50       179 my $severity = (exists $opts{'-severity'}) ? "*** $opts{-severity}: " : '';
627              
628             ## Increment error count and print message "
629             ++($self->{'_NUM_ERRORS'})
630 83 100 66     390 if(!%opts || ($opts{-severity} && $opts{'-severity'} eq 'ERROR'));
      66        
631             ++($self->{'_NUM_WARNINGS'})
632 83 100 66     332 if(!%opts || ($opts{-severity} && $opts{'-severity'} eq 'WARNING'));
      66        
633 83 100       413 unless($self->{'-quiet'}) {
634 82   50     162 my $out_fh = $self->{'output_fh'} || \*STDERR;
635             print $out_fh ($severity, $msg, $line, $file, "\n")
636 82 50 33     469 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 35 $_[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 371 ($_[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 363 my ($self,$text) = @_;
692 186 100       373 if(defined $text) {
693 181         510 $text =~ s/\s+$//s; # strip trailing whitespace
694 181         553 $text =~ s/\s+/ /gs; # collapse whitespace
695             # add node, order important!
696 181         251 push(@{$self->{'_nodes'}}, $text);
  181         415  
697             # keep also a uniqueness counter
698 181 100       832 $self->{'_unique_nodes'}->{$text}++ if($text !~ /^\s*$/s);
699 181         423 return $text;
700             }
701 5         12 @{$self->{'_nodes'}};
  5         74  
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 36 my ($self,$text) = @_;
717 11 100       42 if(defined $text) {
718 6         18 $text =~ s/\s+$//s; # strip trailing whitespace
719 6         15 $text =~ s/\s+/ /gs; # collapse whitespace
720             # add node, order important!
721 6         9 push(@{$self->{'_index'}}, $text);
  6         16  
722             # keep also a uniqueness counter
723 6 100       28 $self->{'_unique_nodes'}->{$text}++ if($text !~ /^\s*$/s);
724 6         13 return $text;
725             }
726 5         11 @{$self->{'_index'}};
  5         20  
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 73 my $self = shift;
735 45         54 push(@{$self->{'_links'}}, $_[0]);
  45         115  
736 45         111 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 3 @{shift->{'_links'}};
  1         7  
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 25051 my ($self, $line, $complaint) = @_;
765              
766 45         66 my $severity = 'ERROR';
767              
768 45         60 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       116 $severity = 'WARNING' if $complaint =~ /\bZ\<\>/;
781              
782 45         192 $self->poderror({ -line => $line,
783             -severity => $severity,
784             -msg => $complaint });
785              
786 45         120 return 1; # assume everything is peachy keen
787             }
788              
789             sub scream {
790 1     1 1 2792 my ($self, $line, $complaint) = @_;
791              
792 1         5 $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   652 $_[0]{'_thispara'} = '';
806 378         576 $_[0]{'_line'} = $_[1]{'start_line'};
807 378         684 $_[0]{'_cmds_since_head'}++;
808             }
809              
810             sub _check_fcode {
811 255     255   473 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     763 return if $inner eq 'L' && $Pod::Simple::VERSION ge '3.33';
818              
819 189 100       491 if (grep { $_ eq $inner } @$outers) {
  76         149  
820 7         43 $self->poderror({ -line => $self->{'_line'},
821             -severity => 'WARNING',
822             -msg => "nested commands $inner<...$inner<...>...>"});
823             }
824             }
825              
826             ##################################
827              
828 736     736 1 8956 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 209 my ($line, $line_n, $self) = @_;
833 2         10 $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 572 my ($line, $line_n, $self) = @_;
842 21         41 $self->{'_cmds_since_head'}++;
843 21 100       86 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 71678 sub start_Para { shift->_init_event(@_); }
851             sub end_Para {
852 162     162 1 1377 my $self = shift;
853             # Get the NAME of the pod document
854 162 100 100     613 if ($self->{'_head_num'} == 1 && $self->{'_head_text'} eq 'NAME') {
855 12 100       67 if ($self->{'_thispara'} =~ /^\s*(\S+?)\s*[,-]/) {
856 5 100       26 $self->{'_pod_name'} = $1 unless defined $self->{'_pod_name'};
857             }
858             }
859             }
860              
861             sub start_Verbatim {
862 10     10 1 2994 my $self = shift;
863 10         37 $self->_init_event(@_);
864              
865 10 100 100     54 if ($self->{'_head_num'} == 1 && $self->{'_head_text'} eq 'NAME') {
866 1         13 $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 161 sub start_Data { shift->_init_event() }
875              
876 19     19 1 6400 sub start_head1 { shift->start_head(1, @_) }
877 22     22 1 6757 sub start_head2 { shift->start_head(2, @_) }
878 2     2 1 629 sub start_head3 { shift->start_head(3, @_) }
879 1     1 1 198 sub start_head4 { shift->start_head(4, @_) }
880             sub start_head {
881 44     44 1 73 my $self = shift;
882 44         64 my $h = shift;
883 44         112 $self->_init_event(@_);
884 44         71 my $prev_h = $self->{'_head_num'};
885 44         62 $self->{'_head_num'} = $h;
886 44         104 $self->{"_count_head$h"}++;
887              
888 44 100 100     185 if ($h > 1 && !$self->{'_count_head'.($h-1)}) {
889 1         8 $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     163 if ($self->{'_cmds_since_head'} == 1 && $prev_h >= $h) {
896 5         22 $self->poderror({ -line => $self->{'_line'},
897             -severity => 'WARNING',
898             -msg => 'empty section in previous paragraph'});
899             }
900             }
901              
902 19     19 1 211 sub end_head1 { shift->end_head(@_) }
903 22     22 1 234 sub end_head2 { shift->end_head(@_) }
904 2     2 1 51 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 83 my $self = shift;
908 44         77 my $arg = $self->{'_thispara'};
909 44         152 $arg =~ s/\s+$//;
910 44         99 $self->{'_head_text'} = $arg;
911 44         70 $self->{'_cmds_since_head'} = 0;
912 44         65 my $h = $self->{'_head_num'};
913 44         118 $self->node($arg); # remember this node
914 44 100       144 if ($arg eq '') {
915 1         14 $self->poderror({ -line => $self->{'_line'},
916             -severity => 'ERROR',
917             -msg => "empty =head$h" });
918             }
919             }
920              
921 6     6 1 1650 sub start_over_bullet { shift->start_over(@_, 'bullet') }
922 1     1 1 261 sub start_over_number { shift->start_over(@_, 'number') }
923 8     8 1 3089 sub start_over_text { shift->start_over(@_, 'definition') }
924 4     4 1 488 sub start_over_block { shift->start_over(@_, 'block') }
925             sub start_over_empty {
926 1     1 1 136 my $self = shift;
927 1         6 $self->start_over(@_, 'empty');
928 1         17 $self->poderror({ -line => $self->{'_line'},
929             -severity => 'WARNING',
930             -msg => 'empty =over/=back block' });
931             }
932             sub start_over {
933 20     20 1 32 my $self = shift;
934 20         31 my $type = pop;
935 20         53 $self->_init_event(@_);
936             }
937              
938 58     58 1 28063 sub start_item_bullet { shift->_init_event(@_) }
939 4     4 1 550 sub start_item_number { shift->_init_event(@_) }
940 75     75 1 37030 sub start_item_text { shift->_init_event(@_) }
941 58     58 1 518 sub end_item_bullet { shift->end_item('bullet') }
942 4     4 1 37 sub end_item_number { shift->end_item('number') }
943 75     75 1 690 sub end_item_text { shift->end_item('definition') }
944             sub end_item {
945 137     137 1 193 my $self = shift;
946 137         189 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     341 if ( $self->{'_thispara'} eq ''
      66        
951             && ( ! @{$self->{'paras'}}
952             || $self->{'paras'}[0][0] !~ /Verbatim/i))
953             {
954 1         7 $self->poderror({ -line => $self->{'_line'},
955             -severity => 'WARNING',
956             -msg => '=item has no contents' });
957             }
958              
959 137         270 $self->node($self->{'_thispara'}); # remember this node
960             }
961              
962             sub start_for { # =for and =begin directives
963 4     4 1 930 my ($self, $flags) = @_;
964 4         12 $self->_init_event($flags);
965 4         5 push @{$self->{'_begin_stack'}}, [$self->{'_line'}, $flags->{'target'}];
  4         23  
966             }
967              
968             sub end_for {
969 4     4 1 435 my ($self, $flags) = @_;
970 4         8 my ($line, $target) = @{pop @{$self->{'_begin_stack'}}};
  4         5  
  4         11  
971 4 100       18 if ($flags->{'fake-closer'}) { # meaning Pod::Simple generated this =end
972 2         12 $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 495 my $self = shift;
982              
983             # no POD found here
984 5 50 0     28 $self->num_errors(-1) && return unless $self->content_seen;
985              
986 5         49 my %nodes;
987 5         19 for ($self->node()) {
988 181         352 $nodes{$_} = 1;
989 181 100       475 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     306 $nodes{$1} ||= 2; # derived node
993             }
994             }
995 5         37 for ($self->idx()) {
996 6         11 $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         51 for my $link (@{ $self->{'_internal_links'} }) {
  5         20  
1004 20         38 my ($name, $line) = @$link;
1005 20 100       54 unless ( $nodes{$name} ) {
1006 8         28 $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       44 if ($self->{'-warnings'} > 1 ) {
1015 3         7 for my $node (sort keys %{ $self->{'_unique_nodes'} }) {
  3         100  
1016 174         237 my $count = $self->{'_unique_nodes'}{$node};
1017 174 100       307 if ($count > 1) { # not unique
1018 3         16 $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 351 sub start_B { shift->start_fcode('B') }
1031 110     110 1 1648 sub start_C { shift->start_fcode('C') }
1032 2     2 1 50 sub start_F { shift->start_fcode('F') }
1033 48     48 1 731 sub start_I { shift->start_fcode('I') }
1034 2     2 1 33 sub start_S { shift->start_fcode('S') }
1035             sub start_fcode {
1036 255     255 1 428 my ($self, $fcode) = @_;
1037 255         309 unshift @{$self->{'_fcode_stack'}}, $fcode;
  255         655  
1038             }
1039              
1040 21     21 1 198 sub end_B { shift->end_fcode() }
1041 110     110 1 945 sub end_C { shift->end_fcode() }
1042 2     2 1 24 sub end_F { shift->end_fcode() }
1043 48     48 1 428 sub end_I { shift->end_fcode() }
1044 2     2 1 28 sub end_S { shift->end_fcode() }
1045             sub end_fcode {
1046 255     255 1 376 my $self = shift;
1047 255         537 $self->_check_fcode(shift @{$self->{'_fcode_stack'}}, # current fcode removed
1048 255         333 $self->{'_fcode_stack'}); # previous fcodes
1049             }
1050              
1051             sub start_L {
1052 66     66 1 1007 my ($self, $flags) = @_;
1053 66         158 $self->start_fcode('L');
1054              
1055 66         229 my $link = Pod::Checker::Hyperlink->new($flags, $self);
1056 66 100       169 if ($link) {
1057 65 100 100     132 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         39 push @{ $self->{'_internal_links'} }, [ $link->{'-raw_node'}, $link->line ];
  20         68  
1065             }
1066             else {
1067 45         96 $self->hyperlink($link);
1068             }
1069             }
1070             }
1071              
1072             sub end_L {
1073 66     66 1 603 my $self = shift;
1074 66         124 $self->end_fcode();
1075             }
1076              
1077             sub start_X {
1078 6     6 1 94 my $self = shift;
1079 6         16 $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         7 push @{$self->{'_fcode_pos'}}, length $self->{'_thispara'};
  6         21  
1083             }
1084             sub end_X {
1085 6     6 1 57 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         13  
1088 6         11 my $end = length($self->{'_thispara'}) - $start; # end at end of X<>
1089 6         15 my $x = substr($self->{'_thispara'}, $start, $end, '');
1090 6 100       17 if ($x eq "") {
1091 1         8 $self->poderror({ -line => $self->{'_line'},
1092             -severity => 'ERROR',
1093             -msg => "An empty X<>" });
1094             }
1095 6         14 $self->idx($x); # remember this node
1096 6         18 $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   118 my ($class,
1106             $simple_link, # The link structure returned by Pod::Simple
1107             $caller # The caller class
1108             ) = @_;
1109              
1110 66         113 my $self = +{};
1111 66         111 bless $self, $class;
1112              
1113 66   33     335 $self->{'-line'} ||= $caller->{'_line'};
1114 66   33     272 $self->{'-type'} ||= $simple_link->{'type'};
1115              
1116             # Force stringification of page and node. (This expands any E<>.)
1117 66 100       193 $self->{'-page'} = exists $simple_link->{'to'} ? "$simple_link->{'to'}" : "";
1118 66 100       818 $self->{'-node'} = exists $simple_link->{'section'} ? "$simple_link->{'section'}" : "";
1119              
1120             # Save the unmodified node text, as the .t files are expecting the message
1121             # for internal link failures to include it (hence this preserves backward
1122             # compatibility).
1123 66         808 $self->{'-raw_node'} = $self->{'-node'};
1124              
1125             # Remove leading/trailing white space. Pod::Simple already warns about
1126             # these, so if the only error is this, and the link is otherwise correct,
1127             # only the Pod::Simple warning will be output, avoiding unnecessary
1128             # confusion.
1129 66         167 $self->{'-page'} =~ s/ ^ \s+ //x;
1130 66         171 $self->{'-page'} =~ s/ \s+ $ //x;
1131              
1132 66         129 $self->{'-node'} =~ s/ ^ \s+ //x;
1133 66         127 $self->{'-node'} =~ s/ \s+ $ //x;
1134              
1135             # Pod::Simple warns about L<> and L< >, but not L
1136 66 100 100     191 if ($self->{'-page'} eq "" && $self->{'-node'} eq "") {
1137 1         8 $caller->poderror({ -line => $caller->{'_line'},
1138             -severity => 'WARNING',
1139             -msg => 'empty link'});
1140 1         4 return;
1141             }
1142              
1143 65         116 return $self;
1144             }
1145              
1146             =item line()
1147              
1148             Returns the approximate line number in which the link was encountered
1149              
1150             =cut
1151              
1152             sub line {
1153 46     46   13054 return $_[0]->{-line};
1154             }
1155              
1156             =item type()
1157              
1158             Returns the type of the link; one of:
1159             C<"url"> for things like
1160             C, C<"man"> for man pages, or C<"pod">.
1161              
1162             =cut
1163              
1164             sub type {
1165 91     91   333 return $_[0]->{-type};
1166             }
1167              
1168             =item page()
1169              
1170             Returns the linked-to page or url.
1171              
1172             =cut
1173              
1174             sub page {
1175 87     87   342 return $_[0]->{-page};
1176             }
1177              
1178             =item node()
1179              
1180             Returns the anchor or node within the linked-to page, or an empty string
1181             (C<"">) if none appears in the link.
1182              
1183             =back
1184              
1185             =cut
1186              
1187             sub node {
1188 83     83   363 return $_[0]->{-node};
1189             }
1190              
1191             =head1 AUTHOR
1192              
1193             Please report bugs using L.
1194              
1195             Brad Appleton Ebradapp@enteract.comE (initial version),
1196             Marek Rouchal Emarekr@cpan.orgE,
1197             Marc Green Emarcgreen@cpan.orgE (port to Pod::Simple)
1198             Ricardo Signes Erjbs@cpan.orgE (more porting to Pod::Simple)
1199             Karl Williamson Ekhw@cpan.orgE (more porting to Pod::Simple)
1200              
1201             Based on code for B written by
1202             Tom Christiansen Etchrist@mox.perl.comE
1203              
1204             =cut
1205              
1206             1