.\" Automatically generated by Pod::Man 4.14 (Pod::Simple 3.43)
.\"
.\" Standard preamble:
.\" ========================================================================
.de Sp \" Vertical space (when we can't use .PP)
.if t .sp .5v
.if n .sp
..
.de Vb \" Begin verbatim text
.ft CW
.nf
.ne \\$1
..
.de Ve \" End verbatim text
.ft R
.fi
..
.\" Set up some character translations and predefined strings. \*(-- will
.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
.\" double quote, and \*(R" will give a right double quote. \*(C+ will
.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
.\" nothing in troff, for use with C<>.
.tr \(*W-
.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
.ie n \{\
. ds -- \(*W-
. ds PI pi
. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
. ds L" ""
. ds R" ""
. ds C` ""
. ds C' ""
'br\}
.el\{\
. ds -- \|\(em\|
. ds PI \(*p
. ds L" ``
. ds R" ''
. ds C`
. ds C'
'br\}
.\"
.\" Escape single quotes in literal strings from groff's Unicode transform.
.ie \n(.g .ds Aq \(aq
.el .ds Aq '
.\"
.\" If the F register is >0, we'll generate index entries on stderr for
.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
.\" entries marked with X<> in POD. Of course, you'll have to process the
.\" output yourself in some meaningful fashion.
.\"
.\" Avoid warning from groff about undefined register 'F'.
.de IX
..
.nr rF 0
.if \n(.g .if rF .nr rF 1
.if (\n(rF:(\n(.g==0)) \{\
. if \nF \{\
. de IX
. tm Index:\\$1\t\\n%\t"\\$2"
..
. if !\nF==2 \{\
. nr % 0
. nr F 2
. \}
. \}
.\}
.rr rF
.\" ========================================================================
.\"
.IX Title "Apache::Admin::Config 3pm"
.TH Apache::Admin::Config 3pm "2022-12-09" "perl v5.36.0" "User Contributed Perl Documentation"
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
.\" way too many mistakes in technical documents.
.if n .ad l
.nh
.SH "NAME"
Apache::Admin::Config \- A module to read/write Apache like configuration files
.SH "SYNOPSIS"
.IX Header "SYNOPSIS"
.Vb 1
\& use Apache::Admin::Config;
\&
\& # Parse an apache configuration file
\&
\& my $conf = new Apache::Admin::Config "/path/to/config_file.conf"
\& or die $Apache::Admin::Config::ERROR;
\&
\& my $directive = $conf\->directive(\*(Aqdocumentroot\*(Aq);
\&
\& print $directive\->name; # "documentroot"
\& print $directive\->value; # "/my/document/root"
\& print $directive\->type; # "directive"
\&
\& $directive\->isin($conf); # true
\&
\& $directive\->delete;
\&
\& # print the directive list
\&
\& foreach($conf\->directive())
\& {
\& print $_\->name, "\en";
\& }
\&
\& # print the virtualhost list
\&
\& print $_\->section(\*(Aqservername\*(Aq)\->value(), "\en"
\& foreach $conf\->section(\-name => "virtualhost");
\&
\& # add a directive in all virtualhosts
\&
\& foreach($conf\->section(\-name => "virtualhost"))
\& {
\& $_\->add_directive(php_admin_value => \*(Aqopen_basedir "/path"\*(Aq);
\& }
\&
\& # Deleting all "AddType" directives
\&
\& $_\->delete for $conf\->directive("AddType");
\&
\& # saving changes in place
\&
\& $conf\->save;
.Ve
.SH "DESCRIPTION"
.IX Header "DESCRIPTION"
\&\f(CW\*(C`Apache::Admin::Config\*(C'\fR provides an object oriented interface for
reading and writing Apache-like configuration files without affecting
comments, indentation, or truncated lines.
.PP
You can easily extract informations from the apache configuration, or
manage htaccess files.
.PP
I wrote this class because I work for an \s-1IPP,\s0 and we often manipulate
apache configuration files for adding new clients, activate some
features or un/locking directories using htaccess, etc. It can also be
useful for writing some one-shoot migrations scripts in few lines.
.SH "METHODES"
.IX Header "METHODES"
.SS "new"
.IX Subsection "new"
.Vb 3
\& $obj = new Apache::Admin::Config [/path/to/file|handle],
\& [\-indent => $integer], [\*(Aq\-create\*(Aq], [\*(Aq\-no\-comment\-grouping\*(Aq],
\& [\*(Aq\-no\-blank\-grouping\*(Aq]
.Ve
.PP
Create or read, if given in argument, an apache like configuration
file, and return an Apache::Admin::Config instence.
.PP
Arguments:
.ie n .IP "\fI\f(CI""/path/to/file""\fI\fR" 4
.el .IP "\fI\f(CI/path/to/file\fI\fR" 4
.IX Item "/path/to/file"
Path to the configuration file to parse. If none given, create a new
one.
.ie n .IP "\fI\f(CI""handle""\fI\fR" 4
.el .IP "\fI\f(CIhandle\fI\fR" 4
.IX Item "handle"
Instead of specify a path to a file, you can give a reference to an
handle that point to an already openned file. You can do this like
this :
.Sp
.Vb 1
\& my $obj = new Apache::Admin::Config (\e*MYHANDLE);
.Ve
.IP "\fI\f(BI\-indent\fI\fR => \fI\f(CI$integer\fI\fR" 4
.IX Item "-indent => $integer"
If greater than 0, activates the indentation on added lines, the
integer tell how many spaces you went per level of indentation
(suggest 4). A negative value means padding with tabulation(s).
.IP "\fI\f(BI\-create\fI\fR" 4
.IX Item "-create"
If present and path to an unexisting file is given, don't return an
error.
.IP "\fI\f(BI\-no\-comment\-grouping\fI\fR" 4
.IX Item "-no-comment-grouping"
When there are several successive comment-lines, if comment grouping
is enabled only one comment item is created.
.Sp
If present, disable comment grouping at parsing time. Enabled by
default.
.IP "\fI\f(BI\-no\-blank\-grouping\fI\fR" 4
.IX Item "-no-blank-grouping"
Same as comment grouping but for blank lines.
.SS "save"
.IX Subsection "save"
.Vb 1
\& $obj\->save([\*(Aq/path/to/file\*(Aq|HANDLE], [\*(Aq\-reformat\*(Aq])
.Ve
.PP
Write modifications to the configuration file. If a path to a file is
given, save the modification to this file instead. You also can give a
reference to a filehandle like this :
.PP
.Vb 1
\& $conf\->save(\e*MYHANDLE) or die($conf\->error());
.Ve
.PP
Note: If you invoke \fBsave()\fR on an object instantiated with a filehandle,
you should emptied it before. Keep in mind that the constructor don't
seek the \s-1FH\s0 to the begin neither before nor after reading it.
.SS "dump_raw"
.IX Subsection "dump_raw"
.Vb 1
\& $obj\->dump_raw
.Ve
.PP
Returns the configuration file as same as it will be if it was saved
in a file with the \fB\fBsave()\fB\fR method. If you don't call this method
from the top level section, it returns the part of the configuration
file that is under the object's context.
.SS "dump_reformat"
.IX Subsection "dump_reformat"
.Vb 1
\& $obj\->dump_raw
.Ve
.PP
Same as \fBdump_raw()\fR, but reformat each line. Usefull used with \-indent
constructor parameter.
.SS "select"
.IX Subsection "select"
.Vb 7
\& @result = $obj\->select
\& (
\& [\-type => $type],
\& [\-name => $name],
\& [\-value => $value],
\& [\-which => $index],
\& );
\&
\& @directives = $obj\->select(\*(Aqdirective\*(Aq);
\& @sections_foo = $obj\->select(\*(Aqsection\*(Aq, \*(AqFoo\*(Aq);
.Ve
.PP
This method search in the current context for items (directives, sections,
comments...) that correspond to a properties given by arguments. It returns
a \fBlist\fR of matched nods.
.PP
This method can only be called on an object of type \*(L"section\*(R". This
method search only for elements in the section pointed by object, and
isn't recursive. So elements \fBin\fR sub-sections of current section
aren's seek (it's not a bug).
.PP
Arguments:
.ie n .IP "\fB\f(CB""type""\fB\fR" 4
.el .IP "\fB\f(CBtype\fB\fR" 4
.IX Item "type"
Selects item(s) of \f(CW\*(C`type\*(C'\fR type.
.ie n .IP "\fB\f(CB""name""\fB\fR" 4
.el .IP "\fB\f(CBname\fB\fR" 4
.IX Item "name"
Selects item(s) with \f(CW\*(C`name\*(C'\fR name.
.ie n .IP "\fB\f(CB""value""\fB\fR" 4
.el .IP "\fB\f(CBvalue\fB\fR" 4
.IX Item "value"
Selects item(s) with \f(CW\*(C`value\*(C'\fR value.
.ie n .IP "\fB\f(CB""which""\fB\fR" 4
.el .IP "\fB\f(CBwhich\fB\fR" 4
.IX Item "which"
Instead of returning a list of items, returns only a single one
pointed by index given to the \-which option. Caution, returns an empty
string if none selected, so don't cascade your methodes calls like
\&\f(CW$obj\fR\->select(\-which=>0)\->name. Index starts at 0.
.PP
Method returns a list of item(s) founds. Each items is an
Apache::Admin::Config object with same methods but pointing to a
different part of the tree.
.SS "directive"
.IX Subsection "directive"
.Vb 1
\& @directives = $obj\->directive(args...)
.Ve
.PP
Same as calling select('directive', args...)
.SS "section"
.IX Subsection "section"
.Vb 1
\& @sections = $obj\->section(args...)
.Ve
.PP
Same as calling select('section', args...)
.SS "comment"
.IX Subsection "comment"
.Vb 1
\& @comments = $obj\->comment(args...)
.Ve
.PP
Same as calling select('comment', args...)
.SS "blank"
.IX Subsection "blank"
.Vb 1
\& @blanks = $obj\->blank(args...)
.Ve
.PP
Same as calling select('blank', args...)
.SS "set_write_directive"
.IX Subsection "set_write_directive"
.Vb 1
\& $conf\->set_write_directive($code);
.Ve
.PP
Replace the directive writing engine by you own code. Code is call for
adding new directives, or when you tell Apache::Admin::Config to
reformat the whole configuration file. See \fB\fBsave()\fB\fR and
\&\fB\fBdump_reformat()\fB\fR methods for more details.
.PP
Your handler receives 3 arguments : \f(CW$self\fR, \f(CW$name\fR and \f(CW$value\fR. You can
call the \f(CW\*(C`indent()\*(C'\fR method to get the number of spaces to put before
the current line (see \fB\fBindent()\fB\fR methods for more details)
.PP
.Vb 5
\& $conf\->set_write_directive(sub
\& {
\& my($self, $name, $value) = @_;
\& return $self\->indent . "$name $value\en";
\& }
.Ve
.SS "set_write_section"
.IX Subsection "set_write_section"
.Vb 1
\& $conf\->set_write_section($code);
.Ve
.PP
Same as \fBset_write_directive()\fR but for section.
.PP
Your handler receives 3 arguments: \f(CW$self\fR, \f(CW$name\fR and \f(CW$value\fR. You can
call the \f(CW\*(C`indent()\*(C'\fR method to get the number of spaces to put before
the current line (see \fB\fBindent()\fB\fR methods for more details)
.PP
.Vb 5
\& $conf\->set_write_section(sub
\& {
\& my($self, $name, $value) = @_;
\& return $self\->indent . "<$name $value>\en";
\& }
.Ve
.SS "set_write_section_closing"
.IX Subsection "set_write_section_closing"
.Vb 1
\& $conf\->set_write_section_closing($code);
.Ve
.PP
Same as \fBset_write_directive()\fR but for end of sections.
.PP
Your handler receives 2 arguments: \f(CW$self\fR and \f(CW$name\fR. You can call the
\&\f(CW\*(C`indent()\*(C'\fR method to get the number of spaces to put before the
current line (see \fB\fBindent()\fB\fR methods for more details)
.PP
.Vb 5
\& $conf\->set_write_section_closing(sub
\& {
\& my($self, $name) = @_;
\& return $self\->indent . "$name>\en";
\& }
.Ve
.SS "set_write_comment"
.IX Subsection "set_write_comment"
.Vb 1
\& $conf\->set_write_comment($code);
.Ve
.PP
Same as \fBset_write_directive()\fR but for comments.
.PP
Your handler receives 2 arguments: \f(CW$self\fR and \f(CW$value\fR. You can call the
\&\f(CW\*(C`indent()\*(C'\fR method to get the number of spaces to put before the
current line (see \fB\fBindent()\fB\fR methods for more details)
.PP
.Vb 7
\& $conf\->set_write_comment(sub
\& {
\& my($self, $value) = @_;
\& # handle comment grouping
\& $value =~ s/\en/\en# /g;
\& return $self\->indent . join(\*(Aq#\*(Aq, split(/\en/, $value));
\& }
.Ve
.SS "set_write_blank"
.IX Subsection "set_write_blank"
.Vb 1
\& $conf\->set_write_blank($code);
.Ve
.PP
Same as \fBset_write_directive()\fR but for blank lines.
.PP
Your handler receives 2 arguments: \f(CW$self\fR and \f(CW$number\fR.
.PP
.Vb 5
\& $conf\->set_write_blank(sub
\& {
\& my($self, $number) = @_;
\& return $number x "\en";
\& }
.Ve
.SS "add"
.IX Subsection "add"
.Vb 5
\& $item = $obj\->add
\& (
\& $type|$item, [$name], [$value],
\& [\-before => $target | \-after => $target | \*(Aq\-ontop\*(Aq | \*(Aq\-onbottom\*(Aq]
\& );
\&
\& $item = $obj\->add(\*(Aqsection\*(Aq, foo => \*(Aqbar\*(Aq, \-after => $conf_item_object);
\& $item = $obj\->add(\*(Aqcomment\*(Aq, \*(Aqa simple comment\*(Aq, \*(Aq\-ontop\*(Aq);
.Ve
.PP
Add a line of type \fI\f(CI$type\fI\fR with name \fIfoo\fR and value \fIbar\fR in the
context pointed by \fB\f(CB$object\fB\fR.
.PP
Aguments:
.ie n .IP "\fB\f(CB""type""\fB\fR" 4
.el .IP "\fB\f(CBtype\fB\fR" 4
.IX Item "type"
Type of object to add (directive, section, comment or blank).
.ie n .IP "\fB\f(CB""name""\fB\fR" 4
.el .IP "\fB\f(CBname\fB\fR" 4
.IX Item "name"
Only relevant for directives and sections.
.ie n .IP "\fB\f(CB""value""\fB\fR" 4
.el .IP "\fB\f(CBvalue\fB\fR" 4
.IX Item "value"
For directive and section, it defines the value, for comments it
defined the text.
.ie n .IP "\fB\f(CB""\-before""\fB\fR => \fItarget\fR" 4
.el .IP "\fB\f(CB\-before\fB\fR => \fItarget\fR" 4
.IX Item "-before => target"
Inserts item one line before \fItarget\fR. \fItarget\fR _have_ to be in the
same context
.ie n .IP "\fB\f(CB""\-after""\fB\fR => \fItarget\fR" 4
.el .IP "\fB\f(CB\-after\fB\fR => \fItarget\fR" 4
.IX Item "-after => target"
Inserts item one line after \fItarget\fR. \fItarget\fR _have_ to be in the
same context
.ie n .IP "\fB\f(CB""\-ontop""\fB\fR" 4
.el .IP "\fB\f(CB\-ontop\fB\fR" 4
.IX Item "-ontop"
Insert item on the fist line of current context;
.ie n .IP "\fB\f(CB""\-onbottom""\fB\fR" 4
.el .IP "\fB\f(CB\-onbottom\fB\fR" 4
.IX Item "-onbottom"
Iinsert item on the last line of current context;
.PP
Returns the added item
.SS "add_section"
.IX Subsection "add_section"
.Vb 1
\& $section = $obj\->add_section($name, $value)
.Ve
.PP
Same as calling add('section', \f(CW$name\fR, \f(CW$value\fR)
.SS "add_directive"
.IX Subsection "add_directive"
.Vb 1
\& $directive = $obj\->add_directive($name, $value)
.Ve
.PP
Same as calling add('directive', \f(CW$name\fR, \f(CW$value\fR)
.SS "add_comment"
.IX Subsection "add_comment"
.Vb 1
\& $comment = $obj\->add_comment("string", [$group])
.Ve
.PP
Same as calling add('comment', 'string', )
.PP
\&\f(CW$group\fR is a boolean value that control grouping of consecutive comment
lines. Disabled by default.
.SS "add_blank"
.IX Subsection "add_blank"
.Vb 1
\& $blank = $obj\->add_blank([$group])
.Ve
.PP
Same as calling add('blank')
.PP
\&\f(CW$group\fR is a boolean value that control grouping of consecutive blank
lines. Enabled by default.
.SS "set_value"
.IX Subsection "set_value"
.Vb 1
\& $obj\->set_value($newvalue)
.Ve
.PP
Change the value of a directive or section. If no argument given,
return the value.
.SS "value"
.IX Subsection "value"
Returns the value of item pointed by the object if any.
.PP
(Actually \f(CW\*(C`value\*(C'\fR and \f(CW\*(C`set_value\*(C'\fR are the same method)
.SS "move"
.IX Subsection "move"
.Vb 8
\& $obj\->move
\& (
\& $dest_section,
\& \-before => target |
\& \-after => $target |
\& \*(Aq\-ontop\*(Aq |
\& \*(Aq\-onbottom\*(Aq
\& )
.Ve
.PP
Move item into given section. See \f(CW\*(C`add()\*(C'\fR method for options
description.
.SS "copy"
.IX Subsection "copy"
.Vb 8
\& $item\->copy
\& (
\& $dest_section,
\& \-before => target |
\& \-after => $target |
\& \*(Aq\-ontop\*(Aq |
\& \*(Aq\-onbottom\*(Aq
\& )
.Ve
.PP
Copy item into given section. See \f(CW\*(C`add()\*(C'\fR method for options
description.
.SS "clone"
.IX Subsection "clone"
.Vb 1
\& $clone = $item\->clone();
.Ve
.PP
Clone item and all its children. Returns the cloned item.
.SS "first_line"
.IX Subsection "first_line"
.SS "last_line"
.IX Subsection "last_line"
.SS "count_lines"
.IX Subsection "count_lines"
.SS "isin"
.IX Subsection "isin"
.Vb 1
\& $boolean = $obj\->($section_obj, [\*(Aq\-recursif\*(Aq])
.Ve
.PP
Returns true if object point to a rule that is in the section
represented by \f(CW$section_obj\fR. If \f(CW\*(C`\-recursif\*(C'\fR option is present, true
is also return if object is a sub-section of target.
.PP
.Vb 5
\&
\&
\& directive test
\&
\&
\&
\& $test_directive\->isin($target_section) => return false
\& $test_directive\->isin($sub_section) => return true
\& $test_directive\->isin($target_section, \*(Aq\-recursif\*(Aq) => return true
\& $target_section\->isin($target_section) => return true
.Ve
.SS "name"
.IX Subsection "name"
Returns the name of the current pointed object if any
.SS "parent"
.IX Subsection "parent"
Returns the parent context of object. This method on the top level
object returns \f(CW\*(C`undef\*(C'\fR.
.SS "type"
.IX Subsection "type"
Returns the type of object.
.SS "remove"
.IX Subsection "remove"
Synonym for unlink (deprecated). See \fB\fBunlink()\fB\fR.
.SS "unlink"
.IX Subsection "unlink"
.Vb 1
\& $boolean = $item\->unlink();
.Ve
.PP
Unlinks item from the tree, resulting in two separate trees. The item
to unlink becomes the root of a new tree.
.SS "destroy"
.IX Subsection "destroy"
.Vb 1
\& $boolean = $item\->destroy();
.Ve
.PP
Destroy item and its children. Caution, you should call \fBdelete()\fR
method instead if you want destroy a part of a tree. This method don't
notice item's parents of its death.
.SS "delete"
.IX Subsection "delete"
.Vb 1
\& $booleen = $item\->delete;
.Ve
.PP
Remove the current item from it's parent children list and destroy it
and all its children (\fBremove()\fR + \fBdestroy()\fR).
.SS "error"
.IX Subsection "error"
Return the last appended error.
.SH "EXAMPLES"
.IX Header "EXAMPLES"
.Vb 3
\& #
\& # Reindent configuration file properly
\& #
\&
\& my $conf = Apache::Admin::Config
\& (
\& \*(Aq/etc/apache/httpd.conf\*(Aq,
\& \-indent => 2
\& );
\&
\& $conf\->save(\*(Aq\-reformat\*(Aq);
\&
\& #
\& # Managing virtual\-hosts:
\& #
\&
\& my $conf = new Apache::Admin::Config "/etc/apache/httpd.conf";
\&
\& # adding a new virtual\-host:
\& my $vhost = $conf\->add_section(VirtualHost=>\*(Aq127.0.0.1\*(Aq);
\& $vhost\->add_directive(ServerAdmin=>\*(Aqwebmaster@localhost.localdomain\*(Aq);
\& $vhost\->add_directive(DocumentRoot=>\*(Aq/usr/share/www\*(Aq);
\& $vhost\->add_directive(ServerName=>\*(Aqwww.localhost.localdomain\*(Aq);
\& $vhost\->add_directive(ErrorLog=>\*(Aq/var/log/apache/www\-error.log\*(Aq);
\& my $location = $vhost\->add_section(Location=>\*(Aq/admin\*(Aq);
\& $location\->add_directive(AuthType=>\*(Aqbasic\*(Aq);
\& $location\->add_directive(Require=>\*(Aqgroup admin\*(Aq);
\& $conf\->save;
\&
\& # selecting a virtual\-host:
\& my $vhost;
\& foreach my $vh (@{$conf\->section(\*(AqVirtualHost\*(Aq)})
\& {
\& if($vh\->directive(\*(AqServerName\*(Aq)\->value eq \*(Aqwww.localhost.localdomain\*(Aq)
\& {
\& $vhost = $vh;
\& last;
\& }
\& }
\&
\& #
\& # Suppress all comments in the file
\& #
\&
\& sub delete_comments
\& {
\& foreach(shift\->comment)
\& {
\& $_\->delete;
\& }
\& }
\&
\& sub delete_all_comments
\& {
\& foreach($_[0]\->section)
\& {
\& delete_all_comments($_);
\& }
\& delete_comments($_[0]);
\& }
\&
\& delete_all_comments($conf);
\&
\& #
\& # Transform configuration file into XML format
\& #
\&
\& my $c = new Apache::Admin::Config "/path/to/file", \-indent => 2
\& or die $Apache::Admin::Config::ERROR;
\&
\& $c\->set_write_directive(sub {
\& my($self, $name, $value) = @_;
\& return($self\->indent.qq(\en));
\& });
\& $c\->set_write_section_closing(sub {
\& my($self, $name) = @_;
\& return($self\->indent."\en");
\& });
\& $c\->set_write_comment(sub {
\& my($self, $value) = @_;
\& $value =~ s/\en//g;
\& return($self\->indent."");
\& });
\& print $c\->dump_reformat();
.Ve
.SH "AUTHOR"
.IX Header "AUTHOR"
Olivier Poitrey
.SH "AVAILABILITY"
.IX Header "AVAILABILITY"
The official \s-1FTP\s0 location is:
.PP
\&\fBftp://ftp.rhapsodyk.net/pub/devel/perl/Apache\-Admin\-Config\-current.tar.gz\fR
.PP
Also available on \s-1CPAN.\s0
.PP
anonymous \s-1CVS\s0 repository:
.PP
CVS_RSH=ssh cvs \-d anonymous@cvs.rhapsodyk.net:/devel co Apache-Admin-Config
.PP
(supply an empty string as password)
.PP
\&\s-1CVS\s0 repository on the web:
.PP
http://www.rhapsodyk.net/cgi\-bin/cvsweb/Apache\-Admin\-Config/
.SH "BUGS"
.IX Header "BUGS"
Please send bug-reports to aac@list.rhapsodyk.net. You can subscribe to the list
by sending an empty mail to aac\-subscribe@list.rhapsodyk.net.
.SH "LICENCE"
.IX Header "LICENCE"
This library is free software; you can redistribute it and/or
modify it under the terms of the \s-1GNU\s0 Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
.PP
This library is distributed in the hope that it will be useful,
but \s-1WITHOUT ANY WARRANTY\s0; without even the implied warranty of
\&\s-1MERCHANTABILITY\s0 or \s-1FITNESS FOR A PARTICULAR PURPOSE.\s0 See the \s-1GNU\s0
Lesser General Public License for more details.
.PP
You should have received a copy of the \s-1GNU\s0 Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, \s-1MA\s0 02111\-1307 \s-1USA\s0
.SH "COPYRIGHT"
.IX Header "COPYRIGHT"
Copyright (C) 2001 \- Olivier Poitrey