xref: /onnv-gate/usr/src/cmd/perl/5.8.4/distrib/lib/Pod/Select.pm (revision 0:68f95e015346)
1*0Sstevel@tonic-gate#############################################################################
2*0Sstevel@tonic-gate# Pod/Select.pm -- function to select portions of POD docs
3*0Sstevel@tonic-gate#
4*0Sstevel@tonic-gate# Copyright (C) 1996-2000 by Bradford Appleton. All rights reserved.
5*0Sstevel@tonic-gate# This file is part of "PodParser". PodParser is free software;
6*0Sstevel@tonic-gate# you can redistribute it and/or modify it under the same terms
7*0Sstevel@tonic-gate# as Perl itself.
8*0Sstevel@tonic-gate#############################################################################
9*0Sstevel@tonic-gate
10*0Sstevel@tonic-gatepackage Pod::Select;
11*0Sstevel@tonic-gate
12*0Sstevel@tonic-gateuse vars qw($VERSION);
13*0Sstevel@tonic-gate$VERSION = 1.13;  ## Current version of this package
14*0Sstevel@tonic-gaterequire  5.005;    ## requires this Perl version or later
15*0Sstevel@tonic-gate
16*0Sstevel@tonic-gate#############################################################################
17*0Sstevel@tonic-gate
18*0Sstevel@tonic-gate=head1 NAME
19*0Sstevel@tonic-gate
20*0Sstevel@tonic-gatePod::Select, podselect() - extract selected sections of POD from input
21*0Sstevel@tonic-gate
22*0Sstevel@tonic-gate=head1 SYNOPSIS
23*0Sstevel@tonic-gate
24*0Sstevel@tonic-gate    use Pod::Select;
25*0Sstevel@tonic-gate
26*0Sstevel@tonic-gate    ## Select all the POD sections for each file in @filelist
27*0Sstevel@tonic-gate    ## and print the result on standard output.
28*0Sstevel@tonic-gate    podselect(@filelist);
29*0Sstevel@tonic-gate
30*0Sstevel@tonic-gate    ## Same as above, but write to tmp.out
31*0Sstevel@tonic-gate    podselect({-output => "tmp.out"}, @filelist):
32*0Sstevel@tonic-gate
33*0Sstevel@tonic-gate    ## Select from the given filelist, only those POD sections that are
34*0Sstevel@tonic-gate    ## within a 1st level section named any of: NAME, SYNOPSIS, OPTIONS.
35*0Sstevel@tonic-gate    podselect({-sections => ["NAME|SYNOPSIS", "OPTIONS"]}, @filelist):
36*0Sstevel@tonic-gate
37*0Sstevel@tonic-gate    ## Select the "DESCRIPTION" section of the PODs from STDIN and write
38*0Sstevel@tonic-gate    ## the result to STDERR.
39*0Sstevel@tonic-gate    podselect({-output => ">&STDERR", -sections => ["DESCRIPTION"]}, \*STDIN);
40*0Sstevel@tonic-gate
41*0Sstevel@tonic-gateor
42*0Sstevel@tonic-gate
43*0Sstevel@tonic-gate    use Pod::Select;
44*0Sstevel@tonic-gate
45*0Sstevel@tonic-gate    ## Create a parser object for selecting POD sections from the input
46*0Sstevel@tonic-gate    $parser = new Pod::Select();
47*0Sstevel@tonic-gate
48*0Sstevel@tonic-gate    ## Select all the POD sections for each file in @filelist
49*0Sstevel@tonic-gate    ## and print the result to tmp.out.
50*0Sstevel@tonic-gate    $parser->parse_from_file("<&STDIN", "tmp.out");
51*0Sstevel@tonic-gate
52*0Sstevel@tonic-gate    ## Select from the given filelist, only those POD sections that are
53*0Sstevel@tonic-gate    ## within a 1st level section named any of: NAME, SYNOPSIS, OPTIONS.
54*0Sstevel@tonic-gate    $parser->select("NAME|SYNOPSIS", "OPTIONS");
55*0Sstevel@tonic-gate    for (@filelist) { $parser->parse_from_file($_); }
56*0Sstevel@tonic-gate
57*0Sstevel@tonic-gate    ## Select the "DESCRIPTION" and "SEE ALSO" sections of the PODs from
58*0Sstevel@tonic-gate    ## STDIN and write the result to STDERR.
59*0Sstevel@tonic-gate    $parser->select("DESCRIPTION");
60*0Sstevel@tonic-gate    $parser->add_selection("SEE ALSO");
61*0Sstevel@tonic-gate    $parser->parse_from_filehandle(\*STDIN, \*STDERR);
62*0Sstevel@tonic-gate
63*0Sstevel@tonic-gate=head1 REQUIRES
64*0Sstevel@tonic-gate
65*0Sstevel@tonic-gateperl5.005, Pod::Parser, Exporter, Carp
66*0Sstevel@tonic-gate
67*0Sstevel@tonic-gate=head1 EXPORTS
68*0Sstevel@tonic-gate
69*0Sstevel@tonic-gatepodselect()
70*0Sstevel@tonic-gate
71*0Sstevel@tonic-gate=head1 DESCRIPTION
72*0Sstevel@tonic-gate
73*0Sstevel@tonic-gateB<podselect()> is a function which will extract specified sections of
74*0Sstevel@tonic-gatepod documentation from an input stream. This ability is provided by the
75*0Sstevel@tonic-gateB<Pod::Select> module which is a subclass of B<Pod::Parser>.
76*0Sstevel@tonic-gateB<Pod::Select> provides a method named B<select()> to specify the set of
77*0Sstevel@tonic-gatePOD sections to select for processing/printing. B<podselect()> merely
78*0Sstevel@tonic-gatecreates a B<Pod::Select> object and then invokes the B<podselect()>
79*0Sstevel@tonic-gatefollowed by B<parse_from_file()>.
80*0Sstevel@tonic-gate
81*0Sstevel@tonic-gate=head1 SECTION SPECIFICATIONS
82*0Sstevel@tonic-gate
83*0Sstevel@tonic-gateB<podselect()> and B<Pod::Select::select()> may be given one or more
84*0Sstevel@tonic-gate"section specifications" to restrict the text processed to only the
85*0Sstevel@tonic-gatedesired set of sections and their corresponding subsections.  A section
86*0Sstevel@tonic-gatespecification is a string containing one or more Perl-style regular
87*0Sstevel@tonic-gateexpressions separated by forward slashes ("/").  If you need to use a
88*0Sstevel@tonic-gateforward slash literally within a section title you can escape it with a
89*0Sstevel@tonic-gatebackslash ("\/").
90*0Sstevel@tonic-gate
91*0Sstevel@tonic-gateThe formal syntax of a section specification is:
92*0Sstevel@tonic-gate
93*0Sstevel@tonic-gate=over 4
94*0Sstevel@tonic-gate
95*0Sstevel@tonic-gate=item *
96*0Sstevel@tonic-gate
97*0Sstevel@tonic-gateI<head1-title-regex>/I<head2-title-regex>/...
98*0Sstevel@tonic-gate
99*0Sstevel@tonic-gate=back
100*0Sstevel@tonic-gate
101*0Sstevel@tonic-gateAny omitted or empty regular expressions will default to ".*".
102*0Sstevel@tonic-gatePlease note that each regular expression given is implicitly
103*0Sstevel@tonic-gateanchored by adding "^" and "$" to the beginning and end.  Also, if a
104*0Sstevel@tonic-gategiven regular expression starts with a "!" character, then the
105*0Sstevel@tonic-gateexpression is I<negated> (so C<!foo> would match anything I<except>
106*0Sstevel@tonic-gateC<foo>).
107*0Sstevel@tonic-gate
108*0Sstevel@tonic-gateSome example section specifications follow.
109*0Sstevel@tonic-gate
110*0Sstevel@tonic-gate=over 4
111*0Sstevel@tonic-gate
112*0Sstevel@tonic-gate=item *
113*0Sstevel@tonic-gate
114*0Sstevel@tonic-gateMatch the C<NAME> and C<SYNOPSIS> sections and all of their subsections:
115*0Sstevel@tonic-gate
116*0Sstevel@tonic-gateC<NAME|SYNOPSIS>
117*0Sstevel@tonic-gate
118*0Sstevel@tonic-gate=item *
119*0Sstevel@tonic-gate
120*0Sstevel@tonic-gateMatch only the C<Question> and C<Answer> subsections of the C<DESCRIPTION>
121*0Sstevel@tonic-gatesection:
122*0Sstevel@tonic-gate
123*0Sstevel@tonic-gateC<DESCRIPTION/Question|Answer>
124*0Sstevel@tonic-gate
125*0Sstevel@tonic-gate=item *
126*0Sstevel@tonic-gate
127*0Sstevel@tonic-gateMatch the C<Comments> subsection of I<all> sections:
128*0Sstevel@tonic-gate
129*0Sstevel@tonic-gateC</Comments>
130*0Sstevel@tonic-gate
131*0Sstevel@tonic-gate=item *
132*0Sstevel@tonic-gate
133*0Sstevel@tonic-gateMatch all subsections of C<DESCRIPTION> I<except> for C<Comments>:
134*0Sstevel@tonic-gate
135*0Sstevel@tonic-gateC<DESCRIPTION/!Comments>
136*0Sstevel@tonic-gate
137*0Sstevel@tonic-gate=item *
138*0Sstevel@tonic-gate
139*0Sstevel@tonic-gateMatch the C<DESCRIPTION> section but do I<not> match any of its subsections:
140*0Sstevel@tonic-gate
141*0Sstevel@tonic-gateC<DESCRIPTION/!.+>
142*0Sstevel@tonic-gate
143*0Sstevel@tonic-gate=item *
144*0Sstevel@tonic-gate
145*0Sstevel@tonic-gateMatch all top level sections but none of their subsections:
146*0Sstevel@tonic-gate
147*0Sstevel@tonic-gateC</!.+>
148*0Sstevel@tonic-gate
149*0Sstevel@tonic-gate=back
150*0Sstevel@tonic-gate
151*0Sstevel@tonic-gate=begin _NOT_IMPLEMENTED_
152*0Sstevel@tonic-gate
153*0Sstevel@tonic-gate=head1 RANGE SPECIFICATIONS
154*0Sstevel@tonic-gate
155*0Sstevel@tonic-gateB<podselect()> and B<Pod::Select::select()> may be given one or more
156*0Sstevel@tonic-gate"range specifications" to restrict the text processed to only the
157*0Sstevel@tonic-gatedesired ranges of paragraphs in the desired set of sections. A range
158*0Sstevel@tonic-gatespecification is a string containing a single Perl-style regular
159*0Sstevel@tonic-gateexpression (a regex), or else two Perl-style regular expressions
160*0Sstevel@tonic-gate(regexs) separated by a ".." (Perl's "range" operator is "..").
161*0Sstevel@tonic-gateThe regexs in a range specification are delimited by forward slashes
162*0Sstevel@tonic-gate("/").  If you need to use a forward slash literally within a regex you
163*0Sstevel@tonic-gatecan escape it with a backslash ("\/").
164*0Sstevel@tonic-gate
165*0Sstevel@tonic-gateThe formal syntax of a range specification is:
166*0Sstevel@tonic-gate
167*0Sstevel@tonic-gate=over 4
168*0Sstevel@tonic-gate
169*0Sstevel@tonic-gate=item *
170*0Sstevel@tonic-gate
171*0Sstevel@tonic-gate/I<start-range-regex>/[../I<end-range-regex>/]
172*0Sstevel@tonic-gate
173*0Sstevel@tonic-gate=back
174*0Sstevel@tonic-gate
175*0Sstevel@tonic-gateWhere each the item inside square brackets (the ".." followed by the
176*0Sstevel@tonic-gateend-range-regex) is optional. Each "range-regex" is of the form:
177*0Sstevel@tonic-gate
178*0Sstevel@tonic-gate    =cmd-expr text-expr
179*0Sstevel@tonic-gate
180*0Sstevel@tonic-gateWhere I<cmd-expr> is intended to match the name of one or more POD
181*0Sstevel@tonic-gatecommands, and I<text-expr> is intended to match the paragraph text for
182*0Sstevel@tonic-gatethe command. If a range-regex is supposed to match a POD command, then
183*0Sstevel@tonic-gatethe first character of the regex (the one after the initial '/')
184*0Sstevel@tonic-gateabsolutely I<must> be a single '=' character; it may not be anything
185*0Sstevel@tonic-gateelse (not even a regex meta-character) if it is supposed to match
186*0Sstevel@tonic-gateagainst the name of a POD command.
187*0Sstevel@tonic-gate
188*0Sstevel@tonic-gateIf no I<=cmd-expr> is given then the text-expr will be matched against
189*0Sstevel@tonic-gateplain textblocks unless it is preceded by a space, in which case it is
190*0Sstevel@tonic-gatematched against verbatim text-blocks. If no I<text-expr> is given then
191*0Sstevel@tonic-gateonly the command-portion of the paragraph is matched against.
192*0Sstevel@tonic-gate
193*0Sstevel@tonic-gateNote that these two expressions are each implicitly anchored. This
194*0Sstevel@tonic-gatemeans that when matching against the command-name, there will be an
195*0Sstevel@tonic-gateimplicit '^' and '$' around the given I<=cmd-expr>; and when matching
196*0Sstevel@tonic-gateagainst the paragraph text there will be an implicit '\A' and '\Z'
197*0Sstevel@tonic-gatearound the given I<text-expr>.
198*0Sstevel@tonic-gate
199*0Sstevel@tonic-gateUnlike with section-specs, the '!' character does I<not> have any special
200*0Sstevel@tonic-gatemeaning (negation or otherwise) at the beginning of a range-spec!
201*0Sstevel@tonic-gate
202*0Sstevel@tonic-gateSome example range specifications follow.
203*0Sstevel@tonic-gate
204*0Sstevel@tonic-gate=over 4
205*0Sstevel@tonic-gate
206*0Sstevel@tonic-gate=item
207*0Sstevel@tonic-gateMatch all C<=for html> paragraphs:
208*0Sstevel@tonic-gate
209*0Sstevel@tonic-gateC</=for html/>
210*0Sstevel@tonic-gate
211*0Sstevel@tonic-gate=item
212*0Sstevel@tonic-gateMatch all paragraphs between C<=begin html> and C<=end html>
213*0Sstevel@tonic-gate(note that this will I<not> work correctly if such sections
214*0Sstevel@tonic-gateare nested):
215*0Sstevel@tonic-gate
216*0Sstevel@tonic-gateC</=begin html/../=end html/>
217*0Sstevel@tonic-gate
218*0Sstevel@tonic-gate=item
219*0Sstevel@tonic-gateMatch all paragraphs between the given C<=item> name until the end of the
220*0Sstevel@tonic-gatecurrent section:
221*0Sstevel@tonic-gate
222*0Sstevel@tonic-gateC</=item mine/../=head\d/>
223*0Sstevel@tonic-gate
224*0Sstevel@tonic-gate=item
225*0Sstevel@tonic-gateMatch all paragraphs between the given C<=item> until the next item, or
226*0Sstevel@tonic-gateuntil the end of the itemized list (note that this will I<not> work as
227*0Sstevel@tonic-gatedesired if the item contains an itemized list nested within it):
228*0Sstevel@tonic-gate
229*0Sstevel@tonic-gateC</=item mine/../=(item|back)/>
230*0Sstevel@tonic-gate
231*0Sstevel@tonic-gate=back
232*0Sstevel@tonic-gate
233*0Sstevel@tonic-gate=end _NOT_IMPLEMENTED_
234*0Sstevel@tonic-gate
235*0Sstevel@tonic-gate=cut
236*0Sstevel@tonic-gate
237*0Sstevel@tonic-gate#############################################################################
238*0Sstevel@tonic-gate
239*0Sstevel@tonic-gateuse strict;
240*0Sstevel@tonic-gate#use diagnostics;
241*0Sstevel@tonic-gateuse Carp;
242*0Sstevel@tonic-gateuse Pod::Parser 1.04;
243*0Sstevel@tonic-gateuse vars qw(@ISA @EXPORT $MAX_HEADING_LEVEL);
244*0Sstevel@tonic-gate
245*0Sstevel@tonic-gate@ISA = qw(Pod::Parser);
246*0Sstevel@tonic-gate@EXPORT = qw(&podselect);
247*0Sstevel@tonic-gate
248*0Sstevel@tonic-gate## Maximum number of heading levels supported for '=headN' directives
249*0Sstevel@tonic-gate*MAX_HEADING_LEVEL = \3;
250*0Sstevel@tonic-gate
251*0Sstevel@tonic-gate#############################################################################
252*0Sstevel@tonic-gate
253*0Sstevel@tonic-gate=head1 OBJECT METHODS
254*0Sstevel@tonic-gate
255*0Sstevel@tonic-gateThe following methods are provided in this module. Each one takes a
256*0Sstevel@tonic-gatereference to the object itself as an implicit first parameter.
257*0Sstevel@tonic-gate
258*0Sstevel@tonic-gate=cut
259*0Sstevel@tonic-gate
260*0Sstevel@tonic-gate##---------------------------------------------------------------------------
261*0Sstevel@tonic-gate
262*0Sstevel@tonic-gate## =begin _PRIVATE_
263*0Sstevel@tonic-gate##
264*0Sstevel@tonic-gate## =head1 B<_init_headings()>
265*0Sstevel@tonic-gate##
266*0Sstevel@tonic-gate## Initialize the current set of active section headings.
267*0Sstevel@tonic-gate##
268*0Sstevel@tonic-gate## =cut
269*0Sstevel@tonic-gate##
270*0Sstevel@tonic-gate## =end _PRIVATE_
271*0Sstevel@tonic-gate
272*0Sstevel@tonic-gateuse vars qw(%myData @section_headings);
273*0Sstevel@tonic-gate
274*0Sstevel@tonic-gatesub _init_headings {
275*0Sstevel@tonic-gate    my $self = shift;
276*0Sstevel@tonic-gate    local *myData = $self;
277*0Sstevel@tonic-gate
278*0Sstevel@tonic-gate    ## Initialize current section heading titles if necessary
279*0Sstevel@tonic-gate    unless (defined $myData{_SECTION_HEADINGS}) {
280*0Sstevel@tonic-gate        local *section_headings = $myData{_SECTION_HEADINGS} = [];
281*0Sstevel@tonic-gate        for (my $i = 0; $i < $MAX_HEADING_LEVEL; ++$i) {
282*0Sstevel@tonic-gate            $section_headings[$i] = '';
283*0Sstevel@tonic-gate        }
284*0Sstevel@tonic-gate    }
285*0Sstevel@tonic-gate}
286*0Sstevel@tonic-gate
287*0Sstevel@tonic-gate##---------------------------------------------------------------------------
288*0Sstevel@tonic-gate
289*0Sstevel@tonic-gate=head1 B<curr_headings()>
290*0Sstevel@tonic-gate
291*0Sstevel@tonic-gate            ($head1, $head2, $head3, ...) = $parser->curr_headings();
292*0Sstevel@tonic-gate            $head1 = $parser->curr_headings(1);
293*0Sstevel@tonic-gate
294*0Sstevel@tonic-gateThis method returns a list of the currently active section headings and
295*0Sstevel@tonic-gatesubheadings in the document being parsed. The list of headings returned
296*0Sstevel@tonic-gatecorresponds to the most recently parsed paragraph of the input.
297*0Sstevel@tonic-gate
298*0Sstevel@tonic-gateIf an argument is given, it must correspond to the desired section
299*0Sstevel@tonic-gateheading number, in which case only the specified section heading is
300*0Sstevel@tonic-gatereturned. If there is no current section heading at the specified
301*0Sstevel@tonic-gatelevel, then C<undef> is returned.
302*0Sstevel@tonic-gate
303*0Sstevel@tonic-gate=cut
304*0Sstevel@tonic-gate
305*0Sstevel@tonic-gatesub curr_headings {
306*0Sstevel@tonic-gate    my $self = shift;
307*0Sstevel@tonic-gate    $self->_init_headings()  unless (defined $self->{_SECTION_HEADINGS});
308*0Sstevel@tonic-gate    my @headings = @{ $self->{_SECTION_HEADINGS} };
309*0Sstevel@tonic-gate    return (@_ > 0  and  $_[0] =~ /^\d+$/) ? $headings[$_[0] - 1] : @headings;
310*0Sstevel@tonic-gate}
311*0Sstevel@tonic-gate
312*0Sstevel@tonic-gate##---------------------------------------------------------------------------
313*0Sstevel@tonic-gate
314*0Sstevel@tonic-gate=head1 B<select()>
315*0Sstevel@tonic-gate
316*0Sstevel@tonic-gate            $parser->select($section_spec1,$section_spec2,...);
317*0Sstevel@tonic-gate
318*0Sstevel@tonic-gateThis method is used to select the particular sections and subsections of
319*0Sstevel@tonic-gatePOD documentation that are to be printed and/or processed. The existing
320*0Sstevel@tonic-gateset of selected sections is I<replaced> with the given set of sections.
321*0Sstevel@tonic-gateSee B<add_selection()> for adding to the current set of selected
322*0Sstevel@tonic-gatesections.
323*0Sstevel@tonic-gate
324*0Sstevel@tonic-gateEach of the C<$section_spec> arguments should be a section specification
325*0Sstevel@tonic-gateas described in L<"SECTION SPECIFICATIONS">.  The section specifications
326*0Sstevel@tonic-gateare parsed by this method and the resulting regular expressions are
327*0Sstevel@tonic-gatestored in the invoking object.
328*0Sstevel@tonic-gate
329*0Sstevel@tonic-gateIf no C<$section_spec> arguments are given, then the existing set of
330*0Sstevel@tonic-gateselected sections is cleared out (which means C<all> sections will be
331*0Sstevel@tonic-gateprocessed).
332*0Sstevel@tonic-gate
333*0Sstevel@tonic-gateThis method should I<not> normally be overridden by subclasses.
334*0Sstevel@tonic-gate
335*0Sstevel@tonic-gate=cut
336*0Sstevel@tonic-gate
337*0Sstevel@tonic-gateuse vars qw(@selected_sections);
338*0Sstevel@tonic-gate
339*0Sstevel@tonic-gatesub select {
340*0Sstevel@tonic-gate    my $self = shift;
341*0Sstevel@tonic-gate    my @sections = @_;
342*0Sstevel@tonic-gate    local *myData = $self;
343*0Sstevel@tonic-gate    local $_;
344*0Sstevel@tonic-gate
345*0Sstevel@tonic-gate### NEED TO DISCERN A SECTION-SPEC FROM A RANGE-SPEC (look for m{^/.+/$}?)
346*0Sstevel@tonic-gate
347*0Sstevel@tonic-gate    ##---------------------------------------------------------------------
348*0Sstevel@tonic-gate    ## The following is a blatant hack for backward compatibility, and for
349*0Sstevel@tonic-gate    ## implementing add_selection(). If the *first* *argument* is the
350*0Sstevel@tonic-gate    ## string "+", then the remaining section specifications are *added*
351*0Sstevel@tonic-gate    ## to the current set of selections; otherwise the given section
352*0Sstevel@tonic-gate    ## specifications will *replace* the current set of selections.
353*0Sstevel@tonic-gate    ##
354*0Sstevel@tonic-gate    ## This should probably be fixed someday, but for the present time,
355*0Sstevel@tonic-gate    ## it seems incredibly unlikely that "+" would ever correspond to
356*0Sstevel@tonic-gate    ## a legitimate section heading
357*0Sstevel@tonic-gate    ##---------------------------------------------------------------------
358*0Sstevel@tonic-gate    my $add = ($sections[0] eq "+") ? shift(@sections) : "";
359*0Sstevel@tonic-gate
360*0Sstevel@tonic-gate    ## Reset the set of sections to use
361*0Sstevel@tonic-gate    unless (@sections > 0) {
362*0Sstevel@tonic-gate        delete $myData{_SELECTED_SECTIONS}  unless ($add);
363*0Sstevel@tonic-gate        return;
364*0Sstevel@tonic-gate    }
365*0Sstevel@tonic-gate    $myData{_SELECTED_SECTIONS} = []
366*0Sstevel@tonic-gate        unless ($add  &&  exists $myData{_SELECTED_SECTIONS});
367*0Sstevel@tonic-gate    local *selected_sections = $myData{_SELECTED_SECTIONS};
368*0Sstevel@tonic-gate
369*0Sstevel@tonic-gate    ## Compile each spec
370*0Sstevel@tonic-gate    my $spec;
371*0Sstevel@tonic-gate    for $spec (@sections) {
372*0Sstevel@tonic-gate        if ( defined($_ = &_compile_section_spec($spec)) ) {
373*0Sstevel@tonic-gate            ## Store them in our sections array
374*0Sstevel@tonic-gate            push(@selected_sections, $_);
375*0Sstevel@tonic-gate        }
376*0Sstevel@tonic-gate        else {
377*0Sstevel@tonic-gate            carp "Ignoring section spec \"$spec\"!\n";
378*0Sstevel@tonic-gate        }
379*0Sstevel@tonic-gate    }
380*0Sstevel@tonic-gate}
381*0Sstevel@tonic-gate
382*0Sstevel@tonic-gate##---------------------------------------------------------------------------
383*0Sstevel@tonic-gate
384*0Sstevel@tonic-gate=head1 B<add_selection()>
385*0Sstevel@tonic-gate
386*0Sstevel@tonic-gate            $parser->add_selection($section_spec1,$section_spec2,...);
387*0Sstevel@tonic-gate
388*0Sstevel@tonic-gateThis method is used to add to the currently selected sections and
389*0Sstevel@tonic-gatesubsections of POD documentation that are to be printed and/or
390*0Sstevel@tonic-gateprocessed. See <select()> for replacing the currently selected sections.
391*0Sstevel@tonic-gate
392*0Sstevel@tonic-gateEach of the C<$section_spec> arguments should be a section specification
393*0Sstevel@tonic-gateas described in L<"SECTION SPECIFICATIONS">. The section specifications
394*0Sstevel@tonic-gateare parsed by this method and the resulting regular expressions are
395*0Sstevel@tonic-gatestored in the invoking object.
396*0Sstevel@tonic-gate
397*0Sstevel@tonic-gateThis method should I<not> normally be overridden by subclasses.
398*0Sstevel@tonic-gate
399*0Sstevel@tonic-gate=cut
400*0Sstevel@tonic-gate
401*0Sstevel@tonic-gatesub add_selection {
402*0Sstevel@tonic-gate    my $self = shift;
403*0Sstevel@tonic-gate    $self->select("+", @_);
404*0Sstevel@tonic-gate}
405*0Sstevel@tonic-gate
406*0Sstevel@tonic-gate##---------------------------------------------------------------------------
407*0Sstevel@tonic-gate
408*0Sstevel@tonic-gate=head1 B<clear_selections()>
409*0Sstevel@tonic-gate
410*0Sstevel@tonic-gate            $parser->clear_selections();
411*0Sstevel@tonic-gate
412*0Sstevel@tonic-gateThis method takes no arguments, it has the exact same effect as invoking
413*0Sstevel@tonic-gate<select()> with no arguments.
414*0Sstevel@tonic-gate
415*0Sstevel@tonic-gate=cut
416*0Sstevel@tonic-gate
417*0Sstevel@tonic-gatesub clear_selections {
418*0Sstevel@tonic-gate    my $self = shift;
419*0Sstevel@tonic-gate    $self->select();
420*0Sstevel@tonic-gate}
421*0Sstevel@tonic-gate
422*0Sstevel@tonic-gate##---------------------------------------------------------------------------
423*0Sstevel@tonic-gate
424*0Sstevel@tonic-gate=head1 B<match_section()>
425*0Sstevel@tonic-gate
426*0Sstevel@tonic-gate            $boolean = $parser->match_section($heading1,$heading2,...);
427*0Sstevel@tonic-gate
428*0Sstevel@tonic-gateReturns a value of true if the given section and subsection heading
429*0Sstevel@tonic-gatetitles match any of the currently selected section specifications in
430*0Sstevel@tonic-gateeffect from prior calls to B<select()> and B<add_selection()> (or if
431*0Sstevel@tonic-gatethere are no explictly selected/deselected sections).
432*0Sstevel@tonic-gate
433*0Sstevel@tonic-gateThe arguments C<$heading1>, C<$heading2>, etc. are the heading titles of
434*0Sstevel@tonic-gatethe corresponding sections, subsections, etc. to try and match.  If
435*0Sstevel@tonic-gateC<$headingN> is omitted then it defaults to the current corresponding
436*0Sstevel@tonic-gatesection heading title in the input.
437*0Sstevel@tonic-gate
438*0Sstevel@tonic-gateThis method should I<not> normally be overridden by subclasses.
439*0Sstevel@tonic-gate
440*0Sstevel@tonic-gate=cut
441*0Sstevel@tonic-gate
442*0Sstevel@tonic-gatesub match_section {
443*0Sstevel@tonic-gate    my $self = shift;
444*0Sstevel@tonic-gate    my (@headings) = @_;
445*0Sstevel@tonic-gate    local *myData = $self;
446*0Sstevel@tonic-gate
447*0Sstevel@tonic-gate    ## Return true if no restrictions were explicitly specified
448*0Sstevel@tonic-gate    my $selections = (exists $myData{_SELECTED_SECTIONS})
449*0Sstevel@tonic-gate                       ?  $myData{_SELECTED_SECTIONS}  :  undef;
450*0Sstevel@tonic-gate    return  1  unless ((defined $selections) && (@{$selections} > 0));
451*0Sstevel@tonic-gate
452*0Sstevel@tonic-gate    ## Default any unspecified sections to the current one
453*0Sstevel@tonic-gate    my @current_headings = $self->curr_headings();
454*0Sstevel@tonic-gate    for (my $i = 0; $i < $MAX_HEADING_LEVEL; ++$i) {
455*0Sstevel@tonic-gate        (defined $headings[$i])  or  $headings[$i] = $current_headings[$i];
456*0Sstevel@tonic-gate    }
457*0Sstevel@tonic-gate
458*0Sstevel@tonic-gate    ## Look for a match against the specified section expressions
459*0Sstevel@tonic-gate    my ($section_spec, $regex, $negated, $match);
460*0Sstevel@tonic-gate    for $section_spec ( @{$selections} ) {
461*0Sstevel@tonic-gate        ##------------------------------------------------------
462*0Sstevel@tonic-gate        ## Each portion of this spec must match in order for
463*0Sstevel@tonic-gate        ## the spec to be matched. So we will start with a
464*0Sstevel@tonic-gate        ## match-value of 'true' and logically 'and' it with
465*0Sstevel@tonic-gate        ## the results of matching a given element of the spec.
466*0Sstevel@tonic-gate        ##------------------------------------------------------
467*0Sstevel@tonic-gate        $match = 1;
468*0Sstevel@tonic-gate        for (my $i = 0; $i < $MAX_HEADING_LEVEL; ++$i) {
469*0Sstevel@tonic-gate            $regex   = $section_spec->[$i];
470*0Sstevel@tonic-gate            $negated = ($regex =~ s/^\!//);
471*0Sstevel@tonic-gate            $match  &= ($negated ? ($headings[$i] !~ /${regex}/)
472*0Sstevel@tonic-gate                                 : ($headings[$i] =~ /${regex}/));
473*0Sstevel@tonic-gate            last unless ($match);
474*0Sstevel@tonic-gate        }
475*0Sstevel@tonic-gate        return  1  if ($match);
476*0Sstevel@tonic-gate    }
477*0Sstevel@tonic-gate    return  0;  ## no match
478*0Sstevel@tonic-gate}
479*0Sstevel@tonic-gate
480*0Sstevel@tonic-gate##---------------------------------------------------------------------------
481*0Sstevel@tonic-gate
482*0Sstevel@tonic-gate=head1 B<is_selected()>
483*0Sstevel@tonic-gate
484*0Sstevel@tonic-gate            $boolean = $parser->is_selected($paragraph);
485*0Sstevel@tonic-gate
486*0Sstevel@tonic-gateThis method is used to determine if the block of text given in
487*0Sstevel@tonic-gateC<$paragraph> falls within the currently selected set of POD sections
488*0Sstevel@tonic-gateand subsections to be printed or processed. This method is also
489*0Sstevel@tonic-gateresponsible for keeping track of the current input section and
490*0Sstevel@tonic-gatesubsections. It is assumed that C<$paragraph> is the most recently read
491*0Sstevel@tonic-gate(but not yet processed) input paragraph.
492*0Sstevel@tonic-gate
493*0Sstevel@tonic-gateThe value returned will be true if the C<$paragraph> and the rest of the
494*0Sstevel@tonic-gatetext in the same section as C<$paragraph> should be selected (included)
495*0Sstevel@tonic-gatefor processing; otherwise a false value is returned.
496*0Sstevel@tonic-gate
497*0Sstevel@tonic-gate=cut
498*0Sstevel@tonic-gate
499*0Sstevel@tonic-gatesub is_selected {
500*0Sstevel@tonic-gate    my ($self, $paragraph) = @_;
501*0Sstevel@tonic-gate    local $_;
502*0Sstevel@tonic-gate    local *myData = $self;
503*0Sstevel@tonic-gate
504*0Sstevel@tonic-gate    $self->_init_headings()  unless (defined $myData{_SECTION_HEADINGS});
505*0Sstevel@tonic-gate
506*0Sstevel@tonic-gate    ## Keep track of current sections levels and headings
507*0Sstevel@tonic-gate    $_ = $paragraph;
508*0Sstevel@tonic-gate    if (/^=((?:sub)*)(?:head(?:ing)?|sec(?:tion)?)(\d*)\s+(.*)\s*$/) {
509*0Sstevel@tonic-gate        ## This is a section heading command
510*0Sstevel@tonic-gate        my ($level, $heading) = ($2, $3);
511*0Sstevel@tonic-gate        $level = 1 + (length($1) / 3)  if ((! length $level) || (length $1));
512*0Sstevel@tonic-gate        ## Reset the current section heading at this level
513*0Sstevel@tonic-gate        $myData{_SECTION_HEADINGS}->[$level - 1] = $heading;
514*0Sstevel@tonic-gate        ## Reset subsection headings of this one to empty
515*0Sstevel@tonic-gate        for (my $i = $level; $i < $MAX_HEADING_LEVEL; ++$i) {
516*0Sstevel@tonic-gate            $myData{_SECTION_HEADINGS}->[$i] = '';
517*0Sstevel@tonic-gate        }
518*0Sstevel@tonic-gate    }
519*0Sstevel@tonic-gate
520*0Sstevel@tonic-gate    return  $self->match_section();
521*0Sstevel@tonic-gate}
522*0Sstevel@tonic-gate
523*0Sstevel@tonic-gate#############################################################################
524*0Sstevel@tonic-gate
525*0Sstevel@tonic-gate=head1 EXPORTED FUNCTIONS
526*0Sstevel@tonic-gate
527*0Sstevel@tonic-gateThe following functions are exported by this module. Please note that
528*0Sstevel@tonic-gatethese are functions (not methods) and therefore C<do not> take an
529*0Sstevel@tonic-gateimplicit first argument.
530*0Sstevel@tonic-gate
531*0Sstevel@tonic-gate=cut
532*0Sstevel@tonic-gate
533*0Sstevel@tonic-gate##---------------------------------------------------------------------------
534*0Sstevel@tonic-gate
535*0Sstevel@tonic-gate=head1 B<podselect()>
536*0Sstevel@tonic-gate
537*0Sstevel@tonic-gate            podselect(\%options,@filelist);
538*0Sstevel@tonic-gate
539*0Sstevel@tonic-gateB<podselect> will print the raw (untranslated) POD paragraphs of all
540*0Sstevel@tonic-gatePOD sections in the given input files specified by C<@filelist>
541*0Sstevel@tonic-gateaccording to the given options.
542*0Sstevel@tonic-gate
543*0Sstevel@tonic-gateIf any argument to B<podselect> is a reference to a hash
544*0Sstevel@tonic-gate(associative array) then the values with the following keys are
545*0Sstevel@tonic-gateprocessed as follows:
546*0Sstevel@tonic-gate
547*0Sstevel@tonic-gate=over 4
548*0Sstevel@tonic-gate
549*0Sstevel@tonic-gate=item B<-output>
550*0Sstevel@tonic-gate
551*0Sstevel@tonic-gateA string corresponding to the desired output file (or ">&STDOUT"
552*0Sstevel@tonic-gateor ">&STDERR"). The default is to use standard output.
553*0Sstevel@tonic-gate
554*0Sstevel@tonic-gate=item B<-sections>
555*0Sstevel@tonic-gate
556*0Sstevel@tonic-gateA reference to an array of sections specifications (as described in
557*0Sstevel@tonic-gateL<"SECTION SPECIFICATIONS">) which indicate the desired set of POD
558*0Sstevel@tonic-gatesections and subsections to be selected from input. If no section
559*0Sstevel@tonic-gatespecifications are given, then all sections of the PODs are used.
560*0Sstevel@tonic-gate
561*0Sstevel@tonic-gate=begin _NOT_IMPLEMENTED_
562*0Sstevel@tonic-gate
563*0Sstevel@tonic-gate=item B<-ranges>
564*0Sstevel@tonic-gate
565*0Sstevel@tonic-gateA reference to an array of range specifications (as described in
566*0Sstevel@tonic-gateL<"RANGE SPECIFICATIONS">) which indicate the desired range of POD
567*0Sstevel@tonic-gateparagraphs to be selected from the desired input sections. If no range
568*0Sstevel@tonic-gatespecifications are given, then all paragraphs of the desired sections
569*0Sstevel@tonic-gateare used.
570*0Sstevel@tonic-gate
571*0Sstevel@tonic-gate=end _NOT_IMPLEMENTED_
572*0Sstevel@tonic-gate
573*0Sstevel@tonic-gate=back
574*0Sstevel@tonic-gate
575*0Sstevel@tonic-gateAll other arguments should correspond to the names of input files
576*0Sstevel@tonic-gatecontaining POD sections. A file name of "-" or "<&STDIN" will
577*0Sstevel@tonic-gatebe interpeted to mean standard input (which is the default if no
578*0Sstevel@tonic-gatefilenames are given).
579*0Sstevel@tonic-gate
580*0Sstevel@tonic-gate=cut 
581*0Sstevel@tonic-gate
582*0Sstevel@tonic-gatesub podselect {
583*0Sstevel@tonic-gate    my(@argv) = @_;
584*0Sstevel@tonic-gate    my %defaults   = ();
585*0Sstevel@tonic-gate    my $pod_parser = new Pod::Select(%defaults);
586*0Sstevel@tonic-gate    my $num_inputs = 0;
587*0Sstevel@tonic-gate    my $output = ">&STDOUT";
588*0Sstevel@tonic-gate    my %opts = ();
589*0Sstevel@tonic-gate    local $_;
590*0Sstevel@tonic-gate    for (@argv) {
591*0Sstevel@tonic-gate        if (ref($_)) {
592*0Sstevel@tonic-gate            next unless (ref($_) eq 'HASH');
593*0Sstevel@tonic-gate            %opts = (%defaults, %{$_});
594*0Sstevel@tonic-gate
595*0Sstevel@tonic-gate            ##-------------------------------------------------------------
596*0Sstevel@tonic-gate            ## Need this for backward compatibility since we formerly used
597*0Sstevel@tonic-gate            ## options that were all uppercase words rather than ones that
598*0Sstevel@tonic-gate            ## looked like Unix command-line options.
599*0Sstevel@tonic-gate            ## to be uppercase keywords)
600*0Sstevel@tonic-gate            ##-------------------------------------------------------------
601*0Sstevel@tonic-gate            %opts = map {
602*0Sstevel@tonic-gate                my ($key, $val) = (lc $_, $opts{$_});
603*0Sstevel@tonic-gate                $key =~ s/^(?=\w)/-/;
604*0Sstevel@tonic-gate                $key =~ /^-se[cl]/  and  $key  = '-sections';
605*0Sstevel@tonic-gate                #! $key eq '-range'    and  $key .= 's';
606*0Sstevel@tonic-gate                ($key => $val);
607*0Sstevel@tonic-gate            } (keys %opts);
608*0Sstevel@tonic-gate
609*0Sstevel@tonic-gate            ## Process the options
610*0Sstevel@tonic-gate            (exists $opts{'-output'})  and  $output = $opts{'-output'};
611*0Sstevel@tonic-gate
612*0Sstevel@tonic-gate            ## Select the desired sections
613*0Sstevel@tonic-gate            $pod_parser->select(@{ $opts{'-sections'} })
614*0Sstevel@tonic-gate                if ( (defined $opts{'-sections'})
615*0Sstevel@tonic-gate                     && ((ref $opts{'-sections'}) eq 'ARRAY') );
616*0Sstevel@tonic-gate
617*0Sstevel@tonic-gate            #! ## Select the desired paragraph ranges
618*0Sstevel@tonic-gate            #! $pod_parser->select(@{ $opts{'-ranges'} })
619*0Sstevel@tonic-gate            #!     if ( (defined $opts{'-ranges'})
620*0Sstevel@tonic-gate            #!          && ((ref $opts{'-ranges'}) eq 'ARRAY') );
621*0Sstevel@tonic-gate        }
622*0Sstevel@tonic-gate        else {
623*0Sstevel@tonic-gate            $pod_parser->parse_from_file($_, $output);
624*0Sstevel@tonic-gate            ++$num_inputs;
625*0Sstevel@tonic-gate        }
626*0Sstevel@tonic-gate    }
627*0Sstevel@tonic-gate    $pod_parser->parse_from_file("-")  unless ($num_inputs > 0);
628*0Sstevel@tonic-gate}
629*0Sstevel@tonic-gate
630*0Sstevel@tonic-gate#############################################################################
631*0Sstevel@tonic-gate
632*0Sstevel@tonic-gate=head1 PRIVATE METHODS AND DATA
633*0Sstevel@tonic-gate
634*0Sstevel@tonic-gateB<Pod::Select> makes uses a number of internal methods and data fields
635*0Sstevel@tonic-gatewhich clients should not need to see or use. For the sake of avoiding
636*0Sstevel@tonic-gatename collisions with client data and methods, these methods and fields
637*0Sstevel@tonic-gateare briefly discussed here. Determined hackers may obtain further
638*0Sstevel@tonic-gateinformation about them by reading the B<Pod::Select> source code.
639*0Sstevel@tonic-gate
640*0Sstevel@tonic-gatePrivate data fields are stored in the hash-object whose reference is
641*0Sstevel@tonic-gatereturned by the B<new()> constructor for this class. The names of all
642*0Sstevel@tonic-gateprivate methods and data-fields used by B<Pod::Select> begin with a
643*0Sstevel@tonic-gateprefix of "_" and match the regular expression C</^_\w+$/>.
644*0Sstevel@tonic-gate
645*0Sstevel@tonic-gate=cut
646*0Sstevel@tonic-gate
647*0Sstevel@tonic-gate##---------------------------------------------------------------------------
648*0Sstevel@tonic-gate
649*0Sstevel@tonic-gate=begin _PRIVATE_
650*0Sstevel@tonic-gate
651*0Sstevel@tonic-gate=head1 B<_compile_section_spec()>
652*0Sstevel@tonic-gate
653*0Sstevel@tonic-gate            $listref = $parser->_compile_section_spec($section_spec);
654*0Sstevel@tonic-gate
655*0Sstevel@tonic-gateThis function (note it is a function and I<not> a method) takes a
656*0Sstevel@tonic-gatesection specification (as described in L<"SECTION SPECIFICATIONS">)
657*0Sstevel@tonic-gategiven in C<$section_sepc>, and compiles it into a list of regular
658*0Sstevel@tonic-gateexpressions. If C<$section_spec> has no syntax errors, then a reference
659*0Sstevel@tonic-gateto the list (array) of corresponding regular expressions is returned;
660*0Sstevel@tonic-gateotherwise C<undef> is returned and an error message is printed (using
661*0Sstevel@tonic-gateB<carp>) for each invalid regex.
662*0Sstevel@tonic-gate
663*0Sstevel@tonic-gate=end _PRIVATE_
664*0Sstevel@tonic-gate
665*0Sstevel@tonic-gate=cut
666*0Sstevel@tonic-gate
667*0Sstevel@tonic-gatesub _compile_section_spec {
668*0Sstevel@tonic-gate    my ($section_spec) = @_;
669*0Sstevel@tonic-gate    my (@regexs, $negated);
670*0Sstevel@tonic-gate
671*0Sstevel@tonic-gate    ## Compile the spec into a list of regexs
672*0Sstevel@tonic-gate    local $_ = $section_spec;
673*0Sstevel@tonic-gate    s|\\\\|\001|g;  ## handle escaped backward slashes
674*0Sstevel@tonic-gate    s|\\/|\002|g;   ## handle escaped forward slashes
675*0Sstevel@tonic-gate
676*0Sstevel@tonic-gate    ## Parse the regexs for the heading titles
677*0Sstevel@tonic-gate    @regexs = split('/', $_, $MAX_HEADING_LEVEL);
678*0Sstevel@tonic-gate
679*0Sstevel@tonic-gate    ## Set default regex for ommitted levels
680*0Sstevel@tonic-gate    for (my $i = 0; $i < $MAX_HEADING_LEVEL; ++$i) {
681*0Sstevel@tonic-gate        $regexs[$i]  = '.*'  unless ((defined $regexs[$i])
682*0Sstevel@tonic-gate                                     && (length $regexs[$i]));
683*0Sstevel@tonic-gate    }
684*0Sstevel@tonic-gate    ## Modify the regexs as needed and validate their syntax
685*0Sstevel@tonic-gate    my $bad_regexs = 0;
686*0Sstevel@tonic-gate    for (@regexs) {
687*0Sstevel@tonic-gate        $_ .= '.+'  if ($_ eq '!');
688*0Sstevel@tonic-gate        s|\001|\\\\|g;       ## restore escaped backward slashes
689*0Sstevel@tonic-gate        s|\002|\\/|g;        ## restore escaped forward slashes
690*0Sstevel@tonic-gate        $negated = s/^\!//;  ## check for negation
691*0Sstevel@tonic-gate        eval "/$_/";         ## check regex syntax
692*0Sstevel@tonic-gate        if ($@) {
693*0Sstevel@tonic-gate            ++$bad_regexs;
694*0Sstevel@tonic-gate            carp "Bad regular expression /$_/ in \"$section_spec\": $@\n";
695*0Sstevel@tonic-gate        }
696*0Sstevel@tonic-gate        else {
697*0Sstevel@tonic-gate            ## Add the forward and rear anchors (and put the negator back)
698*0Sstevel@tonic-gate            $_ = '^' . $_  unless (/^\^/);
699*0Sstevel@tonic-gate            $_ = $_ . '$'  unless (/\$$/);
700*0Sstevel@tonic-gate            $_ = '!' . $_  if ($negated);
701*0Sstevel@tonic-gate        }
702*0Sstevel@tonic-gate    }
703*0Sstevel@tonic-gate    return  (! $bad_regexs) ? [ @regexs ] : undef;
704*0Sstevel@tonic-gate}
705*0Sstevel@tonic-gate
706*0Sstevel@tonic-gate##---------------------------------------------------------------------------
707*0Sstevel@tonic-gate
708*0Sstevel@tonic-gate=begin _PRIVATE_
709*0Sstevel@tonic-gate
710*0Sstevel@tonic-gate=head2 $self->{_SECTION_HEADINGS}
711*0Sstevel@tonic-gate
712*0Sstevel@tonic-gateA reference to an array of the current section heading titles for each
713*0Sstevel@tonic-gateheading level (note that the first heading level title is at index 0).
714*0Sstevel@tonic-gate
715*0Sstevel@tonic-gate=end _PRIVATE_
716*0Sstevel@tonic-gate
717*0Sstevel@tonic-gate=cut
718*0Sstevel@tonic-gate
719*0Sstevel@tonic-gate##---------------------------------------------------------------------------
720*0Sstevel@tonic-gate
721*0Sstevel@tonic-gate=begin _PRIVATE_
722*0Sstevel@tonic-gate
723*0Sstevel@tonic-gate=head2 $self->{_SELECTED_SECTIONS}
724*0Sstevel@tonic-gate
725*0Sstevel@tonic-gateA reference to an array of references to arrays. Each subarray is a list
726*0Sstevel@tonic-gateof anchored regular expressions (preceded by a "!" if the expression is to
727*0Sstevel@tonic-gatebe negated). The index of the expression in the subarray should correspond
728*0Sstevel@tonic-gateto the index of the heading title in C<$self-E<gt>{_SECTION_HEADINGS}>
729*0Sstevel@tonic-gatethat it is to be matched against.
730*0Sstevel@tonic-gate
731*0Sstevel@tonic-gate=end _PRIVATE_
732*0Sstevel@tonic-gate
733*0Sstevel@tonic-gate=cut
734*0Sstevel@tonic-gate
735*0Sstevel@tonic-gate#############################################################################
736*0Sstevel@tonic-gate
737*0Sstevel@tonic-gate=head1 SEE ALSO
738*0Sstevel@tonic-gate
739*0Sstevel@tonic-gateL<Pod::Parser>
740*0Sstevel@tonic-gate
741*0Sstevel@tonic-gate=head1 AUTHOR
742*0Sstevel@tonic-gate
743*0Sstevel@tonic-gatePlease report bugs using L<http://rt.cpan.org>.
744*0Sstevel@tonic-gate
745*0Sstevel@tonic-gateBrad Appleton E<lt>bradapp@enteract.comE<gt>
746*0Sstevel@tonic-gate
747*0Sstevel@tonic-gateBased on code for B<pod2text> written by
748*0Sstevel@tonic-gateTom Christiansen E<lt>tchrist@mox.perl.comE<gt>
749*0Sstevel@tonic-gate
750*0Sstevel@tonic-gate=cut
751*0Sstevel@tonic-gate
752*0Sstevel@tonic-gate1;
753*0Sstevel@tonic-gate
754