/home/fresvfqn/waterdamagerestorationandrepairsmithtown.com/Compressed/share.zip
PK �%[&���� � doc/alt-libzip/LICENSEnu �[��� Copyright (C) 1999-2020 Dieter Baron and Thomas Klausner
The authors can be contacted at <info@libzip.org>
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
3. The names of the authors may not be used to endorse or promote
products derived from this software without specific prior
written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
PK �%[���s% % licenses/alt-libdav1d/COPYINGnu �[��� Copyright © 2018-2019, VideoLAN and dav1d authors
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
PK �%[_�H b b licenses/alt-libdav1d/PATENTSnu �[��� Alliance for Open Media Patent License 1.0
1. License Terms.
1.1. Patent License. Subject to the terms and conditions of this License, each
Licensor, on behalf of itself and successors in interest and assigns,
grants Licensee a non-sublicensable, perpetual, worldwide, non-exclusive,
no-charge, royalty-free, irrevocable (except as expressly stated in this
License) patent license to its Necessary Claims to make, use, sell, offer
for sale, import or distribute any Implementation.
1.2. Conditions.
1.2.1. Availability. As a condition to the grant of rights to Licensee to make,
sell, offer for sale, import or distribute an Implementation under
Section 1.1, Licensee must make its Necessary Claims available under
this License, and must reproduce this License with any Implementation
as follows:
a. For distribution in source code, by including this License in the
root directory of the source code with its Implementation.
b. For distribution in any other form (including binary, object form,
and/or hardware description code (e.g., HDL, RTL, Gate Level Netlist,
GDSII, etc.)), by including this License in the documentation, legal
notices, and/or other written materials provided with the
Implementation.
1.2.2. Additional Conditions. This license is directly from Licensor to
Licensee. Licensee acknowledges as a condition of benefiting from it
that no rights from Licensor are received from suppliers, distributors,
or otherwise in connection with this License.
1.3. Defensive Termination. If any Licensee, its Affiliates, or its agents
initiates patent litigation or files, maintains, or voluntarily
participates in a lawsuit against another entity or any person asserting
that any Implementation infringes Necessary Claims, any patent licenses
granted under this License directly to the Licensee are immediately
terminated as of the date of the initiation of action unless 1) that suit
was in response to a corresponding suit regarding an Implementation first
brought against an initiating entity, or 2) that suit was brought to
enforce the terms of this License (including intervention in a third-party
action by a Licensee).
1.4. Disclaimers. The Reference Implementation and Specification are provided
"AS IS" and without warranty. The entire risk as to implementing or
otherwise using the Reference Implementation or Specification is assumed
by the implementer and user. Licensor expressly disclaims any warranties
(express, implied, or otherwise), including implied warranties of
merchantability, non-infringement, fitness for a particular purpose, or
title, related to the material. IN NO EVENT WILL LICENSOR BE LIABLE TO
ANY OTHER PARTY FOR LOST PROFITS OR ANY FORM OF INDIRECT, SPECIAL,
INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER FROM ANY CAUSES OF
ACTION OF ANY KIND WITH RESPECT TO THIS LICENSE, WHETHER BASED ON BREACH
OF CONTRACT, TORT (INCLUDING NEGLIGENCE), OR OTHERWISE, AND WHETHER OR
NOT THE OTHER PARTRY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2. Definitions.
2.1. Affiliate. “Affiliate” means an entity that directly or indirectly
Controls, is Controlled by, or is under common Control of that party.
2.2. Control. “Control” means direct or indirect control of more than 50% of
the voting power to elect directors of that corporation, or for any other
entity, the power to direct management of such entity.
2.3. Decoder. "Decoder" means any decoder that conforms fully with all
non-optional portions of the Specification.
2.4. Encoder. "Encoder" means any encoder that produces a bitstream that can
be decoded by a Decoder only to the extent it produces such a bitstream.
2.5. Final Deliverable. “Final Deliverable” means the final version of a
deliverable approved by the Alliance for Open Media as a Final
Deliverable.
2.6. Implementation. "Implementation" means any implementation, including the
Reference Implementation, that is an Encoder and/or a Decoder. An
Implementation also includes components of an Implementation only to the
extent they are used as part of an Implementation.
2.7. License. “License” means this license.
2.8. Licensee. “Licensee” means any person or entity who exercises patent
rights granted under this License.
2.9. Licensor. "Licensor" means (i) any Licensee that makes, sells, offers
for sale, imports or distributes any Implementation, or (ii) a person
or entity that has a licensing obligation to the Implementation as a
result of its membership and/or participation in the Alliance for Open
Media working group that developed the Specification.
2.10. Necessary Claims. "Necessary Claims" means all claims of patents or
patent applications, (a) that currently or at any time in the future,
are owned or controlled by the Licensor, and (b) (i) would be an
Essential Claim as defined by the W3C Policy as of February 5, 2004
(https://www.w3.org/Consortium/Patent-Policy-20040205/#def-essential)
as if the Specification was a W3C Recommendation; or (ii) are infringed
by the Reference Implementation.
2.11. Reference Implementation. “Reference Implementation” means an Encoder
and/or Decoder released by the Alliance for Open Media as a Final
Deliverable.
2.12. Specification. “Specification” means the specification designated by
the Alliance for Open Media as a Final Deliverable for which this
License was issued.
PK � %[�_Nvn n doc/alt-pcre/LICENCEnu �[��� PCRE LICENCE
------------
PCRE is a library of functions to support regular expressions whose syntax
and semantics are as close as possible to those of the Perl 5 language.
Release 8 of PCRE is distributed under the terms of the "BSD" licence, as
specified below. The documentation for PCRE, supplied in the "doc"
directory, is distributed under the same terms as the software itself. The data
in the testdata directory is not copyrighted and is in the public domain.
The basic library functions are written in C and are freestanding. Also
included in the distribution is a set of C++ wrapper functions, and a
just-in-time compiler that can be used to optimize pattern matching. These
are both optional features that can be omitted when the library is built.
THE BASIC LIBRARY FUNCTIONS
---------------------------
Written by: Philip Hazel
Email local part: ph10
Email domain: cam.ac.uk
University of Cambridge Computing Service,
Cambridge, England.
Copyright (c) 1997-2017 University of Cambridge
All rights reserved.
PCRE JUST-IN-TIME COMPILATION SUPPORT
-------------------------------------
Written by: Zoltan Herczeg
Email local part: hzmester
Emain domain: freemail.hu
Copyright(c) 2010-2017 Zoltan Herczeg
All rights reserved.
STACK-LESS JUST-IN-TIME COMPILER
--------------------------------
Written by: Zoltan Herczeg
Email local part: hzmester
Emain domain: freemail.hu
Copyright(c) 2009-2017 Zoltan Herczeg
All rights reserved.
THE C++ WRAPPER FUNCTIONS
-------------------------
Contributed by: Google Inc.
Copyright (c) 2007-2012, Google Inc.
All rights reserved.
THE "BSD" LICENCE
-----------------
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the University of Cambridge nor the name of Google
Inc. nor the names of their contributors may be used to endorse or
promote products derived from this software without specific prior
written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
End
PK � %[�al� � doc/alt-pcre/READMEnu �[��� README file for PCRE (Perl-compatible regular expression library)
-----------------------------------------------------------------
NOTE: This set of files relates to PCRE releases that use the original API,
with library names libpcre, libpcre16, and libpcre32. January 2015 saw the
first release of a new API, known as PCRE2, with release numbers starting at
10.00 and library names libpcre2-8, libpcre2-16, and libpcre2-32. The old
libraries (now called PCRE1) are still being maintained for bug fixes, but
there will be no new development. New projects are advised to use the new PCRE2
libraries.
The latest release of PCRE1 is always available in three alternative formats
from:
ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-xxx.tar.gz
ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-xxx.tar.bz2
ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-xxx.zip
There is a mailing list for discussion about the development of PCRE at
pcre-dev@exim.org. You can access the archives and subscribe or manage your
subscription here:
https://lists.exim.org/mailman/listinfo/pcre-dev
Please read the NEWS file if you are upgrading from a previous release.
The contents of this README file are:
The PCRE APIs
Documentation for PCRE
Contributions by users of PCRE
Building PCRE on non-Unix-like systems
Building PCRE without using autotools
Building PCRE using autotools
Retrieving configuration information
Shared libraries
Cross-compiling using autotools
Using HP's ANSI C++ compiler (aCC)
Compiling in Tru64 using native compilers
Using Sun's compilers for Solaris
Using PCRE from MySQL
Making new tarballs
Testing PCRE
Character tables
File manifest
The PCRE APIs
-------------
PCRE is written in C, and it has its own API. There are three sets of
functions, one for the 8-bit library, which processes strings of bytes, one for
the 16-bit library, which processes strings of 16-bit values, and one for the
32-bit library, which processes strings of 32-bit values. The distribution also
includes a set of C++ wrapper functions (see the pcrecpp man page for details),
courtesy of Google Inc., which can be used to call the 8-bit PCRE library from
C++. Other C++ wrappers have been created from time to time. See, for example:
https://github.com/YasserAsmi/regexp, which aims to be simple and similar in
style to the C API.
The distribution also contains a set of C wrapper functions (again, just for
the 8-bit library) that are based on the POSIX regular expression API (see the
pcreposix man page). These end up in the library called libpcreposix. Note that
this just provides a POSIX calling interface to PCRE; the regular expressions
themselves still follow Perl syntax and semantics. The POSIX API is restricted,
and does not give full access to all of PCRE's facilities.
The header file for the POSIX-style functions is called pcreposix.h. The
official POSIX name is regex.h, but I did not want to risk possible problems
with existing files of that name by distributing it that way. To use PCRE with
an existing program that uses the POSIX API, pcreposix.h will have to be
renamed or pointed at by a link.
If you are using the POSIX interface to PCRE and there is already a POSIX regex
library installed on your system, as well as worrying about the regex.h header
file (as mentioned above), you must also take care when linking programs to
ensure that they link with PCRE's libpcreposix library. Otherwise they may pick
up the POSIX functions of the same name from the other library.
One way of avoiding this confusion is to compile PCRE with the addition of
-Dregcomp=PCREregcomp (and similarly for the other POSIX functions) to the
compiler flags (CFLAGS if you are using "configure" -- see below). This has the
effect of renaming the functions so that the names no longer clash. Of course,
you have to do the same thing for your applications, or write them using the
new names.
Documentation for PCRE
----------------------
If you install PCRE in the normal way on a Unix-like system, you will end up
with a set of man pages whose names all start with "pcre". The one that is just
called "pcre" lists all the others. In addition to these man pages, the PCRE
documentation is supplied in two other forms:
1. There are files called doc/pcre.txt, doc/pcregrep.txt, and
doc/pcretest.txt in the source distribution. The first of these is a
concatenation of the text forms of all the section 3 man pages except
the listing of pcredemo.c and those that summarize individual functions.
The other two are the text forms of the section 1 man pages for the
pcregrep and pcretest commands. These text forms are provided for ease of
scanning with text editors or similar tools. They are installed in
<prefix>/share/doc/pcre, where <prefix> is the installation prefix
(defaulting to /usr/local).
2. A set of files containing all the documentation in HTML form, hyperlinked
in various ways, and rooted in a file called index.html, is distributed in
doc/html and installed in <prefix>/share/doc/pcre/html.
Users of PCRE have contributed files containing the documentation for various
releases in CHM format. These can be found in the Contrib directory of the FTP
site (see next section).
Contributions by users of PCRE
------------------------------
You can find contributions from PCRE users in the directory
ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/Contrib
There is a README file giving brief descriptions of what they are. Some are
complete in themselves; others are pointers to URLs containing relevant files.
Some of this material is likely to be well out-of-date. Several of the earlier
contributions provided support for compiling PCRE on various flavours of
Windows (I myself do not use Windows). Nowadays there is more Windows support
in the standard distribution, so these contibutions have been archived.
A PCRE user maintains downloadable Windows binaries of the pcregrep and
pcretest programs here:
http://www.rexegg.com/pcregrep-pcretest.html
Building PCRE on non-Unix-like systems
--------------------------------------
For a non-Unix-like system, please read the comments in the file
NON-AUTOTOOLS-BUILD, though if your system supports the use of "configure" and
"make" you may be able to build PCRE using autotools in the same way as for
many Unix-like systems.
PCRE can also be configured using the GUI facility provided by CMake's
cmake-gui command. This creates Makefiles, solution files, etc. The file
NON-AUTOTOOLS-BUILD has information about CMake.
PCRE has been compiled on many different operating systems. It should be
straightforward to build PCRE on any system that has a Standard C compiler and
library, because it uses only Standard C functions.
Building PCRE without using autotools
-------------------------------------
The use of autotools (in particular, libtool) is problematic in some
environments, even some that are Unix or Unix-like. See the NON-AUTOTOOLS-BUILD
file for ways of building PCRE without using autotools.
Building PCRE using autotools
-----------------------------
If you are using HP's ANSI C++ compiler (aCC), please see the special note
in the section entitled "Using HP's ANSI C++ compiler (aCC)" below.
The following instructions assume the use of the widely used "configure; make;
make install" (autotools) process.
To build PCRE on system that supports autotools, first run the "configure"
command from the PCRE distribution directory, with your current directory set
to the directory where you want the files to be created. This command is a
standard GNU "autoconf" configuration script, for which generic instructions
are supplied in the file INSTALL.
Most commonly, people build PCRE within its own distribution directory, and in
this case, on many systems, just running "./configure" is sufficient. However,
the usual methods of changing standard defaults are available. For example:
CFLAGS='-O2 -Wall' ./configure --prefix=/opt/local
This command specifies that the C compiler should be run with the flags '-O2
-Wall' instead of the default, and that "make install" should install PCRE
under /opt/local instead of the default /usr/local.
If you want to build in a different directory, just run "configure" with that
directory as current. For example, suppose you have unpacked the PCRE source
into /source/pcre/pcre-xxx, but you want to build it in /build/pcre/pcre-xxx:
cd /build/pcre/pcre-xxx
/source/pcre/pcre-xxx/configure
PCRE is written in C and is normally compiled as a C library. However, it is
possible to build it as a C++ library, though the provided building apparatus
does not have any features to support this.
There are some optional features that can be included or omitted from the PCRE
library. They are also documented in the pcrebuild man page.
. By default, both shared and static libraries are built. You can change this
by adding one of these options to the "configure" command:
--disable-shared
--disable-static
(See also "Shared libraries on Unix-like systems" below.)
. By default, only the 8-bit library is built. If you add --enable-pcre16 to
the "configure" command, the 16-bit library is also built. If you add
--enable-pcre32 to the "configure" command, the 32-bit library is also built.
If you want only the 16-bit or 32-bit library, use --disable-pcre8 to disable
building the 8-bit library.
. If you are building the 8-bit library and want to suppress the building of
the C++ wrapper library, you can add --disable-cpp to the "configure"
command. Otherwise, when "configure" is run without --disable-pcre8, it will
try to find a C++ compiler and C++ header files, and if it succeeds, it will
try to build the C++ wrapper.
. If you want to include support for just-in-time compiling, which can give
large performance improvements on certain platforms, add --enable-jit to the
"configure" command. This support is available only for certain hardware
architectures. If you try to enable it on an unsupported architecture, there
will be a compile time error.
. When JIT support is enabled, pcregrep automatically makes use of it, unless
you add --disable-pcregrep-jit to the "configure" command.
. If you want to make use of the support for UTF-8 Unicode character strings in
the 8-bit library, or UTF-16 Unicode character strings in the 16-bit library,
or UTF-32 Unicode character strings in the 32-bit library, you must add
--enable-utf to the "configure" command. Without it, the code for handling
UTF-8, UTF-16 and UTF-8 is not included in the relevant library. Even
when --enable-utf is included, the use of a UTF encoding still has to be
enabled by an option at run time. When PCRE is compiled with this option, its
input can only either be ASCII or UTF-8/16/32, even when running on EBCDIC
platforms. It is not possible to use both --enable-utf and --enable-ebcdic at
the same time.
. There are no separate options for enabling UTF-8, UTF-16 and UTF-32
independently because that would allow ridiculous settings such as requesting
UTF-16 support while building only the 8-bit library. However, the option
--enable-utf8 is retained for backwards compatibility with earlier releases
that did not support 16-bit or 32-bit character strings. It is synonymous with
--enable-utf. It is not possible to configure one library with UTF support
and the other without in the same configuration.
. If, in addition to support for UTF-8/16/32 character strings, you want to
include support for the \P, \p, and \X sequences that recognize Unicode
character properties, you must add --enable-unicode-properties to the
"configure" command. This adds about 30K to the size of the library (in the
form of a property table); only the basic two-letter properties such as Lu
are supported.
. You can build PCRE to recognize either CR or LF or the sequence CRLF or any
of the preceding, or any of the Unicode newline sequences as indicating the
end of a line. Whatever you specify at build time is the default; the caller
of PCRE can change the selection at run time. The default newline indicator
is a single LF character (the Unix standard). You can specify the default
newline indicator by adding --enable-newline-is-cr or --enable-newline-is-lf
or --enable-newline-is-crlf or --enable-newline-is-anycrlf or
--enable-newline-is-any to the "configure" command, respectively.
If you specify --enable-newline-is-cr or --enable-newline-is-crlf, some of
the standard tests will fail, because the lines in the test files end with
LF. Even if the files are edited to change the line endings, there are likely
to be some failures. With --enable-newline-is-anycrlf or
--enable-newline-is-any, many tests should succeed, but there may be some
failures.
. By default, the sequence \R in a pattern matches any Unicode line ending
sequence. This is independent of the option specifying what PCRE considers to
be the end of a line (see above). However, the caller of PCRE can restrict \R
to match only CR, LF, or CRLF. You can make this the default by adding
--enable-bsr-anycrlf to the "configure" command (bsr = "backslash R").
. When called via the POSIX interface, PCRE uses malloc() to get additional
storage for processing capturing parentheses if there are more than 10 of
them in a pattern. You can increase this threshold by setting, for example,
--with-posix-malloc-threshold=20
on the "configure" command.
. PCRE has a counter that limits the depth of nesting of parentheses in a
pattern. This limits the amount of system stack that a pattern uses when it
is compiled. The default is 250, but you can change it by setting, for
example,
--with-parens-nest-limit=500
. PCRE has a counter that can be set to limit the amount of resources it uses
when matching a pattern. If the limit is exceeded during a match, the match
fails. The default is ten million. You can change the default by setting, for
example,
--with-match-limit=500000
on the "configure" command. This is just the default; individual calls to
pcre_exec() can supply their own value. There is more discussion on the
pcreapi man page.
. There is a separate counter that limits the depth of recursive function calls
during a matching process. This also has a default of ten million, which is
essentially "unlimited". You can change the default by setting, for example,
--with-match-limit-recursion=500000
Recursive function calls use up the runtime stack; running out of stack can
cause programs to crash in strange ways. There is a discussion about stack
sizes in the pcrestack man page.
. The default maximum compiled pattern size is around 64K. You can increase
this by adding --with-link-size=3 to the "configure" command. In the 8-bit
library, PCRE then uses three bytes instead of two for offsets to different
parts of the compiled pattern. In the 16-bit library, --with-link-size=3 is
the same as --with-link-size=4, which (in both libraries) uses four-byte
offsets. Increasing the internal link size reduces performance. In the 32-bit
library, the only supported link size is 4.
. You can build PCRE so that its internal match() function that is called from
pcre_exec() does not call itself recursively. Instead, it uses memory blocks
obtained from the heap via the special functions pcre_stack_malloc() and
pcre_stack_free() to save data that would otherwise be saved on the stack. To
build PCRE like this, use
--disable-stack-for-recursion
on the "configure" command. PCRE runs more slowly in this mode, but it may be
necessary in environments with limited stack sizes. This applies only to the
normal execution of the pcre_exec() function; if JIT support is being
successfully used, it is not relevant. Equally, it does not apply to
pcre_dfa_exec(), which does not use deeply nested recursion. There is a
discussion about stack sizes in the pcrestack man page.
. For speed, PCRE uses four tables for manipulating and identifying characters
whose code point values are less than 256. By default, it uses a set of
tables for ASCII encoding that is part of the distribution. If you specify
--enable-rebuild-chartables
a program called dftables is compiled and run in the default C locale when
you obey "make". It builds a source file called pcre_chartables.c. If you do
not specify this option, pcre_chartables.c is created as a copy of
pcre_chartables.c.dist. See "Character tables" below for further information.
. It is possible to compile PCRE for use on systems that use EBCDIC as their
character code (as opposed to ASCII/Unicode) by specifying
--enable-ebcdic
This automatically implies --enable-rebuild-chartables (see above). However,
when PCRE is built this way, it always operates in EBCDIC. It cannot support
both EBCDIC and UTF-8/16/32. There is a second option, --enable-ebcdic-nl25,
which specifies that the code value for the EBCDIC NL character is 0x25
instead of the default 0x15.
. In environments where valgrind is installed, if you specify
--enable-valgrind
PCRE will use valgrind annotations to mark certain memory regions as
unaddressable. This allows it to detect invalid memory accesses, and is
mostly useful for debugging PCRE itself.
. In environments where the gcc compiler is used and lcov version 1.6 or above
is installed, if you specify
--enable-coverage
the build process implements a code coverage report for the test suite. The
report is generated by running "make coverage". If ccache is installed on
your system, it must be disabled when building PCRE for coverage reporting.
You can do this by setting the environment variable CCACHE_DISABLE=1 before
running "make" to build PCRE. There is more information about coverage
reporting in the "pcrebuild" documentation.
. The pcregrep program currently supports only 8-bit data files, and so
requires the 8-bit PCRE library. It is possible to compile pcregrep to use
libz and/or libbz2, in order to read .gz and .bz2 files (respectively), by
specifying one or both of
--enable-pcregrep-libz
--enable-pcregrep-libbz2
Of course, the relevant libraries must be installed on your system.
. The default size (in bytes) of the internal buffer used by pcregrep can be
set by, for example:
--with-pcregrep-bufsize=51200
The value must be a plain integer. The default is 20480.
. It is possible to compile pcretest so that it links with the libreadline
or libedit libraries, by specifying, respectively,
--enable-pcretest-libreadline or --enable-pcretest-libedit
If this is done, when pcretest's input is from a terminal, it reads it using
the readline() function. This provides line-editing and history facilities.
Note that libreadline is GPL-licenced, so if you distribute a binary of
pcretest linked in this way, there may be licensing issues. These can be
avoided by linking with libedit (which has a BSD licence) instead.
Enabling libreadline causes the -lreadline option to be added to the pcretest
build. In many operating environments with a sytem-installed readline
library this is sufficient. However, in some environments (e.g. if an
unmodified distribution version of readline is in use), it may be necessary
to specify something like LIBS="-lncurses" as well. This is because, to quote
the readline INSTALL, "Readline uses the termcap functions, but does not link
with the termcap or curses library itself, allowing applications which link
with readline the to choose an appropriate library." If you get error
messages about missing functions tgetstr, tgetent, tputs, tgetflag, or tgoto,
this is the problem, and linking with the ncurses library should fix it.
The "configure" script builds the following files for the basic C library:
. Makefile the makefile that builds the library
. config.h build-time configuration options for the library
. pcre.h the public PCRE header file
. pcre-config script that shows the building settings such as CFLAGS
that were set for "configure"
. libpcre.pc ) data for the pkg-config command
. libpcre16.pc )
. libpcre32.pc )
. libpcreposix.pc )
. libtool script that builds shared and/or static libraries
Versions of config.h and pcre.h are distributed in the PCRE tarballs under the
names config.h.generic and pcre.h.generic. These are provided for those who
have to built PCRE without using "configure" or CMake. If you use "configure"
or CMake, the .generic versions are not used.
When building the 8-bit library, if a C++ compiler is found, the following
files are also built:
. libpcrecpp.pc data for the pkg-config command
. pcrecpparg.h header file for calling PCRE via the C++ wrapper
. pcre_stringpiece.h header for the C++ "stringpiece" functions
The "configure" script also creates config.status, which is an executable
script that can be run to recreate the configuration, and config.log, which
contains compiler output from tests that "configure" runs.
Once "configure" has run, you can run "make". This builds the the libraries
libpcre, libpcre16 and/or libpcre32, and a test program called pcretest. If you
enabled JIT support with --enable-jit, a test program called pcre_jit_test is
built as well.
If the 8-bit library is built, libpcreposix and the pcregrep command are also
built, and if a C++ compiler was found on your system, and you did not disable
it with --disable-cpp, "make" builds the C++ wrapper library, which is called
libpcrecpp, as well as some test programs called pcrecpp_unittest,
pcre_scanner_unittest, and pcre_stringpiece_unittest.
The command "make check" runs all the appropriate tests. Details of the PCRE
tests are given below in a separate section of this document.
You can use "make install" to install PCRE into live directories on your
system. The following are installed (file names are all relative to the
<prefix> that is set when "configure" is run):
Commands (bin):
pcretest
pcregrep (if 8-bit support is enabled)
pcre-config
Libraries (lib):
libpcre16 (if 16-bit support is enabled)
libpcre32 (if 32-bit support is enabled)
libpcre (if 8-bit support is enabled)
libpcreposix (if 8-bit support is enabled)
libpcrecpp (if 8-bit and C++ support is enabled)
Configuration information (lib/pkgconfig):
libpcre16.pc
libpcre32.pc
libpcre.pc
libpcreposix.pc
libpcrecpp.pc (if C++ support is enabled)
Header files (include):
pcre.h
pcreposix.h
pcre_scanner.h )
pcre_stringpiece.h ) if C++ support is enabled
pcrecpp.h )
pcrecpparg.h )
Man pages (share/man/man{1,3}):
pcregrep.1
pcretest.1
pcre-config.1
pcre.3
pcre*.3 (lots more pages, all starting "pcre")
HTML documentation (share/doc/pcre/html):
index.html
*.html (lots more pages, hyperlinked from index.html)
Text file documentation (share/doc/pcre):
AUTHORS
COPYING
ChangeLog
LICENCE
NEWS
README
pcre.txt (a concatenation of the man(3) pages)
pcretest.txt the pcretest man page
pcregrep.txt the pcregrep man page
pcre-config.txt the pcre-config man page
If you want to remove PCRE from your system, you can run "make uninstall".
This removes all the files that "make install" installed. However, it does not
remove any directories, because these are often shared with other programs.
Retrieving configuration information
------------------------------------
Running "make install" installs the command pcre-config, which can be used to
recall information about the PCRE configuration and installation. For example:
pcre-config --version
prints the version number, and
pcre-config --libs
outputs information about where the library is installed. This command can be
included in makefiles for programs that use PCRE, saving the programmer from
having to remember too many details.
The pkg-config command is another system for saving and retrieving information
about installed libraries. Instead of separate commands for each library, a
single command is used. For example:
pkg-config --cflags pcre
The data is held in *.pc files that are installed in a directory called
<prefix>/lib/pkgconfig.
Shared libraries
----------------
The default distribution builds PCRE as shared libraries and static libraries,
as long as the operating system supports shared libraries. Shared library
support relies on the "libtool" script which is built as part of the
"configure" process.
The libtool script is used to compile and link both shared and static
libraries. They are placed in a subdirectory called .libs when they are newly
built. The programs pcretest and pcregrep are built to use these uninstalled
libraries (by means of wrapper scripts in the case of shared libraries). When
you use "make install" to install shared libraries, pcregrep and pcretest are
automatically re-built to use the newly installed shared libraries before being
installed themselves. However, the versions left in the build directory still
use the uninstalled libraries.
To build PCRE using static libraries only you must use --disable-shared when
configuring it. For example:
./configure --prefix=/usr/gnu --disable-shared
Then run "make" in the usual way. Similarly, you can use --disable-static to
build only shared libraries.
Cross-compiling using autotools
-------------------------------
You can specify CC and CFLAGS in the normal way to the "configure" command, in
order to cross-compile PCRE for some other host. However, you should NOT
specify --enable-rebuild-chartables, because if you do, the dftables.c source
file is compiled and run on the local host, in order to generate the inbuilt
character tables (the pcre_chartables.c file). This will probably not work,
because dftables.c needs to be compiled with the local compiler, not the cross
compiler.
When --enable-rebuild-chartables is not specified, pcre_chartables.c is created
by making a copy of pcre_chartables.c.dist, which is a default set of tables
that assumes ASCII code. Cross-compiling with the default tables should not be
a problem.
If you need to modify the character tables when cross-compiling, you should
move pcre_chartables.c.dist out of the way, then compile dftables.c by hand and
run it on the local host to make a new version of pcre_chartables.c.dist.
Then when you cross-compile PCRE this new version of the tables will be used.
Using HP's ANSI C++ compiler (aCC)
----------------------------------
Unless C++ support is disabled by specifying the "--disable-cpp" option of the
"configure" script, you must include the "-AA" option in the CXXFLAGS
environment variable in order for the C++ components to compile correctly.
Also, note that the aCC compiler on PA-RISC platforms may have a defect whereby
needed libraries fail to get included when specifying the "-AA" compiler
option. If you experience unresolved symbols when linking the C++ programs,
use the workaround of specifying the following environment variable prior to
running the "configure" script:
CXXLDFLAGS="-lstd_v2 -lCsup_v2"
Compiling in Tru64 using native compilers
-----------------------------------------
The following error may occur when compiling with native compilers in the Tru64
operating system:
CXX libpcrecpp_la-pcrecpp.lo
cxx: Error: /usr/lib/cmplrs/cxx/V7.1-006/include/cxx/iosfwd, line 58: #error
directive: "cannot include iosfwd -- define __USE_STD_IOSTREAM to
override default - see section 7.1.2 of the C++ Using Guide"
#error "cannot include iosfwd -- define __USE_STD_IOSTREAM to override default
- see section 7.1.2 of the C++ Using Guide"
This may be followed by other errors, complaining that 'namespace "std" has no
member'. The solution to this is to add the line
#define __USE_STD_IOSTREAM 1
to the config.h file.
Using Sun's compilers for Solaris
---------------------------------
A user reports that the following configurations work on Solaris 9 sparcv9 and
Solaris 9 x86 (32-bit):
Solaris 9 sparcv9: ./configure --disable-cpp CC=/bin/cc CFLAGS="-m64 -g"
Solaris 9 x86: ./configure --disable-cpp CC=/bin/cc CFLAGS="-g"
Using PCRE from MySQL
---------------------
On systems where both PCRE and MySQL are installed, it is possible to make use
of PCRE from within MySQL, as an alternative to the built-in pattern matching.
There is a web page that tells you how to do this:
http://www.mysqludf.org/lib_mysqludf_preg/index.php
Making new tarballs
-------------------
The command "make dist" creates three PCRE tarballs, in tar.gz, tar.bz2, and
zip formats. The command "make distcheck" does the same, but then does a trial
build of the new distribution to ensure that it works.
If you have modified any of the man page sources in the doc directory, you
should first run the PrepareRelease script before making a distribution. This
script creates the .txt and HTML forms of the documentation from the man pages.
Testing PCRE
------------
To test the basic PCRE library on a Unix-like system, run the RunTest script.
There is another script called RunGrepTest that tests the options of the
pcregrep command. If the C++ wrapper library is built, three test programs
called pcrecpp_unittest, pcre_scanner_unittest, and pcre_stringpiece_unittest
are also built. When JIT support is enabled, another test program called
pcre_jit_test is built.
Both the scripts and all the program tests are run if you obey "make check" or
"make test". For other environments, see the instructions in
NON-AUTOTOOLS-BUILD.
The RunTest script runs the pcretest test program (which is documented in its
own man page) on each of the relevant testinput files in the testdata
directory, and compares the output with the contents of the corresponding
testoutput files. RunTest uses a file called testtry to hold the main output
from pcretest. Other files whose names begin with "test" are used as working
files in some tests.
Some tests are relevant only when certain build-time options were selected. For
example, the tests for UTF-8/16/32 support are run only if --enable-utf was
used. RunTest outputs a comment when it skips a test.
Many of the tests that are not skipped are run up to three times. The second
run forces pcre_study() to be called for all patterns except for a few in some
tests that are marked "never study" (see the pcretest program for how this is
done). If JIT support is available, the non-DFA tests are run a third time,
this time with a forced pcre_study() with the PCRE_STUDY_JIT_COMPILE option.
This testing can be suppressed by putting "nojit" on the RunTest command line.
The entire set of tests is run once for each of the 8-bit, 16-bit and 32-bit
libraries that are enabled. If you want to run just one set of tests, call
RunTest with either the -8, -16 or -32 option.
If valgrind is installed, you can run the tests under it by putting "valgrind"
on the RunTest command line. To run pcretest on just one or more specific test
files, give their numbers as arguments to RunTest, for example:
RunTest 2 7 11
You can also specify ranges of tests such as 3-6 or 3- (meaning 3 to the
end), or a number preceded by ~ to exclude a test. For example:
Runtest 3-15 ~10
This runs tests 3 to 15, excluding test 10, and just ~13 runs all the tests
except test 13. Whatever order the arguments are in, the tests are always run
in numerical order.
You can also call RunTest with the single argument "list" to cause it to output
a list of tests.
The first test file can be fed directly into the perltest.pl script to check
that Perl gives the same results. The only difference you should see is in the
first few lines, where the Perl version is given instead of the PCRE version.
The second set of tests check pcre_fullinfo(), pcre_study(),
pcre_copy_substring(), pcre_get_substring(), pcre_get_substring_list(), error
detection, and run-time flags that are specific to PCRE, as well as the POSIX
wrapper API. It also uses the debugging flags to check some of the internals of
pcre_compile().
If you build PCRE with a locale setting that is not the standard C locale, the
character tables may be different (see next paragraph). In some cases, this may
cause failures in the second set of tests. For example, in a locale where the
isprint() function yields TRUE for characters in the range 128-255, the use of
[:isascii:] inside a character class defines a different set of characters, and
this shows up in this test as a difference in the compiled code, which is being
listed for checking. Where the comparison test output contains [\x00-\x7f] the
test will contain [\x00-\xff], and similarly in some other cases. This is not a
bug in PCRE.
The third set of tests checks pcre_maketables(), the facility for building a
set of character tables for a specific locale and using them instead of the
default tables. The tests make use of the "fr_FR" (French) locale. Before
running the test, the script checks for the presence of this locale by running
the "locale" command. If that command fails, or if it doesn't include "fr_FR"
in the list of available locales, the third test cannot be run, and a comment
is output to say why. If running this test produces instances of the error
** Failed to set locale "fr_FR"
in the comparison output, it means that locale is not available on your system,
despite being listed by "locale". This does not mean that PCRE is broken.
[If you are trying to run this test on Windows, you may be able to get it to
work by changing "fr_FR" to "french" everywhere it occurs. Alternatively, use
RunTest.bat. The version of RunTest.bat included with PCRE 7.4 and above uses
Windows versions of test 2. More info on using RunTest.bat is included in the
document entitled NON-UNIX-USE.]
The fourth and fifth tests check the UTF-8/16/32 support and error handling and
internal UTF features of PCRE that are not relevant to Perl, respectively. The
sixth and seventh tests do the same for Unicode character properties support.
The eighth, ninth, and tenth tests check the pcre_dfa_exec() alternative
matching function, in non-UTF-8/16/32 mode, UTF-8/16/32 mode, and UTF-8/16/32
mode with Unicode property support, respectively.
The eleventh test checks some internal offsets and code size features; it is
run only when the default "link size" of 2 is set (in other cases the sizes
change) and when Unicode property support is enabled.
The twelfth test is run only when JIT support is available, and the thirteenth
test is run only when JIT support is not available. They test some JIT-specific
features such as information output from pcretest about JIT compilation.
The fourteenth, fifteenth, and sixteenth tests are run only in 8-bit mode, and
the seventeenth, eighteenth, and nineteenth tests are run only in 16/32-bit
mode. These are tests that generate different output in the two modes. They are
for general cases, UTF-8/16/32 support, and Unicode property support,
respectively.
The twentieth test is run only in 16/32-bit mode. It tests some specific
16/32-bit features of the DFA matching engine.
The twenty-first and twenty-second tests are run only in 16/32-bit mode, when
the link size is set to 2 for the 16-bit library. They test reloading
pre-compiled patterns.
The twenty-third and twenty-fourth tests are run only in 16-bit mode. They are
for general cases, and UTF-16 support, respectively.
The twenty-fifth and twenty-sixth tests are run only in 32-bit mode. They are
for general cases, and UTF-32 support, respectively.
Character tables
----------------
For speed, PCRE uses four tables for manipulating and identifying characters
whose code point values are less than 256. The final argument of the
pcre_compile() function is a pointer to a block of memory containing the
concatenated tables. A call to pcre_maketables() can be used to generate a set
of tables in the current locale. If the final argument for pcre_compile() is
passed as NULL, a set of default tables that is built into the binary is used.
The source file called pcre_chartables.c contains the default set of tables. By
default, this is created as a copy of pcre_chartables.c.dist, which contains
tables for ASCII coding. However, if --enable-rebuild-chartables is specified
for ./configure, a different version of pcre_chartables.c is built by the
program dftables (compiled from dftables.c), which uses the ANSI C character
handling functions such as isalnum(), isalpha(), isupper(), islower(), etc. to
build the table sources. This means that the default C locale which is set for
your system will control the contents of these default tables. You can change
the default tables by editing pcre_chartables.c and then re-building PCRE. If
you do this, you should take care to ensure that the file does not get
automatically re-generated. The best way to do this is to move
pcre_chartables.c.dist out of the way and replace it with your customized
tables.
When the dftables program is run as a result of --enable-rebuild-chartables,
it uses the default C locale that is set on your system. It does not pay
attention to the LC_xxx environment variables. In other words, it uses the
system's default locale rather than whatever the compiling user happens to have
set. If you really do want to build a source set of character tables in a
locale that is specified by the LC_xxx variables, you can run the dftables
program by hand with the -L option. For example:
./dftables -L pcre_chartables.c.special
The first two 256-byte tables provide lower casing and case flipping functions,
respectively. The next table consists of three 32-byte bit maps which identify
digits, "word" characters, and white space, respectively. These are used when
building 32-byte bit maps that represent character classes for code points less
than 256.
The final 256-byte table has bits indicating various character types, as
follows:
1 white space character
2 letter
4 decimal digit
8 hexadecimal digit
16 alphanumeric or '_'
128 regular expression metacharacter or binary zero
You should not alter the set of characters that contain the 128 bit, as that
will cause PCRE to malfunction.
File manifest
-------------
The distribution should contain the files listed below. Where a file name is
given as pcre[16|32]_xxx it means that there are three files, one with the name
pcre_xxx, one with the name pcre16_xx, and a third with the name pcre32_xxx.
(A) Source files of the PCRE library functions and their headers:
dftables.c auxiliary program for building pcre_chartables.c
when --enable-rebuild-chartables is specified
pcre_chartables.c.dist a default set of character tables that assume ASCII
coding; used, unless --enable-rebuild-chartables is
specified, by copying to pcre[16]_chartables.c
pcreposix.c )
pcre[16|32]_byte_order.c )
pcre[16|32]_compile.c )
pcre[16|32]_config.c )
pcre[16|32]_dfa_exec.c )
pcre[16|32]_exec.c )
pcre[16|32]_fullinfo.c )
pcre[16|32]_get.c ) sources for the functions in the library,
pcre[16|32]_globals.c ) and some internal functions that they use
pcre[16|32]_jit_compile.c )
pcre[16|32]_maketables.c )
pcre[16|32]_newline.c )
pcre[16|32]_refcount.c )
pcre[16|32]_string_utils.c )
pcre[16|32]_study.c )
pcre[16|32]_tables.c )
pcre[16|32]_ucd.c )
pcre[16|32]_version.c )
pcre[16|32]_xclass.c )
pcre_ord2utf8.c )
pcre_valid_utf8.c )
pcre16_ord2utf16.c )
pcre16_utf16_utils.c )
pcre16_valid_utf16.c )
pcre32_utf32_utils.c )
pcre32_valid_utf32.c )
pcre[16|32]_printint.c ) debugging function that is used by pcretest,
) and can also be #included in pcre_compile()
pcre.h.in template for pcre.h when built by "configure"
pcreposix.h header for the external POSIX wrapper API
pcre_internal.h header for internal use
sljit/* 16 files that make up the JIT compiler
ucp.h header for Unicode property handling
config.h.in template for config.h, which is built by "configure"
pcrecpp.h public header file for the C++ wrapper
pcrecpparg.h.in template for another C++ header file
pcre_scanner.h public header file for C++ scanner functions
pcrecpp.cc )
pcre_scanner.cc ) source for the C++ wrapper library
pcre_stringpiece.h.in template for pcre_stringpiece.h, the header for the
C++ stringpiece functions
pcre_stringpiece.cc source for the C++ stringpiece functions
(B) Source files for programs that use PCRE:
pcredemo.c simple demonstration of coding calls to PCRE
pcregrep.c source of a grep utility that uses PCRE
pcretest.c comprehensive test program
(C) Auxiliary files:
132html script to turn "man" pages into HTML
AUTHORS information about the author of PCRE
ChangeLog log of changes to the code
CleanTxt script to clean nroff output for txt man pages
Detrail script to remove trailing spaces
HACKING some notes about the internals of PCRE
INSTALL generic installation instructions
LICENCE conditions for the use of PCRE
COPYING the same, using GNU's standard name
Makefile.in ) template for Unix Makefile, which is built by
) "configure"
Makefile.am ) the automake input that was used to create
) Makefile.in
NEWS important changes in this release
NON-UNIX-USE the previous name for NON-AUTOTOOLS-BUILD
NON-AUTOTOOLS-BUILD notes on building PCRE without using autotools
PrepareRelease script to make preparations for "make dist"
README this file
RunTest a Unix shell script for running tests
RunGrepTest a Unix shell script for pcregrep tests
aclocal.m4 m4 macros (generated by "aclocal")
config.guess ) files used by libtool,
config.sub ) used only when building a shared library
configure a configuring shell script (built by autoconf)
configure.ac ) the autoconf input that was used to build
) "configure" and config.h
depcomp ) script to find program dependencies, generated by
) automake
doc/*.3 man page sources for PCRE
doc/*.1 man page sources for pcregrep and pcretest
doc/index.html.src the base HTML page
doc/html/* HTML documentation
doc/pcre.txt plain text version of the man pages
doc/pcretest.txt plain text documentation of test program
doc/perltest.txt plain text documentation of Perl test program
install-sh a shell script for installing files
libpcre16.pc.in template for libpcre16.pc for pkg-config
libpcre32.pc.in template for libpcre32.pc for pkg-config
libpcre.pc.in template for libpcre.pc for pkg-config
libpcreposix.pc.in template for libpcreposix.pc for pkg-config
libpcrecpp.pc.in template for libpcrecpp.pc for pkg-config
ltmain.sh file used to build a libtool script
missing ) common stub for a few missing GNU programs while
) installing, generated by automake
mkinstalldirs script for making install directories
perltest.pl Perl test program
pcre-config.in source of script which retains PCRE information
pcre_jit_test.c test program for the JIT compiler
pcrecpp_unittest.cc )
pcre_scanner_unittest.cc ) test programs for the C++ wrapper
pcre_stringpiece_unittest.cc )
testdata/testinput* test data for main library tests
testdata/testoutput* expected test results
testdata/grep* input and output for pcregrep tests
testdata/* other supporting test files
(D) Auxiliary files for cmake support
cmake/COPYING-CMAKE-SCRIPTS
cmake/FindPackageHandleStandardArgs.cmake
cmake/FindEditline.cmake
cmake/FindReadline.cmake
CMakeLists.txt
config-cmake.h.in
(E) Auxiliary files for VPASCAL
makevp.bat
makevp_c.txt
makevp_l.txt
pcregexp.pas
(F) Auxiliary files for building PCRE "by hand"
pcre.h.generic ) a version of the public PCRE header file
) for use in non-"configure" environments
config.h.generic ) a version of config.h for use in non-"configure"
) environments
(F) Miscellaneous
RunTest.bat a script for running tests under Windows
Philip Hazel
Email local part: ph10
Email domain: cam.ac.uk
Last updated: 10 February 2015
PK � %[�m^�q q doc/alt-pcre/NEWSnu �[��� News about PCRE releases
------------------------
Release 8.41 13-June-2017
-------------------------
This is a bug-fix release.
Release 8.40 11-January-2017
----------------------------
This is a bug-fix release.
Release 8.39 14-June-2016
-------------------------
Some appropriate PCRE2 JIT improvements have been retro-fitted to PCRE1. Apart
from that, this is another bug-fix release. Note that this library (now called
PCRE1) is now being maintained for bug fixes only. New projects are advised to
use the new PCRE2 libraries.
Release 8.38 23-November-2015
-----------------------------
This is bug-fix release. Note that this library (now called PCRE1) is now being
maintained for bug fixes only. New projects are advised to use the new PCRE2
libraries.
Release 8.37 28-April-2015
--------------------------
This is bug-fix release. Note that this library (now called PCRE1) is now being
maintained for bug fixes only. New projects are advised to use the new PCRE2
libraries.
Release 8.36 26-September-2014
------------------------------
This is primarily a bug-fix release. However, in addition, the Unicode data
tables have been updated to Unicode 7.0.0.
Release 8.35 04-April-2014
--------------------------
There have been performance improvements for classes containing non-ASCII
characters and the "auto-possessification" feature has been extended. Other
minor improvements have been implemented and bugs fixed. There is a new callout
feature to enable applications to do detailed stack checks at compile time, to
avoid running out of stack for deeply nested parentheses. The JIT compiler has
been extended with experimental support for ARM-64, MIPS-64, and PPC-LE.
Release 8.34 15-December-2013
-----------------------------
As well as fixing the inevitable bugs, performance has been improved by
refactoring and extending the amount of "auto-possessification" that PCRE does.
Other notable changes:
. Implemented PCRE_INFO_MATCH_EMPTY, which yields 1 if the pattern can match
an empty string. If it can, pcretest shows this in its information output.
. A back reference to a named subpattern when there is more than one of the
same name now checks them in the order in which they appear in the pattern.
The first one that is set is used for the reference. Previously only the
first one was inspected. This change makes PCRE more compatible with Perl.
. Unicode character properties were updated from Unicode 6.3.0.
. The character VT has been added to the set of characters that match \s and
are generally treated as white space, following this same change in Perl
5.18. There is now no difference between "Perl space" and "POSIX space".
. Perl has changed its handling of \8 and \9. If there is no previously
encountered capturing group of those numbers, they are treated as the
literal characters 8 and 9 instead of a binary zero followed by the
literals. PCRE now does the same.
. Following Perl, added \o{} to specify codepoints in octal, making it
possible to specify values greater than 0777 and also making them
unambiguous.
. In UCP mode, \s was not matching two of the characters that Perl matches,
namely NEL (U+0085) and MONGOLIAN VOWEL SEPARATOR (U+180E), though they
were matched by \h.
. Add JIT support for the 64 bit TileGX architecture.
. Upgraded the handling of the POSIX classes [:graph:], [:print:], and
[:punct:] when PCRE_UCP is set so as to include the same characters as Perl
does in Unicode mode.
. Perl no longer allows group names to start with digits, so I have made this
change also in PCRE.
. Added support for [[:<:]] and [[:>:]] as used in the BSD POSIX library to
mean "start of word" and "end of word", respectively, as a transition aid.
Release 8.33 28-May-2013
--------------------------
A number of bugs are fixed, and some performance improvements have been made.
There are also some new features, of which these are the most important:
. The behaviour of the backtracking verbs has been rationalized and
documented in more detail.
. JIT now supports callouts and all of the backtracking verbs.
. Unicode validation has been updated in the light of Unicode Corrigendum #9,
which points out that "non characters" are not "characters that may not
appear in Unicode strings" but rather "characters that are reserved for
internal use and have only local meaning".
. (*LIMIT_MATCH=d) and (*LIMIT_RECURSION=d) have been added so that the
creator of a pattern can specify lower (but not higher) limits for the
matching process.
. The PCRE_NEVER_UTF option is available to prevent pattern-writers from using
the (*UTF) feature, as this could be a security issue.
Release 8.32 30-November-2012
-----------------------------
This release fixes a number of bugs, but also has some new features. These are
the highlights:
. There is now support for 32-bit character strings and UTF-32. Like the
16-bit support, this is done by compiling a separate 32-bit library.
. \X now matches a Unicode extended grapheme cluster.
. Case-independent matching of Unicode characters that have more than one
"other case" now makes all three (or more) characters equivalent. This
applies, for example, to Greek Sigma, which has two lowercase versions.
. Unicode character properties are updated to Unicode 6.2.0.
. The EBCDIC support, which had decayed, has had a spring clean.
. A number of JIT optimizations have been added, which give faster JIT
execution speed. In addition, a new direct interface to JIT execution is
available. This bypasses some of the sanity checks of pcre_exec() to give a
noticeable speed-up.
. A number of issues in pcregrep have been fixed, making it more compatible
with GNU grep. In particular, --exclude and --include (and variants) apply
to all files now, not just those obtained from scanning a directory
recursively. In Windows environments, the default action for directories is
now "skip" instead of "read" (which provokes an error).
. If the --only-matching (-o) option in pcregrep is specified multiple
times, each one causes appropriate output. For example, -o1 -o2 outputs the
substrings matched by the 1st and 2nd capturing parentheses. A separating
string can be specified by --om-separator (default empty).
. When PCRE is built via Autotools using a version of gcc that has the
"visibility" feature, it is used to hide internal library functions that are
not part of the public API.
Release 8.31 06-July-2012
-------------------------
This is mainly a bug-fixing release, with a small number of developments:
. The JIT compiler now supports partial matching and the (*MARK) and
(*COMMIT) verbs.
. PCRE_INFO_MAXLOOKBEHIND can be used to find the longest lookbehind in a
pattern.
. There should be a performance improvement when using the heap instead of the
stack for recursion.
. pcregrep can now be linked with libedit as an alternative to libreadline.
. pcregrep now has a --file-list option where the list of files to scan is
given as a file.
. pcregrep now recognizes binary files and there are related options.
. The Unicode tables have been updated to 6.1.0.
As always, the full list of changes is in the ChangeLog file.
Release 8.30 04-February-2012
-----------------------------
Release 8.30 introduces a major new feature: support for 16-bit character
strings, compiled as a separate library. There are a few changes to the
8-bit library, in addition to some bug fixes.
. The pcre_info() function, which has been obsolete for over 10 years, has
been removed.
. When a compiled pattern was saved to a file and later reloaded on a host
with different endianness, PCRE used automatically to swap the bytes in some
of the data fields. With the advent of the 16-bit library, where more of this
swapping is needed, it is no longer done automatically. Instead, the bad
endianness is detected and a specific error is given. The user can then call
a new function called pcre_pattern_to_host_byte_order() (or an equivalent
16-bit function) to do the swap.
. In UTF-8 mode, the values 0xd800 to 0xdfff are not legal Unicode
code points and are now faulted. (They are the so-called "surrogates"
that are reserved for coding high values in UTF-16.)
Release 8.21 12-Dec-2011
------------------------
This is almost entirely a bug-fix release. The only new feature is the ability
to obtain the size of the memory used by the JIT compiler.
Release 8.20 21-Oct-2011
------------------------
The main change in this release is the inclusion of Zoltan Herczeg's
just-in-time compiler support, which can be accessed by building PCRE with
--enable-jit. Large performance benefits can be had in many situations. 8.20
also fixes an unfortunate bug that was introduced in 8.13 as well as tidying up
a number of infelicities and differences from Perl.
Release 8.13 16-Aug-2011
------------------------
This is mainly a bug-fix release. There has been a lot of internal refactoring.
The Unicode tables have been updated. The only new feature in the library is
the passing of *MARK information to callouts. Some additions have been made to
pcretest to make testing easier and more comprehensive. There is a new option
for pcregrep to adjust its internal buffer size.
Release 8.12 15-Jan-2011
------------------------
This release fixes some bugs in pcregrep, one of which caused the tests to fail
on 64-bit big-endian systems. There are no changes to the code of the library.
Release 8.11 10-Dec-2010
------------------------
A number of bugs in the library and in pcregrep have been fixed. As always, see
ChangeLog for details. The following are the non-bug-fix changes:
. Added --match-limit and --recursion-limit to pcregrep.
. Added an optional parentheses number to the -o and --only-matching options
of pcregrep.
. Changed the way PCRE_PARTIAL_HARD affects the matching of $, \z, \Z, \b, and
\B.
. Added PCRE_ERROR_SHORTUTF8 to make it possible to distinguish between a
bad UTF-8 sequence and one that is incomplete when using PCRE_PARTIAL_HARD.
. Recognize (*NO_START_OPT) at the start of a pattern to set the PCRE_NO_
START_OPTIMIZE option, which is now allowed at compile time
Release 8.10 25-Jun-2010
------------------------
There are two major additions: support for (*MARK) and friends, and the option
PCRE_UCP, which changes the behaviour of \b, \d, \s, and \w (and their
opposites) so that they make use of Unicode properties. There are also a number
of lesser new features, and several bugs have been fixed. A new option,
--line-buffered, has been added to pcregrep, for use when it is connected to
pipes.
Release 8.02 19-Mar-2010
------------------------
Another bug-fix release.
Release 8.01 19-Jan-2010
------------------------
This is a bug-fix release. Several bugs in the code itself and some bugs and
infelicities in the build system have been fixed.
Release 8.00 19-Oct-09
----------------------
Bugs have been fixed in the library and in pcregrep. There are also some
enhancements. Restrictions on patterns used for partial matching have been
removed, extra information is given for partial matches, the partial matching
process has been improved, and an option to make a partial match override a
full match is available. The "study" process has been enhanced by finding a
lower bound matching length. Groups with duplicate numbers may now have
duplicated names without the use of PCRE_DUPNAMES. However, they may not have
different names. The documentation has been revised to reflect these changes.
The version number has been expanded to 3 digits as it is clear that the rate
of change is not slowing down.
Release 7.9 11-Apr-09
---------------------
Mostly bugfixes and tidies with just a couple of minor functional additions.
Release 7.8 05-Sep-08
---------------------
More bug fixes, plus a performance improvement in Unicode character property
lookup.
Release 7.7 07-May-08
---------------------
This is once again mainly a bug-fix release, but there are a couple of new
features.
Release 7.6 28-Jan-08
---------------------
The main reason for having this release so soon after 7.5 is because it fixes a
potential buffer overflow problem in pcre_compile() when run in UTF-8 mode. In
addition, the CMake configuration files have been brought up to date.
Release 7.5 10-Jan-08
---------------------
This is mainly a bug-fix release. However the ability to link pcregrep with
libz or libbz2 and the ability to link pcretest with libreadline have been
added. Also the --line-offsets and --file-offsets options were added to
pcregrep.
Release 7.4 21-Sep-07
---------------------
The only change of specification is the addition of options to control whether
\R matches any Unicode line ending (the default) or just CR, LF, and CRLF.
Otherwise, the changes are bug fixes and a refactoring to reduce the number of
relocations needed in a shared library. There have also been some documentation
updates, in particular, some more information about using CMake to build PCRE
has been added to the NON-UNIX-USE file.
Release 7.3 28-Aug-07
---------------------
Most changes are bug fixes. Some that are not:
1. There is some support for Perl 5.10's experimental "backtracking control
verbs" such as (*PRUNE).
2. UTF-8 checking is now as per RFC 3629 instead of RFC 2279; this is more
restrictive in the strings it accepts.
3. Checking for potential integer overflow has been made more dynamic, and as a
consequence there is no longer a hard limit on the size of a subpattern that
has a limited repeat count.
4. When CRLF is a valid line-ending sequence, pcre_exec() and pcre_dfa_exec()
no longer advance by two characters instead of one when an unanchored match
fails at CRLF if there are explicit CR or LF matches within the pattern.
This gets rid of some anomalous effects that previously occurred.
5. Some PCRE-specific settings for varying the newline options at the start of
a pattern have been added.
Release 7.2 19-Jun-07
---------------------
WARNING: saved patterns that were compiled by earlier versions of PCRE must be
recompiled for use with 7.2 (necessitated by the addition of \K, \h, \H, \v,
and \V).
Correction to the notes for 7.1: the note about shared libraries for Windows is
wrong. Previously, three libraries were built, but each could function
independently. For example, the pcreposix library also included all the
functions from the basic pcre library. The change is that the three libraries
are no longer independent. They are like the Unix libraries. To use the
pcreposix functions, for example, you need to link with both the pcreposix and
the basic pcre library.
Some more features from Perl 5.10 have been added:
(?-n) and (?+n) relative references for recursion and subroutines.
(?(-n) and (?(+n) relative references as conditions.
\k{name} and \g{name} are synonyms for \k<name>.
\K to reset the start of the matched string; for example, (foo)\Kbar
matches bar preceded by foo, but only sets bar as the matched string.
(?| introduces a group where the capturing parentheses in each alternative
start from the same number; for example, (?|(abc)|(xyz)) sets capturing
parentheses number 1 in both cases.
\h, \H, \v, \V match horizontal and vertical whitespace, respectively.
Release 7.1 24-Apr-07
---------------------
There is only one new feature in this release: a linebreak setting of
PCRE_NEWLINE_ANYCRLF. It is a cut-down version of PCRE_NEWLINE_ANY, which
recognizes only CRLF, CR, and LF as linebreaks.
A few bugs are fixed (see ChangeLog for details), but the major change is a
complete re-implementation of the build system. This now has full Autotools
support and so is now "standard" in some sense. It should help with compiling
PCRE in a wide variety of environments.
NOTE: when building shared libraries for Windows, three dlls are now built,
called libpcre, libpcreposix, and libpcrecpp. Previously, everything was
included in a single dll.
Another important change is that the dftables auxiliary program is no longer
compiled and run at "make" time by default. Instead, a default set of character
tables (assuming ASCII coding) is used. If you want to use dftables to generate
the character tables as previously, add --enable-rebuild-chartables to the
"configure" command. You must do this if you are compiling PCRE to run on a
system that uses EBCDIC code.
There is a discussion about character tables in the README file. The default is
not to use dftables so that that there is no problem when cross-compiling.
Release 7.0 19-Dec-06
---------------------
This release has a new major number because there have been some internal
upheavals to facilitate the addition of new optimizations and other facilities,
and to make subsequent maintenance and extension easier. Compilation is likely
to be a bit slower, but there should be no major effect on runtime performance.
Previously compiled patterns are NOT upwards compatible with this release. If
you have saved compiled patterns from a previous release, you will have to
re-compile them. Important changes that are visible to users are:
1. The Unicode property tables have been updated to Unicode 5.0.0, which adds
some more scripts.
2. The option PCRE_NEWLINE_ANY causes PCRE to recognize any Unicode newline
sequence as a newline.
3. The \R escape matches a single Unicode newline sequence as a single unit.
4. New features that will appear in Perl 5.10 are now in PCRE. These include
alternative Perl syntax for named parentheses, and Perl syntax for
recursion.
5. The C++ wrapper interface has been extended by the addition of a
QuoteMeta function and the ability to allow copy construction and
assignment.
For a complete list of changes, see the ChangeLog file.
Release 6.7 04-Jul-06
---------------------
The main additions to this release are the ability to use the same name for
multiple sets of parentheses, and support for CRLF line endings in both the
library and pcregrep (and in pcretest for testing).
Thanks to Ian Taylor, the stack usage for many kinds of pattern has been
significantly reduced for certain subject strings.
Release 6.5 01-Feb-06
---------------------
Important changes in this release:
1. A number of new features have been added to pcregrep.
2. The Unicode property tables have been updated to Unicode 4.1.0, and the
supported properties have been extended with script names such as "Arabic",
and the derived properties "Any" and "L&". This has necessitated a change to
the interal format of compiled patterns. Any saved compiled patterns that
use \p or \P must be recompiled.
3. The specification of recursion in patterns has been changed so that all
recursive subpatterns are automatically treated as atomic groups. Thus, for
example, (?R) is treated as if it were (?>(?R)). This is necessary because
otherwise there are situations where recursion does not work.
See the ChangeLog for a complete list of changes, which include a number of bug
fixes and tidies.
Release 6.0 07-Jun-05
---------------------
The release number has been increased to 6.0 because of the addition of several
major new pieces of functionality.
A new function, pcre_dfa_exec(), which implements pattern matching using a DFA
algorithm, has been added. This has a number of advantages for certain cases,
though it does run more slowly, and lacks the ability to capture substrings. On
the other hand, it does find all matches, not just the first, and it works
better for partial matching. The pcrematching man page discusses the
differences.
The pcretest program has been enhanced so that it can make use of the new
pcre_dfa_exec() matching function and the extra features it provides.
The distribution now includes a C++ wrapper library. This is built
automatically if a C++ compiler is found. The pcrecpp man page discusses this
interface.
The code itself has been re-organized into many more files, one for each
function, so it no longer requires everything to be linked in when static
linkage is used. As a consequence, some internal functions have had to have
their names exposed. These functions all have names starting with _pcre_. They
are undocumented, and are not intended for use by outside callers.
The pcregrep program has been enhanced with new functionality such as
multiline-matching and options for output more matching context. See the
ChangeLog for a complete list of changes to the library and the utility
programs.
Release 5.0 13-Sep-04
---------------------
The licence under which PCRE is released has been changed to the more
conventional "BSD" licence.
In the code, some bugs have been fixed, and there are also some major changes
in this release (which is why I've increased the number to 5.0). Some changes
are internal rearrangements, and some provide a number of new facilities. The
new features are:
1. There's an "automatic callout" feature that inserts callouts before every
item in the regex, and there's a new callout field that gives the position
in the pattern - useful for debugging and tracing.
2. The extra_data structure can now be used to pass in a set of character
tables at exec time. This is useful if compiled regex are saved and re-used
at a later time when the tables may not be at the same address. If the
default internal tables are used, the pointer saved with the compiled
pattern is now set to NULL, which means that you don't need to do anything
special unless you are using custom tables.
3. It is possible, with some restrictions on the content of the regex, to
request "partial" matching. A special return code is given if all of the
subject string matched part of the regex. This could be useful for testing
an input field as it is being typed.
4. There is now some optional support for Unicode character properties, which
means that the patterns items such as \p{Lu} and \X can now be used. Only
the general category properties are supported. If PCRE is compiled with this
support, an additional 90K data structure is include, which increases the
size of the library dramatically.
5. There is support for saving compiled patterns and re-using them later.
6. There is support for running regular expressions that were compiled on a
different host with the opposite endianness.
7. The pcretest program has been extended to accommodate the new features.
The main internal rearrangement is that sequences of literal characters are no
longer handled as strings. Instead, each character is handled on its own. This
makes some UTF-8 handling easier, and makes the support of partial matching
possible. Compiled patterns containing long literal strings will be larger as a
result of this change; I hope that performance will not be much affected.
Release 4.5 01-Dec-03
---------------------
Again mainly a bug-fix and tidying release, with only a couple of new features:
1. It's possible now to compile PCRE so that it does not use recursive
function calls when matching. Instead it gets memory from the heap. This slows
things down, but may be necessary on systems with limited stacks.
2. UTF-8 string checking has been tightened to reject overlong sequences and to
check that a starting offset points to the start of a character. Failure of the
latter returns a new error code: PCRE_ERROR_BADUTF8_OFFSET.
3. PCRE can now be compiled for systems that use EBCDIC code.
Release 4.4 21-Aug-03
---------------------
This is mainly a bug-fix and tidying release. The only new feature is that PCRE
checks UTF-8 strings for validity by default. There is an option to suppress
this, just in case anybody wants that teeny extra bit of performance.
Releases 4.1 - 4.3
------------------
Sorry, I forgot about updating the NEWS file for these releases. Please take a
look at ChangeLog.
Release 4.0 17-Feb-03
---------------------
There have been a lot of changes for the 4.0 release, adding additional
functionality and mending bugs. Below is a list of the highlights of the new
functionality. For full details of these features, please consult the
documentation. For a complete list of changes, see the ChangeLog file.
1. Support for Perl's \Q...\E escapes.
2. "Possessive quantifiers" ?+, *+, ++, and {,}+ which come from Sun's Java
package. They provide some syntactic sugar for simple cases of "atomic
grouping".
3. Support for the \G assertion. It is true when the current matching position
is at the start point of the match.
4. A new feature that provides some of the functionality that Perl provides
with (?{...}). The facility is termed a "callout". The way it is done in PCRE
is for the caller to provide an optional function, by setting pcre_callout to
its entry point. To get the function called, the regex must include (?C) at
appropriate points.
5. Support for recursive calls to individual subpatterns. This makes it really
easy to get totally confused.
6. Support for named subpatterns. The Python syntax (?P<name>...) is used to
name a group.
7. Several extensions to UTF-8 support; it is now fairly complete. There is an
option for pcregrep to make it operate in UTF-8 mode.
8. The single man page has been split into a number of separate man pages.
These also give rise to individual HTML pages which are put in a separate
directory. There is an index.html page that lists them all. Some hyperlinking
between the pages has been installed.
Release 3.5 15-Aug-01
---------------------
1. The configuring system has been upgraded to use later versions of autoconf
and libtool. By default it builds both a shared and a static library if the OS
supports it. You can use --disable-shared or --disable-static on the configure
command if you want only one of them.
2. The pcretest utility is now installed along with pcregrep because it is
useful for users (to test regexs) and by doing this, it automatically gets
relinked by libtool. The documentation has been turned into a man page, so
there are now .1, .txt, and .html versions in /doc.
3. Upgrades to pcregrep:
(i) Added long-form option names like gnu grep.
(ii) Added --help to list all options with an explanatory phrase.
(iii) Added -r, --recursive to recurse into sub-directories.
(iv) Added -f, --file to read patterns from a file.
4. Added --enable-newline-is-cr and --enable-newline-is-lf to the configure
script, to force use of CR or LF instead of \n in the source. On non-Unix
systems, the value can be set in config.h.
5. The limit of 200 on non-capturing parentheses is a _nesting_ limit, not an
absolute limit. Changed the text of the error message to make this clear, and
likewise updated the man page.
6. The limit of 99 on the number of capturing subpatterns has been removed.
The new limit is 65535, which I hope will not be a "real" limit.
Release 3.3 01-Aug-00
---------------------
There is some support for UTF-8 character strings. This is incomplete and
experimental. The documentation describes what is and what is not implemented.
Otherwise, this is just a bug-fixing release.
Release 3.0 01-Feb-00
---------------------
1. A "configure" script is now used to configure PCRE for Unix systems. It
builds a Makefile, a config.h file, and the pcre-config script.
2. PCRE is built as a shared library by default.
3. There is support for POSIX classes such as [:alpha:].
5. There is an experimental recursion feature.
----------------------------------------------------------------------------
IMPORTANT FOR THOSE UPGRADING FROM VERSIONS BEFORE 2.00
Please note that there has been a change in the API such that a larger
ovector is required at matching time, to provide some additional workspace.
The new man page has details. This change was necessary in order to support
some of the new functionality in Perl 5.005.
IMPORTANT FOR THOSE UPGRADING FROM VERSION 2.00
Another (I hope this is the last!) change has been made to the API for the
pcre_compile() function. An additional argument has been added to make it
possible to pass over a pointer to character tables built in the current
locale by pcre_maketables(). To use the default tables, this new argument
should be passed as NULL.
IMPORTANT FOR THOSE UPGRADING FROM VERSION 2.05
Yet another (and again I hope this really is the last) change has been made
to the API for the pcre_exec() function. An additional argument has been
added to make it possible to start the match other than at the start of the
subject string. This is important if there are lookbehinds. The new man
page has the details, but you just want to convert existing programs, all
you need to do is to stick in a new fifth argument to pcre_exec(), with a
value of zero. For example, change
pcre_exec(pattern, extra, subject, length, options, ovec, ovecsize)
to
pcre_exec(pattern, extra, subject, length, 0, options, ovec, ovecsize)
****
PK � %[�*��z �z doc/alt-pcre/ChangeLognu �[��� ChangeLog for PCRE
------------------
Note that the PCRE 8.xx series (PCRE1) is now in a bugfix-only state. All
development is happening in the PCRE2 10.xx series.
Version 8.41 05-July-2017
-------------------------
1. Fixed typo in CMakeLists.txt (wrong number of arguments for
PCRE_STATIC_RUNTIME (affects MSVC only).
2. Issue 1 for 8.40 below was not correctly fixed. If pcregrep in multiline
mode with --only-matching matched several lines, it restarted scanning at the
next line instead of moving on to the end of the matched string, which can be
several lines after the start.
3. Fix a missing else in the JIT compiler reported by 'idaifish'.
4. A (?# style comment is now ignored between a basic quantifier and a
following '+' or '?' (example: /X+(?#comment)?Y/.
5. Avoid use of a potentially overflowing buffer in pcregrep (patch by Petr
Pisar).
6. Fuzzers have reported issues in pcretest. These are NOT serious (it is,
after all, just a test program). However, to stop the reports, some easy ones
are fixed:
(a) Check for values < 256 when calling isprint() in pcretest.
(b) Give an error for too big a number after \O.
7. In the 32-bit library in non-UTF mode, an attempt to find a Unicode
property for a character with a code point greater than 0x10ffff (the Unicode
maximum) caused a crash.
8. The alternative matching function, pcre_dfa_exec() misbehaved if it
encountered a character class with a possessive repeat, for example [a-f]{3}+.
9. When pcretest called pcre_copy_substring() in 32-bit mode, it set the buffer
length incorrectly, which could result in buffer overflow.
10. Remove redundant line of code (accidentally left in ages ago).
11. Applied C++ patch from Irfan Adilovic to guard 'using std::' directives
with namespace pcrecpp (Bugzilla #2084).
12. Remove a duplication typo in pcre_tables.c.
13. Fix returned offsets from regexec() when REG_STARTEND is used with a
starting offset greater than zero.
Version 8.40 11-January-2017
----------------------------
1. Using -o with -M in pcregrep could cause unnecessary repeated output when
the match extended over a line boundary.
2. Applied Chris Wilson's second patch (Bugzilla #1681) to CMakeLists.txt for
MSVC static compilation, putting the first patch under a new option.
3. Fix register overwite in JIT when SSE2 acceleration is enabled.
4. Ignore "show all captures" (/=) for DFA matching.
5. Fix JIT unaligned accesses on x86. Patch by Marc Mutz.
6. In any wide-character mode (8-bit UTF or any 16-bit or 32-bit mode),
without PCRE_UCP set, a negative character type such as \D in a positive
class should cause all characters greater than 255 to match, whatever else
is in the class. There was a bug that caused this not to happen if a
Unicode property item was added to such a class, for example [\D\P{Nd}] or
[\W\pL].
7. When pcretest was outputing information from a callout, the caret indicator
for the current position in the subject line was incorrect if it was after
an escape sequence for a character whose code point was greater than
\x{ff}.
8. A pattern such as (?<RA>abc)(?(R)xyz) was incorrectly compiled such that
the conditional was interpreted as a reference to capturing group 1 instead
of a test for recursion. Any group whose name began with R was
misinterpreted in this way. (The reference interpretation should only
happen if the group's name is precisely "R".)
9. A number of bugs have been mended relating to match start-up optimizations
when the first thing in a pattern is a positive lookahead. These all
applied only when PCRE_NO_START_OPTIMIZE was *not* set:
(a) A pattern such as (?=.*X)X$ was incorrectly optimized as if it needed
both an initial 'X' and a following 'X'.
(b) Some patterns starting with an assertion that started with .* were
incorrectly optimized as having to match at the start of the subject or
after a newline. There are cases where this is not true, for example,
(?=.*[A-Z])(?=.{8,16})(?!.*[\s]) matches after the start in lines that
start with spaces. Starting .* in an assertion is no longer taken as an
indication of matching at the start (or after a newline).
Version 8.39 14-June-2016
-------------------------
1. If PCRE_AUTO_CALLOUT was set on a pattern that had a (?# comment between
an item and its qualifier (for example, A(?#comment)?B) pcre_compile()
misbehaved. This bug was found by the LLVM fuzzer.
2. Similar to the above, if an isolated \E was present between an item and its
qualifier when PCRE_AUTO_CALLOUT was set, pcre_compile() misbehaved. This
bug was found by the LLVM fuzzer.
3. Further to 8.38/46, negated classes such as [^[:^ascii:]\d] were also not
working correctly in UCP mode.
4. The POSIX wrapper function regexec() crashed if the option REG_STARTEND
was set when the pmatch argument was NULL. It now returns REG_INVARG.
5. Allow for up to 32-bit numbers in the ordin() function in pcregrep.
6. An empty \Q\E sequence between an item and its qualifier caused
pcre_compile() to misbehave when auto callouts were enabled. This bug was
found by the LLVM fuzzer.
7. If a pattern that was compiled with PCRE_EXTENDED started with white
space or a #-type comment that was followed by (?-x), which turns off
PCRE_EXTENDED, and there was no subsequent (?x) to turn it on again,
pcre_compile() assumed that (?-x) applied to the whole pattern and
consequently mis-compiled it. This bug was found by the LLVM fuzzer.
8. A call of pcre_copy_named_substring() for a named substring whose number
was greater than the space in the ovector could cause a crash.
9. Yet another buffer overflow bug involved duplicate named groups with a
group that reset capture numbers (compare 8.38/7 below). Once again, I have
just allowed for more memory, even if not needed. (A proper fix is
implemented in PCRE2, but it involves a lot of refactoring.)
10. pcre_get_substring_list() crashed if the use of \K in a match caused the
start of the match to be earlier than the end.
11. Migrating appropriate PCRE2 JIT improvements to PCRE.
12. A pattern such as /(?<=((?C)0))/, which has a callout inside a lookbehind
assertion, caused pcretest to generate incorrect output, and also to read
uninitialized memory (detected by ASAN or valgrind).
13. A pattern that included (*ACCEPT) in the middle of a sufficiently deeply
nested set of parentheses of sufficient size caused an overflow of the
compiling workspace (which was diagnosed, but of course is not desirable).
14. And yet another buffer overflow bug involving duplicate named groups, this
time nested, with a nested back reference. Yet again, I have just allowed
for more memory, because anything more needs all the refactoring that has
been done for PCRE2. An example pattern that provoked this bug is:
/((?J)(?'R'(?'R'(?'R'(?'R'(?'R'(?|(\k'R'))))))))/ and the bug was
registered as CVE-2016-1283.
15. pcretest went into a loop if global matching was requested with an ovector
size less than 2. It now gives an error message. This bug was found by
afl-fuzz.
16. An invalid pattern fragment such as (?(?C)0 was not diagnosing an error
("assertion expected") when (?(?C) was not followed by an opening
parenthesis.
17. Fixed typo ("&&" for "&") in pcre_study(). Fortunately, this could not
actually affect anything, by sheer luck.
18. Applied Chris Wilson's patch (Bugzilla #1681) to CMakeLists.txt for MSVC
static compilation.
19. Modified the RunTest script to incorporate a valgrind suppressions file so
that certain errors, provoked by the SSE2 instruction set when JIT is used,
are ignored.
20. A racing condition is fixed in JIT reported by Mozilla.
21. Minor code refactor to avoid "array subscript is below array bounds"
compiler warning.
22. Minor code refactor to avoid "left shift of negative number" warning.
23. Fix typo causing compile error when 16- or 32-bit JIT is compiled without
UCP support.
24. Refactor to avoid compiler warnings in pcrecpp.cc.
25. Refactor to fix a typo in pcre_jit_test.c
26. Patch to support compiling pcrecpp.cc with Intel compiler.
Version 8.38 23-November-2015
-----------------------------
1. If a group that contained a recursive back reference also contained a
forward reference subroutine call followed by a non-forward-reference
subroutine call, for example /.((?2)(?R)\1)()/, pcre_compile() failed to
compile correct code, leading to undefined behaviour or an internally
detected error. This bug was discovered by the LLVM fuzzer.
2. Quantification of certain items (e.g. atomic back references) could cause
incorrect code to be compiled when recursive forward references were
involved. For example, in this pattern: /(?1)()((((((\1++))\x85)+)|))/.
This bug was discovered by the LLVM fuzzer.
3. A repeated conditional group whose condition was a reference by name caused
a buffer overflow if there was more than one group with the given name.
This bug was discovered by the LLVM fuzzer.
4. A recursive back reference by name within a group that had the same name as
another group caused a buffer overflow. For example:
/(?J)(?'d'(?'d'\g{d}))/. This bug was discovered by the LLVM fuzzer.
5. A forward reference by name to a group whose number is the same as the
current group, for example in this pattern: /(?|(\k'Pm')|(?'Pm'))/, caused
a buffer overflow at compile time. This bug was discovered by the LLVM
fuzzer.
6. A lookbehind assertion within a set of mutually recursive subpatterns could
provoke a buffer overflow. This bug was discovered by the LLVM fuzzer.
7. Another buffer overflow bug involved duplicate named groups with a
reference between their definition, with a group that reset capture
numbers, for example: /(?J:(?|(?'R')(\k'R')|((?'R'))))/. This has been
fixed by always allowing for more memory, even if not needed. (A proper fix
is implemented in PCRE2, but it involves more refactoring.)
8. There was no check for integer overflow in subroutine calls such as (?123).
9. The table entry for \l in EBCDIC environments was incorrect, leading to its
being treated as a literal 'l' instead of causing an error.
10. There was a buffer overflow if pcre_exec() was called with an ovector of
size 1. This bug was found by american fuzzy lop.
11. If a non-capturing group containing a conditional group that could match
an empty string was repeated, it was not identified as matching an empty
string itself. For example: /^(?:(?(1)x|)+)+$()/.
12. In an EBCDIC environment, pcretest was mishandling the escape sequences
\a and \e in test subject lines.
13. In an EBCDIC environment, \a in a pattern was converted to the ASCII
instead of the EBCDIC value.
14. The handling of \c in an EBCDIC environment has been revised so that it is
now compatible with the specification in Perl's perlebcdic page.
15. The EBCDIC character 0x41 is a non-breaking space, equivalent to 0xa0 in
ASCII/Unicode. This has now been added to the list of characters that are
recognized as white space in EBCDIC.
16. When PCRE was compiled without UCP support, the use of \p and \P gave an
error (correctly) when used outside a class, but did not give an error
within a class.
17. \h within a class was incorrectly compiled in EBCDIC environments.
18. A pattern with an unmatched closing parenthesis that contained a backward
assertion which itself contained a forward reference caused buffer
overflow. And example pattern is: /(?=di(?<=(?1))|(?=(.))))/.
19. JIT should return with error when the compiled pattern requires more stack
space than the maximum.
20. A possessively repeated conditional group that could match an empty string,
for example, /(?(R))*+/, was incorrectly compiled.
21. Fix infinite recursion in the JIT compiler when certain patterns such as
/(?:|a|){100}x/ are analysed.
22. Some patterns with character classes involving [: and \\ were incorrectly
compiled and could cause reading from uninitialized memory or an incorrect
error diagnosis.
23. Pathological patterns containing many nested occurrences of [: caused
pcre_compile() to run for a very long time.
24. A conditional group with only one branch has an implicit empty alternative
branch and must therefore be treated as potentially matching an empty
string.
25. If (?R was followed by - or + incorrect behaviour happened instead of a
diagnostic.
26. Arrange to give up on finding the minimum matching length for overly
complex patterns.
27. Similar to (4) above: in a pattern with duplicated named groups and an
occurrence of (?| it is possible for an apparently non-recursive back
reference to become recursive if a later named group with the relevant
number is encountered. This could lead to a buffer overflow. Wen Guanxing
from Venustech ADLAB discovered this bug.
28. If pcregrep was given the -q option with -c or -l, or when handling a
binary file, it incorrectly wrote output to stdout.
29. The JIT compiler did not restore the control verb head in case of *THEN
control verbs. This issue was found by Karl Skomski with a custom LLVM
fuzzer.
30. Error messages for syntax errors following \g and \k were giving inaccurate
offsets in the pattern.
31. Added a check for integer overflow in conditions (?(<digits>) and
(?(R<digits>). This omission was discovered by Karl Skomski with the LLVM
fuzzer.
32. Handling recursive references such as (?2) when the reference is to a group
later in the pattern uses code that is very hacked about and error-prone.
It has been re-written for PCRE2. Here in PCRE1, a check has been added to
give an internal error if it is obvious that compiling has gone wrong.
33. The JIT compiler should not check repeats after a {0,1} repeat byte code.
This issue was found by Karl Skomski with a custom LLVM fuzzer.
34. The JIT compiler should restore the control chain for empty possessive
repeats. This issue was found by Karl Skomski with a custom LLVM fuzzer.
35. Match limit check added to JIT recursion. This issue was found by Karl
Skomski with a custom LLVM fuzzer.
36. Yet another case similar to 27 above has been circumvented by an
unconditional allocation of extra memory. This issue is fixed "properly" in
PCRE2 by refactoring the way references are handled. Wen Guanxing
from Venustech ADLAB discovered this bug.
37. Fix two assertion fails in JIT. These issues were found by Karl Skomski
with a custom LLVM fuzzer.
38. Fixed a corner case of range optimization in JIT.
39. An incorrect error "overran compiling workspace" was given if there were
exactly enough group forward references such that the last one extended
into the workspace safety margin. The next one would have expanded the
workspace. The test for overflow was not including the safety margin.
40. A match limit issue is fixed in JIT which was found by Karl Skomski
with a custom LLVM fuzzer.
41. Remove the use of /dev/null in testdata/testinput2, because it doesn't
work under Windows. (Why has it taken so long for anyone to notice?)
42. In a character class such as [\W\p{Any}] where both a negative-type escape
("not a word character") and a property escape were present, the property
escape was being ignored.
43. Fix crash caused by very long (*MARK) or (*THEN) names.
44. A sequence such as [[:punct:]b] that is, a POSIX character class followed
by a single ASCII character in a class item, was incorrectly compiled in
UCP mode. The POSIX class got lost, but only if the single character
followed it.
45. [:punct:] in UCP mode was matching some characters in the range 128-255
that should not have been matched.
46. If [:^ascii:] or [:^xdigit:] or [:^cntrl:] are present in a non-negated
class, all characters with code points greater than 255 are in the class.
When a Unicode property was also in the class (if PCRE_UCP is set, escapes
such as \w are turned into Unicode properties), wide characters were not
correctly handled, and could fail to match.
Version 8.37 28-April-2015
--------------------------
1. When an (*ACCEPT) is triggered inside capturing parentheses, it arranges
for those parentheses to be closed with whatever has been captured so far.
However, it was failing to mark any other groups between the hightest
capture so far and the currrent group as "unset". Thus, the ovector for
those groups contained whatever was previously there. An example is the
pattern /(x)|((*ACCEPT))/ when matched against "abcd".
2. If an assertion condition was quantified with a minimum of zero (an odd
thing to do, but it happened), SIGSEGV or other misbehaviour could occur.
3. If a pattern in pcretest input had the P (POSIX) modifier followed by an
unrecognized modifier, a crash could occur.
4. An attempt to do global matching in pcretest with a zero-length ovector
caused a crash.
5. Fixed a memory leak during matching that could occur for a subpattern
subroutine call (recursive or otherwise) if the number of captured groups
that had to be saved was greater than ten.
6. Catch a bad opcode during auto-possessification after compiling a bad UTF
string with NO_UTF_CHECK. This is a tidyup, not a bug fix, as passing bad
UTF with NO_UTF_CHECK is documented as having an undefined outcome.
7. A UTF pattern containing a "not" match of a non-ASCII character and a
subroutine reference could loop at compile time. Example: /[^\xff]((?1))/.
8. When a pattern is compiled, it remembers the highest back reference so that
when matching, if the ovector is too small, extra memory can be obtained to
use instead. A conditional subpattern whose condition is a check on a
capture having happened, such as, for example in the pattern
/^(?:(a)|b)(?(1)A|B)/, is another kind of back reference, but it was not
setting the highest backreference number. This mattered only if pcre_exec()
was called with an ovector that was too small to hold the capture, and there
was no other kind of back reference (a situation which is probably quite
rare). The effect of the bug was that the condition was always treated as
FALSE when the capture could not be consulted, leading to a incorrect
behaviour by pcre_exec(). This bug has been fixed.
9. A reference to a duplicated named group (either a back reference or a test
for being set in a conditional) that occurred in a part of the pattern where
PCRE_DUPNAMES was not set caused the amount of memory needed for the pattern
to be incorrectly calculated, leading to overwriting.
10. A mutually recursive set of back references such as (\2)(\1) caused a
segfault at study time (while trying to find the minimum matching length).
The infinite loop is now broken (with the minimum length unset, that is,
zero).
11. If an assertion that was used as a condition was quantified with a minimum
of zero, matching went wrong. In particular, if the whole group had
unlimited repetition and could match an empty string, a segfault was
likely. The pattern (?(?=0)?)+ is an example that caused this. Perl allows
assertions to be quantified, but not if they are being used as conditions,
so the above pattern is faulted by Perl. PCRE has now been changed so that
it also rejects such patterns.
12. A possessive capturing group such as (a)*+ with a minimum repeat of zero
failed to allow the zero-repeat case if pcre2_exec() was called with an
ovector too small to capture the group.
13. Fixed two bugs in pcretest that were discovered by fuzzing and reported by
Red Hat Product Security:
(a) A crash if /K and /F were both set with the option to save the compiled
pattern.
(b) Another crash if the option to print captured substrings in a callout
was combined with setting a null ovector, for example \O\C+ as a subject
string.
14. A pattern such as "((?2){0,1999}())?", which has a group containing a
forward reference repeated a large (but limited) number of times within a
repeated outer group that has a zero minimum quantifier, caused incorrect
code to be compiled, leading to the error "internal error:
previously-checked referenced subpattern not found" when an incorrect
memory address was read. This bug was reported as "heap overflow",
discovered by Kai Lu of Fortinet's FortiGuard Labs and given the CVE number
CVE-2015-2325.
23. A pattern such as "((?+1)(\1))/" containing a forward reference subroutine
call within a group that also contained a recursive back reference caused
incorrect code to be compiled. This bug was reported as "heap overflow",
discovered by Kai Lu of Fortinet's FortiGuard Labs, and given the CVE
number CVE-2015-2326.
24. Computing the size of the JIT read-only data in advance has been a source
of various issues, and new ones are still appear unfortunately. To fix
existing and future issues, size computation is eliminated from the code,
and replaced by on-demand memory allocation.
25. A pattern such as /(?i)[A-`]/, where characters in the other case are
adjacent to the end of the range, and the range contained characters with
more than one other case, caused incorrect behaviour when compiled in UTF
mode. In that example, the range a-j was left out of the class.
26. Fix JIT compilation of conditional blocks, which assertion
is converted to (*FAIL). E.g: /(?(?!))/.
27. The pattern /(?(?!)^)/ caused references to random memory. This bug was
discovered by the LLVM fuzzer.
28. The assertion (?!) is optimized to (*FAIL). This was not handled correctly
when this assertion was used as a condition, for example (?(?!)a|b). In
pcre2_match() it worked by luck; in pcre2_dfa_match() it gave an incorrect
error about an unsupported item.
29. For some types of pattern, for example /Z*(|d*){216}/, the auto-
possessification code could take exponential time to complete. A recursion
depth limit of 1000 has been imposed to limit the resources used by this
optimization.
30. A pattern such as /(*UTF)[\S\V\H]/, which contains a negated special class
such as \S in non-UCP mode, explicit wide characters (> 255) can be ignored
because \S ensures they are all in the class. The code for doing this was
interacting badly with the code for computing the amount of space needed to
compile the pattern, leading to a buffer overflow. This bug was discovered
by the LLVM fuzzer.
31. A pattern such as /((?2)+)((?1))/ which has mutual recursion nested inside
other kinds of group caused stack overflow at compile time. This bug was
discovered by the LLVM fuzzer.
32. A pattern such as /(?1)(?#?'){8}(a)/ which had a parenthesized comment
between a subroutine call and its quantifier was incorrectly compiled,
leading to buffer overflow or other errors. This bug was discovered by the
LLVM fuzzer.
33. The illegal pattern /(?(?<E>.*!.*)?)/ was not being diagnosed as missing an
assertion after (?(. The code was failing to check the character after
(?(?< for the ! or = that would indicate a lookbehind assertion. This bug
was discovered by the LLVM fuzzer.
34. A pattern such as /X((?2)()*+){2}+/ which has a possessive quantifier with
a fixed maximum following a group that contains a subroutine reference was
incorrectly compiled and could trigger buffer overflow. This bug was
discovered by the LLVM fuzzer.
35. A mutual recursion within a lookbehind assertion such as (?<=((?2))((?1)))
caused a stack overflow instead of the diagnosis of a non-fixed length
lookbehind assertion. This bug was discovered by the LLVM fuzzer.
36. The use of \K in a positive lookbehind assertion in a non-anchored pattern
(e.g. /(?<=\Ka)/) could make pcregrep loop.
37. There was a similar problem to 36 in pcretest for global matches.
38. If a greedy quantified \X was preceded by \C in UTF mode (e.g. \C\X*),
and a subsequent item in the pattern caused a non-match, backtracking over
the repeated \X did not stop, but carried on past the start of the subject,
causing reference to random memory and/or a segfault. There were also some
other cases where backtracking after \C could crash. This set of bugs was
discovered by the LLVM fuzzer.
39. The function for finding the minimum length of a matching string could take
a very long time if mutual recursion was present many times in a pattern,
for example, /((?2){73}(?2))((?1))/. A better mutual recursion detection
method has been implemented. This infelicity was discovered by the LLVM
fuzzer.
40. Static linking against the PCRE library using the pkg-config module was
failing on missing pthread symbols.
Version 8.36 26-September-2014
------------------------------
1. Got rid of some compiler warnings in the C++ modules that were shown up by
-Wmissing-field-initializers and -Wunused-parameter.
2. The tests for quantifiers being too big (greater than 65535) were being
applied after reading the number, and stupidly assuming that integer
overflow would give a negative number. The tests are now applied as the
numbers are read.
3. Tidy code in pcre_exec.c where two branches that used to be different are
now the same.
4. The JIT compiler did not generate match limit checks for certain
bracketed expressions with quantifiers. This may lead to exponential
backtracking, instead of returning with PCRE_ERROR_MATCHLIMIT. This
issue should be resolved now.
5. Fixed an issue, which occures when nested alternatives are optimized
with table jumps.
6. Inserted two casts and changed some ints to size_t in the light of some
reported 64-bit compiler warnings (Bugzilla 1477).
7. Fixed a bug concerned with zero-minimum possessive groups that could match
an empty string, which sometimes were behaving incorrectly in the
interpreter (though correctly in the JIT matcher). This pcretest input is
an example:
'\A(?:[^"]++|"(?:[^"]*+|"")*+")++'
NON QUOTED "QUOT""ED" AFTER "NOT MATCHED
the interpreter was reporting a match of 'NON QUOTED ' only, whereas the
JIT matcher and Perl both matched 'NON QUOTED "QUOT""ED" AFTER '. The test
for an empty string was breaking the inner loop and carrying on at a lower
level, when possessive repeated groups should always return to a higher
level as they have no backtrack points in them. The empty string test now
occurs at the outer level.
8. Fixed a bug that was incorrectly auto-possessifying \w+ in the pattern
^\w+(?>\s*)(?<=\w) which caused it not to match "test test".
9. Give a compile-time error for \o{} (as Perl does) and for \x{} (which Perl
doesn't).
10. Change 8.34/15 introduced a bug that caused the amount of memory needed
to hold a pattern to be incorrectly computed (too small) when there were
named back references to duplicated names. This could cause "internal
error: code overflow" or "double free or corruption" or other memory
handling errors.
11. When named subpatterns had the same prefixes, back references could be
confused. For example, in this pattern:
/(?P<Name>a)?(?P<Name2>b)?(?(<Name>)c|d)*l/
the reference to 'Name' was incorrectly treated as a reference to a
duplicate name.
12. A pattern such as /^s?c/mi8 where the optional character has more than
one "other case" was incorrectly compiled such that it would only try to
match starting at "c".
13. When a pattern starting with \s was studied, VT was not included in the
list of possible starting characters; this should have been part of the
8.34/18 patch.
14. If a character class started [\Qx]... where x is any character, the class
was incorrectly terminated at the ].
15. If a pattern that started with a caseless match for a character with more
than one "other case" was studied, PCRE did not set up the starting code
unit bit map for the list of possible characters. Now it does. This is an
optimization improvement, not a bug fix.
16. The Unicode data tables have been updated to Unicode 7.0.0.
17. Fixed a number of memory leaks in pcregrep.
18. Avoid a compiler warning (from some compilers) for a function call with
a cast that removes "const" from an lvalue by using an intermediate
variable (to which the compiler does not object).
19. Incorrect code was compiled if a group that contained an internal recursive
back reference was optional (had quantifier with a minimum of zero). This
example compiled incorrect code: /(((a\2)|(a*)\g<-1>))*/ and other examples
caused segmentation faults because of stack overflows at compile time.
20. A pattern such as /((?(R)a|(?1)))+/, which contains a recursion within a
group that is quantified with an indefinite repeat, caused a compile-time
loop which used up all the system stack and provoked a segmentation fault.
This was not the same bug as 19 above.
21. Add PCRECPP_EXP_DECL declaration to operator<< in pcre_stringpiece.h.
Patch by Mike Frysinger.
Version 8.35 04-April-2014
--------------------------
1. A new flag is set, when property checks are present in an XCLASS.
When this flag is not set, PCRE can perform certain optimizations
such as studying these XCLASS-es.
2. The auto-possessification of character sets were improved: a normal
and an extended character set can be compared now. Furthermore
the JIT compiler optimizes more character set checks.
3. Got rid of some compiler warnings for potentially uninitialized variables
that show up only when compiled with -O2.
4. A pattern such as (?=ab\K) that uses \K in an assertion can set the start
of a match later then the end of the match. The pcretest program was not
handling the case sensibly - it was outputting from the start to the next
binary zero. It now reports this situation in a message, and outputs the
text from the end to the start.
5. Fast forward search is improved in JIT. Instead of the first three
characters, any three characters with fixed position can be searched.
Search order: first, last, middle.
6. Improve character range checks in JIT. Characters are read by an inprecise
function now, which returns with an unknown value if the character code is
above a certain threshold (e.g: 256). The only limitation is that the value
must be bigger than the threshold as well. This function is useful when
the characters above the threshold are handled in the same way.
7. The macros whose names start with RAWUCHAR are placeholders for a future
mode in which only the bottom 21 bits of 32-bit data items are used. To
make this more memorable for those maintaining the code, the names have
been changed to start with UCHAR21, and an extensive comment has been added
to their definition.
8. Add missing (new) files sljitNativeTILEGX.c and sljitNativeTILEGX-encoder.c
to the export list in Makefile.am (they were accidentally omitted from the
8.34 tarball).
9. The informational output from pcretest used the phrase "starting byte set"
which is inappropriate for the 16-bit and 32-bit libraries. As the output
for "first char" and "need char" really means "non-UTF-char", I've changed
"byte" to "char", and slightly reworded the output. The documentation about
these values has also been (I hope) clarified.
10. Another JIT related optimization: use table jumps for selecting the correct
backtracking path, when more than four alternatives are present inside a
bracket.
11. Empty match is not possible, when the minimum length is greater than zero,
and there is no \K in the pattern. JIT should avoid empty match checks in
such cases.
12. In a caseless character class with UCP support, when a character with more
than one alternative case was not the first character of a range, not all
the alternative cases were added to the class. For example, s and \x{17f}
are both alternative cases for S: the class [RST] was handled correctly,
but [R-T] was not.
13. The configure.ac file always checked for pthread support when JIT was
enabled. This is not used in Windows, so I have put this test inside a
check for the presence of windows.h (which was already tested for).
14. Improve pattern prefix search by a simplified Boyer-Moore algorithm in JIT.
The algorithm provides a way to skip certain starting offsets, and usually
faster than linear prefix searches.
15. Change 13 for 8.20 updated RunTest to check for the 'fr' locale as well
as for 'fr_FR' and 'french'. For some reason, however, it then used the
Windows-specific input and output files, which have 'french' screwed in.
So this could never have worked. One of the problems with locales is that
they aren't always the same. I have now updated RunTest so that it checks
the output of the locale test (test 3) against three different output
files, and it allows the test to pass if any one of them matches. With luck
this should make the test pass on some versions of Solaris where it was
failing. Because of the uncertainty, the script did not used to stop if
test 3 failed; it now does. If further versions of a French locale ever
come to light, they can now easily be added.
16. If --with-pcregrep-bufsize was given a non-integer value such as "50K",
there was a message during ./configure, but it did not stop. This now
provokes an error. The invalid example in README has been corrected.
If a value less than the minimum is given, the minimum value has always
been used, but now a warning is given.
17. If --enable-bsr-anycrlf was set, the special 16/32-bit test failed. This
was a bug in the test system, which is now fixed. Also, the list of various
configurations that are tested for each release did not have one with both
16/32 bits and --enable-bar-anycrlf. It now does.
18. pcretest was missing "-C bsr" for displaying the \R default setting.
19. Little endian PowerPC systems are supported now by the JIT compiler.
20. The fast forward newline mechanism could enter to an infinite loop on
certain invalid UTF-8 input. Although we don't support these cases
this issue can be fixed by a performance optimization.
21. Change 33 of 8.34 is not sufficient to ensure stack safety because it does
not take account if existing stack usage. There is now a new global
variable called pcre_stack_guard that can be set to point to an external
function to check stack availability. It is called at the start of
processing every parenthesized group.
22. A typo in the code meant that in ungreedy mode the max/min qualifier
behaved like a min-possessive qualifier, and, for example, /a{1,3}b/U did
not match "ab".
23. When UTF was disabled, the JIT program reported some incorrect compile
errors. These messages are silenced now.
24. Experimental support for ARM-64 and MIPS-64 has been added to the JIT
compiler.
25. Change all the temporary files used in RunGrepTest to be different to those
used by RunTest so that the tests can be run simultaneously, for example by
"make -j check".
Version 8.34 15-December-2013
-----------------------------
1. Add pcre[16|32]_jit_free_unused_memory to forcibly free unused JIT
executable memory. Patch inspired by Carsten Klein.
2. ./configure --enable-coverage defined SUPPORT_GCOV in config.h, although
this macro is never tested and has no effect, because the work to support
coverage involves only compiling and linking options and special targets in
the Makefile. The comment in config.h implied that defining the macro would
enable coverage support, which is totally false. There was also support for
setting this macro in the CMake files (my fault, I just copied it from
configure). SUPPORT_GCOV has now been removed.
3. Make a small performance improvement in strlen16() and strlen32() in
pcretest.
4. Change 36 for 8.33 left some unreachable statements in pcre_exec.c,
detected by the Solaris compiler (gcc doesn't seem to be able to diagnose
these cases). There was also one in pcretest.c.
5. Cleaned up a "may be uninitialized" compiler warning in pcre_exec.c.
6. In UTF mode, the code for checking whether a group could match an empty
string (which is used for indefinitely repeated groups to allow for
breaking an infinite loop) was broken when the group contained a repeated
negated single-character class with a character that occupied more than one
data item and had a minimum repetition of zero (for example, [^\x{100}]* in
UTF-8 mode). The effect was undefined: the group might or might not be
deemed as matching an empty string, or the program might have crashed.
7. The code for checking whether a group could match an empty string was not
recognizing that \h, \H, \v, \V, and \R must match a character.
8. Implemented PCRE_INFO_MATCH_EMPTY, which yields 1 if the pattern can match
an empty string. If it can, pcretest shows this in its information output.
9. Fixed two related bugs that applied to Unicode extended grapheme clusters
that were repeated with a maximizing qualifier (e.g. \X* or \X{2,5}) when
matched by pcre_exec() without using JIT:
(a) If the rest of the pattern did not match after a maximal run of
grapheme clusters, the code for backing up to try with fewer of them
did not always back up over a full grapheme when characters that do not
have the modifier quality were involved, e.g. Hangul syllables.
(b) If the match point in a subject started with modifier character, and
there was no match, the code could incorrectly back up beyond the match
point, and potentially beyond the first character in the subject,
leading to a segfault or an incorrect match result.
10. A conditional group with an assertion condition could lead to PCRE
recording an incorrect first data item for a match if no other first data
item was recorded. For example, the pattern (?(?=ab)ab) recorded "a" as a
first data item, and therefore matched "ca" after "c" instead of at the
start.
11. Change 40 for 8.33 (allowing pcregrep to find empty strings) showed up a
bug that caused the command "echo a | ./pcregrep -M '|a'" to loop.
12. The source of pcregrep now includes z/OS-specific code so that it can be
compiled for z/OS as part of the special z/OS distribution.
13. Added the -T and -TM options to pcretest.
14. The code in pcre_compile.c for creating the table of named capturing groups
has been refactored. Instead of creating the table dynamically during the
actual compiling pass, the information is remembered during the pre-compile
pass (on the stack unless there are more than 20 named groups, in which
case malloc() is used) and the whole table is created before the actual
compile happens. This has simplified the code (it is now nearly 150 lines
shorter) and prepared the way for better handling of references to groups
with duplicate names.
15. A back reference to a named subpattern when there is more than one of the
same name now checks them in the order in which they appear in the pattern.
The first one that is set is used for the reference. Previously only the
first one was inspected. This change makes PCRE more compatible with Perl.
16. Unicode character properties were updated from Unicode 6.3.0.
17. The compile-time code for auto-possessification has been refactored, based
on a patch by Zoltan Herczeg. It now happens after instead of during
compilation. The code is cleaner, and more cases are handled. The option
PCRE_NO_AUTO_POSSESS is added for testing purposes, and the -O and /O
options in pcretest are provided to set it. It can also be set by
(*NO_AUTO_POSSESS) at the start of a pattern.
18. The character VT has been added to the default ("C" locale) set of
characters that match \s and are generally treated as white space,
following this same change in Perl 5.18. There is now no difference between
"Perl space" and "POSIX space". Whether VT is treated as white space in
other locales depends on the locale.
19. The code for checking named groups as conditions, either for being set or
for being recursed, has been refactored (this is related to 14 and 15
above). Processing unduplicated named groups should now be as fast at
numerical groups, and processing duplicated groups should be faster than
before.
20. Two patches to the CMake build system, by Alexander Barkov:
(1) Replace the "source" command by "." in CMakeLists.txt because
"source" is a bash-ism.
(2) Add missing HAVE_STDINT_H and HAVE_INTTYPES_H to config-cmake.h.in;
without these the CMake build does not work on Solaris.
21. Perl has changed its handling of \8 and \9. If there is no previously
encountered capturing group of those numbers, they are treated as the
literal characters 8 and 9 instead of a binary zero followed by the
literals. PCRE now does the same.
22. Following Perl, added \o{} to specify codepoints in octal, making it
possible to specify values greater than 0777 and also making them
unambiguous.
23. Perl now gives an error for missing closing braces after \x{... instead of
treating the string as literal. PCRE now does the same.
24. RunTest used to grumble if an inappropriate test was selected explicitly,
but just skip it when running all tests. This make it awkward to run ranges
of tests when one of them was inappropriate. Now it just skips any
inappropriate tests, as it always did when running all tests.
25. If PCRE_AUTO_CALLOUT and PCRE_UCP were set for a pattern that contained
character types such as \d or \w, too many callouts were inserted, and the
data that they returned was rubbish.
26. In UCP mode, \s was not matching two of the characters that Perl matches,
namely NEL (U+0085) and MONGOLIAN VOWEL SEPARATOR (U+180E), though they
were matched by \h. The code has now been refactored so that the lists of
the horizontal and vertical whitespace characters used for \h and \v (which
are defined only in one place) are now also used for \s.
27. Add JIT support for the 64 bit TileGX architecture.
Patch by Jiong Wang (Tilera Corporation).
28. Possessive quantifiers for classes (both explicit and automatically
generated) now use special opcodes instead of wrapping in ONCE brackets.
29. Whereas an item such as A{4}+ ignored the possessivenes of the quantifier
(because it's meaningless), this was not happening when PCRE_CASELESS was
set. Not wrong, but inefficient.
30. Updated perltest.pl to add /u (force Unicode mode) when /W (use Unicode
properties for \w, \d, etc) is present in a test regex. Otherwise if the
test contains no characters greater than 255, Perl doesn't realise it
should be using Unicode semantics.
31. Upgraded the handling of the POSIX classes [:graph:], [:print:], and
[:punct:] when PCRE_UCP is set so as to include the same characters as Perl
does in Unicode mode.
32. Added the "forbid" facility to pcretest so that putting tests into the
wrong test files can sometimes be quickly detected.
33. There is now a limit (default 250) on the depth of nesting of parentheses.
This limit is imposed to control the amount of system stack used at compile
time. It can be changed at build time by --with-parens-nest-limit=xxx or
the equivalent in CMake.
34. Character classes such as [A-\d] or [a-[:digit:]] now cause compile-time
errors. Perl warns for these when in warning mode, but PCRE has no facility
for giving warnings.
35. Change 34 for 8.13 allowed quantifiers on assertions, because Perl does.
However, this was not working for (?!) because it is optimized to (*FAIL),
for which PCRE does not allow quantifiers. The optimization is now disabled
when a quantifier follows (?!). I can't see any use for this, but it makes
things uniform.
36. Perl no longer allows group names to start with digits, so I have made this
change also in PCRE. It simplifies the code a bit.
37. In extended mode, Perl ignores spaces before a + that indicates a
possessive quantifier. PCRE allowed a space before the quantifier, but not
before the possessive +. It now does.
38. The use of \K (reset reported match start) within a repeated possessive
group such as (a\Kb)*+ was not working.
40. Document that the same character tables must be used at compile time and
run time, and that the facility to pass tables to pcre_exec() and
pcre_dfa_exec() is for use only with saved/restored patterns.
41. Applied Jeff Trawick's patch CMakeLists.txt, which "provides two new
features for Builds with MSVC:
1. Support pcre.rc and/or pcreposix.rc (as is already done for MinGW
builds). The .rc files can be used to set FileDescription and many other
attributes.
2. Add an option (-DINSTALL_MSVC_PDB) to enable installation of .pdb files.
This allows higher-level build scripts which want .pdb files to avoid
hard-coding the exact files needed."
42. Added support for [[:<:]] and [[:>:]] as used in the BSD POSIX library to
mean "start of word" and "end of word", respectively, as a transition aid.
43. A minimizing repeat of a class containing codepoints greater than 255 in
non-UTF 16-bit or 32-bit modes caused an internal error when PCRE was
compiled to use the heap for recursion.
44. Got rid of some compiler warnings for unused variables when UTF but not UCP
is configured.
Version 8.33 28-May-2013
------------------------
1. Added 'U' to some constants that are compared to unsigned integers, to
avoid compiler signed/unsigned warnings. Added (int) casts to unsigned
variables that are added to signed variables, to ensure the result is
signed and can be negated.
2. Applied patch by Daniel Richard G for quashing MSVC warnings to the
CMake config files.
3. Revise the creation of config.h.generic so that all boolean macros are
#undefined, whereas non-boolean macros are #ifndef/#endif-ed. This makes
overriding via -D on the command line possible.
4. Changing the definition of the variable "op" in pcre_exec.c from pcre_uchar
to unsigned int is reported to make a quite noticeable speed difference in
a specific Windows environment. Testing on Linux did also appear to show
some benefit (and it is clearly not harmful). Also fixed the definition of
Xop which should be unsigned.
5. Related to (4), changing the definition of the intermediate variable cc
in repeated character loops from pcre_uchar to pcre_uint32 also gave speed
improvements.
6. Fix forward search in JIT when link size is 3 or greater. Also removed some
unnecessary spaces.
7. Adjust autogen.sh and configure.ac to lose warnings given by automake 1.12
and later.
8. Fix two buffer over read issues in 16 and 32 bit modes. Affects JIT only.
9. Optimizing fast_forward_start_bits in JIT.
10. Adding support for callouts in JIT, and fixing some issues revealed
during this work. Namely:
(a) Unoptimized capturing brackets incorrectly reset on backtrack.
(b) Minimum length was not checked before the matching is started.
11. The value of capture_last that is passed to callouts was incorrect in some
cases when there was a capture on one path that was subsequently abandoned
after a backtrack. Also, the capture_last value is now reset after a
recursion, since all captures are also reset in this case.
12. The interpreter no longer returns the "too many substrings" error in the
case when an overflowing capture is in a branch that is subsequently
abandoned after a backtrack.
13. In the pathological case when an offset vector of size 2 is used, pcretest
now prints out the matched string after a yield of 0 or 1.
14. Inlining subpatterns in recursions, when certain conditions are fulfilled.
Only supported by the JIT compiler at the moment.
15. JIT compiler now supports 32 bit Macs thanks to Lawrence Velazquez.
16. Partial matches now set offsets[2] to the "bumpalong" value, that is, the
offset of the starting point of the matching process, provided the offsets
vector is large enough.
17. The \A escape now records a lookbehind value of 1, though its execution
does not actually inspect the previous character. This is to ensure that,
in partial multi-segment matching, at least one character from the old
segment is retained when a new segment is processed. Otherwise, if there
are no lookbehinds in the pattern, \A might match incorrectly at the start
of a new segment.
18. Added some #ifdef __VMS code into pcretest.c to help VMS implementations.
19. Redefined some pcre_uchar variables in pcre_exec.c as pcre_uint32; this
gives some modest performance improvement in 8-bit mode.
20. Added the PCRE-specific property \p{Xuc} for matching characters that can
be expressed in certain programming languages using Universal Character
Names.
21. Unicode validation has been updated in the light of Unicode Corrigendum #9,
which points out that "non characters" are not "characters that may not
appear in Unicode strings" but rather "characters that are reserved for
internal use and have only local meaning".
22. When a pattern was compiled with automatic callouts (PCRE_AUTO_CALLOUT) and
there was a conditional group that depended on an assertion, if the
assertion was false, the callout that immediately followed the alternation
in the condition was skipped when pcre_exec() was used for matching.
23. Allow an explicit callout to be inserted before an assertion that is the
condition for a conditional group, for compatibility with automatic
callouts, which always insert a callout at this point.
24. In 8.31, (*COMMIT) was confined to within a recursive subpattern. Perl also
confines (*SKIP) and (*PRUNE) in the same way, and this has now been done.
25. (*PRUNE) is now supported by the JIT compiler.
26. Fix infinite loop when /(?<=(*SKIP)ac)a/ is matched against aa.
27. Fix the case where there are two or more SKIPs with arguments that may be
ignored.
28. (*SKIP) is now supported by the JIT compiler.
29. (*THEN) is now supported by the JIT compiler.
30. Update RunTest with additional test selector options.
31. The way PCRE handles backtracking verbs has been changed in two ways.
(1) Previously, in something like (*COMMIT)(*SKIP), COMMIT would override
SKIP. Now, PCRE acts on whichever backtracking verb is reached first by
backtracking. In some cases this makes it more Perl-compatible, but Perl's
rather obscure rules do not always do the same thing.
(2) Previously, backtracking verbs were confined within assertions. This is
no longer the case for positive assertions, except for (*ACCEPT). Again,
this sometimes improves Perl compatibility, and sometimes does not.
32. A number of tests that were in test 2 because Perl did things differently
have been moved to test 1, because either Perl or PCRE has changed, and
these tests are now compatible.
32. Backtracking control verbs are now handled in the same way in JIT and
interpreter.
33. An opening parenthesis in a MARK/PRUNE/SKIP/THEN name in a pattern that
contained a forward subroutine reference caused a compile error.
34. Auto-detect and optimize limited repetitions in JIT.
35. Implement PCRE_NEVER_UTF to lock out the use of UTF, in particular,
blocking (*UTF) etc.
36. In the interpreter, maximizing pattern repetitions for characters and
character types now use tail recursion, which reduces stack usage.
37. The value of the max lookbehind was not correctly preserved if a compiled
and saved regex was reloaded on a host of different endianness.
38. Implemented (*LIMIT_MATCH) and (*LIMIT_RECURSION). As part of the extension
of the compiled pattern block, expand the flags field from 16 to 32 bits
because it was almost full.
39. Try madvise first before posix_madvise.
40. Change 7 for PCRE 7.9 made it impossible for pcregrep to find empty lines
with a pattern such as ^$. It has taken 4 years for anybody to notice! The
original change locked out all matches of empty strings. This has been
changed so that one match of an empty string per line is recognized.
Subsequent searches on the same line (for colouring or for --only-matching,
for example) do not recognize empty strings.
41. Applied a user patch to fix a number of spelling mistakes in comments.
42. Data lines longer than 65536 caused pcretest to crash.
43. Clarified the data type for length and startoffset arguments for pcre_exec
and pcre_dfa_exec in the function-specific man pages, where they were
explicitly stated to be in bytes, never having been updated. I also added
some clarification to the pcreapi man page.
44. A call to pcre_dfa_exec() with an output vector size less than 2 caused
a segmentation fault.
Version 8.32 30-November-2012
-----------------------------
1. Improved JIT compiler optimizations for first character search and single
character iterators.
2. Supporting IBM XL C compilers for PPC architectures in the JIT compiler.
Patch by Daniel Richard G.
3. Single character iterator optimizations in the JIT compiler.
4. Improved JIT compiler optimizations for character ranges.
5. Rename the "leave" variable names to "quit" to improve WinCE compatibility.
Reported by Giuseppe D'Angelo.
6. The PCRE_STARTLINE bit, indicating that a match can occur only at the start
of a line, was being set incorrectly in cases where .* appeared inside
atomic brackets at the start of a pattern, or where there was a subsequent
*PRUNE or *SKIP.
7. Improved instruction cache flush for POWER/PowerPC.
Patch by Daniel Richard G.
8. Fixed a number of issues in pcregrep, making it more compatible with GNU
grep:
(a) There is now no limit to the number of patterns to be matched.
(b) An error is given if a pattern is too long.
(c) Multiple uses of --exclude, --exclude-dir, --include, and --include-dir
are now supported.
(d) --exclude-from and --include-from (multiple use) have been added.
(e) Exclusions and inclusions now apply to all files and directories, not
just to those obtained from scanning a directory recursively.
(f) Multiple uses of -f and --file-list are now supported.
(g) In a Windows environment, the default for -d has been changed from
"read" (the GNU grep default) to "skip", because otherwise the presence
of a directory in the file list provokes an error.
(h) The documentation has been revised and clarified in places.
9. Improve the matching speed of capturing brackets.
10. Changed the meaning of \X so that it now matches a Unicode extended
grapheme cluster.
11. Patch by Daniel Richard G to the autoconf files to add a macro for sorting
out POSIX threads when JIT support is configured.
12. Added support for PCRE_STUDY_EXTRA_NEEDED.
13. In the POSIX wrapper regcomp() function, setting re_nsub field in the preg
structure could go wrong in environments where size_t is not the same size
as int.
14. Applied user-supplied patch to pcrecpp.cc to allow PCRE_NO_UTF8_CHECK to be
set.
15. The EBCDIC support had decayed; later updates to the code had included
explicit references to (e.g.) \x0a instead of CHAR_LF. There has been a
general tidy up of EBCDIC-related issues, and the documentation was also
not quite right. There is now a test that can be run on ASCII systems to
check some of the EBCDIC-related things (but is it not a full test).
16. The new PCRE_STUDY_EXTRA_NEEDED option is now used by pcregrep, resulting
in a small tidy to the code.
17. Fix JIT tests when UTF is disabled and both 8 and 16 bit mode are enabled.
18. If the --only-matching (-o) option in pcregrep is specified multiple
times, each one causes appropriate output. For example, -o1 -o2 outputs the
substrings matched by the 1st and 2nd capturing parentheses. A separating
string can be specified by --om-separator (default empty).
19. Improving the first n character searches.
20. Turn case lists for horizontal and vertical white space into macros so that
they are defined only once.
21. This set of changes together give more compatible Unicode case-folding
behaviour for characters that have more than one other case when UCP
support is available.
(a) The Unicode property table now has offsets into a new table of sets of
three or more characters that are case-equivalent. The MultiStage2.py
script that generates these tables (the pcre_ucd.c file) now scans
CaseFolding.txt instead of UnicodeData.txt for character case
information.
(b) The code for adding characters or ranges of characters to a character
class has been abstracted into a generalized function that also handles
case-independence. In UTF-mode with UCP support, this uses the new data
to handle characters with more than one other case.
(c) A bug that is fixed as a result of (b) is that codepoints less than 256
whose other case is greater than 256 are now correctly matched
caselessly. Previously, the high codepoint matched the low one, but not
vice versa.
(d) The processing of \h, \H, \v, and \ in character classes now makes use
of the new class addition function, using character lists defined as
macros alongside the case definitions of 20 above.
(e) Caseless back references now work with characters that have more than
one other case.
(f) General caseless matching of characters with more than one other case
is supported.
22. Unicode character properties were updated from Unicode 6.2.0
23. Improved CMake support under Windows. Patch by Daniel Richard G.
24. Add support for 32-bit character strings, and UTF-32
25. Major JIT compiler update (code refactoring and bugfixing).
Experimental Sparc 32 support is added.
26. Applied a modified version of Daniel Richard G's patch to create
pcre.h.generic and config.h.generic by "make" instead of in the
PrepareRelease script.
27. Added a definition for CHAR_NULL (helpful for the z/OS port), and use it in
pcre_compile.c when checking for a zero character.
28. Introducing a native interface for JIT. Through this interface, the compiled
machine code can be directly executed. The purpose of this interface is to
provide fast pattern matching, so several sanity checks are not performed.
However, feature tests are still performed. The new interface provides
1.4x speedup compared to the old one.
29. If pcre_exec() or pcre_dfa_exec() was called with a negative value for
the subject string length, the error given was PCRE_ERROR_BADOFFSET, which
was confusing. There is now a new error PCRE_ERROR_BADLENGTH for this case.
30. In 8-bit UTF-8 mode, pcretest failed to give an error for data codepoints
greater than 0x7fffffff (which cannot be represented in UTF-8, even under
the "old" RFC 2279). Instead, it ended up passing a negative length to
pcre_exec().
31. Add support for GCC's visibility feature to hide internal functions.
32. Running "pcretest -C pcre8" or "pcretest -C pcre16" gave a spurious error
"unknown -C option" after outputting 0 or 1.
33. There is now support for generating a code coverage report for the test
suite in environments where gcc is the compiler and lcov is installed. This
is mainly for the benefit of the developers.
34. If PCRE is built with --enable-valgrind, certain memory regions are marked
unaddressable using valgrind annotations, allowing valgrind to detect
invalid memory accesses. This is mainly for the benefit of the developers.
25. (*UTF) can now be used to start a pattern in any of the three libraries.
26. Give configure error if --enable-cpp but no C++ compiler found.
Version 8.31 06-July-2012
-------------------------
1. Fixing a wrong JIT test case and some compiler warnings.
2. Removed a bashism from the RunTest script.
3. Add a cast to pcre_exec.c to fix the warning "unary minus operator applied
to unsigned type, result still unsigned" that was given by an MS compiler
on encountering the code "-sizeof(xxx)".
4. Partial matching support is added to the JIT compiler.
5. Fixed several bugs concerned with partial matching of items that consist
of more than one character:
(a) /^(..)\1/ did not partially match "aba" because checking references was
done on an "all or nothing" basis. This also applied to repeated
references.
(b) \R did not give a hard partial match if \r was found at the end of the
subject.
(c) \X did not give a hard partial match after matching one or more
characters at the end of the subject.
(d) When newline was set to CRLF, a pattern such as /a$/ did not recognize
a partial match for the string "\r".
(e) When newline was set to CRLF, the metacharacter "." did not recognize
a partial match for a CR character at the end of the subject string.
6. If JIT is requested using /S++ or -s++ (instead of just /S+ or -s+) when
running pcretest, the text "(JIT)" added to the output whenever JIT is
actually used to run the match.
7. Individual JIT compile options can be set in pcretest by following -s+[+]
or /S+[+] with a digit between 1 and 7.
8. OP_NOT now supports any UTF character not just single-byte ones.
9. (*MARK) control verb is now supported by the JIT compiler.
10. The command "./RunTest list" lists the available tests without actually
running any of them. (Because I keep forgetting what they all are.)
11. Add PCRE_INFO_MAXLOOKBEHIND.
12. Applied a (slightly modified) user-supplied patch that improves performance
when the heap is used for recursion (compiled with --disable-stack-for-
recursion). Instead of malloc and free for each heap frame each time a
logical recursion happens, frames are retained on a chain and re-used where
possible. This sometimes gives as much as 30% improvement.
13. As documented, (*COMMIT) is now confined to within a recursive subpattern
call.
14. As documented, (*COMMIT) is now confined to within a positive assertion.
15. It is now possible to link pcretest with libedit as an alternative to
libreadline.
16. (*COMMIT) control verb is now supported by the JIT compiler.
17. The Unicode data tables have been updated to Unicode 6.1.0.
18. Added --file-list option to pcregrep.
19. Added binary file support to pcregrep, including the -a, --binary-files,
-I, and --text options.
20. The madvise function is renamed for posix_madvise for QNX compatibility
reasons. Fixed by Giuseppe D'Angelo.
21. Fixed a bug for backward assertions with REVERSE 0 in the JIT compiler.
22. Changed the option for creating symbolic links for 16-bit man pages from
-s to -sf so that re-installing does not cause issues.
23. Support PCRE_NO_START_OPTIMIZE in JIT as (*MARK) support requires it.
24. Fixed a very old bug in pcretest that caused errors with restarted DFA
matches in certain environments (the workspace was not being correctly
retained). Also added to pcre_dfa_exec() a simple plausibility check on
some of the workspace data at the beginning of a restart.
25. \s*\R was auto-possessifying the \s* when it should not, whereas \S*\R
was not doing so when it should - probably a typo introduced by SVN 528
(change 8.10/14).
26. When PCRE_UCP was not set, \w+\x{c4} was incorrectly auto-possessifying the
\w+ when the character tables indicated that \x{c4} was a word character.
There were several related cases, all because the tests for doing a table
lookup were testing for characters less than 127 instead of 255.
27. If a pattern contains capturing parentheses that are not used in a match,
their slots in the ovector are set to -1. For those that are higher than
any matched groups, this happens at the end of processing. In the case when
there were back references that the ovector was too small to contain
(causing temporary malloc'd memory to be used during matching), and the
highest capturing number was not used, memory off the end of the ovector
was incorrectly being set to -1. (It was using the size of the temporary
memory instead of the true size.)
28. To catch bugs like 27 using valgrind, when pcretest is asked to specify an
ovector size, it uses memory at the end of the block that it has got.
29. Check for an overlong MARK name and give an error at compile time. The
limit is 255 for the 8-bit library and 65535 for the 16-bit library.
30. JIT compiler update.
31. JIT is now supported on jailbroken iOS devices. Thanks for Ruiger
Rill for the patch.
32. Put spaces around SLJIT_PRINT_D in the JIT compiler. Required by CXX11.
33. Variable renamings in the PCRE-JIT compiler. No functionality change.
34. Fixed typos in pcregrep: in two places there was SUPPORT_LIBZ2 instead of
SUPPORT_LIBBZ2. This caused a build problem when bzip2 but not gzip (zlib)
was enabled.
35. Improve JIT code generation for greedy plus quantifier.
36. When /((?:a?)*)*c/ or /((?>a?)*)*c/ was matched against "aac", it set group
1 to "aa" instead of to an empty string. The bug affected repeated groups
that could potentially match an empty string.
37. Optimizing single character iterators in JIT.
38. Wide characters specified with \uxxxx in JavaScript mode are now subject to
the same checks as \x{...} characters in non-JavaScript mode. Specifically,
codepoints that are too big for the mode are faulted, and in a UTF mode,
disallowed codepoints are also faulted.
39. If PCRE was compiled with UTF support, in three places in the DFA
matcher there was code that should only have been obeyed in UTF mode, but
was being obeyed unconditionally. In 8-bit mode this could cause incorrect
processing when bytes with values greater than 127 were present. In 16-bit
mode the bug would be provoked by values in the range 0xfc00 to 0xdc00. In
both cases the values are those that cannot be the first data item in a UTF
character. The three items that might have provoked this were recursions,
possessively repeated groups, and atomic groups.
40. Ensure that libpcre is explicitly listed in the link commands for pcretest
and pcregrep, because some OS require shared objects to be explicitly
passed to ld, causing the link step to fail if they are not.
41. There were two incorrect #ifdefs in pcre_study.c, meaning that, in 16-bit
mode, patterns that started with \h* or \R* might be incorrectly matched.
Version 8.30 04-February-2012
-----------------------------
1. Renamed "isnumber" as "is_a_number" because in some Mac environments this
name is defined in ctype.h.
2. Fixed a bug in fixed-length calculation for lookbehinds that would show up
only in quite long subpatterns.
3. Removed the function pcre_info(), which has been obsolete and deprecated
since it was replaced by pcre_fullinfo() in February 2000.
4. For a non-anchored pattern, if (*SKIP) was given with a name that did not
match a (*MARK), and the match failed at the start of the subject, a
reference to memory before the start of the subject could occur. This bug
was introduced by fix 17 of release 8.21.
5. A reference to an unset group with zero minimum repetition was giving
totally wrong answers (in non-JavaScript-compatibility mode). For example,
/(another)?(\1?)test/ matched against "hello world test". This bug was
introduced in release 8.13.
6. Add support for 16-bit character strings (a large amount of work involving
many changes and refactorings).
7. RunGrepTest failed on msys because \r\n was replaced by whitespace when the
command "pattern=`printf 'xxx\r\njkl'`" was run. The pattern is now taken
from a file.
8. Ovector size of 2 is also supported by JIT based pcre_exec (the ovector size
rounding is not applied in this particular case).
9. The invalid Unicode surrogate codepoints U+D800 to U+DFFF are now rejected
if they appear, or are escaped, in patterns.
10. Get rid of a number of -Wunused-but-set-variable warnings.
11. The pattern /(?=(*:x))(q|)/ matches an empty string, and returns the mark
"x". The similar pattern /(?=(*:x))((*:y)q|)/ did not return a mark at all.
Oddly, Perl behaves the same way. PCRE has been fixed so that this pattern
also returns the mark "x". This bug applied to capturing parentheses,
non-capturing parentheses, and atomic parentheses. It also applied to some
assertions.
12. Stephen Kelly's patch to CMakeLists.txt allows it to parse the version
information out of configure.ac instead of relying on pcre.h.generic, which
is not stored in the repository.
13. Applied Dmitry V. Levin's patch for a more portable method for linking with
-lreadline.
14. ZH added PCRE_CONFIG_JITTARGET; added its output to pcretest -C.
15. Applied Graycode's patch to put the top-level frame on the stack rather
than the heap when not using the stack for recursion. This gives a
performance improvement in many cases when recursion is not deep.
16. Experimental code added to "pcretest -C" to output the stack frame size.
Version 8.21 12-Dec-2011
------------------------
1. Updating the JIT compiler.
2. JIT compiler now supports OP_NCREF, OP_RREF and OP_NRREF. New test cases
are added as well.
3. Fix cache-flush issue on PowerPC (It is still an experimental JIT port).
PCRE_EXTRA_TABLES is not suported by JIT, and should be checked before
calling _pcre_jit_exec. Some extra comments are added.
4. (*MARK) settings inside atomic groups that do not contain any capturing
parentheses, for example, (?>a(*:m)), were not being passed out. This bug
was introduced by change 18 for 8.20.
5. Supporting of \x, \U and \u in JavaScript compatibility mode based on the
ECMA-262 standard.
6. Lookbehinds such as (?<=a{2}b) that contained a fixed repetition were
erroneously being rejected as "not fixed length" if PCRE_CASELESS was set.
This bug was probably introduced by change 9 of 8.13.
7. While fixing 6 above, I noticed that a number of other items were being
incorrectly rejected as "not fixed length". This arose partly because newer
opcodes had not been added to the fixed-length checking code. I have (a)
corrected the bug and added tests for these items, and (b) arranged for an
error to occur if an unknown opcode is encountered while checking for fixed
length instead of just assuming "not fixed length". The items that were
rejected were: (*ACCEPT), (*COMMIT), (*FAIL), (*MARK), (*PRUNE), (*SKIP),
(*THEN), \h, \H, \v, \V, and single character negative classes with fixed
repetitions, e.g. [^a]{3}, with and without PCRE_CASELESS.
8. A possessively repeated conditional subpattern such as (?(?=c)c|d)++ was
being incorrectly compiled and would have given unpredicatble results.
9. A possessively repeated subpattern with minimum repeat count greater than
one behaved incorrectly. For example, (A){2,}+ behaved as if it was
(A)(A)++ which meant that, after a subsequent mismatch, backtracking into
the first (A) could occur when it should not.
10. Add a cast and remove a redundant test from the code.
11. JIT should use pcre_malloc/pcre_free for allocation.
12. Updated pcre-config so that it no longer shows -L/usr/lib, which seems
best practice nowadays, and helps with cross-compiling. (If the exec_prefix
is anything other than /usr, -L is still shown).
13. In non-UTF-8 mode, \C is now supported in lookbehinds and DFA matching.
14. Perl does not support \N without a following name in a [] class; PCRE now
also gives an error.
15. If a forward reference was repeated with an upper limit of around 2000,
it caused the error "internal error: overran compiling workspace". The
maximum number of forward references (including repeats) was limited by the
internal workspace, and dependent on the LINK_SIZE. The code has been
rewritten so that the workspace expands (via pcre_malloc) if necessary, and
the default depends on LINK_SIZE. There is a new upper limit (for safety)
of around 200,000 forward references. While doing this, I also speeded up
the filling in of repeated forward references.
16. A repeated forward reference in a pattern such as (a)(?2){2}(.) was
incorrectly expecting the subject to contain another "a" after the start.
17. When (*SKIP:name) is activated without a corresponding (*MARK:name) earlier
in the match, the SKIP should be ignored. This was not happening; instead
the SKIP was being treated as NOMATCH. For patterns such as
/A(*MARK:A)A+(*SKIP:B)Z|AAC/ this meant that the AAC branch was never
tested.
18. The behaviour of (*MARK), (*PRUNE), and (*THEN) has been reworked and is
now much more compatible with Perl, in particular in cases where the result
is a non-match for a non-anchored pattern. For example, if
/b(*:m)f|a(*:n)w/ is matched against "abc", the non-match returns the name
"m", where previously it did not return a name. A side effect of this
change is that for partial matches, the last encountered mark name is
returned, as for non matches. A number of tests that were previously not
Perl-compatible have been moved into the Perl-compatible test files. The
refactoring has had the pleasing side effect of removing one argument from
the match() function, thus reducing its stack requirements.
19. If the /S+ option was used in pcretest to study a pattern using JIT,
subsequent uses of /S (without +) incorrectly behaved like /S+.
21. Retrieve executable code size support for the JIT compiler and fixing
some warnings.
22. A caseless match of a UTF-8 character whose other case uses fewer bytes did
not work when the shorter character appeared right at the end of the
subject string.
23. Added some (int) casts to non-JIT modules to reduce warnings on 64-bit
systems.
24. Added PCRE_INFO_JITSIZE to pass on the value from (21) above, and also
output it when the /M option is used in pcretest.
25. The CheckMan script was not being included in the distribution. Also, added
an explicit "perl" to run Perl scripts from the PrepareRelease script
because this is reportedly needed in Windows.
26. If study data was being save in a file and studying had not found a set of
"starts with" bytes for the pattern, the data written to the file (though
never used) was taken from uninitialized memory and so caused valgrind to
complain.
27. Updated RunTest.bat as provided by Sheri Pierce.
28. Fixed a possible uninitialized memory bug in pcre_jit_compile.c.
29. Computation of memory usage for the table of capturing group names was
giving an unnecessarily large value.
Version 8.20 21-Oct-2011
------------------------
1. Change 37 of 8.13 broke patterns like [:a]...[b:] because it thought it had
a POSIX class. After further experiments with Perl, which convinced me that
Perl has bugs and confusions, a closing square bracket is no longer allowed
in a POSIX name. This bug also affected patterns with classes that started
with full stops.
2. If a pattern such as /(a)b|ac/ is matched against "ac", there is no
captured substring, but while checking the failing first alternative,
substring 1 is temporarily captured. If the output vector supplied to
pcre_exec() was not big enough for this capture, the yield of the function
was still zero ("insufficient space for captured substrings"). This cannot
be totally fixed without adding another stack variable, which seems a lot
of expense for a edge case. However, I have improved the situation in cases
such as /(a)(b)x|abc/ matched against "abc", where the return code
indicates that fewer than the maximum number of slots in the ovector have
been set.
3. Related to (2) above: when there are more back references in a pattern than
slots in the output vector, pcre_exec() uses temporary memory during
matching, and copies in the captures as far as possible afterwards. It was
using the entire output vector, but this conflicts with the specification
that only 2/3 is used for passing back captured substrings. Now it uses
only the first 2/3, for compatibility. This is, of course, another edge
case.
4. Zoltan Herczeg's just-in-time compiler support has been integrated into the
main code base, and can be used by building with --enable-jit. When this is
done, pcregrep automatically uses it unless --disable-pcregrep-jit or the
runtime --no-jit option is given.
5. When the number of matches in a pcre_dfa_exec() run exactly filled the
ovector, the return from the function was zero, implying that there were
other matches that did not fit. The correct "exactly full" value is now
returned.
6. If a subpattern that was called recursively or as a subroutine contained
(*PRUNE) or any other control that caused it to give a non-standard return,
invalid errors such as "Error -26 (nested recursion at the same subject
position)" or even infinite loops could occur.
7. If a pattern such as /a(*SKIP)c|b(*ACCEPT)|/ was studied, it stopped
computing the minimum length on reaching *ACCEPT, and so ended up with the
wrong value of 1 rather than 0. Further investigation indicates that
computing a minimum subject length in the presence of *ACCEPT is difficult
(think back references, subroutine calls), and so I have changed the code
so that no minimum is registered for a pattern that contains *ACCEPT.
8. If (*THEN) was present in the first (true) branch of a conditional group,
it was not handled as intended. [But see 16 below.]
9. Replaced RunTest.bat and CMakeLists.txt with improved versions provided by
Sheri Pierce.
10. A pathological pattern such as /(*ACCEPT)a/ was miscompiled, thinking that
the first byte in a match must be "a".
11. Change 17 for 8.13 increased the recursion depth for patterns like
/a(?:.)*?a/ drastically. I've improved things by remembering whether a
pattern contains any instances of (*THEN). If it does not, the old
optimizations are restored. It would be nice to do this on a per-group
basis, but at the moment that is not feasible.
12. In some environments, the output of pcretest -C is CRLF terminated. This
broke RunTest's code that checks for the link size. A single white space
character after the value is now allowed for.
13. RunTest now checks for the "fr" locale as well as for "fr_FR" and "french".
For "fr", it uses the Windows-specific input and output files.
14. If (*THEN) appeared in a group that was called recursively or as a
subroutine, it did not work as intended. [But see next item.]
15. Consider the pattern /A (B(*THEN)C) | D/ where A, B, C, and D are complex
pattern fragments (but not containing any | characters). If A and B are
matched, but there is a failure in C so that it backtracks to (*THEN), PCRE
was behaving differently to Perl. PCRE backtracked into A, but Perl goes to
D. In other words, Perl considers parentheses that do not contain any |
characters to be part of a surrounding alternative, whereas PCRE was
treading (B(*THEN)C) the same as (B(*THEN)C|(*FAIL)) -- which Perl handles
differently. PCRE now behaves in the same way as Perl, except in the case
of subroutine/recursion calls such as (?1) which have in any case always
been different (but PCRE had them first :-).
16. Related to 15 above: Perl does not treat the | in a conditional group as
creating alternatives. Such a group is treated in the same way as an
ordinary group without any | characters when processing (*THEN). PCRE has
been changed to match Perl's behaviour.
17. If a user had set PCREGREP_COLO(U)R to something other than 1:31, the
RunGrepTest script failed.
18. Change 22 for version 13 caused atomic groups to use more stack. This is
inevitable for groups that contain captures, but it can lead to a lot of
stack use in large patterns. The old behaviour has been restored for atomic
groups that do not contain any capturing parentheses.
19. If the PCRE_NO_START_OPTIMIZE option was set for pcre_compile(), it did not
suppress the check for a minimum subject length at run time. (If it was
given to pcre_exec() or pcre_dfa_exec() it did work.)
20. Fixed an ASCII-dependent infelicity in pcretest that would have made it
fail to work when decoding hex characters in data strings in EBCDIC
environments.
21. It appears that in at least one Mac OS environment, the isxdigit() function
is implemented as a macro that evaluates to its argument more than once,
contravening the C 90 Standard (I haven't checked a later standard). There
was an instance in pcretest which caused it to go wrong when processing
\x{...} escapes in subject strings. The has been rewritten to avoid using
things like p++ in the argument of isxdigit().
Version 8.13 16-Aug-2011
------------------------
1. The Unicode data tables have been updated to Unicode 6.0.0.
2. Two minor typos in pcre_internal.h have been fixed.
3. Added #include <string.h> to pcre_scanner_unittest.cc, pcrecpp.cc, and
pcrecpp_unittest.cc. They are needed for strcmp(), memset(), and strchr()
in some environments (e.g. Solaris 10/SPARC using Sun Studio 12U2).
4. There were a number of related bugs in the code for matching backrefences
caselessly in UTF-8 mode when codes for the characters concerned were
different numbers of bytes. For example, U+023A and U+2C65 are an upper
and lower case pair, using 2 and 3 bytes, respectively. The main bugs were:
(a) A reference to 3 copies of a 2-byte code matched only 2 of a 3-byte
code. (b) A reference to 2 copies of a 3-byte code would not match 2 of a
2-byte code at the end of the subject (it thought there wasn't enough data
left).
5. Comprehensive information about what went wrong is now returned by
pcre_exec() and pcre_dfa_exec() when the UTF-8 string check fails, as long
as the output vector has at least 2 elements. The offset of the start of
the failing character and a reason code are placed in the vector.
6. When the UTF-8 string check fails for pcre_compile(), the offset that is
now returned is for the first byte of the failing character, instead of the
last byte inspected. This is an incompatible change, but I hope it is small
enough not to be a problem. It makes the returned offset consistent with
pcre_exec() and pcre_dfa_exec().
7. pcretest now gives a text phrase as well as the error number when
pcre_exec() or pcre_dfa_exec() fails; if the error is a UTF-8 check
failure, the offset and reason code are output.
8. When \R was used with a maximizing quantifier it failed to skip backwards
over a \r\n pair if the subsequent match failed. Instead, it just skipped
back over a single character (\n). This seems wrong (because it treated the
two characters as a single entity when going forwards), conflicts with the
documentation that \R is equivalent to (?>\r\n|\n|...etc), and makes the
behaviour of \R* different to (\R)*, which also seems wrong. The behaviour
has been changed.
9. Some internal refactoring has changed the processing so that the handling
of the PCRE_CASELESS and PCRE_MULTILINE options is done entirely at compile
time (the PCRE_DOTALL option was changed this way some time ago: version
7.7 change 16). This has made it possible to abolish the OP_OPT op code,
which was always a bit of a fudge. It also means that there is one less
argument for the match() function, which reduces its stack requirements
slightly. This change also fixes an incompatibility with Perl: the pattern
(?i:([^b]))(?1) should not match "ab", but previously PCRE gave a match.
10. More internal refactoring has drastically reduced the number of recursive
calls to match() for possessively repeated groups such as (abc)++ when
using pcre_exec().
11. While implementing 10, a number of bugs in the handling of groups were
discovered and fixed:
(?<=(a)+) was not diagnosed as invalid (non-fixed-length lookbehind).
(a|)*(?1) gave a compile-time internal error.
((a|)+)+ did not notice that the outer group could match an empty string.
(^a|^)+ was not marked as anchored.
(.*a|.*)+ was not marked as matching at start or after a newline.
12. Yet more internal refactoring has removed another argument from the match()
function. Special calls to this function are now indicated by setting a
value in a variable in the "match data" data block.
13. Be more explicit in pcre_study() instead of relying on "default" for
opcodes that mean there is no starting character; this means that when new
ones are added and accidentally left out of pcre_study(), testing should
pick them up.
14. The -s option of pcretest has been documented for ages as being an old
synonym of -m (show memory usage). I have changed it to mean "force study
for every regex", that is, assume /S for every regex. This is similar to -i
and -d etc. It's slightly incompatible, but I'm hoping nobody is still
using it. It makes it easier to run collections of tests with and without
study enabled, and thereby test pcre_study() more easily. All the standard
tests are now run with and without -s (but some patterns can be marked as
"never study" - see 20 below).
15. When (*ACCEPT) was used in a subpattern that was called recursively, the
restoration of the capturing data to the outer values was not happening
correctly.
16. If a recursively called subpattern ended with (*ACCEPT) and matched an
empty string, and PCRE_NOTEMPTY was set, pcre_exec() thought the whole
pattern had matched an empty string, and so incorrectly returned a no
match.
17. There was optimizing code for the last branch of non-capturing parentheses,
and also for the obeyed branch of a conditional subexpression, which used
tail recursion to cut down on stack usage. Unfortunately, now that there is
the possibility of (*THEN) occurring in these branches, tail recursion is
no longer possible because the return has to be checked for (*THEN). These
two optimizations have therefore been removed. [But see 8.20/11 above.]
18. If a pattern containing \R was studied, it was assumed that \R always
matched two bytes, thus causing the minimum subject length to be
incorrectly computed because \R can also match just one byte.
19. If a pattern containing (*ACCEPT) was studied, the minimum subject length
was incorrectly computed.
20. If /S is present twice on a test pattern in pcretest input, it now
*disables* studying, thereby overriding the use of -s on the command line
(see 14 above). This is necessary for one or two tests to keep the output
identical in both cases.
21. When (*ACCEPT) was used in an assertion that matched an empty string and
PCRE_NOTEMPTY was set, PCRE applied the non-empty test to the assertion.
22. When an atomic group that contained a capturing parenthesis was
successfully matched, but the branch in which it appeared failed, the
capturing was not being forgotten if a higher numbered group was later
captured. For example, /(?>(a))b|(a)c/ when matching "ac" set capturing
group 1 to "a", when in fact it should be unset. This applied to multi-
branched capturing and non-capturing groups, repeated or not, and also to
positive assertions (capturing in negative assertions does not happen
in PCRE) and also to nested atomic groups.
23. Add the ++ qualifier feature to pcretest, to show the remainder of the
subject after a captured substring, to make it easier to tell which of a
number of identical substrings has been captured.
24. The way atomic groups are processed by pcre_exec() has been changed so that
if they are repeated, backtracking one repetition now resets captured
values correctly. For example, if ((?>(a+)b)+aabab) is matched against
"aaaabaaabaabab" the value of captured group 2 is now correctly recorded as
"aaa". Previously, it would have been "a". As part of this code
refactoring, the way recursive calls are handled has also been changed.
25. If an assertion condition captured any substrings, they were not passed
back unless some other capturing happened later. For example, if
(?(?=(a))a) was matched against "a", no capturing was returned.
26. When studying a pattern that contained subroutine calls or assertions,
the code for finding the minimum length of a possible match was handling
direct recursions such as (xxx(?1)|yyy) but not mutual recursions (where
group 1 called group 2 while simultaneously a separate group 2 called group
1). A stack overflow occurred in this case. I have fixed this by limiting
the recursion depth to 10.
27. Updated RunTest.bat in the distribution to the version supplied by Tom
Fortmann. This supports explicit test numbers on the command line, and has
argument validation and error reporting.
28. An instance of \X with an unlimited repeat could fail if at any point the
first character it looked at was a mark character.
29. Some minor code refactoring concerning Unicode properties and scripts
should reduce the stack requirement of match() slightly.
30. Added the '=' option to pcretest to check the setting of unused capturing
slots at the end of the pattern, which are documented as being -1, but are
not included in the return count.
31. If \k was not followed by a braced, angle-bracketed, or quoted name, PCRE
compiled something random. Now it gives a compile-time error (as does
Perl).
32. A *MARK encountered during the processing of a positive assertion is now
recorded and passed back (compatible with Perl).
33. If --only-matching or --colour was set on a pcregrep call whose pattern
had alternative anchored branches, the search for a second match in a line
was done as if at the line start. Thus, for example, /^01|^02/ incorrectly
matched the line "0102" twice. The same bug affected patterns that started
with a backwards assertion. For example /\b01|\b02/ also matched "0102"
twice.
34. Previously, PCRE did not allow quantification of assertions. However, Perl
does, and because of capturing effects, quantifying parenthesized
assertions may at times be useful. Quantifiers are now allowed for
parenthesized assertions.
35. A minor code tidy in pcre_compile() when checking options for \R usage.
36. \g was being checked for fancy things in a character class, when it should
just be a literal "g".
37. PCRE was rejecting [:a[:digit:]] whereas Perl was not. It seems that the
appearance of a nested POSIX class supersedes an apparent external class.
For example, [:a[:digit:]b:] matches "a", "b", ":", or a digit. Also,
unescaped square brackets may also appear as part of class names. For
example, [:a[:abc]b:] gives unknown class "[:abc]b:]". PCRE now behaves
more like Perl. (But see 8.20/1 above.)
38. PCRE was giving an error for \N with a braced quantifier such as {1,} (this
was because it thought it was \N{name}, which is not supported).
39. Add minix to OS list not supporting the -S option in pcretest.
40. PCRE tries to detect cases of infinite recursion at compile time, but it
cannot analyze patterns in sufficient detail to catch mutual recursions
such as ((?1))((?2)). There is now a runtime test that gives an error if a
subgroup is called recursively as a subpattern for a second time at the
same position in the subject string. In previous releases this might have
been caught by the recursion limit, or it might have run out of stack.
41. A pattern such as /(?(R)a+|(?R)b)/ is quite safe, as the recursion can
happen only once. PCRE was, however incorrectly giving a compile time error
"recursive call could loop indefinitely" because it cannot analyze the
pattern in sufficient detail. The compile time test no longer happens when
PCRE is compiling a conditional subpattern, but actual runaway loops are
now caught at runtime (see 40 above).
42. It seems that Perl allows any characters other than a closing parenthesis
to be part of the NAME in (*MARK:NAME) and other backtracking verbs. PCRE
has been changed to be the same.
43. Updated configure.ac to put in more quoting round AC_LANG_PROGRAM etc. so
as not to get warnings when autogen.sh is called. Also changed
AC_PROG_LIBTOOL (deprecated) to LT_INIT (the current macro).
44. To help people who use pcregrep to scan files containing exceedingly long
lines, the following changes have been made:
(a) The default value of the buffer size parameter has been increased from
8K to 20K. (The actual buffer used is three times this size.)
(b) The default can be changed by ./configure --with-pcregrep-bufsize when
PCRE is built.
(c) A --buffer-size=n option has been added to pcregrep, to allow the size
to be set at run time.
(d) Numerical values in pcregrep options can be followed by K or M, for
example --buffer-size=50K.
(e) If a line being scanned overflows pcregrep's buffer, an error is now
given and the return code is set to 2.
45. Add a pointer to the latest mark to the callout data block.
46. The pattern /.(*F)/, when applied to "abc" with PCRE_PARTIAL_HARD, gave a
partial match of an empty string instead of no match. This was specific to
the use of ".".
47. The pattern /f.*/8s, when applied to "for" with PCRE_PARTIAL_HARD, gave a
complete match instead of a partial match. This bug was dependent on both
the PCRE_UTF8 and PCRE_DOTALL options being set.
48. For a pattern such as /\babc|\bdef/ pcre_study() was failing to set up the
starting byte set, because \b was not being ignored.
Version 8.12 15-Jan-2011
------------------------
1. Fixed some typos in the markup of the man pages, and wrote a script that
checks for such things as part of the documentation building process.
2. On a big-endian 64-bit system, pcregrep did not correctly process the
--match-limit and --recursion-limit options (added for 8.11). In
particular, this made one of the standard tests fail. (The integer value
went into the wrong half of a long int.)
3. If the --colour option was given to pcregrep with -v (invert match), it
did strange things, either producing crazy output, or crashing. It should,
of course, ignore a request for colour when reporting lines that do not
match.
4. Another pcregrep bug caused similar problems if --colour was specified with
-M (multiline) and the pattern match finished with a line ending.
5. In pcregrep, when a pattern that ended with a literal newline sequence was
matched in multiline mode, the following line was shown as part of the
match. This seems wrong, so I have changed it.
6. Another pcregrep bug in multiline mode, when --colour was specified, caused
the check for further matches in the same line (so they could be coloured)
to overrun the end of the current line. If another match was found, it was
incorrectly shown (and then shown again when found in the next line).
7. If pcregrep was compiled under Windows, there was a reference to the
function pcregrep_exit() before it was defined. I am assuming this was
the cause of the "error C2371: 'pcregrep_exit' : redefinition;" that was
reported by a user. I've moved the definition above the reference.
Version 8.11 10-Dec-2010
------------------------
1. (*THEN) was not working properly if there were untried alternatives prior
to it in the current branch. For example, in ((a|b)(*THEN)(*F)|c..) it
backtracked to try for "b" instead of moving to the next alternative branch
at the same level (in this case, to look for "c"). The Perl documentation
is clear that when (*THEN) is backtracked onto, it goes to the "next
alternative in the innermost enclosing group".
2. (*COMMIT) was not overriding (*THEN), as it does in Perl. In a pattern
such as (A(*COMMIT)B(*THEN)C|D) any failure after matching A should
result in overall failure. Similarly, (*COMMIT) now overrides (*PRUNE) and
(*SKIP), (*SKIP) overrides (*PRUNE) and (*THEN), and (*PRUNE) overrides
(*THEN).
3. If \s appeared in a character class, it removed the VT character from
the class, even if it had been included by some previous item, for example
in [\x00-\xff\s]. (This was a bug related to the fact that VT is not part
of \s, but is part of the POSIX "space" class.)
4. A partial match never returns an empty string (because you can always
match an empty string at the end of the subject); however the checking for
an empty string was starting at the "start of match" point. This has been
changed to the "earliest inspected character" point, because the returned
data for a partial match starts at this character. This means that, for
example, /(?<=abc)def/ gives a partial match for the subject "abc"
(previously it gave "no match").
5. Changes have been made to the way PCRE_PARTIAL_HARD affects the matching
of $, \z, \Z, \b, and \B. If the match point is at the end of the string,
previously a full match would be given. However, setting PCRE_PARTIAL_HARD
has an implication that the given string is incomplete (because a partial
match is preferred over a full match). For this reason, these items now
give a partial match in this situation. [Aside: previously, the one case
/t\b/ matched against "cat" with PCRE_PARTIAL_HARD set did return a partial
match rather than a full match, which was wrong by the old rules, but is
now correct.]
6. There was a bug in the handling of #-introduced comments, recognized when
PCRE_EXTENDED is set, when PCRE_NEWLINE_ANY and PCRE_UTF8 were also set.
If a UTF-8 multi-byte character included the byte 0x85 (e.g. +U0445, whose
UTF-8 encoding is 0xd1,0x85), this was misinterpreted as a newline when
scanning for the end of the comment. (*Character* 0x85 is an "any" newline,
but *byte* 0x85 is not, in UTF-8 mode). This bug was present in several
places in pcre_compile().
7. Related to (6) above, when pcre_compile() was skipping #-introduced
comments when looking ahead for named forward references to subpatterns,
the only newline sequence it recognized was NL. It now handles newlines
according to the set newline convention.
8. SunOS4 doesn't have strerror() or strtoul(); pcregrep dealt with the
former, but used strtoul(), whereas pcretest avoided strtoul() but did not
cater for a lack of strerror(). These oversights have been fixed.
9. Added --match-limit and --recursion-limit to pcregrep.
10. Added two casts needed to build with Visual Studio when NO_RECURSE is set.
11. When the -o option was used, pcregrep was setting a return code of 1, even
when matches were found, and --line-buffered was not being honoured.
12. Added an optional parentheses number to the -o and --only-matching options
of pcregrep.
13. Imitating Perl's /g action for multiple matches is tricky when the pattern
can match an empty string. The code to do it in pcretest and pcredemo
needed fixing:
(a) When the newline convention was "crlf", pcretest got it wrong, skipping
only one byte after an empty string match just before CRLF (this case
just got forgotten; "any" and "anycrlf" were OK).
(b) The pcretest code also had a bug, causing it to loop forever in UTF-8
mode when an empty string match preceded an ASCII character followed by
a non-ASCII character. (The code for advancing by one character rather
than one byte was nonsense.)
(c) The pcredemo.c sample program did not have any code at all to handle
the cases when CRLF is a valid newline sequence.
14. Neither pcre_exec() nor pcre_dfa_exec() was checking that the value given
as a starting offset was within the subject string. There is now a new
error, PCRE_ERROR_BADOFFSET, which is returned if the starting offset is
negative or greater than the length of the string. In order to test this,
pcretest is extended to allow the setting of negative starting offsets.
15. In both pcre_exec() and pcre_dfa_exec() the code for checking that the
starting offset points to the beginning of a UTF-8 character was
unnecessarily clumsy. I tidied it up.
16. Added PCRE_ERROR_SHORTUTF8 to make it possible to distinguish between a
bad UTF-8 sequence and one that is incomplete when using PCRE_PARTIAL_HARD.
17. Nobody had reported that the --include_dir option, which was added in
release 7.7 should have been called --include-dir (hyphen, not underscore)
for compatibility with GNU grep. I have changed it to --include-dir, but
left --include_dir as an undocumented synonym, and the same for
--exclude-dir, though that is not available in GNU grep, at least as of
release 2.5.4.
18. At a user's suggestion, the macros GETCHAR and friends (which pick up UTF-8
characters from a string of bytes) have been redefined so as not to use
loops, in order to improve performance in some environments. At the same
time, I abstracted some of the common code into auxiliary macros to save
repetition (this should not affect the compiled code).
19. If \c was followed by a multibyte UTF-8 character, bad things happened. A
compile-time error is now given if \c is not followed by an ASCII
character, that is, a byte less than 128. (In EBCDIC mode, the code is
different, and any byte value is allowed.)
20. Recognize (*NO_START_OPT) at the start of a pattern to set the PCRE_NO_
START_OPTIMIZE option, which is now allowed at compile time - but just
passed through to pcre_exec() or pcre_dfa_exec(). This makes it available
to pcregrep and other applications that have no direct access to PCRE
options. The new /Y option in pcretest sets this option when calling
pcre_compile().
21. Change 18 of release 8.01 broke the use of named subpatterns for recursive
back references. Groups containing recursive back references were forced to
be atomic by that change, but in the case of named groups, the amount of
memory required was incorrectly computed, leading to "Failed: internal
error: code overflow". This has been fixed.
22. Some patches to pcre_stringpiece.h, pcre_stringpiece_unittest.cc, and
pcretest.c, to avoid build problems in some Borland environments.
Version 8.10 25-Jun-2010
------------------------
1. Added support for (*MARK:ARG) and for ARG additions to PRUNE, SKIP, and
THEN.
2. (*ACCEPT) was not working when inside an atomic group.
3. Inside a character class, \B is treated as a literal by default, but
faulted if PCRE_EXTRA is set. This mimics Perl's behaviour (the -w option
causes the error). The code is unchanged, but I tidied the documentation.
4. Inside a character class, PCRE always treated \R and \X as literals,
whereas Perl faults them if its -w option is set. I have changed PCRE so
that it faults them when PCRE_EXTRA is set.
5. Added support for \N, which always matches any character other than
newline. (It is the same as "." when PCRE_DOTALL is not set.)
6. When compiling pcregrep with newer versions of gcc which may have
FORTIFY_SOURCE set, several warnings "ignoring return value of 'fwrite',
declared with attribute warn_unused_result" were given. Just casting the
result to (void) does not stop the warnings; a more elaborate fudge is
needed. I've used a macro to implement this.
7. Minor change to pcretest.c to avoid a compiler warning.
8. Added four artifical Unicode properties to help with an option to make
\s etc use properties (see next item). The new properties are: Xan
(alphanumeric), Xsp (Perl space), Xps (POSIX space), and Xwd (word).
9. Added PCRE_UCP to make \b, \d, \s, \w, and certain POSIX character classes
use Unicode properties. (*UCP) at the start of a pattern can be used to set
this option. Modified pcretest to add /W to test this facility. Added
REG_UCP to make it available via the POSIX interface.
10. Added --line-buffered to pcregrep.
11. In UTF-8 mode, if a pattern that was compiled with PCRE_CASELESS was
studied, and the match started with a letter with a code point greater than
127 whose first byte was different to the first byte of the other case of
the letter, the other case of this starting letter was not recognized
(#976).
12. If a pattern that was studied started with a repeated Unicode property
test, for example, \p{Nd}+, there was the theoretical possibility of
setting up an incorrect bitmap of starting bytes, but fortunately it could
not have actually happened in practice until change 8 above was made (it
added property types that matched character-matching opcodes).
13. pcre_study() now recognizes \h, \v, and \R when constructing a bit map of
possible starting bytes for non-anchored patterns.
14. Extended the "auto-possessify" feature of pcre_compile(). It now recognizes
\R, and also a number of cases that involve Unicode properties, both
explicit and implicit when PCRE_UCP is set.
15. If a repeated Unicode property match (e.g. \p{Lu}*) was used with non-UTF-8
input, it could crash or give wrong results if characters with values
greater than 0xc0 were present in the subject string. (Detail: it assumed
UTF-8 input when processing these items.)
16. Added a lot of (int) casts to avoid compiler warnings in systems where
size_t is 64-bit (#991).
17. Added a check for running out of memory when PCRE is compiled with
--disable-stack-for-recursion (#990).
18. If the last data line in a file for pcretest does not have a newline on
the end, a newline was missing in the output.
19. The default pcre_chartables.c file recognizes only ASCII characters (values
less than 128) in its various bitmaps. However, there is a facility for
generating tables according to the current locale when PCRE is compiled. It
turns out that in some environments, 0x85 and 0xa0, which are Unicode space
characters, are recognized by isspace() and therefore were getting set in
these tables, and indeed these tables seem to approximate to ISO 8859. This
caused a problem in UTF-8 mode when pcre_study() was used to create a list
of bytes that can start a match. For \s, it was including 0x85 and 0xa0,
which of course cannot start UTF-8 characters. I have changed the code so
that only real ASCII characters (less than 128) and the correct starting
bytes for UTF-8 encodings are set for characters greater than 127 when in
UTF-8 mode. (When PCRE_UCP is set - see 9 above - the code is different
altogether.)
20. Added the /T option to pcretest so as to be able to run tests with non-
standard character tables, thus making it possible to include the tests
used for 19 above in the standard set of tests.
21. A pattern such as (?&t)(?#()(?(DEFINE)(?<t>a)) which has a forward
reference to a subpattern the other side of a comment that contains an
opening parenthesis caused either an internal compiling error, or a
reference to the wrong subpattern.
Version 8.02 19-Mar-2010
------------------------
1. The Unicode data tables have been updated to Unicode 5.2.0.
2. Added the option --libs-cpp to pcre-config, but only when C++ support is
configured.
3. Updated the licensing terms in the pcregexp.pas file, as agreed with the
original author of that file, following a query about its status.
4. On systems that do not have stdint.h (e.g. Solaris), check for and include
inttypes.h instead. This fixes a bug that was introduced by change 8.01/8.
5. A pattern such as (?&t)*+(?(DEFINE)(?<t>.)) which has a possessive
quantifier applied to a forward-referencing subroutine call, could compile
incorrect code or give the error "internal error: previously-checked
referenced subpattern not found".
6. Both MS Visual Studio and Symbian OS have problems with initializing
variables to point to external functions. For these systems, therefore,
pcre_malloc etc. are now initialized to local functions that call the
relevant global functions.
7. There were two entries missing in the vectors called coptable and poptable
in pcre_dfa_exec.c. This could lead to memory accesses outsize the vectors.
I've fixed the data, and added a kludgy way of testing at compile time that
the lengths are correct (equal to the number of opcodes).
8. Following on from 7, I added a similar kludge to check the length of the
eint vector in pcreposix.c.
9. Error texts for pcre_compile() are held as one long string to avoid too
much relocation at load time. To find a text, the string is searched,
counting zeros. There was no check for running off the end of the string,
which could happen if a new error number was added without updating the
string.
10. \K gave a compile-time error if it appeared in a lookbehind assersion.
11. \K was not working if it appeared in an atomic group or in a group that
was called as a "subroutine", or in an assertion. Perl 5.11 documents that
\K is "not well defined" if used in an assertion. PCRE now accepts it if
the assertion is positive, but not if it is negative.
12. Change 11 fortuitously reduced the size of the stack frame used in the
"match()" function of pcre_exec.c by one pointer. Forthcoming
implementation of support for (*MARK) will need an extra pointer on the
stack; I have reserved it now, so that the stack frame size does not
decrease.
13. A pattern such as (?P<L1>(?P<L2>0)|(?P>L2)(?P>L1)) in which the only other
item in branch that calls a recursion is a subroutine call - as in the
second branch in the above example - was incorrectly given the compile-
time error "recursive call could loop indefinitely" because pcre_compile()
was not correctly checking the subroutine for matching a non-empty string.
14. The checks for overrunning compiling workspace could trigger after an
overrun had occurred. This is a "should never occur" error, but it can be
triggered by pathological patterns such as hundreds of nested parentheses.
The checks now trigger 100 bytes before the end of the workspace.
15. Fix typo in configure.ac: "srtoq" should be "strtoq".
Version 8.01 19-Jan-2010
------------------------
1. If a pattern contained a conditional subpattern with only one branch (in
particular, this includes all (*DEFINE) patterns), a call to pcre_study()
computed the wrong minimum data length (which is of course zero for such
subpatterns). This could cause incorrect "no match" results.
2. For patterns such as (?i)a(?-i)b|c where an option setting at the start of
the pattern is reset in the first branch, pcre_compile() failed with
"internal error: code overflow at offset...". This happened only when
the reset was to the original external option setting. (An optimization
abstracts leading options settings into an external setting, which was the
cause of this.)
3. A pattern such as ^(?!a(*SKIP)b) where a negative assertion contained one
of the verbs SKIP, PRUNE, or COMMIT, did not work correctly. When the
assertion pattern did not match (meaning that the assertion was true), it
was incorrectly treated as false if the SKIP had been reached during the
matching. This also applied to assertions used as conditions.
4. If an item that is not supported by pcre_dfa_exec() was encountered in an
assertion subpattern, including such a pattern used as a condition,
unpredictable results occurred, instead of the error return
PCRE_ERROR_DFA_UITEM.
5. The C++ GlobalReplace function was not working like Perl for the special
situation when an empty string is matched. It now does the fancy magic
stuff that is necessary.
6. In pcre_internal.h, obsolete includes to setjmp.h and stdarg.h have been
removed. (These were left over from very, very early versions of PCRE.)
7. Some cosmetic changes to the code to make life easier when compiling it
as part of something else:
(a) Change DEBUG to PCRE_DEBUG.
(b) In pcre_compile(), rename the member of the "branch_chain" structure
called "current" as "current_branch", to prevent a collision with the
Linux macro when compiled as a kernel module.
(c) In pcre_study(), rename the function set_bit() as set_table_bit(), to
prevent a collision with the Linux macro when compiled as a kernel
module.
8. In pcre_compile() there are some checks for integer overflows that used to
cast potentially large values to (double). This has been changed to that
when building, a check for int64_t is made, and if it is found, it is used
instead, thus avoiding the use of floating point arithmetic. (There is no
other use of FP in PCRE.) If int64_t is not found, the fallback is to
double.
9. Added two casts to avoid signed/unsigned warnings from VS Studio Express
2005 (difference between two addresses compared to an unsigned value).
10. Change the standard AC_CHECK_LIB test for libbz2 in configure.ac to a
custom one, because of the following reported problem in Windows:
- libbz2 uses the Pascal calling convention (WINAPI) for the functions
under Win32.
- The standard autoconf AC_CHECK_LIB fails to include "bzlib.h",
therefore missing the function definition.
- The compiler thus generates a "C" signature for the test function.
- The linker fails to find the "C" function.
- PCRE fails to configure if asked to do so against libbz2.
11. When running libtoolize from libtool-2.2.6b as part of autogen.sh, these
messages were output:
Consider adding `AC_CONFIG_MACRO_DIR([m4])' to configure.ac and
rerunning libtoolize, to keep the correct libtool macros in-tree.
Consider adding `-I m4' to ACLOCAL_AMFLAGS in Makefile.am.
I have done both of these things.
12. Although pcre_dfa_exec() does not use nearly as much stack as pcre_exec()
most of the time, it *can* run out if it is given a pattern that contains a
runaway infinite recursion. I updated the discussion in the pcrestack man
page.
13. Now that we have gone to the x.xx style of version numbers, the minor
version may start with zero. Using 08 or 09 is a bad idea because users
might check the value of PCRE_MINOR in their code, and 08 or 09 may be
interpreted as invalid octal numbers. I've updated the previous comment in
configure.ac, and also added a check that gives an error if 08 or 09 are
used.
14. Change 8.00/11 was not quite complete: code had been accidentally omitted,
causing partial matching to fail when the end of the subject matched \W
in a UTF-8 pattern where \W was quantified with a minimum of 3.
15. There were some discrepancies between the declarations in pcre_internal.h
of _pcre_is_newline(), _pcre_was_newline(), and _pcre_valid_utf8() and
their definitions. The declarations used "const uschar *" and the
definitions used USPTR. Even though USPTR is normally defined as "const
unsigned char *" (and uschar is typedeffed as "unsigned char"), it was
reported that: "This difference in casting confuses some C++ compilers, for
example, SunCC recognizes above declarations as different functions and
generates broken code for hbpcre." I have changed the declarations to use
USPTR.
16. GNU libtool is named differently on some systems. The autogen.sh script now
tries several variants such as glibtoolize (MacOSX) and libtoolize1x
(FreeBSD).
17. Applied Craig's patch that fixes an HP aCC compile error in pcre 8.00
(strtoXX undefined when compiling pcrecpp.cc). The patch contains this
comment: "Figure out how to create a longlong from a string: strtoll and
equivalent. It's not enough to call AC_CHECK_FUNCS: hpux has a strtoll, for
instance, but it only takes 2 args instead of 3!"
18. A subtle bug concerned with back references has been fixed by a change of
specification, with a corresponding code fix. A pattern such as
^(xa|=?\1a)+$ which contains a back reference inside the group to which it
refers, was giving matches when it shouldn't. For example, xa=xaaa would
match that pattern. Interestingly, Perl (at least up to 5.11.3) has the
same bug. Such groups have to be quantified to be useful, or contained
inside another quantified group. (If there's no repetition, the reference
can never match.) The problem arises because, having left the group and
moved on to the rest of the pattern, a later failure that backtracks into
the group uses the captured value from the final iteration of the group
rather than the correct earlier one. I have fixed this in PCRE by forcing
any group that contains a reference to itself to be an atomic group; that
is, there cannot be any backtracking into it once it has completed. This is
similar to recursive and subroutine calls.
Version 8.00 19-Oct-09
----------------------
1. The table for translating pcre_compile() error codes into POSIX error codes
was out-of-date, and there was no check on the pcre_compile() error code
being within the table. This could lead to an OK return being given in
error.
2. Changed the call to open a subject file in pcregrep from fopen(pathname,
"r") to fopen(pathname, "rb"), which fixed a problem with some of the tests
in a Windows environment.
3. The pcregrep --count option prints the count for each file even when it is
zero, as does GNU grep. However, pcregrep was also printing all files when
--files-with-matches was added. Now, when both options are given, it prints
counts only for those files that have at least one match. (GNU grep just
prints the file name in this circumstance, but including the count seems
more useful - otherwise, why use --count?) Also ensured that the
combination -clh just lists non-zero counts, with no names.
4. The long form of the pcregrep -F option was incorrectly implemented as
--fixed_strings instead of --fixed-strings. This is an incompatible change,
but it seems right to fix it, and I didn't think it was worth preserving
the old behaviour.
5. The command line items --regex=pattern and --regexp=pattern were not
recognized by pcregrep, which required --regex pattern or --regexp pattern
(with a space rather than an '='). The man page documented the '=' forms,
which are compatible with GNU grep; these now work.
6. No libpcreposix.pc file was created for pkg-config; there was just
libpcre.pc and libpcrecpp.pc. The omission has been rectified.
7. Added #ifndef SUPPORT_UCP into the pcre_ucd.c module, to reduce its size
when UCP support is not needed, by modifying the Python script that
generates it from Unicode data files. This should not matter if the module
is correctly used as a library, but I received one complaint about 50K of
unwanted data. My guess is that the person linked everything into his
program rather than using a library. Anyway, it does no harm.
8. A pattern such as /\x{123}{2,2}+/8 was incorrectly compiled; the trigger
was a minimum greater than 1 for a wide character in a possessive
repetition. The same bug could also affect patterns like /(\x{ff}{0,2})*/8
which had an unlimited repeat of a nested, fixed maximum repeat of a wide
character. Chaos in the form of incorrect output or a compiling loop could
result.
9. The restrictions on what a pattern can contain when partial matching is
requested for pcre_exec() have been removed. All patterns can now be
partially matched by this function. In addition, if there are at least two
slots in the offset vector, the offset of the earliest inspected character
for the match and the offset of the end of the subject are set in them when
PCRE_ERROR_PARTIAL is returned.
10. Partial matching has been split into two forms: PCRE_PARTIAL_SOFT, which is
synonymous with PCRE_PARTIAL, for backwards compatibility, and
PCRE_PARTIAL_HARD, which causes a partial match to supersede a full match,
and may be more useful for multi-segment matching.
11. Partial matching with pcre_exec() is now more intuitive. A partial match
used to be given if ever the end of the subject was reached; now it is
given only if matching could not proceed because another character was
needed. This makes a difference in some odd cases such as Z(*FAIL) with the
string "Z", which now yields "no match" instead of "partial match". In the
case of pcre_dfa_exec(), "no match" is given if every matching path for the
final character ended with (*FAIL).
12. Restarting a match using pcre_dfa_exec() after a partial match did not work
if the pattern had a "must contain" character that was already found in the
earlier partial match, unless partial matching was again requested. For
example, with the pattern /dog.(body)?/, the "must contain" character is
"g". If the first part-match was for the string "dog", restarting with
"sbody" failed. This bug has been fixed.
13. The string returned by pcre_dfa_exec() after a partial match has been
changed so that it starts at the first inspected character rather than the
first character of the match. This makes a difference only if the pattern
starts with a lookbehind assertion or \b or \B (\K is not supported by
pcre_dfa_exec()). It's an incompatible change, but it makes the two
matching functions compatible, and I think it's the right thing to do.
14. Added a pcredemo man page, created automatically from the pcredemo.c file,
so that the demonstration program is easily available in environments where
PCRE has not been installed from source.
15. Arranged to add -DPCRE_STATIC to cflags in libpcre.pc, libpcreposix.cp,
libpcrecpp.pc and pcre-config when PCRE is not compiled as a shared
library.
16. Added REG_UNGREEDY to the pcreposix interface, at the request of a user.
It maps to PCRE_UNGREEDY. It is not, of course, POSIX-compatible, but it
is not the first non-POSIX option to be added. Clearly some people find
these options useful.
17. If a caller to the POSIX matching function regexec() passes a non-zero
value for nmatch with a NULL value for pmatch, the value of
nmatch is forced to zero.
18. RunGrepTest did not have a test for the availability of the -u option of
the diff command, as RunTest does. It now checks in the same way as
RunTest, and also checks for the -b option.
19. If an odd number of negated classes containing just a single character
interposed, within parentheses, between a forward reference to a named
subpattern and the definition of the subpattern, compilation crashed with
an internal error, complaining that it could not find the referenced
subpattern. An example of a crashing pattern is /(?&A)(([^m])(?<A>))/.
[The bug was that it was starting one character too far in when skipping
over the character class, thus treating the ] as data rather than
terminating the class. This meant it could skip too much.]
20. Added PCRE_NOTEMPTY_ATSTART in order to be able to correctly implement the
/g option in pcretest when the pattern contains \K, which makes it possible
to have an empty string match not at the start, even when the pattern is
anchored. Updated pcretest and pcredemo to use this option.
21. If the maximum number of capturing subpatterns in a recursion was greater
than the maximum at the outer level, the higher number was returned, but
with unset values at the outer level. The correct (outer level) value is
now given.
22. If (*ACCEPT) appeared inside capturing parentheses, previous releases of
PCRE did not set those parentheses (unlike Perl). I have now found a way to
make it do so. The string so far is captured, making this feature
compatible with Perl.
23. The tests have been re-organized, adding tests 11 and 12, to make it
possible to check the Perl 5.10 features against Perl 5.10.
24. Perl 5.10 allows subroutine calls in lookbehinds, as long as the subroutine
pattern matches a fixed length string. PCRE did not allow this; now it
does. Neither allows recursion.
25. I finally figured out how to implement a request to provide the minimum
length of subject string that was needed in order to match a given pattern.
(It was back references and recursion that I had previously got hung up
on.) This code has now been added to pcre_study(); it finds a lower bound
to the length of subject needed. It is not necessarily the greatest lower
bound, but using it to avoid searching strings that are too short does give
some useful speed-ups. The value is available to calling programs via
pcre_fullinfo().
26. While implementing 25, I discovered to my embarrassment that pcretest had
not been passing the result of pcre_study() to pcre_dfa_exec(), so the
study optimizations had never been tested with that matching function.
Oops. What is worse, even when it was passed study data, there was a bug in
pcre_dfa_exec() that meant it never actually used it. Double oops. There
were also very few tests of studied patterns with pcre_dfa_exec().
27. If (?| is used to create subpatterns with duplicate numbers, they are now
allowed to have the same name, even if PCRE_DUPNAMES is not set. However,
on the other side of the coin, they are no longer allowed to have different
names, because these cannot be distinguished in PCRE, and this has caused
confusion. (This is a difference from Perl.)
28. When duplicate subpattern names are present (necessarily with different
numbers, as required by 27 above), and a test is made by name in a
conditional pattern, either for a subpattern having been matched, or for
recursion in such a pattern, all the associated numbered subpatterns are
tested, and the overall condition is true if the condition is true for any
one of them. This is the way Perl works, and is also more like the way
testing by number works.
Version 7.9 11-Apr-09
---------------------
1. When building with support for bzlib/zlib (pcregrep) and/or readline
(pcretest), all targets were linked against these libraries. This included
libpcre, libpcreposix, and libpcrecpp, even though they do not use these
libraries. This caused unwanted dependencies to be created. This problem
has been fixed, and now only pcregrep is linked with bzlib/zlib and only
pcretest is linked with readline.
2. The "typedef int BOOL" in pcre_internal.h that was included inside the
"#ifndef FALSE" condition by an earlier change (probably 7.8/18) has been
moved outside it again, because FALSE and TRUE are already defined in AIX,
but BOOL is not.
3. The pcre_config() function was treating the PCRE_MATCH_LIMIT and
PCRE_MATCH_LIMIT_RECURSION values as ints, when they should be long ints.
4. The pcregrep documentation said spaces were inserted as well as colons (or
hyphens) following file names and line numbers when outputting matching
lines. This is not true; no spaces are inserted. I have also clarified the
wording for the --colour (or --color) option.
5. In pcregrep, when --colour was used with -o, the list of matching strings
was not coloured; this is different to GNU grep, so I have changed it to be
the same.
6. When --colo(u)r was used in pcregrep, only the first matching substring in
each matching line was coloured. Now it goes on to look for further matches
of any of the test patterns, which is the same behaviour as GNU grep.
7. A pattern that could match an empty string could cause pcregrep to loop; it
doesn't make sense to accept an empty string match in pcregrep, so I have
locked it out (using PCRE's PCRE_NOTEMPTY option). By experiment, this
seems to be how GNU grep behaves. [But see later change 40 for release
8.33.]
8. The pattern (?(?=.*b)b|^) was incorrectly compiled as "match must be at
start or after a newline", because the conditional assertion was not being
correctly handled. The rule now is that both the assertion and what follows
in the first alternative must satisfy the test.
9. If auto-callout was enabled in a pattern with a conditional group whose
condition was an assertion, PCRE could crash during matching, both with
pcre_exec() and pcre_dfa_exec().
10. The PCRE_DOLLAR_ENDONLY option was not working when pcre_dfa_exec() was
used for matching.
11. Unicode property support in character classes was not working for
characters (bytes) greater than 127 when not in UTF-8 mode.
12. Added the -M command line option to pcretest.
14. Added the non-standard REG_NOTEMPTY option to the POSIX interface.
15. Added the PCRE_NO_START_OPTIMIZE match-time option.
16. Added comments and documentation about mis-use of no_arg in the C++
wrapper.
17. Implemented support for UTF-8 encoding in EBCDIC environments, a patch
from Martin Jerabek that uses macro names for all relevant character and
string constants.
18. Added to pcre_internal.h two configuration checks: (a) If both EBCDIC and
SUPPORT_UTF8 are set, give an error; (b) If SUPPORT_UCP is set without
SUPPORT_UTF8, define SUPPORT_UTF8. The "configure" script handles both of
these, but not everybody uses configure.
19. A conditional group that had only one branch was not being correctly
recognized as an item that could match an empty string. This meant that an
enclosing group might also not be so recognized, causing infinite looping
(and probably a segfault) for patterns such as ^"((?(?=[a])[^"])|b)*"$
with the subject "ab", where knowledge that the repeated group can match
nothing is needed in order to break the loop.
20. If a pattern that was compiled with callouts was matched using pcre_dfa_
exec(), but without supplying a callout function, matching went wrong.
21. If PCRE_ERROR_MATCHLIMIT occurred during a recursion, there was a memory
leak if the size of the offset vector was greater than 30. When the vector
is smaller, the saved offsets during recursion go onto a local stack
vector, but for larger vectors malloc() is used. It was failing to free
when the recursion yielded PCRE_ERROR_MATCH_LIMIT (or any other "abnormal"
error, in fact).
22. There was a missing #ifdef SUPPORT_UTF8 round one of the variables in the
heapframe that is used only when UTF-8 support is enabled. This caused no
problem, but was untidy.
23. Steven Van Ingelgem's patch to CMakeLists.txt to change the name
CMAKE_BINARY_DIR to PROJECT_BINARY_DIR so that it works when PCRE is
included within another project.
24. Steven Van Ingelgem's patches to add more options to the CMake support,
slightly modified by me:
(a) PCRE_BUILD_TESTS can be set OFF not to build the tests, including
not building pcregrep.
(b) PCRE_BUILD_PCREGREP can be see OFF not to build pcregrep, but only
if PCRE_BUILD_TESTS is also set OFF, because the tests use pcregrep.
25. Forward references, both numeric and by name, in patterns that made use of
duplicate group numbers, could behave incorrectly or give incorrect errors,
because when scanning forward to find the reference group, PCRE was not
taking into account the duplicate group numbers. A pattern such as
^X(?3)(a)(?|(b)|(q))(Y) is an example.
26. Changed a few more instances of "const unsigned char *" to USPTR, making
the feature of a custom pointer more persuasive (as requested by a user).
27. Wrapped the definitions of fileno and isatty for Windows, which appear in
pcretest.c, inside #ifndefs, because it seems they are sometimes already
pre-defined.
28. Added support for (*UTF8) at the start of a pattern.
29. Arrange for flags added by the "release type" setting in CMake to be shown
in the configuration summary.
Version 7.8 05-Sep-08
---------------------
1. Replaced UCP searching code with optimized version as implemented for Ad
Muncher (http://www.admuncher.com/) by Peter Kankowski. This uses a two-
stage table and inline lookup instead of a function, giving speed ups of 2
to 5 times on some simple patterns that I tested. Permission was given to
distribute the MultiStage2.py script that generates the tables (it's not in
the tarball, but is in the Subversion repository).
2. Updated the Unicode datatables to Unicode 5.1.0. This adds yet more
scripts.
3. Change 12 for 7.7 introduced a bug in pcre_study() when a pattern contained
a group with a zero qualifier. The result of the study could be incorrect,
or the function might crash, depending on the pattern.
4. Caseless matching was not working for non-ASCII characters in back
references. For example, /(\x{de})\1/8i was not matching \x{de}\x{fe}.
It now works when Unicode Property Support is available.
5. In pcretest, an escape such as \x{de} in the data was always generating
a UTF-8 string, even in non-UTF-8 mode. Now it generates a single byte in
non-UTF-8 mode. If the value is greater than 255, it gives a warning about
truncation.
6. Minor bugfix in pcrecpp.cc (change "" == ... to NULL == ...).
7. Added two (int) casts to pcregrep when printing the difference of two
pointers, in case they are 64-bit values.
8. Added comments about Mac OS X stack usage to the pcrestack man page and to
test 2 if it fails.
9. Added PCRE_CALL_CONVENTION just before the names of all exported functions,
and a #define of that name to empty if it is not externally set. This is to
allow users of MSVC to set it if necessary.
10. The PCRE_EXP_DEFN macro which precedes exported functions was missing from
the convenience functions in the pcre_get.c source file.
11. An option change at the start of a pattern that had top-level alternatives
could cause overwriting and/or a crash. This command provoked a crash in
some environments:
printf "/(?i)[\xc3\xa9\xc3\xbd]|[\xc3\xa9\xc3\xbdA]/8\n" | pcretest
This potential security problem was recorded as CVE-2008-2371.
12. For a pattern where the match had to start at the beginning or immediately
after a newline (e.g /.*anything/ without the DOTALL flag), pcre_exec() and
pcre_dfa_exec() could read past the end of the passed subject if there was
no match. To help with detecting such bugs (e.g. with valgrind), I modified
pcretest so that it places the subject at the end of its malloc-ed buffer.
13. The change to pcretest in 12 above threw up a couple more cases when pcre_
exec() might read past the end of the data buffer in UTF-8 mode.
14. A similar bug to 7.3/2 existed when the PCRE_FIRSTLINE option was set and
the data contained the byte 0x85 as part of a UTF-8 character within its
first line. This applied both to normal and DFA matching.
15. Lazy qualifiers were not working in some cases in UTF-8 mode. For example,
/^[^d]*?$/8 failed to match "abc".
16. Added a missing copyright notice to pcrecpp_internal.h.
17. Make it more clear in the documentation that values returned from
pcre_exec() in ovector are byte offsets, not character counts.
18. Tidied a few places to stop certain compilers from issuing warnings.
19. Updated the Virtual Pascal + BCC files to compile the latest v7.7, as
supplied by Stefan Weber. I made a further small update for 7.8 because
there is a change of source arrangements: the pcre_searchfuncs.c module is
replaced by pcre_ucd.c.
Version 7.7 07-May-08
---------------------
1. Applied Craig's patch to sort out a long long problem: "If we can't convert
a string to a long long, pretend we don't even have a long long." This is
done by checking for the strtoq, strtoll, and _strtoi64 functions.
2. Applied Craig's patch to pcrecpp.cc to restore ABI compatibility with
pre-7.6 versions, which defined a global no_arg variable instead of putting
it in the RE class. (See also #8 below.)
3. Remove a line of dead code, identified by coverity and reported by Nuno
Lopes.
4. Fixed two related pcregrep bugs involving -r with --include or --exclude:
(1) The include/exclude patterns were being applied to the whole pathnames
of files, instead of just to the final components.
(2) If there was more than one level of directory, the subdirectories were
skipped unless they satisfied the include/exclude conditions. This is
inconsistent with GNU grep (and could even be seen as contrary to the
pcregrep specification - which I improved to make it absolutely clear).
The action now is always to scan all levels of directory, and just
apply the include/exclude patterns to regular files.
5. Added the --include_dir and --exclude_dir patterns to pcregrep, and used
--exclude_dir in the tests to avoid scanning .svn directories.
6. Applied Craig's patch to the QuoteMeta function so that it escapes the
NUL character as backslash + 0 rather than backslash + NUL, because PCRE
doesn't support NULs in patterns.
7. Added some missing "const"s to declarations of static tables in
pcre_compile.c and pcre_dfa_exec.c.
8. Applied Craig's patch to pcrecpp.cc to fix a problem in OS X that was
caused by fix #2 above. (Subsequently also a second patch to fix the
first patch. And a third patch - this was a messy problem.)
9. Applied Craig's patch to remove the use of push_back().
10. Applied Alan Lehotsky's patch to add REG_STARTEND support to the POSIX
matching function regexec().
11. Added support for the Oniguruma syntax \g<name>, \g<n>, \g'name', \g'n',
which, however, unlike Perl's \g{...}, are subroutine calls, not back
references. PCRE supports relative numbers with this syntax (I don't think
Oniguruma does).
12. Previously, a group with a zero repeat such as (...){0} was completely
omitted from the compiled regex. However, this means that if the group
was called as a subroutine from elsewhere in the pattern, things went wrong
(an internal error was given). Such groups are now left in the compiled
pattern, with a new opcode that causes them to be skipped at execution
time.
13. Added the PCRE_JAVASCRIPT_COMPAT option. This makes the following changes
to the way PCRE behaves:
(a) A lone ] character is dis-allowed (Perl treats it as data).
(b) A back reference to an unmatched subpattern matches an empty string
(Perl fails the current match path).
(c) A data ] in a character class must be notated as \] because if the
first data character in a class is ], it defines an empty class. (In
Perl it is not possible to have an empty class.) The empty class []
never matches; it forces failure and is equivalent to (*FAIL) or (?!).
The negative empty class [^] matches any one character, independently
of the DOTALL setting.
14. A pattern such as /(?2)[]a()b](abc)/ which had a forward reference to a
non-existent subpattern following a character class starting with ']' and
containing () gave an internal compiling error instead of "reference to
non-existent subpattern". Fortunately, when the pattern did exist, the
compiled code was correct. (When scanning forwards to check for the
existence of the subpattern, it was treating the data ']' as terminating
the class, so got the count wrong. When actually compiling, the reference
was subsequently set up correctly.)
15. The "always fail" assertion (?!) is optimzed to (*FAIL) by pcre_compile;
it was being rejected as not supported by pcre_dfa_exec(), even though
other assertions are supported. I have made pcre_dfa_exec() support
(*FAIL).
16. The implementation of 13c above involved the invention of a new opcode,
OP_ALLANY, which is like OP_ANY but doesn't check the /s flag. Since /s
cannot be changed at match time, I realized I could make a small
improvement to matching performance by compiling OP_ALLANY instead of
OP_ANY for "." when DOTALL was set, and then removing the runtime tests
on the OP_ANY path.
17. Compiling pcretest on Windows with readline support failed without the
following two fixes: (1) Make the unistd.h include conditional on
HAVE_UNISTD_H; (2) #define isatty and fileno as _isatty and _fileno.
18. Changed CMakeLists.txt and cmake/FindReadline.cmake to arrange for the
ncurses library to be included for pcretest when ReadLine support is
requested, but also to allow for it to be overridden. This patch came from
Daniel Bergström.
19. There was a typo in the file ucpinternal.h where f0_rangeflag was defined
as 0x00f00000 instead of 0x00800000. Luckily, this would not have caused
any errors with the current Unicode tables. Thanks to Peter Kankowski for
spotting this.
Version 7.6 28-Jan-08
---------------------
1. A character class containing a very large number of characters with
codepoints greater than 255 (in UTF-8 mode, of course) caused a buffer
overflow.
2. Patch to cut out the "long long" test in pcrecpp_unittest when
HAVE_LONG_LONG is not defined.
3. Applied Christian Ehrlicher's patch to update the CMake build files to
bring them up to date and include new features. This patch includes:
- Fixed PH's badly added libz and libbz2 support.
- Fixed a problem with static linking.
- Added pcredemo. [But later removed - see 7 below.]
- Fixed dftables problem and added an option.
- Added a number of HAVE_XXX tests, including HAVE_WINDOWS_H and
HAVE_LONG_LONG.
- Added readline support for pcretest.
- Added an listing of the option settings after cmake has run.
4. A user submitted a patch to Makefile that makes it easy to create
"pcre.dll" under mingw when using Configure/Make. I added stuff to
Makefile.am that cause it to include this special target, without
affecting anything else. Note that the same mingw target plus all
the other distribution libraries and programs are now supported
when configuring with CMake (see 6 below) instead of with
Configure/Make.
5. Applied Craig's patch that moves no_arg into the RE class in the C++ code.
This is an attempt to solve the reported problem "pcrecpp::no_arg is not
exported in the Windows port". It has not yet been confirmed that the patch
solves the problem, but it does no harm.
6. Applied Sheri's patch to CMakeLists.txt to add NON_STANDARD_LIB_PREFIX and
NON_STANDARD_LIB_SUFFIX for dll names built with mingw when configured
with CMake, and also correct the comment about stack recursion.
7. Remove the automatic building of pcredemo from the ./configure system and
from CMakeLists.txt. The whole idea of pcredemo.c is that it is an example
of a program that users should build themselves after PCRE is installed, so
building it automatically is not really right. What is more, it gave
trouble in some build environments.
8. Further tidies to CMakeLists.txt from Sheri and Christian.
Version 7.5 10-Jan-08
---------------------
1. Applied a patch from Craig: "This patch makes it possible to 'ignore'
values in parens when parsing an RE using the C++ wrapper."
2. Negative specials like \S did not work in character classes in UTF-8 mode.
Characters greater than 255 were excluded from the class instead of being
included.
3. The same bug as (2) above applied to negated POSIX classes such as
[:^space:].
4. PCRECPP_STATIC was referenced in pcrecpp_internal.h, but nowhere was it
defined or documented. It seems to have been a typo for PCRE_STATIC, so
I have changed it.
5. The construct (?&) was not diagnosed as a syntax error (it referenced the
first named subpattern) and a construct such as (?&a) would reference the
first named subpattern whose name started with "a" (in other words, the
length check was missing). Both these problems are fixed. "Subpattern name
expected" is now given for (?&) (a zero-length name), and this patch also
makes it give the same error for \k'' (previously it complained that that
was a reference to a non-existent subpattern).
6. The erroneous patterns (?+-a) and (?-+a) give different error messages;
this is right because (?- can be followed by option settings as well as by
digits. I have, however, made the messages clearer.
7. Patterns such as (?(1)a|b) (a pattern that contains fewer subpatterns
than the number used in the conditional) now cause a compile-time error.
This is actually not compatible with Perl, which accepts such patterns, but
treats the conditional as always being FALSE (as PCRE used to), but it
seems to me that giving a diagnostic is better.
8. Change "alphameric" to the more common word "alphanumeric" in comments
and messages.
9. Fix two occurrences of "backslash" in comments that should have been
"backspace".
10. Remove two redundant lines of code that can never be obeyed (their function
was moved elsewhere).
11. The program that makes PCRE's Unicode character property table had a bug
which caused it to generate incorrect table entries for sequences of
characters that have the same character type, but are in different scripts.
It amalgamated them into a single range, with the script of the first of
them. In other words, some characters were in the wrong script. There were
thirteen such cases, affecting characters in the following ranges:
U+002b0 - U+002c1
U+0060c - U+0060d
U+0061e - U+00612
U+0064b - U+0065e
U+0074d - U+0076d
U+01800 - U+01805
U+01d00 - U+01d77
U+01d9b - U+01dbf
U+0200b - U+0200f
U+030fc - U+030fe
U+03260 - U+0327f
U+0fb46 - U+0fbb1
U+10450 - U+1049d
12. The -o option (show only the matching part of a line) for pcregrep was not
compatible with GNU grep in that, if there was more than one match in a
line, it showed only the first of them. It now behaves in the same way as
GNU grep.
13. If the -o and -v options were combined for pcregrep, it printed a blank
line for every non-matching line. GNU grep prints nothing, and pcregrep now
does the same. The return code can be used to tell if there were any
non-matching lines.
14. Added --file-offsets and --line-offsets to pcregrep.
15. The pattern (?=something)(?R) was not being diagnosed as a potentially
infinitely looping recursion. The bug was that positive lookaheads were not
being skipped when checking for a possible empty match (negative lookaheads
and both kinds of lookbehind were skipped).
16. Fixed two typos in the Windows-only code in pcregrep.c, and moved the
inclusion of <windows.h> to before rather than after the definition of
INVALID_FILE_ATTRIBUTES (patch from David Byron).
17. Specifying a possessive quantifier with a specific limit for a Unicode
character property caused pcre_compile() to compile bad code, which led at
runtime to PCRE_ERROR_INTERNAL (-14). Examples of patterns that caused this
are: /\p{Zl}{2,3}+/8 and /\p{Cc}{2}+/8. It was the possessive "+" that
caused the error; without that there was no problem.
18. Added --enable-pcregrep-libz and --enable-pcregrep-libbz2.
19. Added --enable-pcretest-libreadline.
20. In pcrecpp.cc, the variable 'count' was incremented twice in
RE::GlobalReplace(). As a result, the number of replacements returned was
double what it should be. I removed one of the increments, but Craig sent a
later patch that removed the other one (the right fix) and added unit tests
that check the return values (which was not done before).
21. Several CMake things:
(1) Arranged that, when cmake is used on Unix, the libraries end up with
the names libpcre and libpcreposix, not just pcre and pcreposix.
(2) The above change means that pcretest and pcregrep are now correctly
linked with the newly-built libraries, not previously installed ones.
(3) Added PCRE_SUPPORT_LIBREADLINE, PCRE_SUPPORT_LIBZ, PCRE_SUPPORT_LIBBZ2.
22. In UTF-8 mode, with newline set to "any", a pattern such as .*a.*=.b.*
crashed when matching a string such as a\x{2029}b (note that \x{2029} is a
UTF-8 newline character). The key issue is that the pattern starts .*;
this means that the match must be either at the beginning, or after a
newline. The bug was in the code for advancing after a failed match and
checking that the new position followed a newline. It was not taking
account of UTF-8 characters correctly.
23. PCRE was behaving differently from Perl in the way it recognized POSIX
character classes. PCRE was not treating the sequence [:...:] as a
character class unless the ... were all letters. Perl, however, seems to
allow any characters between [: and :], though of course it rejects as
unknown any "names" that contain non-letters, because all the known class
names consist only of letters. Thus, Perl gives an error for [[:1234:]],
for example, whereas PCRE did not - it did not recognize a POSIX character
class. This seemed a bit dangerous, so the code has been changed to be
closer to Perl. The behaviour is not identical to Perl, because PCRE will
diagnose an unknown class for, for example, [[:l\ower:]] where Perl will
treat it as [[:lower:]]. However, PCRE does now give "unknown" errors where
Perl does, and where it didn't before.
24. Rewrite so as to remove the single use of %n from pcregrep because in some
Windows environments %n is disabled by default.
Version 7.4 21-Sep-07
---------------------
1. Change 7.3/28 was implemented for classes by looking at the bitmap. This
means that a class such as [\s] counted as "explicit reference to CR or
LF". That isn't really right - the whole point of the change was to try to
help when there was an actual mention of one of the two characters. So now
the change happens only if \r or \n (or a literal CR or LF) character is
encountered.
2. The 32-bit options word was also used for 6 internal flags, but the numbers
of both had grown to the point where there were only 3 bits left.
Fortunately, there was spare space in the data structure, and so I have
moved the internal flags into a new 16-bit field to free up more option
bits.
3. The appearance of (?J) at the start of a pattern set the DUPNAMES option,
but did not set the internal JCHANGED flag - either of these is enough to
control the way the "get" function works - but the PCRE_INFO_JCHANGED
facility is supposed to tell if (?J) was ever used, so now (?J) at the
start sets both bits.
4. Added options (at build time, compile time, exec time) to change \R from
matching any Unicode line ending sequence to just matching CR, LF, or CRLF.
5. doc/pcresyntax.html was missing from the distribution.
6. Put back the definition of PCRE_ERROR_NULLWSLIMIT, for backward
compatibility, even though it is no longer used.
7. Added macro for snprintf to pcrecpp_unittest.cc and also for strtoll and
strtoull to pcrecpp.cc to select the available functions in WIN32 when the
windows.h file is present (where different names are used). [This was
reversed later after testing - see 16 below.]
8. Changed all #include <config.h> to #include "config.h". There were also
some further <pcre.h> cases that I changed to "pcre.h".
9. When pcregrep was used with the --colour option, it missed the line ending
sequence off the lines that it output.
10. It was pointed out to me that arrays of string pointers cause lots of
relocations when a shared library is dynamically loaded. A technique of
using a single long string with a table of offsets can drastically reduce
these. I have refactored PCRE in four places to do this. The result is
dramatic:
Originally: 290
After changing UCP table: 187
After changing error message table: 43
After changing table of "verbs" 36
After changing table of Posix names 22
Thanks to the folks working on Gregex for glib for this insight.
11. --disable-stack-for-recursion caused compiling to fail unless -enable-
unicode-properties was also set.
12. Updated the tests so that they work when \R is defaulted to ANYCRLF.
13. Added checks for ANY and ANYCRLF to pcrecpp.cc where it previously
checked only for CRLF.
14. Added casts to pcretest.c to avoid compiler warnings.
15. Added Craig's patch to various pcrecpp modules to avoid compiler warnings.
16. Added Craig's patch to remove the WINDOWS_H tests, that were not working,
and instead check for _strtoi64 explicitly, and avoid the use of snprintf()
entirely. This removes changes made in 7 above.
17. The CMake files have been updated, and there is now more information about
building with CMake in the NON-UNIX-USE document.
Version 7.3 28-Aug-07
---------------------
1. In the rejigging of the build system that eventually resulted in 7.1, the
line "#include <pcre.h>" was included in pcre_internal.h. The use of angle
brackets there is not right, since it causes compilers to look for an
installed pcre.h, not the version that is in the source that is being
compiled (which of course may be different). I have changed it back to:
#include "pcre.h"
I have a vague recollection that the change was concerned with compiling in
different directories, but in the new build system, that is taken care of
by the VPATH setting the Makefile.
2. The pattern .*$ when run in not-DOTALL UTF-8 mode with newline=any failed
when the subject happened to end in the byte 0x85 (e.g. if the last
character was \x{1ec5}). *Character* 0x85 is one of the "any" newline
characters but of course it shouldn't be taken as a newline when it is part
of another character. The bug was that, for an unlimited repeat of . in
not-DOTALL UTF-8 mode, PCRE was advancing by bytes rather than by
characters when looking for a newline.
3. A small performance improvement in the DOTALL UTF-8 mode .* case.
4. Debugging: adjusted the names of opcodes for different kinds of parentheses
in debug output.
5. Arrange to use "%I64d" instead of "%lld" and "%I64u" instead of "%llu" for
long printing in the pcrecpp unittest when running under MinGW.
6. ESC_K was left out of the EBCDIC table.
7. Change 7.0/38 introduced a new limit on the number of nested non-capturing
parentheses; I made it 1000, which seemed large enough. Unfortunately, the
limit also applies to "virtual nesting" when a pattern is recursive, and in
this case 1000 isn't so big. I have been able to remove this limit at the
expense of backing off one optimization in certain circumstances. Normally,
when pcre_exec() would call its internal match() function recursively and
immediately return the result unconditionally, it uses a "tail recursion"
feature to save stack. However, when a subpattern that can match an empty
string has an unlimited repetition quantifier, it no longer makes this
optimization. That gives it a stack frame in which to save the data for
checking that an empty string has been matched. Previously this was taken
from the 1000-entry workspace that had been reserved. So now there is no
explicit limit, but more stack is used.
8. Applied Daniel's patches to solve problems with the import/export magic
syntax that is required for Windows, and which was going wrong for the
pcreposix and pcrecpp parts of the library. These were overlooked when this
problem was solved for the main library.
9. There were some crude static tests to avoid integer overflow when computing
the size of patterns that contain repeated groups with explicit upper
limits. As the maximum quantifier is 65535, the maximum group length was
set at 30,000 so that the product of these two numbers did not overflow a
32-bit integer. However, it turns out that people want to use groups that
are longer than 30,000 bytes (though not repeat them that many times).
Change 7.0/17 (the refactoring of the way the pattern size is computed) has
made it possible to implement the integer overflow checks in a much more
dynamic way, which I have now done. The artificial limitation on group
length has been removed - we now have only the limit on the total length of
the compiled pattern, which depends on the LINK_SIZE setting.
10. Fixed a bug in the documentation for get/copy named substring when
duplicate names are permitted. If none of the named substrings are set, the
functions return PCRE_ERROR_NOSUBSTRING (7); the doc said they returned an
empty string.
11. Because Perl interprets \Q...\E at a high level, and ignores orphan \E
instances, patterns such as [\Q\E] or [\E] or even [^\E] cause an error,
because the ] is interpreted as the first data character and the
terminating ] is not found. PCRE has been made compatible with Perl in this
regard. Previously, it interpreted [\Q\E] as an empty class, and [\E] could
cause memory overwriting.
10. Like Perl, PCRE automatically breaks an unlimited repeat after an empty
string has been matched (to stop an infinite loop). It was not recognizing
a conditional subpattern that could match an empty string if that
subpattern was within another subpattern. For example, it looped when
trying to match (((?(1)X|))*) but it was OK with ((?(1)X|)*) where the
condition was not nested. This bug has been fixed.
12. A pattern like \X?\d or \P{L}?\d in non-UTF-8 mode could cause a backtrack
past the start of the subject in the presence of bytes with the top bit
set, for example "\x8aBCD".
13. Added Perl 5.10 experimental backtracking controls (*FAIL), (*F), (*PRUNE),
(*SKIP), (*THEN), (*COMMIT), and (*ACCEPT).
14. Optimized (?!) to (*FAIL).
15. Updated the test for a valid UTF-8 string to conform to the later RFC 3629.
This restricts code points to be within the range 0 to 0x10FFFF, excluding
the "low surrogate" sequence 0xD800 to 0xDFFF. Previously, PCRE allowed the
full range 0 to 0x7FFFFFFF, as defined by RFC 2279. Internally, it still
does: it's just the validity check that is more restrictive.
16. Inserted checks for integer overflows during escape sequence (backslash)
processing, and also fixed erroneous offset values for syntax errors during
backslash processing.
17. Fixed another case of looking too far back in non-UTF-8 mode (cf 12 above)
for patterns like [\PPP\x8a]{1,}\x80 with the subject "A\x80".
18. An unterminated class in a pattern like (?1)\c[ with a "forward reference"
caused an overrun.
19. A pattern like (?:[\PPa*]*){8,} which had an "extended class" (one with
something other than just ASCII characters) inside a group that had an
unlimited repeat caused a loop at compile time (while checking to see
whether the group could match an empty string).
20. Debugging a pattern containing \p or \P could cause a crash. For example,
[\P{Any}] did so. (Error in the code for printing property names.)
21. An orphan \E inside a character class could cause a crash.
22. A repeated capturing bracket such as (A)? could cause a wild memory
reference during compilation.
23. There are several functions in pcre_compile() that scan along a compiled
expression for various reasons (e.g. to see if it's fixed length for look
behind). There were bugs in these functions when a repeated \p or \P was
present in the pattern. These operators have additional parameters compared
with \d, etc, and these were not being taken into account when moving along
the compiled data. Specifically:
(a) A item such as \p{Yi}{3} in a lookbehind was not treated as fixed
length.
(b) An item such as \pL+ within a repeated group could cause crashes or
loops.
(c) A pattern such as \p{Yi}+(\P{Yi}+)(?1) could give an incorrect
"reference to non-existent subpattern" error.
(d) A pattern like (\P{Yi}{2}\277)? could loop at compile time.
24. A repeated \S or \W in UTF-8 mode could give wrong answers when multibyte
characters were involved (for example /\S{2}/8g with "A\x{a3}BC").
25. Using pcregrep in multiline, inverted mode (-Mv) caused it to loop.
26. Patterns such as [\P{Yi}A] which include \p or \P and just one other
character were causing crashes (broken optimization).
27. Patterns such as (\P{Yi}*\277)* (group with possible zero repeat containing
\p or \P) caused a compile-time loop.
28. More problems have arisen in unanchored patterns when CRLF is a valid line
break. For example, the unstudied pattern [\r\n]A does not match the string
"\r\nA" because change 7.0/46 below moves the current point on by two
characters after failing to match at the start. However, the pattern \nA
*does* match, because it doesn't start till \n, and if [\r\n]A is studied,
the same is true. There doesn't seem any very clean way out of this, but
what I have chosen to do makes the common cases work: PCRE now takes note
of whether there can be an explicit match for \r or \n anywhere in the
pattern, and if so, 7.0/46 no longer applies. As part of this change,
there's a new PCRE_INFO_HASCRORLF option for finding out whether a compiled
pattern has explicit CR or LF references.
29. Added (*CR) etc for changing newline setting at start of pattern.
Version 7.2 19-Jun-07
---------------------
1. If the fr_FR locale cannot be found for test 3, try the "french" locale,
which is apparently normally available under Windows.
2. Re-jig the pcregrep tests with different newline settings in an attempt
to make them independent of the local environment's newline setting.
3. Add code to configure.ac to remove -g from the CFLAGS default settings.
4. Some of the "internals" tests were previously cut out when the link size
was not 2, because the output contained actual offsets. The recent new
"Z" feature of pcretest means that these can be cut out, making the tests
usable with all link sizes.
5. Implemented Stan Switzer's goto replacement for longjmp() when not using
stack recursion. This gives a massive performance boost under BSD, but just
a small improvement under Linux. However, it saves one field in the frame
in all cases.
6. Added more features from the forthcoming Perl 5.10:
(a) (?-n) (where n is a string of digits) is a relative subroutine or
recursion call. It refers to the nth most recently opened parentheses.
(b) (?+n) is also a relative subroutine call; it refers to the nth next
to be opened parentheses.
(c) Conditions that refer to capturing parentheses can be specified
relatively, for example, (?(-2)... or (?(+3)...
(d) \K resets the start of the current match so that everything before
is not part of it.
(e) \k{name} is synonymous with \k<name> and \k'name' (.NET compatible).
(f) \g{name} is another synonym - part of Perl 5.10's unification of
reference syntax.
(g) (?| introduces a group in which the numbering of parentheses in each
alternative starts with the same number.
(h) \h, \H, \v, and \V match horizontal and vertical whitespace.
7. Added two new calls to pcre_fullinfo(): PCRE_INFO_OKPARTIAL and
PCRE_INFO_JCHANGED.
8. A pattern such as (.*(.)?)* caused pcre_exec() to fail by either not
terminating or by crashing. Diagnosed by Viktor Griph; it was in the code
for detecting groups that can match an empty string.
9. A pattern with a very large number of alternatives (more than several
hundred) was running out of internal workspace during the pre-compile
phase, where pcre_compile() figures out how much memory will be needed. A
bit of new cunning has reduced the workspace needed for groups with
alternatives. The 1000-alternative test pattern now uses 12 bytes of
workspace instead of running out of the 4096 that are available.
10. Inserted some missing (unsigned int) casts to get rid of compiler warnings.
11. Applied patch from Google to remove an optimization that didn't quite work.
The report of the bug said:
pcrecpp::RE("a*").FullMatch("aaa") matches, while
pcrecpp::RE("a*?").FullMatch("aaa") does not, and
pcrecpp::RE("a*?\\z").FullMatch("aaa") does again.
12. If \p or \P was used in non-UTF-8 mode on a character greater than 127
it matched the wrong number of bytes.
Version 7.1 24-Apr-07
---------------------
1. Applied Bob Rossi and Daniel G's patches to convert the build system to one
that is more "standard", making use of automake and other Autotools. There
is some re-arrangement of the files and adjustment of comments consequent
on this.
2. Part of the patch fixed a problem with the pcregrep tests. The test of -r
for recursive directory scanning broke on some systems because the files
are not scanned in any specific order and on different systems the order
was different. A call to "sort" has been inserted into RunGrepTest for the
approprate test as a short-term fix. In the longer term there may be an
alternative.
3. I had an email from Eric Raymond about problems translating some of PCRE's
man pages to HTML (despite the fact that I distribute HTML pages, some
people do their own conversions for various reasons). The problems
concerned the use of low-level troff macros .br and .in. I have therefore
removed all such uses from the man pages (some were redundant, some could
be replaced by .nf/.fi pairs). The 132html script that I use to generate
HTML has been updated to handle .nf/.fi and to complain if it encounters
.br or .in.
4. Updated comments in configure.ac that get placed in config.h.in and also
arranged for config.h to be included in the distribution, with the name
config.h.generic, for the benefit of those who have to compile without
Autotools (compare pcre.h, which is now distributed as pcre.h.generic).
5. Updated the support (such as it is) for Virtual Pascal, thanks to Stefan
Weber: (1) pcre_internal.h was missing some function renames; (2) updated
makevp.bat for the current PCRE, using the additional files
makevp_c.txt, makevp_l.txt, and pcregexp.pas.
6. A Windows user reported a minor discrepancy with test 2, which turned out
to be caused by a trailing space on an input line that had got lost in his
copy. The trailing space was an accident, so I've just removed it.
7. Add -Wl,-R... flags in pcre-config.in for *BSD* systems, as I'm told
that is needed.
8. Mark ucp_table (in ucptable.h) and ucp_gentype (in pcre_ucp_searchfuncs.c)
as "const" (a) because they are and (b) because it helps the PHP
maintainers who have recently made a script to detect big data structures
in the php code that should be moved to the .rodata section. I remembered
to update Builducptable as well, so it won't revert if ucptable.h is ever
re-created.
9. Added some extra #ifdef SUPPORT_UTF8 conditionals into pcretest.c,
pcre_printint.src, pcre_compile.c, pcre_study.c, and pcre_tables.c, in
order to be able to cut out the UTF-8 tables in the latter when UTF-8
support is not required. This saves 1.5-2K of code, which is important in
some applications.
Later: more #ifdefs are needed in pcre_ord2utf8.c and pcre_valid_utf8.c
so as not to refer to the tables, even though these functions will never be
called when UTF-8 support is disabled. Otherwise there are problems with a
shared library.
10. Fixed two bugs in the emulated memmove() function in pcre_internal.h:
(a) It was defining its arguments as char * instead of void *.
(b) It was assuming that all moves were upwards in memory; this was true
a long time ago when I wrote it, but is no longer the case.
The emulated memove() is provided for those environments that have neither
memmove() nor bcopy(). I didn't think anyone used it these days, but that
is clearly not the case, as these two bugs were recently reported.
11. The script PrepareRelease is now distributed: it calls 132html, CleanTxt,
and Detrail to create the HTML documentation, the .txt form of the man
pages, and it removes trailing spaces from listed files. It also creates
pcre.h.generic and config.h.generic from pcre.h and config.h. In the latter
case, it wraps all the #defines with #ifndefs. This script should be run
before "make dist".
12. Fixed two fairly obscure bugs concerned with quantified caseless matching
with Unicode property support.
(a) For a maximizing quantifier, if the two different cases of the
character were of different lengths in their UTF-8 codings (there are
some cases like this - I found 11), and the matching function had to
back up over a mixture of the two cases, it incorrectly assumed they
were both the same length.
(b) When PCRE was configured to use the heap rather than the stack for
recursion during matching, it was not correctly preserving the data for
the other case of a UTF-8 character when checking ahead for a match
while processing a minimizing repeat. If the check also involved
matching a wide character, but failed, corruption could cause an
erroneous result when trying to check for a repeat of the original
character.
13. Some tidying changes to the testing mechanism:
(a) The RunTest script now detects the internal link size and whether there
is UTF-8 and UCP support by running ./pcretest -C instead of relying on
values substituted by "configure". (The RunGrepTest script already did
this for UTF-8.) The configure.ac script no longer substitutes the
relevant variables.
(b) The debugging options /B and /D in pcretest show the compiled bytecode
with length and offset values. This means that the output is different
for different internal link sizes. Test 2 is skipped for link sizes
other than 2 because of this, bypassing the problem. Unfortunately,
there was also a test in test 3 (the locale tests) that used /B and
failed for link sizes other than 2. Rather than cut the whole test out,
I have added a new /Z option to pcretest that replaces the length and
offset values with spaces. This is now used to make test 3 independent
of link size. (Test 2 will be tidied up later.)
14. If erroroffset was passed as NULL to pcre_compile, it provoked a
segmentation fault instead of returning the appropriate error message.
15. In multiline mode when the newline sequence was set to "any", the pattern
^$ would give a match between the \r and \n of a subject such as "A\r\nB".
This doesn't seem right; it now treats the CRLF combination as the line
ending, and so does not match in that case. It's only a pattern such as ^$
that would hit this one: something like ^ABC$ would have failed after \r
and then tried again after \r\n.
16. Changed the comparison command for RunGrepTest from "diff -u" to "diff -ub"
in an attempt to make files that differ only in their line terminators
compare equal. This works on Linux.
17. Under certain error circumstances pcregrep might try to free random memory
as it exited. This is now fixed, thanks to valgrind.
19. In pcretest, if the pattern /(?m)^$/g<any> was matched against the string
"abc\r\n\r\n", it found an unwanted second match after the second \r. This
was because its rules for how to advance for /g after matching an empty
string at the end of a line did not allow for this case. They now check for
it specially.
20. pcretest is supposed to handle patterns and data of any length, by
extending its buffers when necessary. It was getting this wrong when the
buffer for a data line had to be extended.
21. Added PCRE_NEWLINE_ANYCRLF which is like ANY, but matches only CR, LF, or
CRLF as a newline sequence.
22. Code for handling Unicode properties in pcre_dfa_exec() wasn't being cut
out by #ifdef SUPPORT_UCP. This did no harm, as it could never be used, but
I have nevertheless tidied it up.
23. Added some casts to kill warnings from HP-UX ia64 compiler.
24. Added a man page for pcre-config.
Version 7.0 19-Dec-06
---------------------
1. Fixed a signed/unsigned compiler warning in pcre_compile.c, shown up by
moving to gcc 4.1.1.
2. The -S option for pcretest uses setrlimit(); I had omitted to #include
sys/time.h, which is documented as needed for this function. It doesn't
seem to matter on Linux, but it showed up on some releases of OS X.
3. It seems that there are systems where bytes whose values are greater than
127 match isprint() in the "C" locale. The "C" locale should be the
default when a C program starts up. In most systems, only ASCII printing
characters match isprint(). This difference caused the output from pcretest
to vary, making some of the tests fail. I have changed pcretest so that:
(a) When it is outputting text in the compiled version of a pattern, bytes
other than 32-126 are always shown as hex escapes.
(b) When it is outputting text that is a matched part of a subject string,
it does the same, unless a different locale has been set for the match
(using the /L modifier). In this case, it uses isprint() to decide.
4. Fixed a major bug that caused incorrect computation of the amount of memory
required for a compiled pattern when options that changed within the
pattern affected the logic of the preliminary scan that determines the
length. The relevant options are -x, and -i in UTF-8 mode. The result was
that the computed length was too small. The symptoms of this bug were
either the PCRE error "internal error: code overflow" from pcre_compile(),
or a glibc crash with a message such as "pcretest: free(): invalid next
size (fast)". Examples of patterns that provoked this bug (shown in
pcretest format) are:
/(?-x: )/x
/(?x)(?-x: \s*#\s*)/
/((?i)[\x{c0}])/8
/(?i:[\x{c0}])/8
HOWEVER: Change 17 below makes this fix obsolete as the memory computation
is now done differently.
5. Applied patches from Google to: (a) add a QuoteMeta function to the C++
wrapper classes; (b) implement a new function in the C++ scanner that is
more efficient than the old way of doing things because it avoids levels of
recursion in the regex matching; (c) add a paragraph to the documentation
for the FullMatch() function.
6. The escape sequence \n was being treated as whatever was defined as
"newline". Not only was this contrary to the documentation, which states
that \n is character 10 (hex 0A), but it also went horribly wrong when
"newline" was defined as CRLF. This has been fixed.
7. In pcre_dfa_exec.c the value of an unsigned integer (the variable called c)
was being set to -1 for the "end of line" case (supposedly a value that no
character can have). Though this value is never used (the check for end of
line is "zero bytes in current character"), it caused compiler complaints.
I've changed it to 0xffffffff.
8. In pcre_version.c, the version string was being built by a sequence of
C macros that, in the event of PCRE_PRERELEASE being defined as an empty
string (as it is for production releases) called a macro with an empty
argument. The C standard says the result of this is undefined. The gcc
compiler treats it as an empty string (which was what was wanted) but it is
reported that Visual C gives an error. The source has been hacked around to
avoid this problem.
9. On the advice of a Windows user, included <io.h> and <fcntl.h> in Windows
builds of pcretest, and changed the call to _setmode() to use _O_BINARY
instead of 0x8000. Made all the #ifdefs test both _WIN32 and WIN32 (not all
of them did).
10. Originally, pcretest opened its input and output without "b"; then I was
told that "b" was needed in some environments, so it was added for release
5.0 to both the input and output. (It makes no difference on Unix-like
systems.) Later I was told that it is wrong for the input on Windows. I've
now abstracted the modes into two macros, to make it easier to fiddle with
them, and removed "b" from the input mode under Windows.
11. Added pkgconfig support for the C++ wrapper library, libpcrecpp.
12. Added -help and --help to pcretest as an official way of being reminded
of the options.
13. Removed some redundant semicolons after macro calls in pcrecpparg.h.in
and pcrecpp.cc because they annoy compilers at high warning levels.
14. A bit of tidying/refactoring in pcre_exec.c in the main bumpalong loop.
15. Fixed an occurrence of == in configure.ac that should have been = (shell
scripts are not C programs :-) and which was not noticed because it works
on Linux.
16. pcretest is supposed to handle any length of pattern and data line (as one
line or as a continued sequence of lines) by extending its input buffer if
necessary. This feature was broken for very long pattern lines, leading to
a string of junk being passed to pcre_compile() if the pattern was longer
than about 50K.
17. I have done a major re-factoring of the way pcre_compile() computes the
amount of memory needed for a compiled pattern. Previously, there was code
that made a preliminary scan of the pattern in order to do this. That was
OK when PCRE was new, but as the facilities have expanded, it has become
harder and harder to keep it in step with the real compile phase, and there
have been a number of bugs (see for example, 4 above). I have now found a
cunning way of running the real compile function in a "fake" mode that
enables it to compute how much memory it would need, while actually only
ever using a few hundred bytes of working memory and without too many
tests of the mode. This should make future maintenance and development
easier. A side effect of this work is that the limit of 200 on the nesting
depth of parentheses has been removed (though this was never a serious
limitation, I suspect). However, there is a downside: pcre_compile() now
runs more slowly than before (30% or more, depending on the pattern). I
hope this isn't a big issue. There is no effect on runtime performance.
18. Fixed a minor bug in pcretest: if a pattern line was not terminated by a
newline (only possible for the last line of a file) and it was a
pattern that set a locale (followed by /Lsomething), pcretest crashed.
19. Added additional timing features to pcretest. (1) The -tm option now times
matching only, not compiling. (2) Both -t and -tm can be followed, as a
separate command line item, by a number that specifies the number of
repeats to use when timing. The default is 50000; this gives better
precision, but takes uncomfortably long for very large patterns.
20. Extended pcre_study() to be more clever in cases where a branch of a
subpattern has no definite first character. For example, (a*|b*)[cd] would
previously give no result from pcre_study(). Now it recognizes that the
first character must be a, b, c, or d.
21. There was an incorrect error "recursive call could loop indefinitely" if
a subpattern (or the entire pattern) that was being tested for matching an
empty string contained only one non-empty item after a nested subpattern.
For example, the pattern (?>\x{100}*)\d(?R) provoked this error
incorrectly, because the \d was being skipped in the check.
22. The pcretest program now has a new pattern option /B and a command line
option -b, which is equivalent to adding /B to every pattern. This causes
it to show the compiled bytecode, without the additional information that
-d shows. The effect of -d is now the same as -b with -i (and similarly, /D
is the same as /B/I).
23. A new optimization is now able automatically to treat some sequences such
as a*b as a*+b. More specifically, if something simple (such as a character
or a simple class like \d) has an unlimited quantifier, and is followed by
something that cannot possibly match the quantified thing, the quantifier
is automatically "possessified".
24. A recursive reference to a subpattern whose number was greater than 39
went wrong under certain circumstances in UTF-8 mode. This bug could also
have affected the operation of pcre_study().
25. Realized that a little bit of performance could be had by replacing
(c & 0xc0) == 0xc0 with c >= 0xc0 when processing UTF-8 characters.
26. Timing data from pcretest is now shown to 4 decimal places instead of 3.
27. Possessive quantifiers such as a++ were previously implemented by turning
them into atomic groups such as ($>a+). Now they have their own opcodes,
which improves performance. This includes the automatically created ones
from 23 above.
28. A pattern such as (?=(\w+))\1: which simulates an atomic group using a
lookahead was broken if it was not anchored. PCRE was mistakenly expecting
the first matched character to be a colon. This applied both to named and
numbered groups.
29. The ucpinternal.h header file was missing its idempotency #ifdef.
30. I was sent a "project" file called libpcre.a.dev which I understand makes
building PCRE on Windows easier, so I have included it in the distribution.
31. There is now a check in pcretest against a ridiculously large number being
returned by pcre_exec() or pcre_dfa_exec(). If this happens in a /g or /G
loop, the loop is abandoned.
32. Forward references to subpatterns in conditions such as (?(2)...) where
subpattern 2 is defined later cause pcre_compile() to search forwards in
the pattern for the relevant set of parentheses. This search went wrong
when there were unescaped parentheses in a character class, parentheses
escaped with \Q...\E, or parentheses in a #-comment in /x mode.
33. "Subroutine" calls and backreferences were previously restricted to
referencing subpatterns earlier in the regex. This restriction has now
been removed.
34. Added a number of extra features that are going to be in Perl 5.10. On the
whole, these are just syntactic alternatives for features that PCRE had
previously implemented using the Python syntax or my own invention. The
other formats are all retained for compatibility.
(a) Named groups can now be defined as (?<name>...) or (?'name'...) as well
as (?P<name>...). The new forms, as well as being in Perl 5.10, are
also .NET compatible.
(b) A recursion or subroutine call to a named group can now be defined as
(?&name) as well as (?P>name).
(c) A backreference to a named group can now be defined as \k<name> or
\k'name' as well as (?P=name). The new forms, as well as being in Perl
5.10, are also .NET compatible.
(d) A conditional reference to a named group can now use the syntax
(?(<name>) or (?('name') as well as (?(name).
(e) A "conditional group" of the form (?(DEFINE)...) can be used to define
groups (named and numbered) that are never evaluated inline, but can be
called as "subroutines" from elsewhere. In effect, the DEFINE condition
is always false. There may be only one alternative in such a group.
(f) A test for recursion can be given as (?(R1).. or (?(R&name)... as well
as the simple (?(R). The condition is true only if the most recent
recursion is that of the given number or name. It does not search out
through the entire recursion stack.
(g) The escape \gN or \g{N} has been added, where N is a positive or
negative number, specifying an absolute or relative reference.
35. Tidied to get rid of some further signed/unsigned compiler warnings and
some "unreachable code" warnings.
36. Updated the Unicode property tables to Unicode version 5.0.0. Amongst other
things, this adds five new scripts.
37. Perl ignores orphaned \E escapes completely. PCRE now does the same.
There were also incompatibilities regarding the handling of \Q..\E inside
character classes, for example with patterns like [\Qa\E-\Qz\E] where the
hyphen was adjacent to \Q or \E. I hope I've cleared all this up now.
38. Like Perl, PCRE detects when an indefinitely repeated parenthesized group
matches an empty string, and forcibly breaks the loop. There were bugs in
this code in non-simple cases. For a pattern such as ^(a()*)* matched
against aaaa the result was just "a" rather than "aaaa", for example. Two
separate and independent bugs (that affected different cases) have been
fixed.
39. Refactored the code to abolish the use of different opcodes for small
capturing bracket numbers. This is a tidy that I avoided doing when I
removed the limit on the number of capturing brackets for 3.5 back in 2001.
The new approach is not only tidier, it makes it possible to reduce the
memory needed to fix the previous bug (38).
40. Implemented PCRE_NEWLINE_ANY to recognize any of the Unicode newline
sequences (http://unicode.org/unicode/reports/tr18/) as "newline" when
processing dot, circumflex, or dollar metacharacters, or #-comments in /x
mode.
41. Add \R to match any Unicode newline sequence, as suggested in the Unicode
report.
42. Applied patch, originally from Ari Pollak, modified by Google, to allow
copy construction and assignment in the C++ wrapper.
43. Updated pcregrep to support "--newline=any". In the process, I fixed a
couple of bugs that could have given wrong results in the "--newline=crlf"
case.
44. Added a number of casts and did some reorganization of signed/unsigned int
variables following suggestions from Dair Grant. Also renamed the variable
"this" as "item" because it is a C++ keyword.
45. Arranged for dftables to add
#include "pcre_internal.h"
to pcre_chartables.c because without it, gcc 4.x may remove the array
definition from the final binary if PCRE is built into a static library and
dead code stripping is activated.
46. For an unanchored pattern, if a match attempt fails at the start of a
newline sequence, and the newline setting is CRLF or ANY, and the next two
characters are CRLF, advance by two characters instead of one.
Version 6.7 04-Jul-06
---------------------
1. In order to handle tests when input lines are enormously long, pcretest has
been re-factored so that it automatically extends its buffers when
necessary. The code is crude, but this _is_ just a test program. The
default size has been increased from 32K to 50K.
2. The code in pcre_study() was using the value of the re argument before
testing it for NULL. (Of course, in any sensible call of the function, it
won't be NULL.)
3. The memmove() emulation function in pcre_internal.h, which is used on
systems that lack both memmove() and bcopy() - that is, hardly ever -
was missing a "static" storage class specifier.
4. When UTF-8 mode was not set, PCRE looped when compiling certain patterns
containing an extended class (one that cannot be represented by a bitmap
because it contains high-valued characters or Unicode property items, e.g.
[\pZ]). Almost always one would set UTF-8 mode when processing such a
pattern, but PCRE should not loop if you do not (it no longer does).
[Detail: two cases were found: (a) a repeated subpattern containing an
extended class; (b) a recursive reference to a subpattern that followed a
previous extended class. It wasn't skipping over the extended class
correctly when UTF-8 mode was not set.]
5. A negated single-character class was not being recognized as fixed-length
in lookbehind assertions such as (?<=[^f]), leading to an incorrect
compile error "lookbehind assertion is not fixed length".
6. The RunPerlTest auxiliary script was showing an unexpected difference
between PCRE and Perl for UTF-8 tests. It turns out that it is hard to
write a Perl script that can interpret lines of an input file either as
byte characters or as UTF-8, which is what "perltest" was being required to
do for the non-UTF-8 and UTF-8 tests, respectively. Essentially what you
can't do is switch easily at run time between having the "use utf8;" pragma
or not. In the end, I fudged it by using the RunPerlTest script to insert
"use utf8;" explicitly for the UTF-8 tests.
7. In multiline (/m) mode, PCRE was matching ^ after a terminating newline at
the end of the subject string, contrary to the documentation and to what
Perl does. This was true of both matching functions. Now it matches only at
the start of the subject and immediately after *internal* newlines.
8. A call of pcre_fullinfo() from pcretest to get the option bits was passing
a pointer to an int instead of a pointer to an unsigned long int. This
caused problems on 64-bit systems.
9. Applied a patch from the folks at Google to pcrecpp.cc, to fix "another
instance of the 'standard' template library not being so standard".
10. There was no check on the number of named subpatterns nor the maximum
length of a subpattern name. The product of these values is used to compute
the size of the memory block for a compiled pattern. By supplying a very
long subpattern name and a large number of named subpatterns, the size
computation could be caused to overflow. This is now prevented by limiting
the length of names to 32 characters, and the number of named subpatterns
to 10,000.
11. Subpatterns that are repeated with specific counts have to be replicated in
the compiled pattern. The size of memory for this was computed from the
length of the subpattern and the repeat count. The latter is limited to
65535, but there was no limit on the former, meaning that integer overflow
could in principle occur. The compiled length of a repeated subpattern is
now limited to 30,000 bytes in order to prevent this.
12. Added the optional facility to have named substrings with the same name.
13. Added the ability to use a named substring as a condition, using the
Python syntax: (?(name)yes|no). This overloads (?(R)... and names that
are numbers (not recommended). Forward references are permitted.
14. Added forward references in named backreferences (if you see what I mean).
15. In UTF-8 mode, with the PCRE_DOTALL option set, a quantified dot in the
pattern could run off the end of the subject. For example, the pattern
"(?s)(.{1,5})"8 did this with the subject "ab".
16. If PCRE_DOTALL or PCRE_MULTILINE were set, pcre_dfa_exec() behaved as if
PCRE_CASELESS was set when matching characters that were quantified with ?
or *.
17. A character class other than a single negated character that had a minimum
but no maximum quantifier - for example [ab]{6,} - was not handled
correctly by pce_dfa_exec(). It would match only one character.
18. A valid (though odd) pattern that looked like a POSIX character
class but used an invalid character after [ (for example [[,abc,]]) caused
pcre_compile() to give the error "Failed: internal error: code overflow" or
in some cases to crash with a glibc free() error. This could even happen if
the pattern terminated after [[ but there just happened to be a sequence of
letters, a binary zero, and a closing ] in the memory that followed.
19. Perl's treatment of octal escapes in the range \400 to \777 has changed
over the years. Originally (before any Unicode support), just the bottom 8
bits were taken. Thus, for example, \500 really meant \100. Nowadays the
output from "man perlunicode" includes this:
The regular expression compiler produces polymorphic opcodes. That
is, the pattern adapts to the data and automatically switches to
the Unicode character scheme when presented with Unicode data--or
instead uses a traditional byte scheme when presented with byte
data.
Sadly, a wide octal escape does not cause a switch, and in a string with
no other multibyte characters, these octal escapes are treated as before.
Thus, in Perl, the pattern /\500/ actually matches \100 but the pattern
/\500|\x{1ff}/ matches \500 or \777 because the whole thing is treated as a
Unicode string.
I have not perpetrated such confusion in PCRE. Up till now, it took just
the bottom 8 bits, as in old Perl. I have now made octal escapes with
values greater than \377 illegal in non-UTF-8 mode. In UTF-8 mode they
translate to the appropriate multibyte character.
29. Applied some refactoring to reduce the number of warnings from Microsoft
and Borland compilers. This has included removing the fudge introduced
seven years ago for the OS/2 compiler (see 2.02/2 below) because it caused
a warning about an unused variable.
21. PCRE has not included VT (character 0x0b) in the set of whitespace
characters since release 4.0, because Perl (from release 5.004) does not.
[Or at least, is documented not to: some releases seem to be in conflict
with the documentation.] However, when a pattern was studied with
pcre_study() and all its branches started with \s, PCRE still included VT
as a possible starting character. Of course, this did no harm; it just
caused an unnecessary match attempt.
22. Removed a now-redundant internal flag bit that recorded the fact that case
dependency changed within the pattern. This was once needed for "required
byte" processing, but is no longer used. This recovers a now-scarce options
bit. Also moved the least significant internal flag bit to the most-
significant bit of the word, which was not previously used (hangover from
the days when it was an int rather than a uint) to free up another bit for
the future.
23. Added support for CRLF line endings as well as CR and LF. As well as the
default being selectable at build time, it can now be changed at runtime
via the PCRE_NEWLINE_xxx flags. There are now options for pcregrep to
specify that it is scanning data with non-default line endings.
24. Changed the definition of CXXLINK to make it agree with the definition of
LINK in the Makefile, by replacing LDFLAGS to CXXFLAGS.
25. Applied Ian Taylor's patches to avoid using another stack frame for tail
recursions. This makes a big different to stack usage for some patterns.
26. If a subpattern containing a named recursion or subroutine reference such
as (?P>B) was quantified, for example (xxx(?P>B)){3}, the calculation of
the space required for the compiled pattern went wrong and gave too small a
value. Depending on the environment, this could lead to "Failed: internal
error: code overflow at offset 49" or "glibc detected double free or
corruption" errors.
27. Applied patches from Google (a) to support the new newline modes and (b) to
advance over multibyte UTF-8 characters in GlobalReplace.
28. Change free() to pcre_free() in pcredemo.c. Apparently this makes a
difference for some implementation of PCRE in some Windows version.
29. Added some extra testing facilities to pcretest:
\q<number> in a data line sets the "match limit" value
\Q<number> in a data line sets the "match recursion limt" value
-S <number> sets the stack size, where <number> is in megabytes
The -S option isn't available for Windows.
Version 6.6 06-Feb-06
---------------------
1. Change 16(a) for 6.5 broke things, because PCRE_DATA_SCOPE was not defined
in pcreposix.h. I have copied the definition from pcre.h.
2. Change 25 for 6.5 broke compilation in a build directory out-of-tree
because pcre.h is no longer a built file.
3. Added Jeff Friedl's additional debugging patches to pcregrep. These are
not normally included in the compiled code.
Version 6.5 01-Feb-06
---------------------
1. When using the partial match feature with pcre_dfa_exec(), it was not
anchoring the second and subsequent partial matches at the new starting
point. This could lead to incorrect results. For example, with the pattern
/1234/, partially matching against "123" and then "a4" gave a match.
2. Changes to pcregrep:
(a) All non-match returns from pcre_exec() were being treated as failures
to match the line. Now, unless the error is PCRE_ERROR_NOMATCH, an
error message is output. Some extra information is given for the
PCRE_ERROR_MATCHLIMIT and PCRE_ERROR_RECURSIONLIMIT errors, which are
probably the only errors that are likely to be caused by users (by
specifying a regex that has nested indefinite repeats, for instance).
If there are more than 20 of these errors, pcregrep is abandoned.
(b) A binary zero was treated as data while matching, but terminated the
output line if it was written out. This has been fixed: binary zeroes
are now no different to any other data bytes.
(c) Whichever of the LC_ALL or LC_CTYPE environment variables is set is
used to set a locale for matching. The --locale=xxxx long option has
been added (no short equivalent) to specify a locale explicitly on the
pcregrep command, overriding the environment variables.
(d) When -B was used with -n, some line numbers in the output were one less
than they should have been.
(e) Added the -o (--only-matching) option.
(f) If -A or -C was used with -c (count only), some lines of context were
accidentally printed for the final match.
(g) Added the -H (--with-filename) option.
(h) The combination of options -rh failed to suppress file names for files
that were found from directory arguments.
(i) Added the -D (--devices) and -d (--directories) options.
(j) Added the -F (--fixed-strings) option.
(k) Allow "-" to be used as a file name for -f as well as for a data file.
(l) Added the --colo(u)r option.
(m) Added Jeffrey Friedl's -S testing option, but within #ifdefs so that it
is not present by default.
3. A nasty bug was discovered in the handling of recursive patterns, that is,
items such as (?R) or (?1), when the recursion could match a number of
alternatives. If it matched one of the alternatives, but subsequently,
outside the recursion, there was a failure, the code tried to back up into
the recursion. However, because of the way PCRE is implemented, this is not
possible, and the result was an incorrect result from the match.
In order to prevent this happening, the specification of recursion has
been changed so that all such subpatterns are automatically treated as
atomic groups. Thus, for example, (?R) is treated as if it were (?>(?R)).
4. I had overlooked the fact that, in some locales, there are characters for
which isalpha() is true but neither isupper() nor islower() are true. In
the fr_FR locale, for instance, the \xAA and \xBA characters (ordmasculine
and ordfeminine) are like this. This affected the treatment of \w and \W
when they appeared in character classes, but not when they appeared outside
a character class. The bit map for "word" characters is now created
separately from the results of isalnum() instead of just taking it from the
upper, lower, and digit maps. (Plus the underscore character, of course.)
5. The above bug also affected the handling of POSIX character classes such as
[[:alpha:]] and [[:alnum:]]. These do not have their own bit maps in PCRE's
permanent tables. Instead, the bit maps for such a class were previously
created as the appropriate unions of the upper, lower, and digit bitmaps.
Now they are created by subtraction from the [[:word:]] class, which has
its own bitmap.
6. The [[:blank:]] character class matches horizontal, but not vertical space.
It is created by subtracting the vertical space characters (\x09, \x0a,
\x0b, \x0c) from the [[:space:]] bitmap. Previously, however, the
subtraction was done in the overall bitmap for a character class, meaning
that a class such as [\x0c[:blank:]] was incorrect because \x0c would not
be recognized. This bug has been fixed.
7. Patches from the folks at Google:
(a) pcrecpp.cc: "to handle a corner case that may or may not happen in
real life, but is still worth protecting against".
(b) pcrecpp.cc: "corrects a bug when negative radixes are used with
regular expressions".
(c) pcre_scanner.cc: avoid use of std::count() because not all systems
have it.
(d) Split off pcrecpparg.h from pcrecpp.h and had the former built by
"configure" and the latter not, in order to fix a problem somebody had
with compiling the Arg class on HP-UX.
(e) Improve the error-handling of the C++ wrapper a little bit.
(f) New tests for checking recursion limiting.
8. The pcre_memmove() function, which is used only if the environment does not
have a standard memmove() function (and is therefore rarely compiled),
contained two bugs: (a) use of int instead of size_t, and (b) it was not
returning a result (though PCRE never actually uses the result).
9. In the POSIX regexec() interface, if nmatch is specified as a ridiculously
large number - greater than INT_MAX/(3*sizeof(int)) - REG_ESPACE is
returned instead of calling malloc() with an overflowing number that would
most likely cause subsequent chaos.
10. The debugging option of pcretest was not showing the NO_AUTO_CAPTURE flag.
11. The POSIX flag REG_NOSUB is now supported. When a pattern that was compiled
with this option is matched, the nmatch and pmatch options of regexec() are
ignored.
12. Added REG_UTF8 to the POSIX interface. This is not defined by POSIX, but is
provided in case anyone wants to the the POSIX interface with UTF-8
strings.
13. Added CXXLDFLAGS to the Makefile parameters to provide settings only on the
C++ linking (needed for some HP-UX environments).
14. Avoid compiler warnings in get_ucpname() when compiled without UCP support
(unused parameter) and in the pcre_printint() function (omitted "default"
switch label when the default is to do nothing).
15. Added some code to make it possible, when PCRE is compiled as a C++
library, to replace subject pointers for pcre_exec() with a smart pointer
class, thus making it possible to process discontinuous strings.
16. The two macros PCRE_EXPORT and PCRE_DATA_SCOPE are confusing, and perform
much the same function. They were added by different people who were trying
to make PCRE easy to compile on non-Unix systems. It has been suggested
that PCRE_EXPORT be abolished now that there is more automatic apparatus
for compiling on Windows systems. I have therefore replaced it with
PCRE_DATA_SCOPE. This is set automatically for Windows; if not set it
defaults to "extern" for C or "extern C" for C++, which works fine on
Unix-like systems. It is now possible to override the value of PCRE_DATA_
SCOPE with something explicit in config.h. In addition:
(a) pcreposix.h still had just "extern" instead of either of these macros;
I have replaced it with PCRE_DATA_SCOPE.
(b) Functions such as _pcre_xclass(), which are internal to the library,
but external in the C sense, all had PCRE_EXPORT in their definitions.
This is apparently wrong for the Windows case, so I have removed it.
(It makes no difference on Unix-like systems.)
17. Added a new limit, MATCH_LIMIT_RECURSION, which limits the depth of nesting
of recursive calls to match(). This is different to MATCH_LIMIT because
that limits the total number of calls to match(), not all of which increase
the depth of recursion. Limiting the recursion depth limits the amount of
stack (or heap if NO_RECURSE is set) that is used. The default can be set
when PCRE is compiled, and changed at run time. A patch from Google adds
this functionality to the C++ interface.
18. Changes to the handling of Unicode character properties:
(a) Updated the table to Unicode 4.1.0.
(b) Recognize characters that are not in the table as "Cn" (undefined).
(c) I revised the way the table is implemented to a much improved format
which includes recognition of ranges. It now supports the ranges that
are defined in UnicodeData.txt, and it also amalgamates other
characters into ranges. This has reduced the number of entries in the
table from around 16,000 to around 3,000, thus reducing its size
considerably. I realized I did not need to use a tree structure after
all - a binary chop search is just as efficient. Having reduced the
number of entries, I extended their size from 6 bytes to 8 bytes to
allow for more data.
(d) Added support for Unicode script names via properties such as \p{Han}.
19. In UTF-8 mode, a backslash followed by a non-Ascii character was not
matching that character.
20. When matching a repeated Unicode property with a minimum greater than zero,
(for example \pL{2,}), PCRE could look past the end of the subject if it
reached it while seeking the minimum number of characters. This could
happen only if some of the characters were more than one byte long, because
there is a check for at least the minimum number of bytes.
21. Refactored the implementation of \p and \P so as to be more general, to
allow for more different types of property in future. This has changed the
compiled form incompatibly. Anybody with saved compiled patterns that use
\p or \P will have to recompile them.
22. Added "Any" and "L&" to the supported property types.
23. Recognize \x{...} as a code point specifier, even when not in UTF-8 mode,
but give a compile time error if the value is greater than 0xff.
24. The man pages for pcrepartial, pcreprecompile, and pcre_compile2 were
accidentally not being installed or uninstalled.
25. The pcre.h file was built from pcre.h.in, but the only changes that were
made were to insert the current release number. This seemed silly, because
it made things harder for people building PCRE on systems that don't run
"configure". I have turned pcre.h into a distributed file, no longer built
by "configure", with the version identification directly included. There is
no longer a pcre.h.in file.
However, this change necessitated a change to the pcre-config script as
well. It is built from pcre-config.in, and one of the substitutions was the
release number. I have updated configure.ac so that ./configure now finds
the release number by grepping pcre.h.
26. Added the ability to run the tests under valgrind.
Version 6.4 05-Sep-05
---------------------
1. Change 6.0/10/(l) to pcregrep introduced a bug that caused separator lines
"--" to be printed when multiple files were scanned, even when none of the
-A, -B, or -C options were used. This is not compatible with Gnu grep, so I
consider it to be a bug, and have restored the previous behaviour.
2. A couple of code tidies to get rid of compiler warnings.
3. The pcretest program used to cheat by referring to symbols in the library
whose names begin with _pcre_. These are internal symbols that are not
really supposed to be visible externally, and in some environments it is
possible to suppress them. The cheating is now confined to including
certain files from the library's source, which is a bit cleaner.
4. Renamed pcre.in as pcre.h.in to go with pcrecpp.h.in; it also makes the
file's purpose clearer.
5. Reorganized pcre_ucp_findchar().
Version 6.3 15-Aug-05
---------------------
1. The file libpcre.pc.in did not have general read permission in the tarball.
2. There were some problems when building without C++ support:
(a) If C++ support was not built, "make install" and "make test" still
tried to test it.
(b) There were problems when the value of CXX was explicitly set. Some
changes have been made to try to fix these, and ...
(c) --disable-cpp can now be used to explicitly disable C++ support.
(d) The use of @CPP_OBJ@ directly caused a blank line preceded by a
backslash in a target when C++ was disabled. This confuses some
versions of "make", apparently. Using an intermediate variable solves
this. (Same for CPP_LOBJ.)
3. $(LINK_FOR_BUILD) now includes $(CFLAGS_FOR_BUILD) and $(LINK)
(non-Windows) now includes $(CFLAGS) because these flags are sometimes
necessary on certain architectures.
4. Added a setting of -export-symbols-regex to the link command to remove
those symbols that are exported in the C sense, but actually are local
within the library, and not documented. Their names all begin with
"_pcre_". This is not a perfect job, because (a) we have to except some
symbols that pcretest ("illegally") uses, and (b) the facility isn't always
available (and never for static libraries). I have made a note to try to
find a way round (a) in the future.
Version 6.2 01-Aug-05
---------------------
1. There was no test for integer overflow of quantifier values. A construction
such as {1111111111111111} would give undefined results. What is worse, if
a minimum quantifier for a parenthesized subpattern overflowed and became
negative, the calculation of the memory size went wrong. This could have
led to memory overwriting.
2. Building PCRE using VPATH was broken. Hopefully it is now fixed.
3. Added "b" to the 2nd argument of fopen() in dftables.c, for non-Unix-like
operating environments where this matters.
4. Applied Giuseppe Maxia's patch to add additional features for controlling
PCRE options from within the C++ wrapper.
5. Named capturing subpatterns were not being correctly counted when a pattern
was compiled. This caused two problems: (a) If there were more than 100
such subpatterns, the calculation of the memory needed for the whole
compiled pattern went wrong, leading to an overflow error. (b) Numerical
back references of the form \12, where the number was greater than 9, were
not recognized as back references, even though there were sufficient
previous subpatterns.
6. Two minor patches to pcrecpp.cc in order to allow it to compile on older
versions of gcc, e.g. 2.95.4.
Version 6.1 21-Jun-05
---------------------
1. There was one reference to the variable "posix" in pcretest.c that was not
surrounded by "#if !defined NOPOSIX".
2. Make it possible to compile pcretest without DFA support, UTF8 support, or
the cross-check on the old pcre_info() function, for the benefit of the
cut-down version of PCRE that is currently imported into Exim.
3. A (silly) pattern starting with (?i)(?-i) caused an internal space
allocation error. I've done the easy fix, which wastes 2 bytes for sensible
patterns that start (?i) but I don't think that matters. The use of (?i) is
just an example; this all applies to the other options as well.
4. Since libtool seems to echo the compile commands it is issuing, the output
from "make" can be reduced a bit by putting "@" in front of each libtool
compile command.
5. Patch from the folks at Google for configure.in to be a bit more thorough
in checking for a suitable C++ installation before trying to compile the
C++ stuff. This should fix a reported problem when a compiler was present,
but no suitable headers.
6. The man pages all had just "PCRE" as their title. I have changed them to
be the relevant file name. I have also arranged that these names are
retained in the file doc/pcre.txt, which is a concatenation in text format
of all the man pages except the little individual ones for each function.
7. The NON-UNIX-USE file had not been updated for the different set of source
files that come with release 6. I also added a few comments about the C++
wrapper.
Version 6.0 07-Jun-05
---------------------
1. Some minor internal re-organization to help with my DFA experiments.
2. Some missing #ifdef SUPPORT_UCP conditionals in pcretest and printint that
didn't matter for the library itself when fully configured, but did matter
when compiling without UCP support, or within Exim, where the ucp files are
not imported.
3. Refactoring of the library code to split up the various functions into
different source modules. The addition of the new DFA matching code (see
below) to a single monolithic source would have made it really too
unwieldy, quite apart from causing all the code to be include in a
statically linked application, when only some functions are used. This is
relevant even without the DFA addition now that patterns can be compiled in
one application and matched in another.
The downside of splitting up is that there have to be some external
functions and data tables that are used internally in different modules of
the library but which are not part of the API. These have all had their
names changed to start with "_pcre_" so that they are unlikely to clash
with other external names.
4. Added an alternate matching function, pcre_dfa_exec(), which matches using
a different (DFA) algorithm. Although it is slower than the original
function, it does have some advantages for certain types of matching
problem.
5. Upgrades to pcretest in order to test the features of pcre_dfa_exec(),
including restarting after a partial match.
6. A patch for pcregrep that defines INVALID_FILE_ATTRIBUTES if it is not
defined when compiling for Windows was sent to me. I have put it into the
code, though I have no means of testing or verifying it.
7. Added the pcre_refcount() auxiliary function.
8. Added the PCRE_FIRSTLINE option. This constrains an unanchored pattern to
match before or at the first newline in the subject string. In pcretest,
the /f option on a pattern can be used to set this.
9. A repeated \w when used in UTF-8 mode with characters greater than 256
would behave wrongly. This has been present in PCRE since release 4.0.
10. A number of changes to the pcregrep command:
(a) Refactored how -x works; insert ^(...)$ instead of setting
PCRE_ANCHORED and checking the length, in preparation for adding
something similar for -w.
(b) Added the -w (match as a word) option.
(c) Refactored the way lines are read and buffered so as to have more
than one at a time available.
(d) Implemented a pcregrep test script.
(e) Added the -M (multiline match) option. This allows patterns to match
over several lines of the subject. The buffering ensures that at least
8K, or the rest of the document (whichever is the shorter) is available
for matching (and similarly the previous 8K for lookbehind assertions).
(f) Changed the --help output so that it now says
-w, --word-regex(p)
instead of two lines, one with "regex" and the other with "regexp"
because that confused at least one person since the short forms are the
same. (This required a bit of code, as the output is generated
automatically from a table. It wasn't just a text change.)
(g) -- can be used to terminate pcregrep options if the next thing isn't an
option but starts with a hyphen. Could be a pattern or a path name
starting with a hyphen, for instance.
(h) "-" can be given as a file name to represent stdin.
(i) When file names are being printed, "(standard input)" is used for
the standard input, for compatibility with GNU grep. Previously
"<stdin>" was used.
(j) The option --label=xxx can be used to supply a name to be used for
stdin when file names are being printed. There is no short form.
(k) Re-factored the options decoding logic because we are going to add
two more options that take data. Such options can now be given in four
different ways, e.g. "-fname", "-f name", "--file=name", "--file name".
(l) Added the -A, -B, and -C options for requesting that lines of context
around matches be printed.
(m) Added the -L option to print the names of files that do not contain
any matching lines, that is, the complement of -l.
(n) The return code is 2 if any file cannot be opened, but pcregrep does
continue to scan other files.
(o) The -s option was incorrectly implemented. For compatibility with other
greps, it now suppresses the error message for a non-existent or non-
accessible file (but not the return code). There is a new option called
-q that suppresses the output of matching lines, which was what -s was
previously doing.
(p) Added --include and --exclude options to specify files for inclusion
and exclusion when recursing.
11. The Makefile was not using the Autoconf-supported LDFLAGS macro properly.
Hopefully, it now does.
12. Missing cast in pcre_study().
13. Added an "uninstall" target to the makefile.
14. Replaced "extern" in the function prototypes in Makefile.in with
"PCRE_DATA_SCOPE", which defaults to 'extern' or 'extern "C"' in the Unix
world, but is set differently for Windows.
15. Added a second compiling function called pcre_compile2(). The only
difference is that it has an extra argument, which is a pointer to an
integer error code. When there is a compile-time failure, this is set
non-zero, in addition to the error test pointer being set to point to an
error message. The new argument may be NULL if no error number is required
(but then you may as well call pcre_compile(), which is now just a
wrapper). This facility is provided because some applications need a
numeric error indication, but it has also enabled me to tidy up the way
compile-time errors are handled in the POSIX wrapper.
16. Added VPATH=.libs to the makefile; this should help when building with one
prefix path and installing with another. (Or so I'm told by someone who
knows more about this stuff than I do.)
17. Added a new option, REG_DOTALL, to the POSIX function regcomp(). This
passes PCRE_DOTALL to the pcre_compile() function, making the "." character
match everything, including newlines. This is not POSIX-compatible, but
somebody wanted the feature. From pcretest it can be activated by using
both the P and the s flags.
18. AC_PROG_LIBTOOL appeared twice in Makefile.in. Removed one.
19. libpcre.pc was being incorrectly installed as executable.
20. A couple of places in pcretest check for end-of-line by looking for '\n';
it now also looks for '\r' so that it will work unmodified on Windows.
21. Added Google's contributed C++ wrapper to the distribution.
22. Added some untidy missing memory free() calls in pcretest, to keep
Electric Fence happy when testing.
Version 5.0 13-Sep-04
---------------------
1. Internal change: literal characters are no longer packed up into items
containing multiple characters in a single byte-string. Each character
is now matched using a separate opcode. However, there may be more than one
byte in the character in UTF-8 mode.
2. The pcre_callout_block structure has two new fields: pattern_position and
next_item_length. These contain the offset in the pattern to the next match
item, and its length, respectively.
3. The PCRE_AUTO_CALLOUT option for pcre_compile() requests the automatic
insertion of callouts before each pattern item. Added the /C option to
pcretest to make use of this.
4. On the advice of a Windows user, the lines
#if defined(_WIN32) || defined(WIN32)
_setmode( _fileno( stdout ), 0x8000 );
#endif /* defined(_WIN32) || defined(WIN32) */
have been added to the source of pcretest. This apparently does useful
magic in relation to line terminators.
5. Changed "r" and "w" in the calls to fopen() in pcretest to "rb" and "wb"
for the benefit of those environments where the "b" makes a difference.
6. The icc compiler has the same options as gcc, but "configure" doesn't seem
to know about it. I have put a hack into configure.in that adds in code
to set GCC=yes if CC=icc. This seems to end up at a point in the
generated configure script that is early enough to affect the setting of
compiler options, which is what is needed, but I have no means of testing
whether it really works. (The user who reported this had patched the
generated configure script, which of course I cannot do.)
LATER: After change 22 below (new libtool files), the configure script
seems to know about icc (and also ecc). Therefore, I have commented out
this hack in configure.in.
7. Added support for pkg-config (2 patches were sent in).
8. Negated POSIX character classes that used a combination of internal tables
were completely broken. These were [[:^alpha:]], [[:^alnum:]], and
[[:^ascii]]. Typically, they would match almost any characters. The other
POSIX classes were not broken in this way.
9. Matching the pattern "\b.*?" against "ab cd", starting at offset 1, failed
to find the match, as PCRE was deluded into thinking that the match had to
start at the start point or following a newline. The same bug applied to
patterns with negative forward assertions or any backward assertions
preceding ".*" at the start, unless the pattern required a fixed first
character. This was a failing pattern: "(?!.bcd).*". The bug is now fixed.
10. In UTF-8 mode, when moving forwards in the subject after a failed match
starting at the last subject character, bytes beyond the end of the subject
string were read.
11. Renamed the variable "class" as "classbits" to make life easier for C++
users. (Previously there was a macro definition, but it apparently wasn't
enough.)
12. Added the new field "tables" to the extra data so that tables can be passed
in at exec time, or the internal tables can be re-selected. This allows
a compiled regex to be saved and re-used at a later time by a different
program that might have everything at different addresses.
13. Modified the pcre-config script so that, when run on Solaris, it shows a
-R library as well as a -L library.
14. The debugging options of pcretest (-d on the command line or D on a
pattern) showed incorrect output for anything following an extended class
that contained multibyte characters and which was followed by a quantifier.
15. Added optional support for general category Unicode character properties
via the \p, \P, and \X escapes. Unicode property support implies UTF-8
support. It adds about 90K to the size of the library. The meanings of the
inbuilt class escapes such as \d and \s have NOT been changed.
16. Updated pcredemo.c to include calls to free() to release the memory for the
compiled pattern.
17. The generated file chartables.c was being created in the source directory
instead of in the building directory. This caused the build to fail if the
source directory was different from the building directory, and was
read-only.
18. Added some sample Win commands from Mark Tetrode into the NON-UNIX-USE
file. No doubt somebody will tell me if they don't make sense... Also added
Dan Mooney's comments about building on OpenVMS.
19. Added support for partial matching via the PCRE_PARTIAL option for
pcre_exec() and the \P data escape in pcretest.
20. Extended pcretest with 3 new pattern features:
(i) A pattern option of the form ">rest-of-line" causes pcretest to
write the compiled pattern to the file whose name is "rest-of-line".
This is a straight binary dump of the data, with the saved pointer to
the character tables forced to be NULL. The study data, if any, is
written too. After writing, pcretest reads a new pattern.
(ii) If, instead of a pattern, "<rest-of-line" is given, pcretest reads a
compiled pattern from the given file. There must not be any
occurrences of "<" in the file name (pretty unlikely); if there are,
pcretest will instead treat the initial "<" as a pattern delimiter.
After reading in the pattern, pcretest goes on to read data lines as
usual.
(iii) The F pattern option causes pcretest to flip the bytes in the 32-bit
and 16-bit fields in a compiled pattern, to simulate a pattern that
was compiled on a host of opposite endianness.
21. The pcre-exec() function can now cope with patterns that were compiled on
hosts of opposite endianness, with this restriction:
As for any compiled expression that is saved and used later, the tables
pointer field cannot be preserved; the extra_data field in the arguments
to pcre_exec() should be used to pass in a tables address if a value
other than the default internal tables were used at compile time.
22. Calling pcre_exec() with a negative value of the "ovecsize" parameter is
now diagnosed as an error. Previously, most of the time, a negative number
would have been treated as zero, but if in addition "ovector" was passed as
NULL, a crash could occur.
23. Updated the files ltmain.sh, config.sub, config.guess, and aclocal.m4 with
new versions from the libtool 1.5 distribution (the last one is a copy of
a file called libtool.m4). This seems to have fixed the need to patch
"configure" to support Darwin 1.3 (which I used to do). However, I still
had to patch ltmain.sh to ensure that ${SED} is set (it isn't on my
workstation).
24. Changed the PCRE licence to be the more standard "BSD" licence.
Version 4.5 01-Dec-03
---------------------
1. There has been some re-arrangement of the code for the match() function so
that it can be compiled in a version that does not call itself recursively.
Instead, it keeps those local variables that need separate instances for
each "recursion" in a frame on the heap, and gets/frees frames whenever it
needs to "recurse". Keeping track of where control must go is done by means
of setjmp/longjmp. The whole thing is implemented by a set of macros that
hide most of the details from the main code, and operates only if
NO_RECURSE is defined while compiling pcre.c. If PCRE is built using the
"configure" mechanism, "--disable-stack-for-recursion" turns on this way of
operating.
To make it easier for callers to provide specially tailored get/free
functions for this usage, two new functions, pcre_stack_malloc, and
pcre_stack_free, are used. They are always called in strict stacking order,
and the size of block requested is always the same.
The PCRE_CONFIG_STACKRECURSE info parameter can be used to find out whether
PCRE has been compiled to use the stack or the heap for recursion. The
-C option of pcretest uses this to show which version is compiled.
A new data escape \S, is added to pcretest; it causes the amounts of store
obtained and freed by both kinds of malloc/free at match time to be added
to the output.
2. Changed the locale test to use "fr_FR" instead of "fr" because that's
what's available on my current Linux desktop machine.
3. When matching a UTF-8 string, the test for a valid string at the start has
been extended. If start_offset is not zero, PCRE now checks that it points
to a byte that is the start of a UTF-8 character. If not, it returns
PCRE_ERROR_BADUTF8_OFFSET (-11). Note: the whole string is still checked;
this is necessary because there may be backward assertions in the pattern.
When matching the same subject several times, it may save resources to use
PCRE_NO_UTF8_CHECK on all but the first call if the string is long.
4. The code for checking the validity of UTF-8 strings has been tightened so
that it rejects (a) strings containing 0xfe or 0xff bytes and (b) strings
containing "overlong sequences".
5. Fixed a bug (appearing twice) that I could not find any way of exploiting!
I had written "if ((digitab[*p++] && chtab_digit) == 0)" where the "&&"
should have been "&", but it just so happened that all the cases this let
through by mistake were picked up later in the function.
6. I had used a variable called "isblank" - this is a C99 function, causing
some compilers to warn. To avoid this, I renamed it (as "blankclass").
7. Cosmetic: (a) only output another newline at the end of pcretest if it is
prompting; (b) run "./pcretest /dev/null" at the start of the test script
so the version is shown; (c) stop "make test" echoing "./RunTest".
8. Added patches from David Burgess to enable PCRE to run on EBCDIC systems.
9. The prototype for memmove() for systems that don't have it was using
size_t, but the inclusion of the header that defines size_t was later. I've
moved the #includes for the C headers earlier to avoid this.
10. Added some adjustments to the code to make it easier to compiler on certain
special systems:
(a) Some "const" qualifiers were missing.
(b) Added the macro EXPORT before all exported functions; by default this
is defined to be empty.
(c) Changed the dftables auxiliary program (that builds chartables.c) so
that it reads its output file name as an argument instead of writing
to the standard output and assuming this can be redirected.
11. In UTF-8 mode, if a recursive reference (e.g. (?1)) followed a character
class containing characters with values greater than 255, PCRE compilation
went into a loop.
12. A recursive reference to a subpattern that was within another subpattern
that had a minimum quantifier of zero caused PCRE to crash. For example,
(x(y(?2))z)? provoked this bug with a subject that got as far as the
recursion. If the recursively-called subpattern itself had a zero repeat,
that was OK.
13. In pcretest, the buffer for reading a data line was set at 30K, but the
buffer into which it was copied (for escape processing) was still set at
1024, so long lines caused crashes.
14. A pattern such as /[ab]{1,3}+/ failed to compile, giving the error
"internal error: code overflow...". This applied to any character class
that was followed by a possessive quantifier.
15. Modified the Makefile to add libpcre.la as a prerequisite for
libpcreposix.la because I was told this is needed for a parallel build to
work.
16. If a pattern that contained .* following optional items at the start was
studied, the wrong optimizing data was generated, leading to matching
errors. For example, studying /[ab]*.*c/ concluded, erroneously, that any
matching string must start with a or b or c. The correct conclusion for
this pattern is that a match can start with any character.
Version 4.4 13-Aug-03
---------------------
1. In UTF-8 mode, a character class containing characters with values between
127 and 255 was not handled correctly if the compiled pattern was studied.
In fixing this, I have also improved the studying algorithm for such
classes (slightly).
2. Three internal functions had redundant arguments passed to them. Removal
might give a very teeny performance improvement.
3. Documentation bug: the value of the capture_top field in a callout is *one
more than* the number of the hightest numbered captured substring.
4. The Makefile linked pcretest and pcregrep with -lpcre, which could result
in incorrectly linking with a previously installed version. They now link
explicitly with libpcre.la.
5. configure.in no longer needs to recognize Cygwin specially.
6. A problem in pcre.in for Windows platforms is fixed.
7. If a pattern was successfully studied, and the -d (or /D) flag was given to
pcretest, it used to include the size of the study block as part of its
output. Unfortunately, the structure contains a field that has a different
size on different hardware architectures. This meant that the tests that
showed this size failed. As the block is currently always of a fixed size,
this information isn't actually particularly useful in pcretest output, so
I have just removed it.
8. Three pre-processor statements accidentally did not start in column 1.
Sadly, there are *still* compilers around that complain, even though
standard C has not required this for well over a decade. Sigh.
9. In pcretest, the code for checking callouts passed small integers in the
callout_data field, which is a void * field. However, some picky compilers
complained about the casts involved for this on 64-bit systems. Now
pcretest passes the address of the small integer instead, which should get
rid of the warnings.
10. By default, when in UTF-8 mode, PCRE now checks for valid UTF-8 strings at
both compile and run time, and gives an error if an invalid UTF-8 sequence
is found. There is a option for disabling this check in cases where the
string is known to be correct and/or the maximum performance is wanted.
11. In response to a bug report, I changed one line in Makefile.in from
-Wl,--out-implib,.libs/lib@WIN_PREFIX@pcreposix.dll.a \
to
-Wl,--out-implib,.libs/@WIN_PREFIX@libpcreposix.dll.a \
to look similar to other lines, but I have no way of telling whether this
is the right thing to do, as I do not use Windows. No doubt I'll get told
if it's wrong...
Version 4.3 21-May-03
---------------------
1. Two instances of @WIN_PREFIX@ omitted from the Windows targets in the
Makefile.
2. Some refactoring to improve the quality of the code:
(i) The utf8_table... variables are now declared "const".
(ii) The code for \cx, which used the "case flipping" table to upper case
lower case letters, now just substracts 32. This is ASCII-specific,
but the whole concept of \cx is ASCII-specific, so it seems
reasonable.
(iii) PCRE was using its character types table to recognize decimal and
hexadecimal digits in the pattern. This is silly, because it handles
only 0-9, a-f, and A-F, but the character types table is locale-
specific, which means strange things might happen. A private
table is now used for this - though it costs 256 bytes, a table is
much faster than multiple explicit tests. Of course, the standard
character types table is still used for matching digits in subject
strings against \d.
(iv) Strictly, the identifier ESC_t is reserved by POSIX (all identifiers
ending in _t are). So I've renamed it as ESC_tee.
3. The first argument for regexec() in the POSIX wrapper should have been
defined as "const".
4. Changed pcretest to use malloc() for its buffers so that they can be
Electric Fenced for debugging.
5. There were several places in the code where, in UTF-8 mode, PCRE would try
to read one or more bytes before the start of the subject string. Often this
had no effect on PCRE's behaviour, but in some circumstances it could
provoke a segmentation fault.
6. A lookbehind at the start of a pattern in UTF-8 mode could also cause PCRE
to try to read one or more bytes before the start of the subject string.
7. A lookbehind in a pattern matched in non-UTF-8 mode on a PCRE compiled with
UTF-8 support could misbehave in various ways if the subject string
contained bytes with the 0x80 bit set and the 0x40 bit unset in a lookbehind
area. (PCRE was not checking for the UTF-8 mode flag, and trying to move
back over UTF-8 characters.)
Version 4.2 14-Apr-03
---------------------
1. Typo "#if SUPPORT_UTF8" instead of "#ifdef SUPPORT_UTF8" fixed.
2. Changes to the building process, supplied by Ronald Landheer-Cieslak
[ON_WINDOWS]: new variable, "#" on non-Windows platforms
[NOT_ON_WINDOWS]: new variable, "#" on Windows platforms
[WIN_PREFIX]: new variable, "cyg" for Cygwin
* Makefile.in: use autoconf substitution for OBJEXT, EXEEXT, BUILD_OBJEXT
and BUILD_EXEEXT
Note: automatic setting of the BUILD variables is not yet working
set CPPFLAGS and BUILD_CPPFLAGS (but don't use yet) - should be used at
compile-time but not at link-time
[LINK]: use for linking executables only
make different versions for Windows and non-Windows
[LINKLIB]: new variable, copy of UNIX-style LINK, used for linking
libraries
[LINK_FOR_BUILD]: new variable
[OBJEXT]: use throughout
[EXEEXT]: use throughout
<winshared>: new target
<wininstall>: new target
<dftables.o>: use native compiler
<dftables>: use native linker
<install>: handle Windows platform correctly
<clean>: ditto
<check>: ditto
copy DLL to top builddir before testing
As part of these changes, -no-undefined was removed again. This was reported
to give trouble on HP-UX 11.0, so getting rid of it seems like a good idea
in any case.
3. Some tidies to get rid of compiler warnings:
. In the match_data structure, match_limit was an unsigned long int, whereas
match_call_count was an int. I've made them both unsigned long ints.
. In pcretest the fact that a const uschar * doesn't automatically cast to
a void * provoked a warning.
. Turning on some more compiler warnings threw up some "shadow" variables
and a few more missing casts.
4. If PCRE was complied with UTF-8 support, but called without the PCRE_UTF8
option, a class that contained a single character with a value between 128
and 255 (e.g. /[\xFF]/) caused PCRE to crash.
5. If PCRE was compiled with UTF-8 support, but called without the PCRE_UTF8
option, a class that contained several characters, but with at least one
whose value was between 128 and 255 caused PCRE to crash.
Version 4.1 12-Mar-03
---------------------
1. Compiling with gcc -pedantic found a couple of places where casts were
needed, and a string in dftables.c that was longer than standard compilers are
required to support.
2. Compiling with Sun's compiler found a few more places where the code could
be tidied up in order to avoid warnings.
3. The variables for cross-compiling were called HOST_CC and HOST_CFLAGS; the
first of these names is deprecated in the latest Autoconf in favour of the name
CC_FOR_BUILD, because "host" is typically used to mean the system on which the
compiled code will be run. I can't find a reference for HOST_CFLAGS, but by
analogy I have changed it to CFLAGS_FOR_BUILD.
4. Added -no-undefined to the linking command in the Makefile, because this is
apparently helpful for Windows. To make it work, also added "-L. -lpcre" to the
linking step for the pcreposix library.
5. PCRE was failing to diagnose the case of two named groups with the same
name.
6. A problem with one of PCRE's optimizations was discovered. PCRE remembers a
literal character that is needed in the subject for a match, and scans along to
ensure that it is present before embarking on the full matching process. This
saves time in cases of nested unlimited repeats that are never going to match.
Problem: the scan can take a lot of time if the subject is very long (e.g.
megabytes), thus penalizing straightforward matches. It is now done only if the
amount of subject to be scanned is less than 1000 bytes.
7. A lesser problem with the same optimization is that it was recording the
first character of an anchored pattern as "needed", thus provoking a search
right along the subject, even when the first match of the pattern was going to
fail. The "needed" character is now not set for anchored patterns, unless it
follows something in the pattern that is of non-fixed length. Thus, it still
fulfils its original purpose of finding quick non-matches in cases of nested
unlimited repeats, but isn't used for simple anchored patterns such as /^abc/.
Version 4.0 17-Feb-03
---------------------
1. If a comment in an extended regex that started immediately after a meta-item
extended to the end of string, PCRE compiled incorrect data. This could lead to
all kinds of weird effects. Example: /#/ was bad; /()#/ was bad; /a#/ was not.
2. Moved to autoconf 2.53 and libtool 1.4.2.
3. Perl 5.8 no longer needs "use utf8" for doing UTF-8 things. Consequently,
the special perltest8 script is no longer needed - all the tests can be run
from a single perltest script.
4. From 5.004, Perl has not included the VT character (0x0b) in the set defined
by \s. It has now been removed in PCRE. This means it isn't recognized as
whitespace in /x regexes too, which is the same as Perl. Note that the POSIX
class [:space:] *does* include VT, thereby creating a mess.
5. Added the class [:blank:] (a GNU extension from Perl 5.8) to match only
space and tab.
6. Perl 5.005 was a long time ago. It's time to amalgamate the tests that use
its new features into the main test script, reducing the number of scripts.
7. Perl 5.8 has changed the meaning of patterns like /a(?i)b/. Earlier versions
were backward compatible, and made the (?i) apply to the whole pattern, as if
/i were given. Now it behaves more logically, and applies the option setting
only to what follows. PCRE has been changed to follow suit. However, if it
finds options settings right at the start of the pattern, it extracts them into
the global options, as before. Thus, they show up in the info data.
8. Added support for the \Q...\E escape sequence. Characters in between are
treated as literals. This is slightly different from Perl in that $ and @ are
also handled as literals inside the quotes. In Perl, they will cause variable
interpolation. Note the following examples:
Pattern PCRE matches Perl matches
\Qabc$xyz\E abc$xyz abc followed by the contents of $xyz
\Qabc\$xyz\E abc\$xyz abc\$xyz
\Qabc\E\$\Qxyz\E abc$xyz abc$xyz
For compatibility with Perl, \Q...\E sequences are recognized inside character
classes as well as outside them.
9. Re-organized 3 code statements in pcretest to avoid "overflow in
floating-point constant arithmetic" warnings from a Microsoft compiler. Added a
(size_t) cast to one statement in pcretest and one in pcreposix to avoid
signed/unsigned warnings.
10. SunOS4 doesn't have strtoul(). This was used only for unpicking the -o
option for pcretest, so I've replaced it by a simple function that does just
that job.
11. pcregrep was ending with code 0 instead of 2 for the commands "pcregrep" or
"pcregrep -".
12. Added "possessive quantifiers" ?+, *+, ++, and {,}+ which come from Sun's
Java package. This provides some syntactic sugar for simple cases of what my
documentation calls "once-only subpatterns". A pattern such as x*+ is the same
as (?>x*). In other words, if what is inside (?>...) is just a single repeated
item, you can use this simplified notation. Note that only makes sense with
greedy quantifiers. Consequently, the use of the possessive quantifier forces
greediness, whatever the setting of the PCRE_UNGREEDY option.
13. A change of greediness default within a pattern was not taking effect at
the current level for patterns like /(b+(?U)a+)/. It did apply to parenthesized
subpatterns that followed. Patterns like /b+(?U)a+/ worked because the option
was abstracted outside.
14. PCRE now supports the \G assertion. It is true when the current matching
position is at the start point of the match. This differs from \A when the
starting offset is non-zero. Used with the /g option of pcretest (or similar
code), it works in the same way as it does for Perl's /g option. If all
alternatives of a regex begin with \G, the expression is anchored to the start
match position, and the "anchored" flag is set in the compiled expression.
15. Some bugs concerning the handling of certain option changes within patterns
have been fixed. These applied to options other than (?ims). For example,
"a(?x: b c )d" did not match "XabcdY" but did match "Xa b c dY". It should have
been the other way round. Some of this was related to change 7 above.
16. PCRE now gives errors for /[.x.]/ and /[=x=]/ as unsupported POSIX
features, as Perl does. Previously, PCRE gave the warnings only for /[[.x.]]/
and /[[=x=]]/. PCRE now also gives an error for /[:name:]/ because it supports
POSIX classes only within a class (e.g. /[[:alpha:]]/).
17. Added support for Perl's \C escape. This matches one byte, even in UTF8
mode. Unlike ".", it always matches newline, whatever the setting of
PCRE_DOTALL. However, PCRE does not permit \C to appear in lookbehind
assertions. Perl allows it, but it doesn't (in general) work because it can't
calculate the length of the lookbehind. At least, that's the case for Perl
5.8.0 - I've been told they are going to document that it doesn't work in
future.
18. Added an error diagnosis for escapes that PCRE does not support: these are
\L, \l, \N, \P, \p, \U, \u, and \X.
19. Although correctly diagnosing a missing ']' in a character class, PCRE was
reading past the end of the pattern in cases such as /[abcd/.
20. PCRE was getting more memory than necessary for patterns with classes that
contained both POSIX named classes and other characters, e.g. /[[:space:]abc/.
21. Added some code, conditional on #ifdef VPCOMPAT, to make life easier for
compiling PCRE for use with Virtual Pascal.
22. Small fix to the Makefile to make it work properly if the build is done
outside the source tree.
23. Added a new extension: a condition to go with recursion. If a conditional
subpattern starts with (?(R) the "true" branch is used if recursion has
happened, whereas the "false" branch is used only at the top level.
24. When there was a very long string of literal characters (over 255 bytes
without UTF support, over 250 bytes with UTF support), the computation of how
much memory was required could be incorrect, leading to segfaults or other
strange effects.
25. PCRE was incorrectly assuming anchoring (either to start of subject or to
start of line for a non-DOTALL pattern) when a pattern started with (.*) and
there was a subsequent back reference to those brackets. This meant that, for
example, /(.*)\d+\1/ failed to match "abc123bc". Unfortunately, it isn't
possible to check for precisely this case. All we can do is abandon the
optimization if .* occurs inside capturing brackets when there are any back
references whatsoever. (See below for a better fix that came later.)
26. The handling of the optimization for finding the first character of a
non-anchored pattern, and for finding a character that is required later in the
match were failing in some cases. This didn't break the matching; it just
failed to optimize when it could. The way this is done has been re-implemented.
27. Fixed typo in error message for invalid (?R item (it said "(?p").
28. Added a new feature that provides some of the functionality that Perl
provides with (?{...}). The facility is termed a "callout". The way it is done
in PCRE is for the caller to provide an optional function, by setting
pcre_callout to its entry point. Like pcre_malloc and pcre_free, this is a
global variable. By default it is unset, which disables all calling out. To get
the function called, the regex must include (?C) at appropriate points. This
is, in fact, equivalent to (?C0), and any number <= 255 may be given with (?C).
This provides a means of identifying different callout points. When PCRE
reaches such a point in the regex, if pcre_callout has been set, the external
function is called. It is provided with data in a structure called
pcre_callout_block, which is defined in pcre.h. If the function returns 0,
matching continues; if it returns a non-zero value, the match at the current
point fails. However, backtracking will occur if possible. [This was changed
later and other features added - see item 49 below.]
29. pcretest is upgraded to test the callout functionality. It provides a
callout function that displays information. By default, it shows the start of
the match and the current position in the text. There are some new data escapes
to vary what happens:
\C+ in addition, show current contents of captured substrings
\C- do not supply a callout function
\C!n return 1 when callout number n is reached
\C!n!m return 1 when callout number n is reached for the mth time
30. If pcregrep was called with the -l option and just a single file name, it
output "<stdin>" if a match was found, instead of the file name.
31. Improve the efficiency of the POSIX API to PCRE. If the number of capturing
slots is less than POSIX_MALLOC_THRESHOLD, use a block on the stack to pass to
pcre_exec(). This saves a malloc/free per call. The default value of
POSIX_MALLOC_THRESHOLD is 10; it can be changed by --with-posix-malloc-threshold
when configuring.
32. The default maximum size of a compiled pattern is 64K. There have been a
few cases of people hitting this limit. The code now uses macros to handle the
storing of links as offsets within the compiled pattern. It defaults to 2-byte
links, but this can be changed to 3 or 4 bytes by --with-link-size when
configuring. Tests 2 and 5 work only with 2-byte links because they output
debugging information about compiled patterns.
33. Internal code re-arrangements:
(a) Moved the debugging function for printing out a compiled regex into
its own source file (printint.c) and used #include to pull it into
pcretest.c and, when DEBUG is defined, into pcre.c, instead of having two
separate copies.
(b) Defined the list of op-code names for debugging as a macro in
internal.h so that it is next to the definition of the opcodes.
(c) Defined a table of op-code lengths for simpler skipping along compiled
code. This is again a macro in internal.h so that it is next to the
definition of the opcodes.
34. Added support for recursive calls to individual subpatterns, along the
lines of Robin Houston's patch (but implemented somewhat differently).
35. Further mods to the Makefile to help Win32. Also, added code to pcregrep to
allow it to read and process whole directories in Win32. This code was
contributed by Lionel Fourquaux; it has not been tested by me.
36. Added support for named subpatterns. The Python syntax (?P<name>...) is
used to name a group. Names consist of alphanumerics and underscores, and must
be unique. Back references use the syntax (?P=name) and recursive calls use
(?P>name) which is a PCRE extension to the Python extension. Groups still have
numbers. The function pcre_fullinfo() can be used after compilation to extract
a name/number map. There are three relevant calls:
PCRE_INFO_NAMEENTRYSIZE yields the size of each entry in the map
PCRE_INFO_NAMECOUNT yields the number of entries
PCRE_INFO_NAMETABLE yields a pointer to the map.
The map is a vector of fixed-size entries. The size of each entry depends on
the length of the longest name used. The first two bytes of each entry are the
group number, most significant byte first. There follows the corresponding
name, zero terminated. The names are in alphabetical order.
37. Make the maximum literal string in the compiled code 250 for the non-UTF-8
case instead of 255. Making it the same both with and without UTF-8 support
means that the same test output works with both.
38. There was a case of malloc(0) in the POSIX testing code in pcretest. Avoid
calling malloc() with a zero argument.
39. Change 25 above had to resort to a heavy-handed test for the .* anchoring
optimization. I've improved things by keeping a bitmap of backreferences with
numbers 1-31 so that if .* occurs inside capturing brackets that are not in
fact referenced, the optimization can be applied. It is unlikely that a
relevant occurrence of .* (i.e. one which might indicate anchoring or forcing
the match to follow \n) will appear inside brackets with a number greater than
31, but if it does, any back reference > 31 suppresses the optimization.
40. Added a new compile-time option PCRE_NO_AUTO_CAPTURE. This has the effect
of disabling numbered capturing parentheses. Any opening parenthesis that is
not followed by ? behaves as if it were followed by ?: but named parentheses
can still be used for capturing (and they will acquire numbers in the usual
way).
41. Redesigned the return codes from the match() function into yes/no/error so
that errors can be passed back from deep inside the nested calls. A malloc
failure while inside a recursive subpattern call now causes the
PCRE_ERROR_NOMEMORY return instead of quietly going wrong.
42. It is now possible to set a limit on the number of times the match()
function is called in a call to pcre_exec(). This facility makes it possible to
limit the amount of recursion and backtracking, though not in a directly
obvious way, because the match() function is used in a number of different
circumstances. The count starts from zero for each position in the subject
string (for non-anchored patterns). The default limit is, for compatibility, a
large number, namely 10 000 000. You can change this in two ways:
(a) When configuring PCRE before making, you can use --with-match-limit=n
to set a default value for the compiled library.
(b) For each call to pcre_exec(), you can pass a pcre_extra block in which
a different value is set. See 45 below.
If the limit is exceeded, pcre_exec() returns PCRE_ERROR_MATCHLIMIT.
43. Added a new function pcre_config(int, void *) to enable run-time extraction
of things that can be changed at compile time. The first argument specifies
what is wanted and the second points to where the information is to be placed.
The current list of available information is:
PCRE_CONFIG_UTF8
The output is an integer that is set to one if UTF-8 support is available;
otherwise it is set to zero.
PCRE_CONFIG_NEWLINE
The output is an integer that it set to the value of the code that is used for
newline. It is either LF (10) or CR (13).
PCRE_CONFIG_LINK_SIZE
The output is an integer that contains the number of bytes used for internal
linkage in compiled expressions. The value is 2, 3, or 4. See item 32 above.
PCRE_CONFIG_POSIX_MALLOC_THRESHOLD
The output is an integer that contains the threshold above which the POSIX
interface uses malloc() for output vectors. See item 31 above.
PCRE_CONFIG_MATCH_LIMIT
The output is an unsigned integer that contains the default limit of the number
of match() calls in a pcre_exec() execution. See 42 above.
44. pcretest has been upgraded by the addition of the -C option. This causes it
to extract all the available output from the new pcre_config() function, and to
output it. The program then exits immediately.
45. A need has arisen to pass over additional data with calls to pcre_exec() in
order to support additional features. One way would have been to define
pcre_exec2() (for example) with extra arguments, but this would not have been
extensible, and would also have required all calls to the original function to
be mapped to the new one. Instead, I have chosen to extend the mechanism that
is used for passing in "extra" data from pcre_study().
The pcre_extra structure is now exposed and defined in pcre.h. It currently
contains the following fields:
flags a bitmap indicating which of the following fields are set
study_data opaque data from pcre_study()
match_limit a way of specifying a limit on match() calls for a specific
call to pcre_exec()
callout_data data for callouts (see 49 below)
The flag bits are also defined in pcre.h, and are
PCRE_EXTRA_STUDY_DATA
PCRE_EXTRA_MATCH_LIMIT
PCRE_EXTRA_CALLOUT_DATA
The pcre_study() function now returns one of these new pcre_extra blocks, with
the actual study data pointed to by the study_data field, and the
PCRE_EXTRA_STUDY_DATA flag set. This can be passed directly to pcre_exec() as
before. That is, this change is entirely upwards-compatible and requires no
change to existing code.
If you want to pass in additional data to pcre_exec(), you can either place it
in a pcre_extra block provided by pcre_study(), or create your own pcre_extra
block.
46. pcretest has been extended to test the PCRE_EXTRA_MATCH_LIMIT feature. If a
data string contains the escape sequence \M, pcretest calls pcre_exec() several
times with different match limits, until it finds the minimum value needed for
pcre_exec() to complete. The value is then output. This can be instructive; for
most simple matches the number is quite small, but for pathological cases it
gets very large very quickly.
47. There's a new option for pcre_fullinfo() called PCRE_INFO_STUDYSIZE. It
returns the size of the data block pointed to by the study_data field in a
pcre_extra block, that is, the value that was passed as the argument to
pcre_malloc() when PCRE was getting memory in which to place the information
created by pcre_study(). The fourth argument should point to a size_t variable.
pcretest has been extended so that this information is shown after a successful
pcre_study() call when information about the compiled regex is being displayed.
48. Cosmetic change to Makefile: there's no need to have / after $(DESTDIR)
because what follows is always an absolute path. (Later: it turns out that this
is more than cosmetic for MinGW, because it doesn't like empty path
components.)
49. Some changes have been made to the callout feature (see 28 above):
(i) A callout function now has three choices for what it returns:
0 => success, carry on matching
> 0 => failure at this point, but backtrack if possible
< 0 => serious error, return this value from pcre_exec()
Negative values should normally be chosen from the set of PCRE_ERROR_xxx
values. In particular, returning PCRE_ERROR_NOMATCH forces a standard
"match failed" error. The error number PCRE_ERROR_CALLOUT is reserved for
use by callout functions. It will never be used by PCRE itself.
(ii) The pcre_extra structure (see 45 above) has a void * field called
callout_data, with corresponding flag bit PCRE_EXTRA_CALLOUT_DATA. The
pcre_callout_block structure has a field of the same name. The contents of
the field passed in the pcre_extra structure are passed to the callout
function in the corresponding field in the callout block. This makes it
easier to use the same callout-containing regex from multiple threads. For
testing, the pcretest program has a new data escape
\C*n pass the number n (may be negative) as callout_data
If the callout function in pcretest receives a non-zero value as
callout_data, it returns that value.
50. Makefile wasn't handling CFLAGS properly when compiling dftables. Also,
there were some redundant $(CFLAGS) in commands that are now specified as
$(LINK), which already includes $(CFLAGS).
51. Extensions to UTF-8 support are listed below. These all apply when (a) PCRE
has been compiled with UTF-8 support *and* pcre_compile() has been compiled
with the PCRE_UTF8 flag. Patterns that are compiled without that flag assume
one-byte characters throughout. Note that case-insensitive matching applies
only to characters whose values are less than 256. PCRE doesn't support the
notion of cases for higher-valued characters.
(i) A character class whose characters are all within 0-255 is handled as
a bit map, and the map is inverted for negative classes. Previously, a
character > 255 always failed to match such a class; however it should
match if the class was a negative one (e.g. [^ab]). This has been fixed.
(ii) A negated character class with a single character < 255 is coded as
"not this character" (OP_NOT). This wasn't working properly when the test
character was multibyte, either singly or repeated.
(iii) Repeats of multibyte characters are now handled correctly in UTF-8
mode, for example: \x{100}{2,3}.
(iv) The character escapes \b, \B, \d, \D, \s, \S, \w, and \W (either
singly or repeated) now correctly test multibyte characters. However,
PCRE doesn't recognize any characters with values greater than 255 as
digits, spaces, or word characters. Such characters always match \D, \S,
and \W, and never match \d, \s, or \w.
(v) Classes may now contain characters and character ranges with values
greater than 255. For example: [ab\x{100}-\x{400}].
(vi) pcregrep now has a --utf-8 option (synonym -u) which makes it call
PCRE in UTF-8 mode.
52. The info request value PCRE_INFO_FIRSTCHAR has been renamed
PCRE_INFO_FIRSTBYTE because it is a byte value. However, the old name is
retained for backwards compatibility. (Note that LASTLITERAL is also a byte
value.)
53. The single man page has become too large. I have therefore split it up into
a number of separate man pages. These also give rise to individual HTML pages;
these are now put in a separate directory, and there is an index.html page that
lists them all. Some hyperlinking between the pages has been installed.
54. Added convenience functions for handling named capturing parentheses.
55. Unknown escapes inside character classes (e.g. [\M]) and escapes that
aren't interpreted therein (e.g. [\C]) are literals in Perl. This is now also
true in PCRE, except when the PCRE_EXTENDED option is set, in which case they
are faulted.
56. Introduced HOST_CC and HOST_CFLAGS which can be set in the environment when
calling configure. These values are used when compiling the dftables.c program
which is run to generate the source of the default character tables. They
default to the values of CC and CFLAGS. If you are cross-compiling PCRE,
you will need to set these values.
57. Updated the building process for Windows DLL, as provided by Fred Cox.
Version 3.9 02-Jan-02
---------------------
1. A bit of extraneous text had somehow crept into the pcregrep documentation.
2. If --disable-static was given, the building process failed when trying to
build pcretest and pcregrep. (For some reason it was using libtool to compile
them, which is not right, as they aren't part of the library.)
Version 3.8 18-Dec-01
---------------------
1. The experimental UTF-8 code was completely screwed up. It was packing the
bytes in the wrong order. How dumb can you get?
Version 3.7 29-Oct-01
---------------------
1. In updating pcretest to check change 1 of version 3.6, I screwed up.
This caused pcretest, when used on the test data, to segfault. Unfortunately,
this didn't happen under Solaris 8, where I normally test things.
2. The Makefile had to be changed to make it work on BSD systems, where 'make'
doesn't seem to recognize that ./xxx and xxx are the same file. (This entry
isn't in ChangeLog distributed with 3.7 because I forgot when I hastily made
this fix an hour or so after the initial 3.7 release.)
Version 3.6 23-Oct-01
---------------------
1. Crashed with /(sens|respons)e and \1ibility/ and "sense and sensibility" if
offsets passed as NULL with zero offset count.
2. The config.guess and config.sub files had not been updated when I moved to
the latest autoconf.
Version 3.5 15-Aug-01
---------------------
1. Added some missing #if !defined NOPOSIX conditionals in pcretest.c that
had been forgotten.
2. By using declared but undefined structures, we can avoid using "void"
definitions in pcre.h while keeping the internal definitions of the structures
private.
3. The distribution is now built using autoconf 2.50 and libtool 1.4. From a
user point of view, this means that both static and shared libraries are built
by default, but this can be individually controlled. More of the work of
handling this static/shared cases is now inside libtool instead of PCRE's make
file.
4. The pcretest utility is now installed along with pcregrep because it is
useful for users (to test regexs) and by doing this, it automatically gets
relinked by libtool. The documentation has been turned into a man page, so
there are now .1, .txt, and .html versions in /doc.
5. Upgrades to pcregrep:
(i) Added long-form option names like gnu grep.
(ii) Added --help to list all options with an explanatory phrase.
(iii) Added -r, --recursive to recurse into sub-directories.
(iv) Added -f, --file to read patterns from a file.
6. pcre_exec() was referring to its "code" argument before testing that
argument for NULL (and giving an error if it was NULL).
7. Upgraded Makefile.in to allow for compiling in a different directory from
the source directory.
8. Tiny buglet in pcretest: when pcre_fullinfo() was called to retrieve the
options bits, the pointer it was passed was to an int instead of to an unsigned
long int. This mattered only on 64-bit systems.
9. Fixed typo (3.4/1) in pcre.h again. Sigh. I had changed pcre.h (which is
generated) instead of pcre.in, which it its source. Also made the same change
in several of the .c files.
10. A new release of gcc defines printf() as a macro, which broke pcretest
because it had an ifdef in the middle of a string argument for printf(). Fixed
by using separate calls to printf().
11. Added --enable-newline-is-cr and --enable-newline-is-lf to the configure
script, to force use of CR or LF instead of \n in the source. On non-Unix
systems, the value can be set in config.h.
12. The limit of 200 on non-capturing parentheses is a _nesting_ limit, not an
absolute limit. Changed the text of the error message to make this clear, and
likewise updated the man page.
13. The limit of 99 on the number of capturing subpatterns has been removed.
The new limit is 65535, which I hope will not be a "real" limit.
Version 3.4 22-Aug-00
---------------------
1. Fixed typo in pcre.h: unsigned const char * changed to const unsigned char *.
2. Diagnose condition (?(0) as an error instead of crashing on matching.
Version 3.3 01-Aug-00
---------------------
1. If an octal character was given, but the value was greater than \377, it
was not getting masked to the least significant bits, as documented. This could
lead to crashes in some systems.
2. Perl 5.6 (if not earlier versions) accepts classes like [a-\d] and treats
the hyphen as a literal. PCRE used to give an error; it now behaves like Perl.
3. Added the functions pcre_free_substring() and pcre_free_substring_list().
These just pass their arguments on to (pcre_free)(), but they are provided
because some uses of PCRE bind it to non-C systems that can call its functions,
but cannot call free() or pcre_free() directly.
4. Add "make test" as a synonym for "make check". Corrected some comments in
the Makefile.
5. Add $(DESTDIR)/ in front of all the paths in the "install" target in the
Makefile.
6. Changed the name of pgrep to pcregrep, because Solaris has introduced a
command called pgrep for grepping around the active processes.
7. Added the beginnings of support for UTF-8 character strings.
8. Arranged for the Makefile to pass over the settings of CC, CFLAGS, and
RANLIB to ./ltconfig so that they are used by libtool. I think these are all
the relevant ones. (AR is not passed because ./ltconfig does its own figuring
out for the ar command.)
Version 3.2 12-May-00
---------------------
This is purely a bug fixing release.
1. If the pattern /((Z)+|A)*/ was matched agained ZABCDEFG it matched Z instead
of ZA. This was just one example of several cases that could provoke this bug,
which was introduced by change 9 of version 2.00. The code for breaking
infinite loops after an iteration that matches an empty string was't working
correctly.
2. The pcretest program was not imitating Perl correctly for the pattern /a*/g
when matched against abbab (for example). After matching an empty string, it
wasn't forcing anchoring when setting PCRE_NOTEMPTY for the next attempt; this
caused it to match further down the string than it should.
3. The code contained an inclusion of sys/types.h. It isn't clear why this
was there because it doesn't seem to be needed, and it causes trouble on some
systems, as it is not a Standard C header. It has been removed.
4. Made 4 silly changes to the source to avoid stupid compiler warnings that
were reported on the Macintosh. The changes were from
while ((c = *(++ptr)) != 0 && c != '\n');
to
while ((c = *(++ptr)) != 0 && c != '\n') ;
Totally extraordinary, but if that's what it takes...
5. PCRE is being used in one environment where neither memmove() nor bcopy() is
available. Added HAVE_BCOPY and an autoconf test for it; if neither
HAVE_MEMMOVE nor HAVE_BCOPY is set, use a built-in emulation function which
assumes the way PCRE uses memmove() (always moving upwards).
6. PCRE is being used in one environment where strchr() is not available. There
was only one use in pcre.c, and writing it out to avoid strchr() probably gives
faster code anyway.
Version 3.1 09-Feb-00
---------------------
The only change in this release is the fixing of some bugs in Makefile.in for
the "install" target:
(1) It was failing to install pcreposix.h.
(2) It was overwriting the pcre.3 man page with the pcreposix.3 man page.
Version 3.0 01-Feb-00
---------------------
1. Add support for the /+ modifier to perltest (to output $` like it does in
pcretest).
2. Add support for the /g modifier to perltest.
3. Fix pcretest so that it behaves even more like Perl for /g when the pattern
matches null strings.
4. Fix perltest so that it doesn't do unwanted things when fed an empty
pattern. Perl treats empty patterns specially - it reuses the most recent
pattern, which is not what we want. Replace // by /(?#)/ in order to avoid this
effect.
5. The POSIX interface was broken in that it was just handing over the POSIX
captured string vector to pcre_exec(), but (since release 2.00) PCRE has
required a bigger vector, with some working space on the end. This means that
the POSIX wrapper now has to get and free some memory, and copy the results.
6. Added some simple autoconf support, placing the test data and the
documentation in separate directories, re-organizing some of the
information files, and making it build pcre-config (a GNU standard). Also added
libtool support for building PCRE as a shared library, which is now the
default.
7. Got rid of the leading zero in the definition of PCRE_MINOR because 08 and
09 are not valid octal constants. Single digits will be used for minor values
less than 10.
8. Defined REG_EXTENDED and REG_NOSUB as zero in the POSIX header, so that
existing programs that set these in the POSIX interface can use PCRE without
modification.
9. Added a new function, pcre_fullinfo() with an extensible interface. It can
return all that pcre_info() returns, plus additional data. The pcre_info()
function is retained for compatibility, but is considered to be obsolete.
10. Added experimental recursion feature (?R) to handle one common case that
Perl 5.6 will be able to do with (?p{...}).
11. Added support for POSIX character classes like [:alpha:], which Perl is
adopting.
Version 2.08 31-Aug-99
----------------------
1. When startoffset was not zero and the pattern began with ".*", PCRE was not
trying to match at the startoffset position, but instead was moving forward to
the next newline as if a previous match had failed.
2. pcretest was not making use of PCRE_NOTEMPTY when repeating for /g and /G,
and could get into a loop if a null string was matched other than at the start
of the subject.
3. Added definitions of PCRE_MAJOR and PCRE_MINOR to pcre.h so the version can
be distinguished at compile time, and for completeness also added PCRE_DATE.
5. Added Paul Sokolovsky's minor changes to make it easy to compile a Win32 DLL
in GnuWin32 environments.
Version 2.07 29-Jul-99
----------------------
1. The documentation is now supplied in plain text form and HTML as well as in
the form of man page sources.
2. C++ compilers don't like assigning (void *) values to other pointer types.
In particular this affects malloc(). Although there is no problem in Standard
C, I've put in casts to keep C++ compilers happy.
3. Typo on pcretest.c; a cast of (unsigned char *) in the POSIX regexec() call
should be (const char *).
4. If NOPOSIX is defined, pcretest.c compiles without POSIX support. This may
be useful for non-Unix systems who don't want to bother with the POSIX stuff.
However, I haven't made this a standard facility. The documentation doesn't
mention it, and the Makefile doesn't support it.
5. The Makefile now contains an "install" target, with editable destinations at
the top of the file. The pcretest program is not installed.
6. pgrep -V now gives the PCRE version number and date.
7. Fixed bug: a zero repetition after a literal string (e.g. /abcde{0}/) was
causing the entire string to be ignored, instead of just the last character.
8. If a pattern like /"([^\\"]+|\\.)*"/ is applied in the normal way to a
non-matching string, it can take a very, very long time, even for strings of
quite modest length, because of the nested recursion. PCRE now does better in
some of these cases. It does this by remembering the last required literal
character in the pattern, and pre-searching the subject to ensure it is present
before running the real match. In other words, it applies a heuristic to detect
some types of certain failure quickly, and in the above example, if presented
with a string that has no trailing " it gives "no match" very quickly.
9. A new runtime option PCRE_NOTEMPTY causes null string matches to be ignored;
other alternatives are tried instead.
Version 2.06 09-Jun-99
----------------------
1. Change pcretest's output for amount of store used to show just the code
space, because the remainder (the data block) varies in size between 32-bit and
64-bit systems.
2. Added an extra argument to pcre_exec() to supply an offset in the subject to
start matching at. This allows lookbehinds to work when searching for multiple
occurrences in a string.
3. Added additional options to pcretest for testing multiple occurrences:
/+ outputs the rest of the string that follows a match
/g loops for multiple occurrences, using the new startoffset argument
/G loops for multiple occurrences by passing an incremented pointer
4. PCRE wasn't doing the "first character" optimization for patterns starting
with \b or \B, though it was doing it for other lookbehind assertions. That is,
it wasn't noticing that a match for a pattern such as /\bxyz/ has to start with
the letter 'x'. On long subject strings, this gives a significant speed-up.
Version 2.05 21-Apr-99
----------------------
1. Changed the type of magic_number from int to long int so that it works
properly on 16-bit systems.
2. Fixed a bug which caused patterns starting with .* not to work correctly
when the subject string contained newline characters. PCRE was assuming
anchoring for such patterns in all cases, which is not correct because .* will
not pass a newline unless PCRE_DOTALL is set. It now assumes anchoring only if
DOTALL is set at top level; otherwise it knows that patterns starting with .*
must be retried after every newline in the subject.
Version 2.04 18-Feb-99
----------------------
1. For parenthesized subpatterns with repeats whose minimum was zero, the
computation of the store needed to hold the pattern was incorrect (too large).
If such patterns were nested a few deep, this could multiply and become a real
problem.
2. Added /M option to pcretest to show the memory requirement of a specific
pattern. Made -m a synonym of -s (which does this globally) for compatibility.
3. Subpatterns of the form (regex){n,m} (i.e. limited maximum) were being
compiled in such a way that the backtracking after subsequent failure was
pessimal. Something like (a){0,3} was compiled as (a)?(a)?(a)? instead of
((a)((a)(a)?)?)? with disastrous performance if the maximum was of any size.
Version 2.03 02-Feb-99
----------------------
1. Fixed typo and small mistake in man page.
2. Added 4th condition (GPL supersedes if conflict) and created separate
LICENCE file containing the conditions.
3. Updated pcretest so that patterns such as /abc\/def/ work like they do in
Perl, that is the internal \ allows the delimiter to be included in the
pattern. Locked out the use of \ as a delimiter. If \ immediately follows
the final delimiter, add \ to the end of the pattern (to test the error).
4. Added the convenience functions for extracting substrings after a successful
match. Updated pcretest to make it able to test these functions.
Version 2.02 14-Jan-99
----------------------
1. Initialized the working variables associated with each extraction so that
their saving and restoring doesn't refer to uninitialized store.
2. Put dummy code into study.c in order to trick the optimizer of the IBM C
compiler for OS/2 into generating correct code. Apparently IBM isn't going to
fix the problem.
3. Pcretest: the timing code wasn't using LOOPREPEAT for timing execution
calls, and wasn't printing the correct value for compiling calls. Increased the
default value of LOOPREPEAT, and the number of significant figures in the
times.
4. Changed "/bin/rm" in the Makefile to "-rm" so it works on Windows NT.
5. Renamed "deftables" as "dftables" to get it down to 8 characters, to avoid
a building problem on Windows NT with a FAT file system.
Version 2.01 21-Oct-98
----------------------
1. Changed the API for pcre_compile() to allow for the provision of a pointer
to character tables built by pcre_maketables() in the current locale. If NULL
is passed, the default tables are used.
Version 2.00 24-Sep-98
----------------------
1. Since the (>?) facility is in Perl 5.005, don't require PCRE_EXTRA to enable
it any more.
2. Allow quantification of (?>) groups, and make it work correctly.
3. The first character computation wasn't working for (?>) groups.
4. Correct the implementation of \Z (it is permitted to match on the \n at the
end of the subject) and add 5.005's \z, which really does match only at the
very end of the subject.
5. Remove the \X "cut" facility; Perl doesn't have it, and (?> is neater.
6. Remove the ability to specify CASELESS, MULTILINE, DOTALL, and
DOLLAR_END_ONLY at runtime, to make it possible to implement the Perl 5.005
localized options. All options to pcre_study() were also removed.
7. Add other new features from 5.005:
$(?<= positive lookbehind
$(?<! negative lookbehind
(?imsx-imsx) added the unsetting capability
such a setting is global if at outer level; local otherwise
(?imsx-imsx:) non-capturing groups with option setting
(?(cond)re|re) conditional pattern matching
A backreference to itself in a repeated group matches the previous
captured string.
8. General tidying up of studying (both automatic and via "study")
consequential on the addition of new assertions.
9. As in 5.005, unlimited repeated groups that could match an empty substring
are no longer faulted at compile time. Instead, the loop is forcibly broken at
runtime if any iteration does actually match an empty substring.
10. Include the RunTest script in the distribution.
11. Added tests from the Perl 5.005_02 distribution. This showed up a few
discrepancies, some of which were old and were also with respect to 5.004. They
have now been fixed.
Version 1.09 28-Apr-98
----------------------
1. A negated single character class followed by a quantifier with a minimum
value of one (e.g. [^x]{1,6} ) was not compiled correctly. This could lead to
program crashes, or just wrong answers. This did not apply to negated classes
containing more than one character, or to minima other than one.
Version 1.08 27-Mar-98
----------------------
1. Add PCRE_UNGREEDY to invert the greediness of quantifiers.
2. Add (?U) and (?X) to set PCRE_UNGREEDY and PCRE_EXTRA respectively. The
latter must appear before anything that relies on it in the pattern.
Version 1.07 16-Feb-98
----------------------
1. A pattern such as /((a)*)*/ was not being diagnosed as in error (unlimited
repeat of a potentially empty string).
Version 1.06 23-Jan-98
----------------------
1. Added Markus Oberhumer's little patches for C++.
2. Literal strings longer than 255 characters were broken.
Version 1.05 23-Dec-97
----------------------
1. Negated character classes containing more than one character were failing if
PCRE_CASELESS was set at run time.
Version 1.04 19-Dec-97
----------------------
1. Corrected the man page, where some "const" qualifiers had been omitted.
2. Made debugging output print "{0,xxx}" instead of just "{,xxx}" to agree with
input syntax.
3. Fixed memory leak which occurred when a regex with back references was
matched with an offsets vector that wasn't big enough. The temporary memory
that is used in this case wasn't being freed if the match failed.
4. Tidied pcretest to ensure it frees memory that it gets.
5. Temporary memory was being obtained in the case where the passed offsets
vector was exactly big enough.
6. Corrected definition of offsetof() from change 5 below.
7. I had screwed up change 6 below and broken the rules for the use of
setjmp(). Now fixed.
Version 1.03 18-Dec-97
----------------------
1. A erroneous regex with a missing opening parenthesis was correctly
diagnosed, but PCRE attempted to access brastack[-1], which could cause crashes
on some systems.
2. Replaced offsetof(real_pcre, code) by offsetof(real_pcre, code[0]) because
it was reported that one broken compiler failed on the former because "code" is
also an independent variable.
3. The erroneous regex a[]b caused an array overrun reference.
4. A regex ending with a one-character negative class (e.g. /[^k]$/) did not
fail on data ending with that character. (It was going on too far, and checking
the next character, typically a binary zero.) This was specific to the
optimized code for single-character negative classes.
5. Added a contributed patch from the TIN world which does the following:
+ Add an undef for memmove, in case the the system defines a macro for it.
+ Add a definition of offsetof(), in case there isn't one. (I don't know
the reason behind this - offsetof() is part of the ANSI standard - but
it does no harm).
+ Reduce the ifdef's in pcre.c using macro DPRINTF, thereby eliminating
most of the places where whitespace preceded '#'. I have given up and
allowed the remaining 2 cases to be at the margin.
+ Rename some variables in pcre to eliminate shadowing. This seems very
pedantic, but does no harm, of course.
6. Moved the call to setjmp() into its own function, to get rid of warnings
from gcc -Wall, and avoided calling it at all unless PCRE_EXTRA is used.
7. Constructs such as \d{8,} were compiling into the equivalent of
\d{8}\d{0,65527} instead of \d{8}\d* which didn't make much difference to the
outcome, but in this particular case used more store than had been allocated,
which caused the bug to be discovered because it threw up an internal error.
8. The debugging code in both pcre and pcretest for outputting the compiled
form of a regex was going wrong in the case of back references followed by
curly-bracketed repeats.
Version 1.02 12-Dec-97
----------------------
1. Typos in pcre.3 and comments in the source fixed.
2. Applied a contributed patch to get rid of places where it used to remove
'const' from variables, and fixed some signed/unsigned and uninitialized
variable warnings.
3. Added the "runtest" target to Makefile.
4. Set default compiler flag to -O2 rather than just -O.
Version 1.01 19-Nov-97
----------------------
1. PCRE was failing to diagnose unlimited repeat of empty string for patterns
like /([ab]*)*/, that is, for classes with more than one character in them.
2. Likewise, it wasn't diagnosing patterns with "once-only" subpatterns, such
as /((?>a*))*/ (a PCRE_EXTRA facility).
Version 1.00 18-Nov-97
----------------------
1. Added compile-time macros to support systems such as SunOS4 which don't have
memmove() or strerror() but have other things that can be used instead.
2. Arranged that "make clean" removes the executables.
Version 0.99 27-Oct-97
----------------------
1. Fixed bug in code for optimizing classes with only one character. It was
initializing a 32-byte map regardless, which could cause it to run off the end
of the memory it had got.
2. Added, conditional on PCRE_EXTRA, the proposed (?>REGEX) construction.
Version 0.98 22-Oct-97
----------------------
1. Fixed bug in code for handling temporary memory usage when there are more
back references than supplied space in the ovector. This could cause segfaults.
Version 0.97 21-Oct-97
----------------------
1. Added the \X "cut" facility, conditional on PCRE_EXTRA.
2. Optimized negated single characters not to use a bit map.
3. Brought error texts together as macro definitions; clarified some of them;
fixed one that was wrong - it said "range out of order" when it meant "invalid
escape sequence".
4. Changed some char * arguments to const char *.
5. Added PCRE_NOTBOL and PCRE_NOTEOL (from POSIX).
6. Added the POSIX-style API wrapper in pcreposix.a and testing facilities in
pcretest.
Version 0.96 16-Oct-97
----------------------
1. Added a simple "pgrep" utility to the distribution.
2. Fixed an incompatibility with Perl: "{" is now treated as a normal character
unless it appears in one of the precise forms "{ddd}", "{ddd,}", or "{ddd,ddd}"
where "ddd" means "one or more decimal digits".
3. Fixed serious bug. If a pattern had a back reference, but the call to
pcre_exec() didn't supply a large enough ovector to record the related
identifying subpattern, the match always failed. PCRE now remembers the number
of the largest back reference, and gets some temporary memory in which to save
the offsets during matching if necessary, in order to ensure that
backreferences always work.
4. Increased the compatibility with Perl in a number of ways:
(a) . no longer matches \n by default; an option PCRE_DOTALL is provided
to request this handling. The option can be set at compile or exec time.
(b) $ matches before a terminating newline by default; an option
PCRE_DOLLAR_ENDONLY is provided to override this (but not in multiline
mode). The option can be set at compile or exec time.
(c) The handling of \ followed by a digit other than 0 is now supposed to be
the same as Perl's. If the decimal number it represents is less than 10
or there aren't that many previous left capturing parentheses, an octal
escape is read. Inside a character class, it's always an octal escape,
even if it is a single digit.
(d) An escaped but undefined alphabetic character is taken as a literal,
unless PCRE_EXTRA is set. Currently this just reserves the remaining
escapes.
(e) {0} is now permitted. (The previous item is removed from the compiled
pattern).
5. Changed all the names of code files so that the basic parts are no longer
than 10 characters, and abolished the teeny "globals.c" file.
6. Changed the handling of character classes; they are now done with a 32-byte
bit map always.
7. Added the -d and /D options to pcretest to make it possible to look at the
internals of compilation without having to recompile pcre.
Version 0.95 23-Sep-97
----------------------
1. Fixed bug in pre-pass concerning escaped "normal" characters such as \x5c or
\x20 at the start of a run of normal characters. These were being treated as
real characters, instead of the source characters being re-checked.
Version 0.94 18-Sep-97
----------------------
1. The functions are now thread-safe, with the caveat that the global variables
containing pointers to malloc() and free() or alternative functions are the
same for all threads.
2. Get pcre_study() to generate a bitmap of initial characters for non-
anchored patterns when this is possible, and use it if passed to pcre_exec().
Version 0.93 15-Sep-97
----------------------
1. /(b)|(:+)/ was computing an incorrect first character.
2. Add pcre_study() to the API and the passing of pcre_extra to pcre_exec(),
but not actually doing anything yet.
3. Treat "-" characters in classes that cannot be part of ranges as literals,
as Perl does (e.g. [-az] or [az-]).
4. Set the anchored flag if a branch starts with .* or .*? because that tests
all possible positions.
5. Split up into different modules to avoid including unneeded functions in a
compiled binary. However, compile and exec are still in one module. The "study"
function is split off.
6. The character tables are now in a separate module whose source is generated
by an auxiliary program - but can then be edited by hand if required. There are
now no calls to isalnum(), isspace(), isdigit(), isxdigit(), tolower() or
toupper() in the code.
7. Turn the malloc/free funtions variables into pcre_malloc and pcre_free and
make them global. Abolish the function for setting them, as the caller can now
set them directly.
Version 0.92 11-Sep-97
----------------------
1. A repeat with a fixed maximum and a minimum of 1 for an ordinary character
(e.g. /a{1,3}/) was broken (I mis-optimized it).
2. Caseless matching was not working in character classes if the characters in
the pattern were in upper case.
3. Make ranges like [W-c] work in the same way as Perl for caseless matching.
4. Make PCRE_ANCHORED public and accept as a compile option.
5. Add an options word to pcre_exec() and accept PCRE_ANCHORED and
PCRE_CASELESS at run time. Add escapes \A and \I to pcretest to cause it to
pass them.
6. Give an error if bad option bits passed at compile or run time.
7. Add PCRE_MULTILINE at compile and exec time, and (?m) as well. Add \M to
pcretest to cause it to pass that flag.
8. Add pcre_info(), to get the number of identifying subpatterns, the stored
options, and the first character, if set.
9. Recognize C+ or C{n,m} where n >= 1 as providing a fixed starting character.
Version 0.91 10-Sep-97
----------------------
1. PCRE was failing to diagnose unlimited repeats of subpatterns that could
match the empty string as in /(a*)*/. It was looping and ultimately crashing.
2. PCRE was looping on encountering an indefinitely repeated back reference to
a subpattern that had matched an empty string, e.g. /(a|)\1*/. It now does what
Perl does - treats the match as successful.
****
PK � %[!���_ _ doc/alt-pcre/COPYINGnu �[��� PCRE LICENCE
Please see the file LICENCE in the PCRE distribution for licensing details.
End
PK � %[ʿ��S S doc/alt-pcre/AUTHORSnu �[��� THE MAIN PCRE LIBRARY
---------------------
Written by: Philip Hazel
Email local part: ph10
Email domain: cam.ac.uk
University of Cambridge Computing Service,
Cambridge, England.
Copyright (c) 1997-2017 University of Cambridge
All rights reserved
PCRE JUST-IN-TIME COMPILATION SUPPORT
-------------------------------------
Written by: Zoltan Herczeg
Email local part: hzmester
Emain domain: freemail.hu
Copyright(c) 2010-2017 Zoltan Herczeg
All rights reserved.
STACK-LESS JUST-IN-TIME COMPILER
--------------------------------
Written by: Zoltan Herczeg
Email local part: hzmester
Emain domain: freemail.hu
Copyright(c) 2009-2017 Zoltan Herczeg
All rights reserved.
THE C++ WRAPPER LIBRARY
-----------------------
Written by: Google Inc.
Copyright (c) 2007-2012 Google Inc
All rights reserved
####
PK � %[1ⱐ�
�
man/man1/pcre-config.1nu �[��� .TH PCRE-CONFIG 1 "01 January 2012" "PCRE 8.30"
.SH NAME
pcre-config - program to return PCRE configuration
.SH SYNOPSIS
.rs
.sp
.nf
.B pcre-config [--prefix] [--exec-prefix] [--version] [--libs]
.B " [--libs16] [--libs32] [--libs-cpp] [--libs-posix]"
.B " [--cflags] [--cflags-posix]"
.fi
.
.
.SH DESCRIPTION
.rs
.sp
\fBpcre-config\fP returns the configuration of the installed PCRE
libraries and the options required to compile a program to use them. Some of
the options apply only to the 8-bit, or 16-bit, or 32-bit libraries,
respectively, and are
not available if only one of those libraries has been built. If an unavailable
option is encountered, the "usage" information is output.
.
.
.SH OPTIONS
.rs
.TP 10
\fB--prefix\fP
Writes the directory prefix used in the PCRE installation for architecture
independent files (\fI/usr\fP on many systems, \fI/usr/local\fP on some
systems) to the standard output.
.TP 10
\fB--exec-prefix\fP
Writes the directory prefix used in the PCRE installation for architecture
dependent files (normally the same as \fB--prefix\fP) to the standard output.
.TP 10
\fB--version\fP
Writes the version number of the installed PCRE libraries to the standard
output.
.TP 10
\fB--libs\fP
Writes to the standard output the command line options required to link
with the 8-bit PCRE library (\fB-lpcre\fP on many systems).
.TP 10
\fB--libs16\fP
Writes to the standard output the command line options required to link
with the 16-bit PCRE library (\fB-lpcre16\fP on many systems).
.TP 10
\fB--libs32\fP
Writes to the standard output the command line options required to link
with the 32-bit PCRE library (\fB-lpcre32\fP on many systems).
.TP 10
\fB--libs-cpp\fP
Writes to the standard output the command line options required to link with
PCRE's C++ wrapper library (\fB-lpcrecpp\fP \fB-lpcre\fP on many
systems).
.TP 10
\fB--libs-posix\fP
Writes to the standard output the command line options required to link with
PCRE's POSIX API wrapper library (\fB-lpcreposix\fP \fB-lpcre\fP on many
systems).
.TP 10
\fB--cflags\fP
Writes to the standard output the command line options required to compile
files that use PCRE (this may include some \fB-I\fP options, but is blank on
many systems).
.TP 10
\fB--cflags-posix\fP
Writes to the standard output the command line options required to compile
files that use PCRE's POSIX API wrapper library (this may include some \fB-I\fP
options, but is blank on many systems).
.
.
.SH "SEE ALSO"
.rs
.sp
\fBpcre(3)\fP
.
.
.SH AUTHOR
.rs
.sp
This manual page was originally written by Mark Baker for the Debian GNU/Linux
system. It has been subsequently revised as a generic PCRE man page.
.
.
.SH REVISION
.rs
.sp
.nf
Last updated: 24 June 2012
.fi
PK � %[<��z� z� man/man1/pcregrep.1nu �[��� .TH PCREGREP 1 "03 April 2014" "PCRE 8.35"
.SH NAME
pcregrep - a grep with Perl-compatible regular expressions.
.SH SYNOPSIS
.B pcregrep [options] [long options] [pattern] [path1 path2 ...]
.
.SH DESCRIPTION
.rs
.sp
\fBpcregrep\fP searches files for character patterns, in the same way as other
grep commands do, but it uses the PCRE regular expression library to support
patterns that are compatible with the regular expressions of Perl 5. See
.\" HREF
\fBpcresyntax\fP(3)
.\"
for a quick-reference summary of pattern syntax, or
.\" HREF
\fBpcrepattern\fP(3)
.\"
for a full description of the syntax and semantics of the regular expressions
that PCRE supports.
.P
Patterns, whether supplied on the command line or in a separate file, are given
without delimiters. For example:
.sp
pcregrep Thursday /etc/motd
.sp
If you attempt to use delimiters (for example, by surrounding a pattern with
slashes, as is common in Perl scripts), they are interpreted as part of the
pattern. Quotes can of course be used to delimit patterns on the command line
because they are interpreted by the shell, and indeed quotes are required if a
pattern contains white space or shell metacharacters.
.P
The first argument that follows any option settings is treated as the single
pattern to be matched when neither \fB-e\fP nor \fB-f\fP is present.
Conversely, when one or both of these options are used to specify patterns, all
arguments are treated as path names. At least one of \fB-e\fP, \fB-f\fP, or an
argument pattern must be provided.
.P
If no files are specified, \fBpcregrep\fP reads the standard input. The
standard input can also be referenced by a name consisting of a single hyphen.
For example:
.sp
pcregrep some-pattern /file1 - /file3
.sp
By default, each line that matches a pattern is copied to the standard
output, and if there is more than one file, the file name is output at the
start of each line, followed by a colon. However, there are options that can
change how \fBpcregrep\fP behaves. In particular, the \fB-M\fP option makes it
possible to search for patterns that span line boundaries. What defines a line
boundary is controlled by the \fB-N\fP (\fB--newline\fP) option.
.P
The amount of memory used for buffering files that are being scanned is
controlled by a parameter that can be set by the \fB--buffer-size\fP option.
The default value for this parameter is specified when \fBpcregrep\fP is built,
with the default default being 20K. A block of memory three times this size is
used (to allow for buffering "before" and "after" lines). An error occurs if a
line overflows the buffer.
.P
Patterns can be no longer than 8K or BUFSIZ bytes, whichever is the greater.
BUFSIZ is defined in \fB<stdio.h>\fP. When there is more than one pattern
(specified by the use of \fB-e\fP and/or \fB-f\fP), each pattern is applied to
each line in the order in which they are defined, except that all the \fB-e\fP
patterns are tried before the \fB-f\fP patterns.
.P
By default, as soon as one pattern matches a line, no further patterns are
considered. However, if \fB--colour\fP (or \fB--color\fP) is used to colour the
matching substrings, or if \fB--only-matching\fP, \fB--file-offsets\fP, or
\fB--line-offsets\fP is used to output only the part of the line that matched
(either shown literally, or as an offset), scanning resumes immediately
following the match, so that further matches on the same line can be found. If
there are multiple patterns, they are all tried on the remainder of the line,
but patterns that follow the one that matched are not tried on the earlier part
of the line.
.P
This behaviour means that the order in which multiple patterns are specified
can affect the output when one of the above options is used. This is no longer
the same behaviour as GNU grep, which now manages to display earlier matches
for later patterns (as long as there is no overlap).
.P
Patterns that can match an empty string are accepted, but empty string
matches are never recognized. An example is the pattern "(super)?(man)?", in
which all components are optional. This pattern finds all occurrences of both
"super" and "man"; the output differs from matching with "super|man" when only
the matching substrings are being shown.
.P
If the \fBLC_ALL\fP or \fBLC_CTYPE\fP environment variable is set,
\fBpcregrep\fP uses the value to set a locale when calling the PCRE library.
The \fB--locale\fP option can be used to override this.
.
.
.SH "SUPPORT FOR COMPRESSED FILES"
.rs
.sp
It is possible to compile \fBpcregrep\fP so that it uses \fBlibz\fP or
\fBlibbz2\fP to read files whose names end in \fB.gz\fP or \fB.bz2\fP,
respectively. You can find out whether your binary has support for one or both
of these file types by running it with the \fB--help\fP option. If the
appropriate support is not present, files are treated as plain text. The
standard input is always so treated.
.
.
.SH "BINARY FILES"
.rs
.sp
By default, a file that contains a binary zero byte within the first 1024 bytes
is identified as a binary file, and is processed specially. (GNU grep also
identifies binary files in this manner.) See the \fB--binary-files\fP option
for a means of changing the way binary files are handled.
.
.
.SH OPTIONS
.rs
.sp
The order in which some of the options appear can affect the output. For
example, both the \fB-h\fP and \fB-l\fP options affect the printing of file
names. Whichever comes later in the command line will be the one that takes
effect. Similarly, except where noted below, if an option is given twice, the
later setting is used. Numerical values for options may be followed by K or M,
to signify multiplication by 1024 or 1024*1024 respectively.
.TP 10
\fB--\fP
This terminates the list of options. It is useful if the next item on the
command line starts with a hyphen but is not an option. This allows for the
processing of patterns and filenames that start with hyphens.
.TP
\fB-A\fP \fInumber\fP, \fB--after-context=\fP\fInumber\fP
Output \fInumber\fP lines of context after each matching line. If filenames
and/or line numbers are being output, a hyphen separator is used instead of a
colon for the context lines. A line containing "--" is output between each
group of lines, unless they are in fact contiguous in the input file. The value
of \fInumber\fP is expected to be relatively small. However, \fBpcregrep\fP
guarantees to have up to 8K of following text available for context output.
.TP
\fB-a\fP, \fB--text\fP
Treat binary files as text. This is equivalent to
\fB--binary-files\fP=\fItext\fP.
.TP
\fB-B\fP \fInumber\fP, \fB--before-context=\fP\fInumber\fP
Output \fInumber\fP lines of context before each matching line. If filenames
and/or line numbers are being output, a hyphen separator is used instead of a
colon for the context lines. A line containing "--" is output between each
group of lines, unless they are in fact contiguous in the input file. The value
of \fInumber\fP is expected to be relatively small. However, \fBpcregrep\fP
guarantees to have up to 8K of preceding text available for context output.
.TP
\fB--binary-files=\fP\fIword\fP
Specify how binary files are to be processed. If the word is "binary" (the
default), pattern matching is performed on binary files, but the only output is
"Binary file <name> matches" when a match succeeds. If the word is "text",
which is equivalent to the \fB-a\fP or \fB--text\fP option, binary files are
processed in the same way as any other file. In this case, when a match
succeeds, the output may be binary garbage, which can have nasty effects if
sent to a terminal. If the word is "without-match", which is equivalent to the
\fB-I\fP option, binary files are not processed at all; they are assumed not to
be of interest.
.TP
\fB--buffer-size=\fP\fInumber\fP
Set the parameter that controls how much memory is used for buffering files
that are being scanned.
.TP
\fB-C\fP \fInumber\fP, \fB--context=\fP\fInumber\fP
Output \fInumber\fP lines of context both before and after each matching line.
This is equivalent to setting both \fB-A\fP and \fB-B\fP to the same value.
.TP
\fB-c\fP, \fB--count\fP
Do not output individual lines from the files that are being scanned; instead
output the number of lines that would otherwise have been shown. If no lines
are selected, the number zero is output. If several files are are being
scanned, a count is output for each of them. However, if the
\fB--files-with-matches\fP option is also used, only those files whose counts
are greater than zero are listed. When \fB-c\fP is used, the \fB-A\fP,
\fB-B\fP, and \fB-C\fP options are ignored.
.TP
\fB--colour\fP, \fB--color\fP
If this option is given without any data, it is equivalent to "--colour=auto".
If data is required, it must be given in the same shell item, separated by an
equals sign.
.TP
\fB--colour=\fP\fIvalue\fP, \fB--color=\fP\fIvalue\fP
This option specifies under what circumstances the parts of a line that matched
a pattern should be coloured in the output. By default, the output is not
coloured. The value (which is optional, see above) may be "never", "always", or
"auto". In the latter case, colouring happens only if the standard output is
connected to a terminal. More resources are used when colouring is enabled,
because \fBpcregrep\fP has to search for all possible matches in a line, not
just one, in order to colour them all.
.sp
The colour that is used can be specified by setting the environment variable
PCREGREP_COLOUR or PCREGREP_COLOR. The value of this variable should be a
string of two numbers, separated by a semicolon. They are copied directly into
the control string for setting colour on a terminal, so it is your
responsibility to ensure that they make sense. If neither of the environment
variables is set, the default is "1;31", which gives red.
.TP
\fB-D\fP \fIaction\fP, \fB--devices=\fP\fIaction\fP
If an input path is not a regular file or a directory, "action" specifies how
it is to be processed. Valid values are "read" (the default) or "skip"
(silently skip the path).
.TP
\fB-d\fP \fIaction\fP, \fB--directories=\fP\fIaction\fP
If an input path is a directory, "action" specifies how it is to be processed.
Valid values are "read" (the default in non-Windows environments, for
compatibility with GNU grep), "recurse" (equivalent to the \fB-r\fP option), or
"skip" (silently skip the path, the default in Windows environments). In the
"read" case, directories are read as if they were ordinary files. In some
operating systems the effect of reading a directory like this is an immediate
end-of-file; in others it may provoke an error.
.TP
\fB-e\fP \fIpattern\fP, \fB--regex=\fP\fIpattern\fP, \fB--regexp=\fP\fIpattern\fP
Specify a pattern to be matched. This option can be used multiple times in
order to specify several patterns. It can also be used as a way of specifying a
single pattern that starts with a hyphen. When \fB-e\fP is used, no argument
pattern is taken from the command line; all arguments are treated as file
names. There is no limit to the number of patterns. They are applied to each
line in the order in which they are defined until one matches.
.sp
If \fB-f\fP is used with \fB-e\fP, the command line patterns are matched first,
followed by the patterns from the file(s), independent of the order in which
these options are specified. Note that multiple use of \fB-e\fP is not the same
as a single pattern with alternatives. For example, X|Y finds the first
character in a line that is X or Y, whereas if the two patterns are given
separately, with X first, \fBpcregrep\fP finds X if it is present, even if it
follows Y in the line. It finds Y only if there is no X in the line. This
matters only if you are using \fB-o\fP or \fB--colo(u)r\fP to show the part(s)
of the line that matched.
.TP
\fB--exclude\fP=\fIpattern\fP
Files (but not directories) whose names match the pattern are skipped without
being processed. This applies to all files, whether listed on the command line,
obtained from \fB--file-list\fP, or by scanning a directory. The pattern is a
PCRE regular expression, and is matched against the final component of the file
name, not the entire path. The \fB-F\fP, \fB-w\fP, and \fB-x\fP options do not
apply to this pattern. The option may be given any number of times in order to
specify multiple patterns. If a file name matches both an \fB--include\fP
and an \fB--exclude\fP pattern, it is excluded. There is no short form for this
option.
.TP
\fB--exclude-from=\fP\fIfilename\fP
Treat each non-empty line of the file as the data for an \fB--exclude\fP
option. What constitutes a newline when reading the file is the operating
system's default. The \fB--newline\fP option has no effect on this option. This
option may be given more than once in order to specify a number of files to
read.
.TP
\fB--exclude-dir\fP=\fIpattern\fP
Directories whose names match the pattern are skipped without being processed,
whatever the setting of the \fB--recursive\fP option. This applies to all
directories, whether listed on the command line, obtained from
\fB--file-list\fP, or by scanning a parent directory. The pattern is a PCRE
regular expression, and is matched against the final component of the directory
name, not the entire path. The \fB-F\fP, \fB-w\fP, and \fB-x\fP options do not
apply to this pattern. The option may be given any number of times in order to
specify more than one pattern. If a directory matches both \fB--include-dir\fP
and \fB--exclude-dir\fP, it is excluded. There is no short form for this
option.
.TP
\fB-F\fP, \fB--fixed-strings\fP
Interpret each data-matching pattern as a list of fixed strings, separated by
newlines, instead of as a regular expression. What constitutes a newline for
this purpose is controlled by the \fB--newline\fP option. The \fB-w\fP (match
as a word) and \fB-x\fP (match whole line) options can be used with \fB-F\fP.
They apply to each of the fixed strings. A line is selected if any of the fixed
strings are found in it (subject to \fB-w\fP or \fB-x\fP, if present). This
option applies only to the patterns that are matched against the contents of
files; it does not apply to patterns specified by any of the \fB--include\fP or
\fB--exclude\fP options.
.TP
\fB-f\fP \fIfilename\fP, \fB--file=\fP\fIfilename\fP
Read patterns from the file, one per line, and match them against
each line of input. What constitutes a newline when reading the file is the
operating system's default. The \fB--newline\fP option has no effect on this
option. Trailing white space is removed from each line, and blank lines are
ignored. An empty file contains no patterns and therefore matches nothing. See
also the comments about multiple patterns versus a single pattern with
alternatives in the description of \fB-e\fP above.
.sp
If this option is given more than once, all the specified files are
read. A data line is output if any of the patterns match it. A filename can
be given as "-" to refer to the standard input. When \fB-f\fP is used, patterns
specified on the command line using \fB-e\fP may also be present; they are
tested before the file's patterns. However, no other pattern is taken from the
command line; all arguments are treated as the names of paths to be searched.
.TP
\fB--file-list\fP=\fIfilename\fP
Read a list of files and/or directories that are to be scanned from the given
file, one per line. Trailing white space is removed from each line, and blank
lines are ignored. These paths are processed before any that are listed on the
command line. The filename can be given as "-" to refer to the standard input.
If \fB--file\fP and \fB--file-list\fP are both specified as "-", patterns are
read first. This is useful only when the standard input is a terminal, from
which further lines (the list of files) can be read after an end-of-file
indication. If this option is given more than once, all the specified files are
read.
.TP
\fB--file-offsets\fP
Instead of showing lines or parts of lines that match, show each match as an
offset from the start of the file and a length, separated by a comma. In this
mode, no context is shown. That is, the \fB-A\fP, \fB-B\fP, and \fB-C\fP
options are ignored. If there is more than one match in a line, each of them is
shown separately. This option is mutually exclusive with \fB--line-offsets\fP
and \fB--only-matching\fP.
.TP
\fB-H\fP, \fB--with-filename\fP
Force the inclusion of the filename at the start of output lines when searching
a single file. By default, the filename is not shown in this case. For matching
lines, the filename is followed by a colon; for context lines, a hyphen
separator is used. If a line number is also being output, it follows the file
name.
.TP
\fB-h\fP, \fB--no-filename\fP
Suppress the output filenames when searching multiple files. By default,
filenames are shown when multiple files are searched. For matching lines, the
filename is followed by a colon; for context lines, a hyphen separator is used.
If a line number is also being output, it follows the file name.
.TP
\fB--help\fP
Output a help message, giving brief details of the command options and file
type support, and then exit. Anything else on the command line is
ignored.
.TP
\fB-I\fP
Treat binary files as never matching. This is equivalent to
\fB--binary-files\fP=\fIwithout-match\fP.
.TP
\fB-i\fP, \fB--ignore-case\fP
Ignore upper/lower case distinctions during comparisons.
.TP
\fB--include\fP=\fIpattern\fP
If any \fB--include\fP patterns are specified, the only files that are
processed are those that match one of the patterns (and do not match an
\fB--exclude\fP pattern). This option does not affect directories, but it
applies to all files, whether listed on the command line, obtained from
\fB--file-list\fP, or by scanning a directory. The pattern is a PCRE regular
expression, and is matched against the final component of the file name, not
the entire path. The \fB-F\fP, \fB-w\fP, and \fB-x\fP options do not apply to
this pattern. The option may be given any number of times. If a file name
matches both an \fB--include\fP and an \fB--exclude\fP pattern, it is excluded.
There is no short form for this option.
.TP
\fB--include-from=\fP\fIfilename\fP
Treat each non-empty line of the file as the data for an \fB--include\fP
option. What constitutes a newline for this purpose is the operating system's
default. The \fB--newline\fP option has no effect on this option. This option
may be given any number of times; all the files are read.
.TP
\fB--include-dir\fP=\fIpattern\fP
If any \fB--include-dir\fP patterns are specified, the only directories that
are processed are those that match one of the patterns (and do not match an
\fB--exclude-dir\fP pattern). This applies to all directories, whether listed
on the command line, obtained from \fB--file-list\fP, or by scanning a parent
directory. The pattern is a PCRE regular expression, and is matched against the
final component of the directory name, not the entire path. The \fB-F\fP,
\fB-w\fP, and \fB-x\fP options do not apply to this pattern. The option may be
given any number of times. If a directory matches both \fB--include-dir\fP and
\fB--exclude-dir\fP, it is excluded. There is no short form for this option.
.TP
\fB-L\fP, \fB--files-without-match\fP
Instead of outputting lines from the files, just output the names of the files
that do not contain any lines that would have been output. Each file name is
output once, on a separate line.
.TP
\fB-l\fP, \fB--files-with-matches\fP
Instead of outputting lines from the files, just output the names of the files
containing lines that would have been output. Each file name is output
once, on a separate line. Searching normally stops as soon as a matching line
is found in a file. However, if the \fB-c\fP (count) option is also used,
matching continues in order to obtain the correct count, and those files that
have at least one match are listed along with their counts. Using this option
with \fB-c\fP is a way of suppressing the listing of files with no matches.
.TP
\fB--label\fP=\fIname\fP
This option supplies a name to be used for the standard input when file names
are being output. If not supplied, "(standard input)" is used. There is no
short form for this option.
.TP
\fB--line-buffered\fP
When this option is given, input is read and processed line by line, and the
output is flushed after each write. By default, input is read in large chunks,
unless \fBpcregrep\fP can determine that it is reading from a terminal (which
is currently possible only in Unix-like environments). Output to terminal is
normally automatically flushed by the operating system. This option can be
useful when the input or output is attached to a pipe and you do not want
\fBpcregrep\fP to buffer up large amounts of data. However, its use will affect
performance, and the \fB-M\fP (multiline) option ceases to work.
.TP
\fB--line-offsets\fP
Instead of showing lines or parts of lines that match, show each match as a
line number, the offset from the start of the line, and a length. The line
number is terminated by a colon (as usual; see the \fB-n\fP option), and the
offset and length are separated by a comma. In this mode, no context is shown.
That is, the \fB-A\fP, \fB-B\fP, and \fB-C\fP options are ignored. If there is
more than one match in a line, each of them is shown separately. This option is
mutually exclusive with \fB--file-offsets\fP and \fB--only-matching\fP.
.TP
\fB--locale\fP=\fIlocale-name\fP
This option specifies a locale to be used for pattern matching. It overrides
the value in the \fBLC_ALL\fP or \fBLC_CTYPE\fP environment variables. If no
locale is specified, the PCRE library's default (usually the "C" locale) is
used. There is no short form for this option.
.TP
\fB--match-limit\fP=\fInumber\fP
Processing some regular expression patterns can require a very large amount of
memory, leading in some cases to a program crash if not enough is available.
Other patterns may take a very long time to search for all possible matching
strings. The \fBpcre_exec()\fP function that is called by \fBpcregrep\fP to do
the matching has two parameters that can limit the resources that it uses.
.sp
The \fB--match-limit\fP option provides a means of limiting resource usage
when processing patterns that are not going to match, but which have a very
large number of possibilities in their search trees. The classic example is a
pattern that uses nested unlimited repeats. Internally, PCRE uses a function
called \fBmatch()\fP which it calls repeatedly (sometimes recursively). The
limit set by \fB--match-limit\fP is imposed on the number of times this
function is called during a match, which has the effect of limiting the amount
of backtracking that can take place.
.sp
The \fB--recursion-limit\fP option is similar to \fB--match-limit\fP, but
instead of limiting the total number of times that \fBmatch()\fP is called, it
limits the depth of recursive calls, which in turn limits the amount of memory
that can be used. The recursion depth is a smaller number than the total number
of calls, because not all calls to \fBmatch()\fP are recursive. This limit is
of use only if it is set smaller than \fB--match-limit\fP.
.sp
There are no short forms for these options. The default settings are specified
when the PCRE library is compiled, with the default default being 10 million.
.TP
\fB-M\fP, \fB--multiline\fP
Allow patterns to match more than one line. When this option is given, patterns
may usefully contain literal newline characters and internal occurrences of ^
and $ characters. The output for a successful match may consist of more than
one line, the last of which is the one in which the match ended. If the matched
string ends with a newline sequence the output ends at the end of that line.
.sp
When this option is set, the PCRE library is called in "multiline" mode.
There is a limit to the number of lines that can be matched, imposed by the way
that \fBpcregrep\fP buffers the input file as it scans it. However,
\fBpcregrep\fP ensures that at least 8K characters or the rest of the document
(whichever is the shorter) are available for forward matching, and similarly
the previous 8K characters (or all the previous characters, if fewer than 8K)
are guaranteed to be available for lookbehind assertions. This option does not
work when input is read line by line (see \fP--line-buffered\fP.)
.TP
\fB-N\fP \fInewline-type\fP, \fB--newline\fP=\fInewline-type\fP
The PCRE library supports five different conventions for indicating
the ends of lines. They are the single-character sequences CR (carriage return)
and LF (linefeed), the two-character sequence CRLF, an "anycrlf" convention,
which recognizes any of the preceding three types, and an "any" convention, in
which any Unicode line ending sequence is assumed to end a line. The Unicode
sequences are the three just mentioned, plus VT (vertical tab, U+000B), FF
(form feed, U+000C), NEL (next line, U+0085), LS (line separator, U+2028), and
PS (paragraph separator, U+2029).
.sp
When the PCRE library is built, a default line-ending sequence is specified.
This is normally the standard sequence for the operating system. Unless
otherwise specified by this option, \fBpcregrep\fP uses the library's default.
The possible values for this option are CR, LF, CRLF, ANYCRLF, or ANY. This
makes it possible to use \fBpcregrep\fP to scan files that have come from other
environments without having to modify their line endings. If the data that is
being scanned does not agree with the convention set by this option,
\fBpcregrep\fP may behave in strange ways. Note that this option does not
apply to files specified by the \fB-f\fP, \fB--exclude-from\fP, or
\fB--include-from\fP options, which are expected to use the operating system's
standard newline sequence.
.TP
\fB-n\fP, \fB--line-number\fP
Precede each output line by its line number in the file, followed by a colon
for matching lines or a hyphen for context lines. If the filename is also being
output, it precedes the line number. This option is forced if
\fB--line-offsets\fP is used.
.TP
\fB--no-jit\fP
If the PCRE library is built with support for just-in-time compiling (which
speeds up matching), \fBpcregrep\fP automatically makes use of this, unless it
was explicitly disabled at build time. This option can be used to disable the
use of JIT at run time. It is provided for testing and working round problems.
It should never be needed in normal use.
.TP
\fB-o\fP, \fB--only-matching\fP
Show only the part of the line that matched a pattern instead of the whole
line. In this mode, no context is shown. That is, the \fB-A\fP, \fB-B\fP, and
\fB-C\fP options are ignored. If there is more than one match in a line, each
of them is shown separately. If \fB-o\fP is combined with \fB-v\fP (invert the
sense of the match to find non-matching lines), no output is generated, but the
return code is set appropriately. If the matched portion of the line is empty,
nothing is output unless the file name or line number are being printed, in
which case they are shown on an otherwise empty line. This option is mutually
exclusive with \fB--file-offsets\fP and \fB--line-offsets\fP.
.TP
\fB-o\fP\fInumber\fP, \fB--only-matching\fP=\fInumber\fP
Show only the part of the line that matched the capturing parentheses of the
given number. Up to 32 capturing parentheses are supported, and -o0 is
equivalent to \fB-o\fP without a number. Because these options can be given
without an argument (see above), if an argument is present, it must be given in
the same shell item, for example, -o3 or --only-matching=2. The comments given
for the non-argument case above also apply to this case. If the specified
capturing parentheses do not exist in the pattern, or were not set in the
match, nothing is output unless the file name or line number are being printed.
.sp
If this option is given multiple times, multiple substrings are output, in the
order the options are given. For example, -o3 -o1 -o3 causes the substrings
matched by capturing parentheses 3 and 1 and then 3 again to be output. By
default, there is no separator (but see the next option).
.TP
\fB--om-separator\fP=\fItext\fP
Specify a separating string for multiple occurrences of \fB-o\fP. The default
is an empty string. Separating strings are never coloured.
.TP
\fB-q\fP, \fB--quiet\fP
Work quietly, that is, display nothing except error messages. The exit
status indicates whether or not any matches were found.
.TP
\fB-r\fP, \fB--recursive\fP
If any given path is a directory, recursively scan the files it contains,
taking note of any \fB--include\fP and \fB--exclude\fP settings. By default, a
directory is read as a normal file; in some operating systems this gives an
immediate end-of-file. This option is a shorthand for setting the \fB-d\fP
option to "recurse".
.TP
\fB--recursion-limit\fP=\fInumber\fP
See \fB--match-limit\fP above.
.TP
\fB-s\fP, \fB--no-messages\fP
Suppress error messages about non-existent or unreadable files. Such files are
quietly skipped. However, the return code is still 2, even if matches were
found in other files.
.TP
\fB-u\fP, \fB--utf-8\fP
Operate in UTF-8 mode. This option is available only if PCRE has been compiled
with UTF-8 support. All patterns (including those for any \fB--exclude\fP and
\fB--include\fP options) and all subject lines that are scanned must be valid
strings of UTF-8 characters.
.TP
\fB-V\fP, \fB--version\fP
Write the version numbers of \fBpcregrep\fP and the PCRE library to the
standard output and then exit. Anything else on the command line is
ignored.
.TP
\fB-v\fP, \fB--invert-match\fP
Invert the sense of the match, so that lines which do \fInot\fP match any of
the patterns are the ones that are found.
.TP
\fB-w\fP, \fB--word-regex\fP, \fB--word-regexp\fP
Force the patterns to match only whole words. This is equivalent to having \eb
at the start and end of the pattern. This option applies only to the patterns
that are matched against the contents of files; it does not apply to patterns
specified by any of the \fB--include\fP or \fB--exclude\fP options.
.TP
\fB-x\fP, \fB--line-regex\fP, \fB--line-regexp\fP
Force the patterns to be anchored (each must start matching at the beginning of
a line) and in addition, require them to match entire lines. This is equivalent
to having ^ and $ characters at the start and end of each alternative branch in
every pattern. This option applies only to the patterns that are matched
against the contents of files; it does not apply to patterns specified by any
of the \fB--include\fP or \fB--exclude\fP options.
.
.
.SH "ENVIRONMENT VARIABLES"
.rs
.sp
The environment variables \fBLC_ALL\fP and \fBLC_CTYPE\fP are examined, in that
order, for a locale. The first one that is set is used. This can be overridden
by the \fB--locale\fP option. If no locale is set, the PCRE library's default
(usually the "C" locale) is used.
.
.
.SH "NEWLINES"
.rs
.sp
The \fB-N\fP (\fB--newline\fP) option allows \fBpcregrep\fP to scan files with
different newline conventions from the default. Any parts of the input files
that are written to the standard output are copied identically, with whatever
newline sequences they have in the input. However, the setting of this option
does not affect the interpretation of files specified by the \fB-f\fP,
\fB--exclude-from\fP, or \fB--include-from\fP options, which are assumed to use
the operating system's standard newline sequence, nor does it affect the way in
which \fBpcregrep\fP writes informational messages to the standard error and
output streams. For these it uses the string "\en" to indicate newlines,
relying on the C I/O library to convert this to an appropriate sequence.
.
.
.SH "OPTIONS COMPATIBILITY"
.rs
.sp
Many of the short and long forms of \fBpcregrep\fP's options are the same
as in the GNU \fBgrep\fP program. Any long option of the form
\fB--xxx-regexp\fP (GNU terminology) is also available as \fB--xxx-regex\fP
(PCRE terminology). However, the \fB--file-list\fP, \fB--file-offsets\fP,
\fB--include-dir\fP, \fB--line-offsets\fP, \fB--locale\fP, \fB--match-limit\fP,
\fB-M\fP, \fB--multiline\fP, \fB-N\fP, \fB--newline\fP, \fB--om-separator\fP,
\fB--recursion-limit\fP, \fB-u\fP, and \fB--utf-8\fP options are specific to
\fBpcregrep\fP, as is the use of the \fB--only-matching\fP option with a
capturing parentheses number.
.P
Although most of the common options work the same way, a few are different in
\fBpcregrep\fP. For example, the \fB--include\fP option's argument is a glob
for GNU \fBgrep\fP, but a regular expression for \fBpcregrep\fP. If both the
\fB-c\fP and \fB-l\fP options are given, GNU grep lists only file names,
without counts, but \fBpcregrep\fP gives the counts.
.
.
.SH "OPTIONS WITH DATA"
.rs
.sp
There are four different ways in which an option with data can be specified.
If a short form option is used, the data may follow immediately, or (with one
exception) in the next command line item. For example:
.sp
-f/some/file
-f /some/file
.sp
The exception is the \fB-o\fP option, which may appear with or without data.
Because of this, if data is present, it must follow immediately in the same
item, for example -o3.
.P
If a long form option is used, the data may appear in the same command line
item, separated by an equals character, or (with two exceptions) it may appear
in the next command line item. For example:
.sp
--file=/some/file
--file /some/file
.sp
Note, however, that if you want to supply a file name beginning with ~ as data
in a shell command, and have the shell expand ~ to a home directory, you must
separate the file name from the option, because the shell does not treat ~
specially unless it is at the start of an item.
.P
The exceptions to the above are the \fB--colour\fP (or \fB--color\fP) and
\fB--only-matching\fP options, for which the data is optional. If one of these
options does have data, it must be given in the first form, using an equals
character. Otherwise \fBpcregrep\fP will assume that it has no data.
.
.
.SH "MATCHING ERRORS"
.rs
.sp
It is possible to supply a regular expression that takes a very long time to
fail to match certain lines. Such patterns normally involve nested indefinite
repeats, for example: (a+)*\ed when matched against a line of a's with no final
digit. The PCRE matching function has a resource limit that causes it to abort
in these circumstances. If this happens, \fBpcregrep\fP outputs an error
message and the line that caused the problem to the standard error stream. If
there are more than 20 such errors, \fBpcregrep\fP gives up.
.P
The \fB--match-limit\fP option of \fBpcregrep\fP can be used to set the overall
resource limit; there is a second option called \fB--recursion-limit\fP that
sets a limit on the amount of memory (usually stack) that is used (see the
discussion of these options above).
.
.
.SH DIAGNOSTICS
.rs
.sp
Exit status is 0 if any matches were found, 1 if no matches were found, and 2
for syntax errors, overlong lines, non-existent or inaccessible files (even if
matches were found in other files) or too many matching errors. Using the
\fB-s\fP option to suppress error messages about inaccessible files does not
affect the return code.
.
.
.SH "SEE ALSO"
.rs
.sp
\fBpcrepattern\fP(3), \fBpcresyntax\fP(3), \fBpcretest\fP(1).
.
.
.SH AUTHOR
.rs
.sp
.nf
Philip Hazel
University Computing Service
Cambridge CB2 3QH, England.
.fi
.
.
.SH REVISION
.rs
.sp
.nf
Last updated: 03 April 2014
Copyright (c) 1997-2014 University of Cambridge.
.fi
PK � %[� �0� 0� man/man1/pcretest.1nu �[��� .TH PCRETEST 1 "23 February 2017" "PCRE 8.41"
.SH NAME
pcretest - a program for testing Perl-compatible regular expressions.
.SH SYNOPSIS
.rs
.sp
.B pcretest "[options] [input file [output file]]"
.sp
\fBpcretest\fP was written as a test program for the PCRE regular expression
library itself, but it can also be used for experimenting with regular
expressions. This document describes the features of the test program; for
details of the regular expressions themselves, see the
.\" HREF
\fBpcrepattern\fP
.\"
documentation. For details of the PCRE library function calls and their
options, see the
.\" HREF
\fBpcreapi\fP
.\"
,
.\" HREF
\fBpcre16\fP
and
.\" HREF
\fBpcre32\fP
.\"
documentation.
.P
The input for \fBpcretest\fP is a sequence of regular expression patterns and
strings to be matched, as described below. The output shows the result of each
match. Options on the command line and the patterns control PCRE options and
exactly what is output.
.P
As PCRE has evolved, it has acquired many different features, and as a result,
\fBpcretest\fP now has rather a lot of obscure options for testing every
possible feature. Some of these options are specifically designed for use in
conjunction with the test script and data files that are distributed as part of
PCRE, and are unlikely to be of use otherwise. They are all documented here,
but without much justification.
.
.
.SH "INPUT DATA FORMAT"
.rs
.sp
Input to \fBpcretest\fP is processed line by line, either by calling the C
library's \fBfgets()\fP function, or via the \fBlibreadline\fP library (see
below). In Unix-like environments, \fBfgets()\fP treats any bytes other than
newline as data characters. However, in some Windows environments character 26
(hex 1A) causes an immediate end of file, and no further data is read. For
maximum portability, therefore, it is safest to use only ASCII characters in
\fBpcretest\fP input files.
.P
The input is processed using using C's string functions, so must not
contain binary zeroes, even though in Unix-like environments, \fBfgets()\fP
treats any bytes other than newline as data characters.
.
.
.SH "PCRE's 8-BIT, 16-BIT AND 32-BIT LIBRARIES"
.rs
.sp
From release 8.30, two separate PCRE libraries can be built. The original one
supports 8-bit character strings, whereas the newer 16-bit library supports
character strings encoded in 16-bit units. From release 8.32, a third library
can be built, supporting character strings encoded in 32-bit units. The
\fBpcretest\fP program can be used to test all three libraries. However, it is
itself still an 8-bit program, reading 8-bit input and writing 8-bit output.
When testing the 16-bit or 32-bit library, the patterns and data strings are
converted to 16- or 32-bit format before being passed to the PCRE library
functions. Results are converted to 8-bit for output.
.P
References to functions and structures of the form \fBpcre[16|32]_xx\fP below
mean "\fBpcre_xx\fP when using the 8-bit library, \fBpcre16_xx\fP when using
the 16-bit library, or \fBpcre32_xx\fP when using the 32-bit library".
.
.
.SH "COMMAND LINE OPTIONS"
.rs
.TP 10
\fB-8\fP
If both the 8-bit library has been built, this option causes the 8-bit library
to be used (which is the default); if the 8-bit library has not been built,
this option causes an error.
.TP 10
\fB-16\fP
If both the 8-bit or the 32-bit, and the 16-bit libraries have been built, this
option causes the 16-bit library to be used. If only the 16-bit library has been
built, this is the default (so has no effect). If only the 8-bit or the 32-bit
library has been built, this option causes an error.
.TP 10
\fB-32\fP
If both the 8-bit or the 16-bit, and the 32-bit libraries have been built, this
option causes the 32-bit library to be used. If only the 32-bit library has been
built, this is the default (so has no effect). If only the 8-bit or the 16-bit
library has been built, this option causes an error.
.TP 10
\fB-b\fP
Behave as if each pattern has the \fB/B\fP (show byte code) modifier; the
internal form is output after compilation.
.TP 10
\fB-C\fP
Output the version number of the PCRE library, and all available information
about the optional features that are included, and then exit with zero exit
code. All other options are ignored.
.TP 10
\fB-C\fP \fIoption\fP
Output information about a specific build-time option, then exit. This
functionality is intended for use in scripts such as \fBRunTest\fP. The
following options output the value and set the exit code as indicated:
.sp
ebcdic-nl the code for LF (= NL) in an EBCDIC environment:
0x15 or 0x25
0 if used in an ASCII environment
exit code is always 0
linksize the configured internal link size (2, 3, or 4)
exit code is set to the link size
newline the default newline setting:
CR, LF, CRLF, ANYCRLF, or ANY
exit code is always 0
bsr the default setting for what \eR matches:
ANYCRLF or ANY
exit code is always 0
.sp
The following options output 1 for true or 0 for false, and set the exit code
to the same value:
.sp
ebcdic compiled for an EBCDIC environment
jit just-in-time support is available
pcre16 the 16-bit library was built
pcre32 the 32-bit library was built
pcre8 the 8-bit library was built
ucp Unicode property support is available
utf UTF-8 and/or UTF-16 and/or UTF-32 support
is available
.sp
If an unknown option is given, an error message is output; the exit code is 0.
.TP 10
\fB-d\fP
Behave as if each pattern has the \fB/D\fP (debug) modifier; the internal
form and information about the compiled pattern is output after compilation;
\fB-d\fP is equivalent to \fB-b -i\fP.
.TP 10
\fB-dfa\fP
Behave as if each data line contains the \eD escape sequence; this causes the
alternative matching function, \fBpcre[16|32]_dfa_exec()\fP, to be used instead
of the standard \fBpcre[16|32]_exec()\fP function (more detail is given below).
.TP 10
\fB-help\fP
Output a brief summary these options and then exit.
.TP 10
\fB-i\fP
Behave as if each pattern has the \fB/I\fP modifier; information about the
compiled pattern is given after compilation.
.TP 10
\fB-M\fP
Behave as if each data line contains the \eM escape sequence; this causes
PCRE to discover the minimum MATCH_LIMIT and MATCH_LIMIT_RECURSION settings by
calling \fBpcre[16|32]_exec()\fP repeatedly with different limits.
.TP 10
\fB-m\fP
Output the size of each compiled pattern after it has been compiled. This is
equivalent to adding \fB/M\fP to each regular expression. The size is given in
bytes for both libraries.
.TP 10
\fB-O\fP
Behave as if each pattern has the \fB/O\fP modifier, that is disable
auto-possessification for all patterns.
.TP 10
\fB-o\fP \fIosize\fP
Set the number of elements in the output vector that is used when calling
\fBpcre[16|32]_exec()\fP or \fBpcre[16|32]_dfa_exec()\fP to be \fIosize\fP. The
default value is 45, which is enough for 14 capturing subexpressions for
\fBpcre[16|32]_exec()\fP or 22 different matches for
\fBpcre[16|32]_dfa_exec()\fP.
The vector size can be changed for individual matching calls by including \eO
in the data line (see below).
.TP 10
\fB-p\fP
Behave as if each pattern has the \fB/P\fP modifier; the POSIX wrapper API is
used to call PCRE. None of the other options has any effect when \fB-p\fP is
set. This option can be used only with the 8-bit library.
.TP 10
\fB-q\fP
Do not output the version number of \fBpcretest\fP at the start of execution.
.TP 10
\fB-S\fP \fIsize\fP
On Unix-like systems, set the size of the run-time stack to \fIsize\fP
megabytes.
.TP 10
\fB-s\fP or \fB-s+\fP
Behave as if each pattern has the \fB/S\fP modifier; in other words, force each
pattern to be studied. If \fB-s+\fP is used, all the JIT compile options are
passed to \fBpcre[16|32]_study()\fP, causing just-in-time optimization to be set
up if it is available, for both full and partial matching. Specific JIT compile
options can be selected by following \fB-s+\fP with a digit in the range 1 to
7, which selects the JIT compile modes as follows:
.sp
1 normal match only
2 soft partial match only
3 normal match and soft partial match
4 hard partial match only
6 soft and hard partial match
7 all three modes (default)
.sp
If \fB-s++\fP is used instead of \fB-s+\fP (with or without a following digit),
the text "(JIT)" is added to the first output line after a match or no match
when JIT-compiled code was actually used.
.sp
Note that there are pattern options that can override \fB-s\fP, either
specifying no studying at all, or suppressing JIT compilation.
.sp
If the \fB/I\fP or \fB/D\fP option is present on a pattern (requesting output
about the compiled pattern), information about the result of studying is not
included when studying is caused only by \fB-s\fP and neither \fB-i\fP nor
\fB-d\fP is present on the command line. This behaviour means that the output
from tests that are run with and without \fB-s\fP should be identical, except
when options that output information about the actual running of a match are
set.
.sp
The \fB-M\fP, \fB-t\fP, and \fB-tm\fP options, which give information about
resources used, are likely to produce different output with and without
\fB-s\fP. Output may also differ if the \fB/C\fP option is present on an
individual pattern. This uses callouts to trace the the matching process, and
this may be different between studied and non-studied patterns. If the pattern
contains (*MARK) items there may also be differences, for the same reason. The
\fB-s\fP command line option can be overridden for specific patterns that
should never be studied (see the \fB/S\fP pattern modifier below).
.TP 10
\fB-t\fP
Run each compile, study, and match many times with a timer, and output the
resulting times per compile, study, or match (in milliseconds). Do not set
\fB-m\fP with \fB-t\fP, because you will then get the size output a zillion
times, and the timing will be distorted. You can control the number of
iterations that are used for timing by following \fB-t\fP with a number (as a
separate item on the command line). For example, "-t 1000" iterates 1000 times.
The default is to iterate 500000 times.
.TP 10
\fB-tm\fP
This is like \fB-t\fP except that it times only the matching phase, not the
compile or study phases.
.TP 10
\fB-T\fP \fB-TM\fP
These behave like \fB-t\fP and \fB-tm\fP, but in addition, at the end of a run,
the total times for all compiles, studies, and matches are output.
.
.
.SH DESCRIPTION
.rs
.sp
If \fBpcretest\fP is given two filename arguments, it reads from the first and
writes to the second. If it is given only one filename argument, it reads from
that file and writes to stdout. Otherwise, it reads from stdin and writes to
stdout, and prompts for each line of input, using "re>" to prompt for regular
expressions, and "data>" to prompt for data lines.
.P
When \fBpcretest\fP is built, a configuration option can specify that it should
be linked with the \fBlibreadline\fP library. When this is done, if the input
is from a terminal, it is read using the \fBreadline()\fP function. This
provides line-editing and history facilities. The output from the \fB-help\fP
option states whether or not \fBreadline()\fP will be used.
.P
The program handles any number of sets of input on a single input file. Each
set starts with a regular expression, and continues with any number of data
lines to be matched against that pattern.
.P
Each data line is matched separately and independently. If you want to do
multi-line matches, you have to use the \en escape sequence (or \er or \er\en,
etc., depending on the newline setting) in a single line of input to encode the
newline sequences. There is no limit on the length of data lines; the input
buffer is automatically extended if it is too small.
.P
An empty line signals the end of the data lines, at which point a new regular
expression is read. The regular expressions are given enclosed in any
non-alphanumeric delimiters other than backslash, for example:
.sp
/(a|bc)x+yz/
.sp
White space before the initial delimiter is ignored. A regular expression may
be continued over several input lines, in which case the newline characters are
included within it. It is possible to include the delimiter within the pattern
by escaping it, for example
.sp
/abc\e/def/
.sp
If you do so, the escape and the delimiter form part of the pattern, but since
delimiters are always non-alphanumeric, this does not affect its interpretation.
If the terminating delimiter is immediately followed by a backslash, for
example,
.sp
/abc/\e
.sp
then a backslash is added to the end of the pattern. This is done to provide a
way of testing the error condition that arises if a pattern finishes with a
backslash, because
.sp
/abc\e/
.sp
is interpreted as the first line of a pattern that starts with "abc/", causing
pcretest to read the next line as a continuation of the regular expression.
.
.
.SH "PATTERN MODIFIERS"
.rs
.sp
A pattern may be followed by any number of modifiers, which are mostly single
characters, though some of these can be qualified by further characters.
Following Perl usage, these are referred to below as, for example, "the
\fB/i\fP modifier", even though the delimiter of the pattern need not always be
a slash, and no slash is used when writing modifiers. White space may appear
between the final pattern delimiter and the first modifier, and between the
modifiers themselves. For reference, here is a complete list of modifiers. They
fall into several groups that are described in detail in the following
sections.
.sp
\fB/8\fP set UTF mode
\fB/9\fP set PCRE_NEVER_UTF (locks out UTF mode)
\fB/?\fP disable UTF validity check
\fB/+\fP show remainder of subject after match
\fB/=\fP show all captures (not just those that are set)
.sp
\fB/A\fP set PCRE_ANCHORED
\fB/B\fP show compiled code
\fB/C\fP set PCRE_AUTO_CALLOUT
\fB/D\fP same as \fB/B\fP plus \fB/I\fP
\fB/E\fP set PCRE_DOLLAR_ENDONLY
\fB/F\fP flip byte order in compiled pattern
\fB/f\fP set PCRE_FIRSTLINE
\fB/G\fP find all matches (shorten string)
\fB/g\fP find all matches (use startoffset)
\fB/I\fP show information about pattern
\fB/i\fP set PCRE_CASELESS
\fB/J\fP set PCRE_DUPNAMES
\fB/K\fP show backtracking control names
\fB/L\fP set locale
\fB/M\fP show compiled memory size
\fB/m\fP set PCRE_MULTILINE
\fB/N\fP set PCRE_NO_AUTO_CAPTURE
\fB/O\fP set PCRE_NO_AUTO_POSSESS
\fB/P\fP use the POSIX wrapper
\fB/Q\fP test external stack check function
\fB/S\fP study the pattern after compilation
\fB/s\fP set PCRE_DOTALL
\fB/T\fP select character tables
\fB/U\fP set PCRE_UNGREEDY
\fB/W\fP set PCRE_UCP
\fB/X\fP set PCRE_EXTRA
\fB/x\fP set PCRE_EXTENDED
\fB/Y\fP set PCRE_NO_START_OPTIMIZE
\fB/Z\fP don't show lengths in \fB/B\fP output
.sp
\fB/<any>\fP set PCRE_NEWLINE_ANY
\fB/<anycrlf>\fP set PCRE_NEWLINE_ANYCRLF
\fB/<cr>\fP set PCRE_NEWLINE_CR
\fB/<crlf>\fP set PCRE_NEWLINE_CRLF
\fB/<lf>\fP set PCRE_NEWLINE_LF
\fB/<bsr_anycrlf>\fP set PCRE_BSR_ANYCRLF
\fB/<bsr_unicode>\fP set PCRE_BSR_UNICODE
\fB/<JS>\fP set PCRE_JAVASCRIPT_COMPAT
.sp
.
.
.SS "Perl-compatible modifiers"
.rs
.sp
The \fB/i\fP, \fB/m\fP, \fB/s\fP, and \fB/x\fP modifiers set the PCRE_CASELESS,
PCRE_MULTILINE, PCRE_DOTALL, or PCRE_EXTENDED options, respectively, when
\fBpcre[16|32]_compile()\fP is called. These four modifier letters have the same
effect as they do in Perl. For example:
.sp
/caseless/i
.sp
.
.
.SS "Modifiers for other PCRE options"
.rs
.sp
The following table shows additional modifiers for setting PCRE compile-time
options that do not correspond to anything in Perl:
.sp
\fB/8\fP PCRE_UTF8 ) when using the 8-bit
\fB/?\fP PCRE_NO_UTF8_CHECK ) library
.sp
\fB/8\fP PCRE_UTF16 ) when using the 16-bit
\fB/?\fP PCRE_NO_UTF16_CHECK ) library
.sp
\fB/8\fP PCRE_UTF32 ) when using the 32-bit
\fB/?\fP PCRE_NO_UTF32_CHECK ) library
.sp
\fB/9\fP PCRE_NEVER_UTF
\fB/A\fP PCRE_ANCHORED
\fB/C\fP PCRE_AUTO_CALLOUT
\fB/E\fP PCRE_DOLLAR_ENDONLY
\fB/f\fP PCRE_FIRSTLINE
\fB/J\fP PCRE_DUPNAMES
\fB/N\fP PCRE_NO_AUTO_CAPTURE
\fB/O\fP PCRE_NO_AUTO_POSSESS
\fB/U\fP PCRE_UNGREEDY
\fB/W\fP PCRE_UCP
\fB/X\fP PCRE_EXTRA
\fB/Y\fP PCRE_NO_START_OPTIMIZE
\fB/<any>\fP PCRE_NEWLINE_ANY
\fB/<anycrlf>\fP PCRE_NEWLINE_ANYCRLF
\fB/<cr>\fP PCRE_NEWLINE_CR
\fB/<crlf>\fP PCRE_NEWLINE_CRLF
\fB/<lf>\fP PCRE_NEWLINE_LF
\fB/<bsr_anycrlf>\fP PCRE_BSR_ANYCRLF
\fB/<bsr_unicode>\fP PCRE_BSR_UNICODE
\fB/<JS>\fP PCRE_JAVASCRIPT_COMPAT
.sp
The modifiers that are enclosed in angle brackets are literal strings as shown,
including the angle brackets, but the letters within can be in either case.
This example sets multiline matching with CRLF as the line ending sequence:
.sp
/^abc/m<CRLF>
.sp
As well as turning on the PCRE_UTF8/16/32 option, the \fB/8\fP modifier causes
all non-printing characters in output strings to be printed using the
\ex{hh...} notation. Otherwise, those less than 0x100 are output in hex without
the curly brackets.
.P
Full details of the PCRE options are given in the
.\" HREF
\fBpcreapi\fP
.\"
documentation.
.
.
.SS "Finding all matches in a string"
.rs
.sp
Searching for all possible matches within each subject string can be requested
by the \fB/g\fP or \fB/G\fP modifier. After finding a match, PCRE is called
again to search the remainder of the subject string. The difference between
\fB/g\fP and \fB/G\fP is that the former uses the \fIstartoffset\fP argument to
\fBpcre[16|32]_exec()\fP to start searching at a new point within the entire
string (which is in effect what Perl does), whereas the latter passes over a
shortened substring. This makes a difference to the matching process if the
pattern begins with a lookbehind assertion (including \eb or \eB).
.P
If any call to \fBpcre[16|32]_exec()\fP in a \fB/g\fP or \fB/G\fP sequence matches
an empty string, the next call is done with the PCRE_NOTEMPTY_ATSTART and
PCRE_ANCHORED flags set in order to search for another, non-empty, match at the
same point. If this second match fails, the start offset is advanced, and the
normal match is retried. This imitates the way Perl handles such cases when
using the \fB/g\fP modifier or the \fBsplit()\fP function. Normally, the start
offset is advanced by one character, but if the newline convention recognizes
CRLF as a newline, and the current character is CR followed by LF, an advance
of two is used.
.
.
.SS "Other modifiers"
.rs
.sp
There are yet more modifiers for controlling the way \fBpcretest\fP
operates.
.P
The \fB/+\fP modifier requests that as well as outputting the substring that
matched the entire pattern, \fBpcretest\fP should in addition output the
remainder of the subject string. This is useful for tests where the subject
contains multiple copies of the same substring. If the \fB+\fP modifier appears
twice, the same action is taken for captured substrings. In each case the
remainder is output on the following line with a plus character following the
capture number. Note that this modifier must not immediately follow the /S
modifier because /S+ and /S++ have other meanings.
.P
The \fB/=\fP modifier requests that the values of all potential captured
parentheses be output after a match. By default, only those up to the highest
one actually used in the match are output (corresponding to the return code
from \fBpcre[16|32]_exec()\fP). Values in the offsets vector corresponding to
higher numbers should be set to -1, and these are output as "<unset>". This
modifier gives a way of checking that this is happening.
.P
The \fB/B\fP modifier is a debugging feature. It requests that \fBpcretest\fP
output a representation of the compiled code after compilation. Normally this
information contains length and offset values; however, if \fB/Z\fP is also
present, this data is replaced by spaces. This is a special feature for use in
the automatic test scripts; it ensures that the same output is generated for
different internal link sizes.
.P
The \fB/D\fP modifier is a PCRE debugging feature, and is equivalent to
\fB/BI\fP, that is, both the \fB/B\fP and the \fB/I\fP modifiers.
.P
The \fB/F\fP modifier causes \fBpcretest\fP to flip the byte order of the
2-byte and 4-byte fields in the compiled pattern. This facility is for testing
the feature in PCRE that allows it to execute patterns that were compiled on a
host with a different endianness. This feature is not available when the POSIX
interface to PCRE is being used, that is, when the \fB/P\fP pattern modifier is
specified. See also the section about saving and reloading compiled patterns
below.
.P
The \fB/I\fP modifier requests that \fBpcretest\fP output information about the
compiled pattern (whether it is anchored, has a fixed first character, and
so on). It does this by calling \fBpcre[16|32]_fullinfo()\fP after compiling a
pattern. If the pattern is studied, the results of that are also output. In
this output, the word "char" means a non-UTF character, that is, the value of a
single data item (8-bit, 16-bit, or 32-bit, depending on the library that is
being tested).
.P
The \fB/K\fP modifier requests \fBpcretest\fP to show names from backtracking
control verbs that are returned from calls to \fBpcre[16|32]_exec()\fP. It causes
\fBpcretest\fP to create a \fBpcre[16|32]_extra\fP block if one has not already
been created by a call to \fBpcre[16|32]_study()\fP, and to set the
PCRE_EXTRA_MARK flag and the \fBmark\fP field within it, every time that
\fBpcre[16|32]_exec()\fP is called. If the variable that the \fBmark\fP field
points to is non-NULL for a match, non-match, or partial match, \fBpcretest\fP
prints the string to which it points. For a match, this is shown on a line by
itself, tagged with "MK:". For a non-match it is added to the message.
.P
The \fB/L\fP modifier must be followed directly by the name of a locale, for
example,
.sp
/pattern/Lfr_FR
.sp
For this reason, it must be the last modifier. The given locale is set,
\fBpcre[16|32]_maketables()\fP is called to build a set of character tables for
the locale, and this is then passed to \fBpcre[16|32]_compile()\fP when compiling
the regular expression. Without an \fB/L\fP (or \fB/T\fP) modifier, NULL is
passed as the tables pointer; that is, \fB/L\fP applies only to the expression
on which it appears.
.P
The \fB/M\fP modifier causes the size in bytes of the memory block used to hold
the compiled pattern to be output. This does not include the size of the
\fBpcre[16|32]\fP block; it is just the actual compiled data. If the pattern is
successfully studied with the PCRE_STUDY_JIT_COMPILE option, the size of the
JIT compiled code is also output.
.P
The \fB/Q\fP modifier is used to test the use of \fBpcre_stack_guard\fP. It
must be followed by '0' or '1', specifying the return code to be given from an
external function that is passed to PCRE and used for stack checking during
compilation (see the
.\" HREF
\fBpcreapi\fP
.\"
documentation for details).
.P
The \fB/S\fP modifier causes \fBpcre[16|32]_study()\fP to be called after the
expression has been compiled, and the results used when the expression is
matched. There are a number of qualifying characters that may follow \fB/S\fP.
They may appear in any order.
.P
If \fB/S\fP is followed by an exclamation mark, \fBpcre[16|32]_study()\fP is
called with the PCRE_STUDY_EXTRA_NEEDED option, causing it always to return a
\fBpcre_extra\fP block, even when studying discovers no useful information.
.P
If \fB/S\fP is followed by a second S character, it suppresses studying, even
if it was requested externally by the \fB-s\fP command line option. This makes
it possible to specify that certain patterns are always studied, and others are
never studied, independently of \fB-s\fP. This feature is used in the test
files in a few cases where the output is different when the pattern is studied.
.P
If the \fB/S\fP modifier is followed by a + character, the call to
\fBpcre[16|32]_study()\fP is made with all the JIT study options, requesting
just-in-time optimization support if it is available, for both normal and
partial matching. If you want to restrict the JIT compiling modes, you can
follow \fB/S+\fP with a digit in the range 1 to 7:
.sp
1 normal match only
2 soft partial match only
3 normal match and soft partial match
4 hard partial match only
6 soft and hard partial match
7 all three modes (default)
.sp
If \fB/S++\fP is used instead of \fB/S+\fP (with or without a following digit),
the text "(JIT)" is added to the first output line after a match or no match
when JIT-compiled code was actually used.
.P
Note that there is also an independent \fB/+\fP modifier; it must not be given
immediately after \fB/S\fP or \fB/S+\fP because this will be misinterpreted.
.P
If JIT studying is successful, the compiled JIT code will automatically be used
when \fBpcre[16|32]_exec()\fP is run, except when incompatible run-time options
are specified. For more details, see the
.\" HREF
\fBpcrejit\fP
.\"
documentation. See also the \fB\eJ\fP escape sequence below for a way of
setting the size of the JIT stack.
.P
Finally, if \fB/S\fP is followed by a minus character, JIT compilation is
suppressed, even if it was requested externally by the \fB-s\fP command line
option. This makes it possible to specify that JIT is never to be used for
certain patterns.
.P
The \fB/T\fP modifier must be followed by a single digit. It causes a specific
set of built-in character tables to be passed to \fBpcre[16|32]_compile()\fP. It
is used in the standard PCRE tests to check behaviour with different character
tables. The digit specifies the tables as follows:
.sp
0 the default ASCII tables, as distributed in
pcre_chartables.c.dist
1 a set of tables defining ISO 8859 characters
.sp
In table 1, some characters whose codes are greater than 128 are identified as
letters, digits, spaces, etc.
.
.
.SS "Using the POSIX wrapper API"
.rs
.sp
The \fB/P\fP modifier causes \fBpcretest\fP to call PCRE via the POSIX wrapper
API rather than its native API. This supports only the 8-bit library. When
\fB/P\fP is set, the following modifiers set options for the \fBregcomp()\fP
function:
.sp
/i REG_ICASE
/m REG_NEWLINE
/N REG_NOSUB
/s REG_DOTALL )
/U REG_UNGREEDY ) These options are not part of
/W REG_UCP ) the POSIX standard
/8 REG_UTF8 )
.sp
The \fB/+\fP modifier works as described above. All other modifiers are
ignored.
.
.
.SS "Locking out certain modifiers"
.rs
.sp
PCRE can be compiled with or without support for certain features such as
UTF-8/16/32 or Unicode properties. Accordingly, the standard tests are split up
into a number of different files that are selected for running depending on
which features are available. When updating the tests, it is all too easy to
put a new test into the wrong file by mistake; for example, to put a test that
requires UTF support into a file that is used when it is not available. To help
detect such mistakes as early as possible, there is a facility for locking out
specific modifiers. If an input line for \fBpcretest\fP starts with the string
"< forbid " the following sequence of characters is taken as a list of
forbidden modifiers. For example, in the test files that must not use UTF or
Unicode property support, this line appears:
.sp
< forbid 8W
.sp
This locks out the /8 and /W modifiers. An immediate error is given if they are
subsequently encountered. If the character string contains < but not >, all the
multi-character modifiers that begin with < are locked out. Otherwise, such
modifiers must be explicitly listed, for example:
.sp
< forbid <JS><cr>
.sp
There must be a single space between < and "forbid" for this feature to be
recognised. If there is not, the line is interpreted either as a request to
re-load a pre-compiled pattern (see "SAVING AND RELOADING COMPILED PATTERNS"
below) or, if there is a another < character, as a pattern that uses < as its
delimiter.
.
.
.SH "DATA LINES"
.rs
.sp
Before each data line is passed to \fBpcre[16|32]_exec()\fP, leading and trailing
white space is removed, and it is then scanned for \e escapes. Some of these
are pretty esoteric features, intended for checking out some of the more
complicated features of PCRE. If you are just testing "ordinary" regular
expressions, you probably don't need any of these. The following escapes are
recognized:
.sp
\ea alarm (BEL, \ex07)
\eb backspace (\ex08)
\ee escape (\ex27)
\ef form feed (\ex0c)
\en newline (\ex0a)
.\" JOIN
\eqdd set the PCRE_MATCH_LIMIT limit to dd
(any number of digits)
\er carriage return (\ex0d)
\et tab (\ex09)
\ev vertical tab (\ex0b)
\ennn octal character (up to 3 octal digits); always
a byte unless > 255 in UTF-8 or 16-bit or 32-bit mode
\eo{dd...} octal character (any number of octal digits}
\exhh hexadecimal byte (up to 2 hex digits)
\ex{hh...} hexadecimal character (any number of hex digits)
.\" JOIN
\eA pass the PCRE_ANCHORED option to \fBpcre[16|32]_exec()\fP
or \fBpcre[16|32]_dfa_exec()\fP
.\" JOIN
\eB pass the PCRE_NOTBOL option to \fBpcre[16|32]_exec()\fP
or \fBpcre[16|32]_dfa_exec()\fP
.\" JOIN
\eCdd call pcre[16|32]_copy_substring() for substring dd
after a successful match (number less than 32)
.\" JOIN
\eCname call pcre[16|32]_copy_named_substring() for substring
"name" after a successful match (name terminated
by next non alphanumeric character)
.\" JOIN
\eC+ show the current captured substrings at callout
time
\eC- do not supply a callout function
.\" JOIN
\eC!n return 1 instead of 0 when callout number n is
reached
.\" JOIN
\eC!n!m return 1 instead of 0 when callout number n is
reached for the nth time
.\" JOIN
\eC*n pass the number n (may be negative) as callout
data; this is used as the callout return value
\eD use the \fBpcre[16|32]_dfa_exec()\fP match function
\eF only shortest match for \fBpcre[16|32]_dfa_exec()\fP
.\" JOIN
\eGdd call pcre[16|32]_get_substring() for substring dd
after a successful match (number less than 32)
.\" JOIN
\eGname call pcre[16|32]_get_named_substring() for substring
"name" after a successful match (name terminated
by next non-alphanumeric character)
.\" JOIN
\eJdd set up a JIT stack of dd kilobytes maximum (any
number of digits)
.\" JOIN
\eL call pcre[16|32]_get_substringlist() after a
successful match
.\" JOIN
\eM discover the minimum MATCH_LIMIT and
MATCH_LIMIT_RECURSION settings
.\" JOIN
\eN pass the PCRE_NOTEMPTY option to \fBpcre[16|32]_exec()\fP
or \fBpcre[16|32]_dfa_exec()\fP; if used twice, pass the
PCRE_NOTEMPTY_ATSTART option
.\" JOIN
\eOdd set the size of the output vector passed to
\fBpcre[16|32]_exec()\fP to dd (any number of digits)
.\" JOIN
\eP pass the PCRE_PARTIAL_SOFT option to \fBpcre[16|32]_exec()\fP
or \fBpcre[16|32]_dfa_exec()\fP; if used twice, pass the
PCRE_PARTIAL_HARD option
.\" JOIN
\eQdd set the PCRE_MATCH_LIMIT_RECURSION limit to dd
(any number of digits)
\eR pass the PCRE_DFA_RESTART option to \fBpcre[16|32]_dfa_exec()\fP
\eS output details of memory get/free calls during matching
.\" JOIN
\eY pass the PCRE_NO_START_OPTIMIZE option to \fBpcre[16|32]_exec()\fP
or \fBpcre[16|32]_dfa_exec()\fP
.\" JOIN
\eZ pass the PCRE_NOTEOL option to \fBpcre[16|32]_exec()\fP
or \fBpcre[16|32]_dfa_exec()\fP
.\" JOIN
\e? pass the PCRE_NO_UTF[8|16|32]_CHECK option to
\fBpcre[16|32]_exec()\fP or \fBpcre[16|32]_dfa_exec()\fP
.\" JOIN
\e>dd start the match at offset dd (optional "-"; then
any number of digits); this sets the \fIstartoffset\fP
argument for \fBpcre[16|32]_exec()\fP or \fBpcre[16|32]_dfa_exec()\fP
.\" JOIN
\e<cr> pass the PCRE_NEWLINE_CR option to \fBpcre[16|32]_exec()\fP
or \fBpcre[16|32]_dfa_exec()\fP
.\" JOIN
\e<lf> pass the PCRE_NEWLINE_LF option to \fBpcre[16|32]_exec()\fP
or \fBpcre[16|32]_dfa_exec()\fP
.\" JOIN
\e<crlf> pass the PCRE_NEWLINE_CRLF option to \fBpcre[16|32]_exec()\fP
or \fBpcre[16|32]_dfa_exec()\fP
.\" JOIN
\e<anycrlf> pass the PCRE_NEWLINE_ANYCRLF option to \fBpcre[16|32]_exec()\fP
or \fBpcre[16|32]_dfa_exec()\fP
.\" JOIN
\e<any> pass the PCRE_NEWLINE_ANY option to \fBpcre[16|32]_exec()\fP
or \fBpcre[16|32]_dfa_exec()\fP
.sp
The use of \ex{hh...} is not dependent on the use of the \fB/8\fP modifier on
the pattern. It is recognized always. There may be any number of hexadecimal
digits inside the braces; invalid values provoke error messages.
.P
Note that \exhh specifies one byte rather than one character in UTF-8 mode;
this makes it possible to construct invalid UTF-8 sequences for testing
purposes. On the other hand, \ex{hh} is interpreted as a UTF-8 character in
UTF-8 mode, generating more than one byte if the value is greater than 127.
When testing the 8-bit library not in UTF-8 mode, \ex{hh} generates one byte
for values less than 256, and causes an error for greater values.
.P
In UTF-16 mode, all 4-digit \ex{hhhh} values are accepted. This makes it
possible to construct invalid UTF-16 sequences for testing purposes.
.P
In UTF-32 mode, all 4- to 8-digit \ex{...} values are accepted. This makes it
possible to construct invalid UTF-32 sequences for testing purposes.
.P
The escapes that specify line ending sequences are literal strings, exactly as
shown. No more than one newline setting should be present in any data line.
.P
A backslash followed by anything else just escapes the anything else. If
the very last character is a backslash, it is ignored. This gives a way of
passing an empty line as data, since a real empty line terminates the data
input.
.P
The \fB\eJ\fP escape provides a way of setting the maximum stack size that is
used by the just-in-time optimization code. It is ignored if JIT optimization
is not being used. Providing a stack that is larger than the default 32K is
necessary only for very complicated patterns.
.P
If \eM is present, \fBpcretest\fP calls \fBpcre[16|32]_exec()\fP several times,
with different values in the \fImatch_limit\fP and \fImatch_limit_recursion\fP
fields of the \fBpcre[16|32]_extra\fP data structure, until it finds the minimum
numbers for each parameter that allow \fBpcre[16|32]_exec()\fP to complete without
error. Because this is testing a specific feature of the normal interpretive
\fBpcre[16|32]_exec()\fP execution, the use of any JIT optimization that might
have been set up by the \fB/S+\fP qualifier of \fB-s+\fP option is disabled.
.P
The \fImatch_limit\fP number is a measure of the amount of backtracking
that takes place, and checking it out can be instructive. For most simple
matches, the number is quite small, but for patterns with very large numbers of
matching possibilities, it can become large very quickly with increasing length
of subject string. The \fImatch_limit_recursion\fP number is a measure of how
much stack (or, if PCRE is compiled with NO_RECURSE, how much heap) memory is
needed to complete the match attempt.
.P
When \eO is used, the value specified may be higher or lower than the size set
by the \fB-O\fP command line option (or defaulted to 45); \eO applies only to
the call of \fBpcre[16|32]_exec()\fP for the line in which it appears.
.P
If the \fB/P\fP modifier was present on the pattern, causing the POSIX wrapper
API to be used, the only option-setting sequences that have any effect are \eB,
\eN, and \eZ, causing REG_NOTBOL, REG_NOTEMPTY, and REG_NOTEOL, respectively,
to be passed to \fBregexec()\fP.
.
.
.SH "THE ALTERNATIVE MATCHING FUNCTION"
.rs
.sp
By default, \fBpcretest\fP uses the standard PCRE matching function,
\fBpcre[16|32]_exec()\fP to match each data line. PCRE also supports an
alternative matching function, \fBpcre[16|32]_dfa_test()\fP, which operates in a
different way, and has some restrictions. The differences between the two
functions are described in the
.\" HREF
\fBpcrematching\fP
.\"
documentation.
.P
If a data line contains the \eD escape sequence, or if the command line
contains the \fB-dfa\fP option, the alternative matching function is used.
This function finds all possible matches at a given point. If, however, the \eF
escape sequence is present in the data line, it stops after the first match is
found. This is always the shortest possible match.
.
.
.SH "DEFAULT OUTPUT FROM PCRETEST"
.rs
.sp
This section describes the output when the normal matching function,
\fBpcre[16|32]_exec()\fP, is being used.
.P
When a match succeeds, \fBpcretest\fP outputs the list of captured substrings
that \fBpcre[16|32]_exec()\fP returns, starting with number 0 for the string that
matched the whole pattern. Otherwise, it outputs "No match" when the return is
PCRE_ERROR_NOMATCH, and "Partial match:" followed by the partially matching
substring when \fBpcre[16|32]_exec()\fP returns PCRE_ERROR_PARTIAL. (Note that
this is the entire substring that was inspected during the partial match; it
may include characters before the actual match start if a lookbehind assertion,
\eK, \eb, or \eB was involved.) For any other return, \fBpcretest\fP outputs
the PCRE negative error number and a short descriptive phrase. If the error is
a failed UTF string check, the offset of the start of the failing character and
the reason code are also output, provided that the size of the output vector is
at least two. Here is an example of an interactive \fBpcretest\fP run.
.sp
$ pcretest
PCRE version 8.13 2011-04-30
.sp
re> /^abc(\ed+)/
data> abc123
0: abc123
1: 123
data> xyz
No match
.sp
Unset capturing substrings that are not followed by one that is set are not
returned by \fBpcre[16|32]_exec()\fP, and are not shown by \fBpcretest\fP. In the
following example, there are two capturing substrings, but when the first data
line is matched, the second, unset substring is not shown. An "internal" unset
substring is shown as "<unset>", as for the second data line.
.sp
re> /(a)|(b)/
data> a
0: a
1: a
data> b
0: b
1: <unset>
2: b
.sp
If the strings contain any non-printing characters, they are output as \exhh
escapes if the value is less than 256 and UTF mode is not set. Otherwise they
are output as \ex{hh...} escapes. See below for the definition of non-printing
characters. If the pattern has the \fB/+\fP modifier, the output for substring
0 is followed by the the rest of the subject string, identified by "0+" like
this:
.sp
re> /cat/+
data> cataract
0: cat
0+ aract
.sp
If the pattern has the \fB/g\fP or \fB/G\fP modifier, the results of successive
matching attempts are output in sequence, like this:
.sp
re> /\eBi(\ew\ew)/g
data> Mississippi
0: iss
1: ss
0: iss
1: ss
0: ipp
1: pp
.sp
"No match" is output only if the first match attempt fails. Here is an example
of a failure message (the offset 4 that is specified by \e>4 is past the end of
the subject string):
.sp
re> /xyz/
data> xyz\e>4
Error -24 (bad offset value)
.P
If any of the sequences \fB\eC\fP, \fB\eG\fP, or \fB\eL\fP are present in a
data line that is successfully matched, the substrings extracted by the
convenience functions are output with C, G, or L after the string number
instead of a colon. This is in addition to the normal full list. The string
length (that is, the return from the extraction function) is given in
parentheses after each string for \fB\eC\fP and \fB\eG\fP.
.P
Note that whereas patterns can be continued over several lines (a plain ">"
prompt is used for continuations), data lines may not. However newlines can be
included in data by means of the \en escape (or \er, \er\en, etc., depending on
the newline sequence setting).
.
.
.
.SH "OUTPUT FROM THE ALTERNATIVE MATCHING FUNCTION"
.rs
.sp
When the alternative matching function, \fBpcre[16|32]_dfa_exec()\fP, is used (by
means of the \eD escape sequence or the \fB-dfa\fP command line option), the
output consists of a list of all the matches that start at the first point in
the subject where there is at least one match. For example:
.sp
re> /(tang|tangerine|tan)/
data> yellow tangerine\eD
0: tangerine
1: tang
2: tan
.sp
(Using the normal matching function on this data finds only "tang".) The
longest matching string is always given first (and numbered zero). After a
PCRE_ERROR_PARTIAL return, the output is "Partial match:", followed by the
partially matching substring. (Note that this is the entire substring that was
inspected during the partial match; it may include characters before the actual
match start if a lookbehind assertion, \eK, \eb, or \eB was involved.)
.P
If \fB/g\fP is present on the pattern, the search for further matches resumes
at the end of the longest match. For example:
.sp
re> /(tang|tangerine|tan)/g
data> yellow tangerine and tangy sultana\eD
0: tangerine
1: tang
2: tan
0: tang
1: tan
0: tan
.sp
Since the matching function does not support substring capture, the escape
sequences that are concerned with captured substrings are not relevant.
.
.
.SH "RESTARTING AFTER A PARTIAL MATCH"
.rs
.sp
When the alternative matching function has given the PCRE_ERROR_PARTIAL return,
indicating that the subject partially matched the pattern, you can restart the
match with additional subject data by means of the \eR escape sequence. For
example:
.sp
re> /^\ed?\ed(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)\ed\ed$/
data> 23ja\eP\eD
Partial match: 23ja
data> n05\eR\eD
0: n05
.sp
For further information about partial matching, see the
.\" HREF
\fBpcrepartial\fP
.\"
documentation.
.
.
.SH CALLOUTS
.rs
.sp
If the pattern contains any callout requests, \fBpcretest\fP's callout function
is called during matching. This works with both matching functions. By default,
the called function displays the callout number, the start and current
positions in the text at the callout time, and the next pattern item to be
tested. For example:
.sp
--->pqrabcdef
0 ^ ^ \ed
.sp
This output indicates that callout number 0 occurred for a match attempt
starting at the fourth character of the subject string, when the pointer was at
the seventh character of the data, and when the next pattern item was \ed. Just
one circumflex is output if the start and current positions are the same.
.P
Callouts numbered 255 are assumed to be automatic callouts, inserted as a
result of the \fB/C\fP pattern modifier. In this case, instead of showing the
callout number, the offset in the pattern, preceded by a plus, is output. For
example:
.sp
re> /\ed?[A-E]\e*/C
data> E*
--->E*
+0 ^ \ed?
+3 ^ [A-E]
+8 ^^ \e*
+10 ^ ^
0: E*
.sp
If a pattern contains (*MARK) items, an additional line is output whenever
a change of latest mark is passed to the callout function. For example:
.sp
re> /a(*MARK:X)bc/C
data> abc
--->abc
+0 ^ a
+1 ^^ (*MARK:X)
+10 ^^ b
Latest Mark: X
+11 ^ ^ c
+12 ^ ^
0: abc
.sp
The mark changes between matching "a" and "b", but stays the same for the rest
of the match, so nothing more is output. If, as a result of backtracking, the
mark reverts to being unset, the text "<unset>" is output.
.P
The callout function in \fBpcretest\fP returns zero (carry on matching) by
default, but you can use a \eC item in a data line (as described above) to
change this and other parameters of the callout.
.P
Inserting callouts can be helpful when using \fBpcretest\fP to check
complicated regular expressions. For further information about callouts, see
the
.\" HREF
\fBpcrecallout\fP
.\"
documentation.
.
.
.
.SH "NON-PRINTING CHARACTERS"
.rs
.sp
When \fBpcretest\fP is outputting text in the compiled version of a pattern,
bytes other than 32-126 are always treated as non-printing characters are are
therefore shown as hex escapes.
.P
When \fBpcretest\fP is outputting text that is a matched part of a subject
string, it behaves in the same way, unless a different locale has been set for
the pattern (using the \fB/L\fP modifier). In this case, the \fBisprint()\fP
function to distinguish printing and non-printing characters.
.
.
.
.SH "SAVING AND RELOADING COMPILED PATTERNS"
.rs
.sp
The facilities described in this section are not available when the POSIX
interface to PCRE is being used, that is, when the \fB/P\fP pattern modifier is
specified.
.P
When the POSIX interface is not in use, you can cause \fBpcretest\fP to write a
compiled pattern to a file, by following the modifiers with > and a file name.
For example:
.sp
/pattern/im >/some/file
.sp
See the
.\" HREF
\fBpcreprecompile\fP
.\"
documentation for a discussion about saving and re-using compiled patterns.
Note that if the pattern was successfully studied with JIT optimization, the
JIT data cannot be saved.
.P
The data that is written is binary. The first eight bytes are the length of the
compiled pattern data followed by the length of the optional study data, each
written as four bytes in big-endian order (most significant byte first). If
there is no study data (either the pattern was not studied, or studying did not
return any data), the second length is zero. The lengths are followed by an
exact copy of the compiled pattern. If there is additional study data, this
(excluding any JIT data) follows immediately after the compiled pattern. After
writing the file, \fBpcretest\fP expects to read a new pattern.
.P
A saved pattern can be reloaded into \fBpcretest\fP by specifying < and a file
name instead of a pattern. There must be no space between < and the file name,
which must not contain a < character, as otherwise \fBpcretest\fP will
interpret the line as a pattern delimited by < characters. For example:
.sp
re> </some/file
Compiled pattern loaded from /some/file
No study data
.sp
If the pattern was previously studied with the JIT optimization, the JIT
information cannot be saved and restored, and so is lost. When the pattern has
been loaded, \fBpcretest\fP proceeds to read data lines in the usual way.
.P
You can copy a file written by \fBpcretest\fP to a different host and reload it
there, even if the new host has opposite endianness to the one on which the
pattern was compiled. For example, you can compile on an i86 machine and run on
a SPARC machine. When a pattern is reloaded on a host with different
endianness, the confirmation message is changed to:
.sp
Compiled pattern (byte-inverted) loaded from /some/file
.sp
The test suite contains some saved pre-compiled patterns with different
endianness. These are reloaded using "<!" instead of just "<". This suppresses
the "(byte-inverted)" text so that the output is the same on all hosts. It also
forces debugging output once the pattern has been reloaded.
.P
File names for saving and reloading can be absolute or relative, but note that
the shell facility of expanding a file name that starts with a tilde (~) is not
available.
.P
The ability to save and reload files in \fBpcretest\fP is intended for testing
and experimentation. It is not intended for production use because only a
single pattern can be written to a file. Furthermore, there is no facility for
supplying custom character tables for use with a reloaded pattern. If the
original pattern was compiled with custom tables, an attempt to match a subject
string using a reloaded pattern is likely to cause \fBpcretest\fP to crash.
Finally, if you attempt to load a file that is not in the correct format, the
result is undefined.
.
.
.SH "SEE ALSO"
.rs
.sp
\fBpcre\fP(3), \fBpcre16\fP(3), \fBpcre32\fP(3), \fBpcreapi\fP(3),
\fBpcrecallout\fP(3),
\fBpcrejit\fP, \fBpcrematching\fP(3), \fBpcrepartial\fP(d),
\fBpcrepattern\fP(3), \fBpcreprecompile\fP(3).
.
.
.SH AUTHOR
.rs
.sp
.nf
Philip Hazel
University Computing Service
Cambridge CB2 3QH, England.
.fi
.
.
.SH REVISION
.rs
.sp
.nf
Last updated: 23 February 2017
Copyright (c) 1997-2017 University of Cambridge.
.fi
PK 1N%[ ���� �� perl5/Expect.pmnu �7��m # -*-cperl-*-
# This module is copyrighted as per the usual perl legalese:
# Copyright (c) 1997 Austin Schutz.
# expect() interface & functionality enhancements (c) 1999 Roland Giersig.
#
# All rights reserved. This program is free software; you can
# redistribute it and/or modify it under the same terms as Perl
# itself.
#
# Don't blame/flame me if you bust your stuff.
# Austin Schutz <ASchutz@users.sourceforge.net>
#
# This module now is maintained by
# Dave Jacoby <jacoby@cpan.org>
#
use 5.006;
package Expect;
use strict;
use warnings;
use IO::Pty 1.11; # We need make_slave_controlling_terminal()
use IO::Tty;
use POSIX qw(:sys_wait_h :unistd_h); # For WNOHANG and isatty
use Fcntl qw(:DEFAULT); # For checking file handle settings.
use Carp qw(cluck croak carp confess);
use IO::Handle ();
use Exporter qw(import);
use Errno;
use Scalar::Util qw/ looks_like_number /;
# This is necessary to make routines within Expect work.
@Expect::ISA = qw(IO::Pty);
@Expect::EXPORT = qw(expect exp_continue exp_continue_timeout);
BEGIN {
$Expect::VERSION = '1.38';
# These are defaults which may be changed per object, or set as
# the user wishes.
# This will be unset, since the default behavior differs between
# spawned processes and initialized filehandles.
# $Expect::Log_Stdout = 1;
$Expect::Log_Group = 1;
$Expect::Debug = 0;
$Expect::Exp_Max_Accum = 0; # unlimited
$Expect::Exp_Internal = 0;
$Expect::IgnoreEintr = 0;
$Expect::Manual_Stty = 0;
$Expect::Multiline_Matching = 1;
$Expect::Do_Soft_Close = 0;
@Expect::Before_List = ();
@Expect::After_List = ();
%Expect::Spawned_PIDs = ();
}
sub version {
my ($version) = @_;
warn "Version $version is later than $Expect::VERSION. It may not be supported"
if ( defined($version) && ( $version > $Expect::VERSION ) );
die "Versions before 1.03 are not supported in this release"
if ( ( defined($version) ) && ( $version < 1.03 ) );
return $Expect::VERSION;
}
sub new {
my ($class, @args) = @_;
$class = ref($class) if ref($class); # so we can be called as $exp->new()
# Create the pty which we will use to pass process info.
my ($self) = IO::Pty->new;
die "$class: Could not assign a pty" unless $self;
bless $self => $class;
$self->autoflush(1);
# This is defined here since the default is different for
# initialized handles as opposed to spawned processes.
${*$self}{exp_Log_Stdout} = 1;
$self->_init_vars();
if (@args) {
# we got add'l parms, so pass them to spawn
return $self->spawn(@args);
}
return $self;
}
sub timeout {
my $self = shift;
${*$self}{expect_timeout} = shift if @_;
return ${*$self}{expect_timeout};
}
sub spawn {
my ($class, @cmd) = @_;
# spawn is passed command line args.
my $self;
if ( ref($class) ) {
$self = $class;
} else {
$self = $class->new();
}
croak "Cannot reuse an object with an already spawned command"
if exists ${*$self}{"exp_Command"};
${*$self}{"exp_Command"} = \@cmd;
# set up pipe to detect childs exec error
pipe( FROM_CHILD, TO_PARENT ) or die "Cannot open pipe: $!";
pipe( FROM_PARENT, TO_CHILD ) or die "Cannot open pipe: $!";
TO_PARENT->autoflush(1);
TO_CHILD->autoflush(1);
eval { fcntl( TO_PARENT, Fcntl::F_SETFD, Fcntl::FD_CLOEXEC ); };
my $pid = fork;
unless ( defined($pid) ) {
warn "Cannot fork: $!" if $^W;
return;
}
if ($pid) {
# parent
my $errno;
${*$self}{exp_Pid} = $pid;
close TO_PARENT;
close FROM_PARENT;
$self->close_slave();
$self->set_raw() if $self->raw_pty and isatty($self);
close TO_CHILD; # so child gets EOF and can go ahead
# now wait for child exec (eof due to close-on-exit) or exec error
my $errstatus = sysread( FROM_CHILD, $errno, 256 );
die "Cannot sync with child: $!" if not defined $errstatus;
close FROM_CHILD;
if ($errstatus) {
$! = $errno + 0;
warn "Cannot exec(@cmd): $!\n" if $^W;
return;
}
} else {
# child
close FROM_CHILD;
close TO_CHILD;
$self->make_slave_controlling_terminal();
my $slv = $self->slave()
or die "Cannot get slave: $!";
$slv->set_raw() if $self->raw_pty;
close($self);
# wait for parent before we detach
my $buffer;
my $errstatus = sysread( FROM_PARENT, $buffer, 256 );
die "Cannot sync with parent: $!" if not defined $errstatus;
close FROM_PARENT;
close(STDIN);
open( STDIN, "<&" . $slv->fileno() )
or die "Couldn't reopen STDIN for reading, $!\n";
close(STDOUT);
open( STDOUT, ">&" . $slv->fileno() )
or die "Couldn't reopen STDOUT for writing, $!\n";
close(STDERR);
open( STDERR, ">&" . $slv->fileno() )
or die "Couldn't reopen STDERR for writing, $!\n";
{ exec(@cmd) };
print TO_PARENT $! + 0;
die "Cannot exec(@cmd): $!\n";
}
# This is sort of for code compatibility, and to make debugging a little
# easier. By code compatibility I mean that previously the process's
# handle was referenced by $process{Pty_Handle} instead of just $process.
# This is almost like 'naming' the handle to the process.
# I think this also reflects Tcl Expect-like behavior.
${*$self}{exp_Pty_Handle} = "spawn id(" . $self->fileno() . ")";
if ( ( ${*$self}{"exp_Debug"} ) or ( ${*$self}{"exp_Exp_Internal"} ) ) {
cluck(
"Spawned '@cmd'\r\n",
"\t${*$self}{exp_Pty_Handle}\r\n",
"\tPid: ${*$self}{exp_Pid}\r\n",
"\tTty: " . $self->SUPER::ttyname() . "\r\n",
);
}
$Expect::Spawned_PIDs{ ${*$self}{exp_Pid} } = undef;
return $self;
}
sub exp_init {
my ($class, $self) = @_;
# take a filehandle, for use later with expect() or interconnect() .
# All the functions are written for reading from a tty, so if the naming
# scheme looks odd, that's why.
bless $self, $class;
croak "exp_init not passed a file object, stopped"
unless defined( $self->fileno() );
$self->autoflush(1);
# Define standard variables.. debug states, etc.
$self->_init_vars();
# Turn of logging. By default we don't want crap from a file to get spewed
# on screen as we read it.
${*$self}{exp_Log_Stdout} = 0;
${*$self}{exp_Pty_Handle} = "handle id(" . $self->fileno() . ")";
${*$self}{exp_Pty_Handle} = "STDIN" if $self->fileno() == fileno(STDIN);
print STDERR "Initialized ${*$self}{exp_Pty_Handle}.'\r\n"
if ${*$self}{"exp_Debug"};
return $self;
}
# make an alias
*init = \&exp_init;
######################################################################
# We're happy OOP people. No direct access to stuff.
# For standard read-writeable parameters, we define some autoload magic...
my %Writeable_Vars = (
debug => 'exp_Debug',
exp_internal => 'exp_Exp_Internal',
do_soft_close => 'exp_Do_Soft_Close',
max_accum => 'exp_Max_Accum',
match_max => 'exp_Max_Accum',
notransfer => 'exp_NoTransfer',
log_stdout => 'exp_Log_Stdout',
log_user => 'exp_Log_Stdout',
log_group => 'exp_Log_Group',
manual_stty => 'exp_Manual_Stty',
restart_timeout_upon_receive => 'exp_Continue',
raw_pty => 'exp_Raw_Pty',
);
my %Readable_Vars = (
pid => 'exp_Pid',
exp_pid => 'exp_Pid',
exp_match_number => 'exp_Match_Number',
match_number => 'exp_Match_Number',
exp_error => 'exp_Error',
error => 'exp_Error',
exp_command => 'exp_Command',
command => 'exp_Command',
exp_match => 'exp_Match',
match => 'exp_Match',
exp_matchlist => 'exp_Matchlist',
matchlist => 'exp_Matchlist',
exp_before => 'exp_Before',
before => 'exp_Before',
exp_after => 'exp_After',
after => 'exp_After',
exp_exitstatus => 'exp_Exit',
exitstatus => 'exp_Exit',
exp_pty_handle => 'exp_Pty_Handle',
pty_handle => 'exp_Pty_Handle',
exp_logfile => 'exp_Log_File',
logfile => 'exp_Log_File',
%Writeable_Vars,
);
sub AUTOLOAD {
my ($self, @args) = @_;
my $type = ref($self)
or croak "$self is not an object";
use vars qw($AUTOLOAD);
my $name = $AUTOLOAD;
$name =~ s/.*:://; # strip fully-qualified portion
unless ( exists $Readable_Vars{$name} ) {
croak "ERROR: cannot find method `$name' in class $type";
}
my $varname = $Readable_Vars{$name};
my $tmp;
$tmp = ${*$self}{$varname} if exists ${*$self}{$varname};
if (@args) {
if ( exists $Writeable_Vars{$name} ) {
my $ref = ref($tmp);
if ( $ref eq 'ARRAY' ) {
${*$self}{$varname} = [@args];
} elsif ( $ref eq 'HASH' ) {
${*$self}{$varname} = {@args};
} else {
${*$self}{$varname} = shift @args;
}
} else {
carp "Trying to set read-only variable `$name'"
if $^W;
}
}
my $ref = ref($tmp);
return ( wantarray ? @{$tmp} : $tmp ) if ( $ref eq 'ARRAY' );
return ( wantarray ? %{$tmp} : $tmp ) if ( $ref eq 'HASH' );
return $tmp;
}
######################################################################
sub set_seq {
my ( $self, $escape_sequence, $function, $params, @args ) = @_;
# Set an escape sequence/function combo for a read handle for interconnect.
# Ex: $read_handle->set_seq('',\&function,\@parameters);
${ ${*$self}{exp_Function} }{$escape_sequence} = $function;
if ( ( !defined($function) ) || ( $function eq 'undef' ) ) {
${ ${*$self}{exp_Function} }{$escape_sequence} = \&_undef;
}
${ ${*$self}{exp_Parameters} }{$escape_sequence} = $params;
# This'll be a joy to execute. :)
if ( ${*$self}{"exp_Debug"} ) {
print STDERR "Escape seq. '" . $escape_sequence;
print STDERR "' function for ${*$self}{exp_Pty_Handle} set to '";
print STDERR ${ ${*$self}{exp_Function} }{$escape_sequence};
print STDERR "(" . join( ',', @args ) . ")'\r\n";
}
}
sub set_group {
my ($self, @args) = @_;
# Make sure we can read from the read handle
if ( !defined( $args[0] ) ) {
if ( defined( ${*$self}{exp_Listen_Group} ) ) {
return @{ ${*$self}{exp_Listen_Group} };
} else {
# Refrain from referencing an undef
return;
}
}
@{ ${*$self}{exp_Listen_Group} } = ();
if ( $self->_get_mode() !~ 'r' ) {
warn(
"Attempting to set a handle group on ${*$self}{exp_Pty_Handle}, ",
"a non-readable handle!\r\n"
);
}
while ( my $write_handle = shift @args ) {
if ( $write_handle->_get_mode() !~ 'w' ) {
warn(
"Attempting to set a non-writeable listen handle ",
"${*$write_handle}{exp_Pty_handle} for ",
"${*$self}{exp_Pty_Handle}!\r\n"
);
}
push( @{ ${*$self}{exp_Listen_Group} }, $write_handle );
}
}
sub log_file {
my ($self, $file, $mode) = @_;
$mode ||= "a";
return ( ${*$self}{exp_Log_File} )
if @_ < 2; # we got no param, return filehandle
# $e->log_file(undef) is an acceptable call hence we need to check the number of parameters here
if ( ${*$self}{exp_Log_File} and ref( ${*$self}{exp_Log_File} ) ne 'CODE' ) {
close( ${*$self}{exp_Log_File} );
}
${*$self}{exp_Log_File} = undef;
return if ( not $file );
my $fh = $file;
if ( not ref($file) ) {
# it's a filename
$fh = IO::File->new( $file, $mode )
or croak "Cannot open logfile $file: $!";
}
if ( ref($file) ne 'CODE' ) {
croak "Given logfile doesn't have a 'print' method"
if not $fh->can("print");
$fh->autoflush(1); # so logfile is up to date
}
${*$self}{exp_Log_File} = $fh;
return $fh;
}
# I'm going to leave this here in case I might need to change something.
# Previously this was calling `stty`, in a most bastardized manner.
sub exp_stty {
my ($self) = shift;
my ($mode) = "@_";
return unless defined $mode;
if ( not defined $INC{"IO/Stty.pm"} ) {
carp "IO::Stty not installed, cannot change mode";
return;
}
if ( ${*$self}{"exp_Debug"} ) {
print STDERR "Setting ${*$self}{exp_Pty_Handle} to tty mode '$mode'\r\n";
}
unless ( POSIX::isatty($self) ) {
if ( ${*$self}{"exp_Debug"} or $^W ) {
warn "${*$self}{exp_Pty_Handle} is not a tty. Not changing mode";
}
return ''; # No undef to avoid warnings elsewhere.
}
IO::Stty::stty( $self, split( /\s/, $mode ) );
}
*stty = \&exp_stty;
# If we want to clear the buffer. Otherwise Accum will grow during send_slow
# etc. and contain the remainder after matches.
sub clear_accum {
my ($self) = @_;
return $self->set_accum('');
}
sub set_accum {
my ($self, $accum) = @_;
my $old_accum = ${*$self}{exp_Accum};
${*$self}{exp_Accum} = $accum;
# return the contents of the accumulator.
return $old_accum;
}
sub get_accum {
my ($self) = @_;
return ${*$self}{exp_Accum};
}
######################################################################
# define constants for pattern subs
sub exp_continue {"exp_continue"}
sub exp_continue_timeout {"exp_continue_timeout"}
######################################################################
# Expect on multiple objects at once.
#
# Call as Expect::expect($timeout, -i => \@exp_list, @patternlist,
# -i => $exp, @pattern_list, ...);
# or $exp->expect($timeout, @patternlist, -i => \@exp_list, @patternlist,
# -i => $exp, @pattern_list, ...);
#
# Patterns are arrays that consist of
# [ $pattern_type, $pattern, $sub, @subparms ]
#
# Optional $pattern_type is '-re' (RegExp, default) or '-ex' (exact);
#
# $sub is optional CODE ref, which is called as &{$sub}($exp, @subparms)
# if pattern matched; may return exp_continue or exp_continue_timeout.
#
# Old-style syntax (pure pattern strings with optional type) also supported.
#
sub expect {
my $self;
print STDERR ("expect(@_) called...\n") if $Expect::Debug;
if ( defined( $_[0] ) ) {
if ( ref( $_[0] ) and $_[0]->isa('Expect') ) {
$self = shift;
} elsif ( $_[0] eq 'Expect' ) {
shift; # or as Expect->expect
}
}
croak "expect(): not enough arguments, should be expect(timeout, [patterns...])"
if @_ < 1;
my $timeout;
if ( looks_like_number($_[0]) or not defined $_[0] ) {
$timeout = shift;
}
else {
$timeout = $self->timeout;
}
my $timeout_hook = undef;
my @object_list;
my %patterns;
my @pattern_list;
my @timeout_list;
my $curr_list;
if ($self) {
$curr_list = [$self];
} else {
# called directly, so first parameter must be '-i' to establish
# object list.
$curr_list = [];
croak
"expect(): ERROR: if called directly (not as \$obj->expect(...), but as Expect::expect(...), first parameter MUST be '-i' to set an object (list) for the patterns to work on."
if ( $_[0] ne '-i' );
}
# Let's make a list of patterns wanting to be evaled as regexps.
my $parm;
my $parm_nr = 1;
while ( defined( $parm = shift ) ) {
print STDERR ("expect(): handling param '$parm'...\n")
if $Expect::Debug;
if ( ref($parm) ) {
if ( ref($parm) eq 'Regexp' ) {
push @pattern_list, [ $parm_nr, '-re', $parm, undef ];
}
elsif ( ref($parm) eq 'ARRAY' ) {
# if ( ref($parm) eq 'ARRAY' ) {
my $err = _add_patterns_to_list(
\@pattern_list, \@timeout_list,
$parm_nr, $parm
);
carp(
"expect(): Warning: multiple `timeout' patterns (",
scalar(@timeout_list), ").\r\n"
) if @timeout_list > 1;
$timeout_hook = $timeout_list[-1] if $timeout_list[-1];
croak $err if $err;
$parm_nr++;
} else {
croak("expect(): Unknown pattern ref $parm");
}
} else {
# not a ref, is an option or raw pattern
if ( substr( $parm, 0, 1 ) eq '-' ) {
# it's an option
print STDERR ("expect(): handling option '$parm'...\n")
if $Expect::Debug;
if ( $parm eq '-i' ) {
# first add collected patterns to object list
if ( scalar(@$curr_list) ) {
push @object_list, $curr_list
if not exists $patterns{"$curr_list"};
push @{ $patterns{"$curr_list"} }, @pattern_list;
@pattern_list = ();
}
# now put parm(s) into current object list
if ( ref( $_[0] ) eq 'ARRAY' ) {
$curr_list = shift;
} else {
$curr_list = [shift];
}
} elsif ( $parm eq '-re'
or $parm eq '-ex' )
{
if ( ref( $_[1] ) eq 'CODE' ) {
push @pattern_list, [ $parm_nr, $parm, shift, shift ];
} else {
push @pattern_list, [ $parm_nr, $parm, shift, undef ];
}
$parm_nr++;
} else {
croak("Unknown option $parm");
}
} else {
# a plain pattern, check if it is followed by a CODE ref
if ( ref( $_[0] ) eq 'CODE' ) {
if ( $parm eq 'timeout' ) {
push @timeout_list, shift;
carp(
"expect(): Warning: multiple `timeout' patterns (",
scalar(@timeout_list),
").\r\n"
) if @timeout_list > 1;
$timeout_hook = $timeout_list[-1] if $timeout_list[-1];
} elsif ( $parm eq 'eof' ) {
push @pattern_list, [ $parm_nr, "-$parm", undef, shift ];
} else {
push @pattern_list, [ $parm_nr, '-ex', $parm, shift ];
}
} else {
print STDERR ("expect(): exact match '$parm'...\n")
if $Expect::Debug;
push @pattern_list, [ $parm_nr, '-ex', $parm, undef ];
}
$parm_nr++;
}
}
}
# add rest of collected patterns to object list
carp "expect(): Empty object list" unless $curr_list;
push @object_list, $curr_list if not exists $patterns{"$curr_list"};
push @{ $patterns{"$curr_list"} }, @pattern_list;
my $debug = $self ? ${*$self}{exp_Debug} : $Expect::Debug;
my $internal = $self ? ${*$self}{exp_Exp_Internal} : $Expect::Exp_Internal;
# now start matching...
if (@Expect::Before_List) {
print STDERR ("Starting BEFORE pattern matching...\r\n")
if ( $debug or $internal );
_multi_expect( 0, undef, @Expect::Before_List );
}
cluck("Starting EXPECT pattern matching...\r\n")
if ( $debug or $internal );
my @ret;
@ret = _multi_expect(
$timeout, $timeout_hook,
map { [ $_, @{ $patterns{"$_"} } ] } @object_list
);
if (@Expect::After_List) {
print STDERR ("Starting AFTER pattern matching...\r\n")
if ( $debug or $internal );
_multi_expect( 0, undef, @Expect::After_List );
}
return wantarray ? @ret : $ret[0];
}
######################################################################
# the real workhorse
#
sub _multi_expect {
my ($timeout, $timeout_hook, @params) = @_;
if ($timeout_hook) {
croak "Unknown timeout_hook type $timeout_hook"
unless ( ref($timeout_hook) eq 'CODE'
or ref($timeout_hook) eq 'ARRAY' );
}
foreach my $pat (@params) {
my @patterns = @{$pat}[ 1 .. $#{$pat} ];
foreach my $exp ( @{ $pat->[0] } ) {
${*$exp}{exp_New_Data} = 1; # first round we always try to match
if ( exists ${*$exp}{"exp_Max_Accum"}
and ${*$exp}{"exp_Max_Accum"} )
{
${*$exp}{exp_Accum} = $exp->_trim_length(
${*$exp}{exp_Accum},
${*$exp}{exp_Max_Accum}
);
}
print STDERR (
"${*$exp}{exp_Pty_Handle}: beginning expect.\r\n",
"\tTimeout: ",
( defined($timeout) ? $timeout : "unlimited" ),
" seconds.\r\n",
"\tCurrent time: " . localtime() . "\r\n",
) if $Expect::Debug;
# What are we expecting? What do you expect? :-)
if ( ${*$exp}{exp_Exp_Internal} ) {
print STDERR "${*$exp}{exp_Pty_Handle}: list of patterns:\r\n";
foreach my $pattern (@patterns) {
print STDERR (
' ',
defined( $pattern->[0] )
? '#' . $pattern->[0] . ': '
: '',
$pattern->[1],
" `",
_make_readable( $pattern->[2] ),
"'\r\n"
);
}
print STDERR "\r\n";
}
}
}
my $successful_pattern;
my $exp_matched;
my $err;
my $before;
my $after;
my $match;
my @matchlist;
# Set the last loop time to now for time comparisons at end of loop.
my $start_loop_time = time();
my $exp_cont = 1;
READLOOP:
while ($exp_cont) {
$exp_cont = 1;
$err = "";
my $rmask = '';
my $time_left = undef;
if ( defined $timeout ) {
$time_left = $timeout - ( time() - $start_loop_time );
$time_left = 0 if $time_left < 0;
}
$exp_matched = undef;
# Test for a match first so we can test the current Accum w/out
# worrying about an EOF.
foreach my $pat (@params) {
my @patterns = @{$pat}[ 1 .. $#{$pat} ];
foreach my $exp ( @{ $pat->[0] } ) {
# build mask for select in next section...
my $fn = $exp->fileno();
vec( $rmask, $fn, 1 ) = 1 if defined $fn;
next unless ${*$exp}{exp_New_Data};
# clear error status
${*$exp}{exp_Error} = undef;
${*$exp}{exp_After} = undef;
${*$exp}{exp_Match_Number} = undef;
${*$exp}{exp_Match} = undef;
# This could be huge. We should attempt to do something
# about this. Because the output is used for debugging
# I'm of the opinion that showing smaller amounts if the
# total is huge should be ok.
# Thus the 'trim_length'
print STDERR (
"\r\n${*$exp}{exp_Pty_Handle}: Does `",
$exp->_trim_length( _make_readable( ${*$exp}{exp_Accum} ) ),
"'\r\nmatch:\r\n"
) if ${*$exp}{exp_Exp_Internal};
# we don't keep the parameter number anymore
# (clashes with before & after), instead the parameter number is
# stored inside the pattern; we keep the pattern ref
# and look up the number later.
foreach my $pattern (@patterns) {
print STDERR (
" pattern",
defined( $pattern->[0] ) ? ' #' . $pattern->[0] : '',
": ",
$pattern->[1],
" `",
_make_readable( $pattern->[2] ),
"'? "
) if ( ${*$exp}{exp_Exp_Internal} );
# Matching exactly
if ( $pattern->[1] eq '-ex' ) {
my $match_index =
index( ${*$exp}{exp_Accum}, $pattern->[2] );
# We matched if $match_index > -1
if ( $match_index > -1 ) {
$before =
substr( ${*$exp}{exp_Accum}, 0, $match_index );
$match = substr(
${*$exp}{exp_Accum},
$match_index, length( $pattern->[2] )
);
$after = substr(
${*$exp}{exp_Accum},
$match_index + length( $pattern->[2] )
);
${*$exp}{exp_Before} = $before;
${*$exp}{exp_Match} = $match;
${*$exp}{exp_After} = $after;
${*$exp}{exp_Match_Number} = $pattern->[0];
$exp_matched = $exp;
}
} elsif ( $pattern->[1] eq '-re' ) {
if ($Expect::Multiline_Matching) {
@matchlist =
( ${*$exp}{exp_Accum} =~ m/($pattern->[2])/m);
} else {
@matchlist =
( ${*$exp}{exp_Accum} =~ m/($pattern->[2])/);
}
if (@matchlist) {
# Matching regexp
$match = shift @matchlist;
my $start = index ${*$exp}{exp_Accum}, $match;
die 'The match could not be found' if $start == -1;
$before = substr ${*$exp}{exp_Accum}, 0, $start;
$after = substr ${*$exp}{exp_Accum}, $start + length($match);
${*$exp}{exp_Before} = $before;
${*$exp}{exp_Match} = $match;
${*$exp}{exp_After} = $after;
#pop @matchlist; # remove kludged empty bracket from end
@{ ${*$exp}{exp_Matchlist} } = @matchlist;
${*$exp}{exp_Match_Number} = $pattern->[0];
$exp_matched = $exp;
}
} else {
# 'timeout' or 'eof'
}
if ($exp_matched) {
${*$exp}{exp_Accum} = $after
unless ${*$exp}{exp_NoTransfer};
print STDERR "YES!!\r\n"
if ${*$exp}{exp_Exp_Internal};
print STDERR (
" Before match string: `",
$exp->_trim_length( _make_readable( ($before) ) ),
"'\r\n",
" Match string: `",
_make_readable($match),
"'\r\n",
" After match string: `",
$exp->_trim_length( _make_readable( ($after) ) ),
"'\r\n",
" Matchlist: (",
join(
", ",
map { "`" . $exp->_trim_length( _make_readable( ($_) ) ) . "'" } @matchlist,
),
")\r\n",
) if ( ${*$exp}{exp_Exp_Internal} );
# call hook function if defined
if ( $pattern->[3] ) {
print STDERR (
"Calling hook $pattern->[3]...\r\n",
)
if ( ${*$exp}{exp_Exp_Internal}
or $Expect::Debug );
if ( $#{$pattern} > 3 ) {
# call with parameters if given
$exp_cont = &{ $pattern->[3] }( $exp, @{$pattern}[ 4 .. $#{$pattern} ] );
} else {
$exp_cont = &{ $pattern->[3] }($exp);
}
}
if ( $exp_cont and $exp_cont eq exp_continue ) {
print STDERR ("Continuing expect, restarting timeout...\r\n")
if ( ${*$exp}{exp_Exp_Internal}
or $Expect::Debug );
$start_loop_time = time(); # restart timeout count
next READLOOP;
} elsif ( $exp_cont
and $exp_cont eq exp_continue_timeout )
{
print STDERR ("Continuing expect...\r\n")
if ( ${*$exp}{exp_Exp_Internal}
or $Expect::Debug );
next READLOOP;
}
last READLOOP;
}
print STDERR "No.\r\n" if ${*$exp}{exp_Exp_Internal};
}
print STDERR "\r\n" if ${*$exp}{exp_Exp_Internal};
# don't have to match again until we get new data
${*$exp}{exp_New_Data} = 0;
}
} # End of matching section
# No match, let's see what is pending on the filehandles...
print STDERR (
"Waiting for new data (",
defined($time_left) ? $time_left : 'unlimited',
" seconds)...\r\n",
) if ( $Expect::Exp_Internal or $Expect::Debug );
my $nfound;
SELECT: {
$nfound = select( $rmask, undef, undef, $time_left );
if ( $nfound < 0 ) {
if ( $!{EINTR} and $Expect::IgnoreEintr ) {
print STDERR ("ignoring EINTR, restarting select()...\r\n")
if ( $Expect::Exp_Internal or $Expect::Debug );
next SELECT;
}
print STDERR ("select() returned error code '$!'\r\n")
if ( $Expect::Exp_Internal or $Expect::Debug );
# returned error
$err = "4:$!";
last READLOOP;
}
}
# go until we don't find something (== timeout).
if ( $nfound == 0 ) {
# No pattern, no EOF. Did we time out?
$err = "1:TIMEOUT";
foreach my $pat (@params) {
foreach my $exp ( @{ $pat->[0] } ) {
$before = ${*$exp}{exp_Before} = ${*$exp}{exp_Accum};
next if not defined $exp->fileno(); # skip already closed
${*$exp}{exp_Error} = $err unless ${*$exp}{exp_Error};
}
}
print STDERR ("TIMEOUT\r\n")
if ( $Expect::Debug or $Expect::Exp_Internal );
if ($timeout_hook) {
my $ret;
print STDERR ("Calling timeout function $timeout_hook...\r\n")
if ( $Expect::Debug or $Expect::Exp_Internal );
if ( ref($timeout_hook) eq 'CODE' ) {
$ret = &{$timeout_hook}( $params[0]->[0] );
} else {
if ( $#{$timeout_hook} > 3 ) {
$ret = &{ $timeout_hook->[3] }(
$params[0]->[0],
@{$timeout_hook}[ 4 .. $#{$timeout_hook} ]
);
} else {
$ret = &{ $timeout_hook->[3] }( $params[0]->[0] );
}
}
if ( $ret and $ret eq exp_continue ) {
$start_loop_time = time(); # restart timeout count
next READLOOP;
}
}
last READLOOP;
}
my @bits = split( //, unpack( 'b*', $rmask ) );
foreach my $pat (@params) {
foreach my $exp ( @{ $pat->[0] } ) {
next if not defined $exp->fileno(); # skip already closed
if ( $bits[ $exp->fileno() ] ) {
print STDERR ("${*$exp}{exp_Pty_Handle}: new data.\r\n")
if $Expect::Debug;
# read in what we found.
my $buffer;
my $nread = sysread( $exp, $buffer, 2048 );
# Make errors (nread undef) show up as EOF.
$nread = 0 unless defined($nread);
if ( $nread == 0 ) {
print STDERR ("${*$exp}{exp_Pty_Handle}: EOF\r\n")
if ($Expect::Debug);
$before = ${*$exp}{exp_Before} = $exp->clear_accum();
$err = "2:EOF";
${*$exp}{exp_Error} = $err;
${*$exp}{exp_Has_EOF} = 1;
$exp_cont = undef;
foreach my $eof_pat ( grep { $_->[1] eq '-eof' } @{$pat}[ 1 .. $#{$pat} ] ) {
my $ret;
print STDERR ( "Calling EOF hook $eof_pat->[3]...\r\n", )
if ($Expect::Debug);
if ( $#{$eof_pat} > 3 ) {
# call with parameters if given
$ret = &{ $eof_pat->[3] }( $exp, @{$eof_pat}[ 4 .. $#{$eof_pat} ] );
} else {
$ret = &{ $eof_pat->[3] }($exp);
}
if ($ret
and ( $ret eq exp_continue
or $ret eq exp_continue_timeout )
)
{
$exp_cont = $ret;
}
}
# is it dead?
if ( defined( ${*$exp}{exp_Pid} ) ) {
my $ret =
waitpid( ${*$exp}{exp_Pid}, POSIX::WNOHANG );
if ( $ret == ${*$exp}{exp_Pid} ) {
printf STDERR (
"%s: exit(0x%02X)\r\n",
${*$exp}{exp_Pty_Handle}, $?
) if ($Expect::Debug);
$err = "3:Child PID ${*$exp}{exp_Pid} exited with status $?";
${*$exp}{exp_Error} = $err;
${*$exp}{exp_Exit} = $?;
delete $Expect::Spawned_PIDs{ ${*$exp}{exp_Pid} };
${*$exp}{exp_Pid} = undef;
}
}
print STDERR ("${*$exp}{exp_Pty_Handle}: closing...\r\n")
if ($Expect::Debug);
$exp->hard_close();
next;
}
print STDERR ("${*$exp}{exp_Pty_Handle}: read $nread byte(s).\r\n")
if ($Expect::Debug);
# ugly hack for broken solaris ttys that spew <blank><backspace>
# into our pretty output
$buffer =~ s/ \cH//g if not ${*$exp}{exp_Raw_Pty};
# Append it to the accumulator.
${*$exp}{exp_Accum} .= $buffer;
if ( exists ${*$exp}{exp_Max_Accum}
and ${*$exp}{exp_Max_Accum} )
{
${*$exp}{exp_Accum} = $exp->_trim_length(
${*$exp}{exp_Accum},
${*$exp}{exp_Max_Accum}
);
}
${*$exp}{exp_New_Data} = 1; # next round we try to match again
$exp_cont = exp_continue
if ( exists ${*$exp}{exp_Continue}
and ${*$exp}{exp_Continue} );
# Now propagate what we have read to other listeners...
$exp->_print_handles($buffer);
# End handle reading section.
}
}
} # end read loop
$start_loop_time = time() # restart timeout count
if ( $exp_cont and $exp_cont eq exp_continue );
}
# End READLOOP
# Post loop. Do we have anything?
# Tell us status
if ( $Expect::Debug or $Expect::Exp_Internal ) {
if ($exp_matched) {
print STDERR (
"Returning from expect ",
${*$exp_matched}{exp_Error} ? 'un' : '',
"successfully.",
${*$exp_matched}{exp_Error}
? "\r\n Error: ${*$exp_matched}{exp_Error}."
: '',
"\r\n"
);
} else {
print STDERR ("Returning from expect with TIMEOUT or EOF\r\n");
}
if ( $Expect::Debug and $exp_matched ) {
print STDERR " ${*$exp_matched}{exp_Pty_Handle}: accumulator: `";
if ( ${*$exp_matched}{exp_Error} ) {
print STDERR (
$exp_matched->_trim_length( _make_readable( ${*$exp_matched}{exp_Before} ) ),
"'\r\n"
);
} else {
print STDERR (
$exp_matched->_trim_length( _make_readable( ${*$exp_matched}{exp_Accum} ) ),
"'\r\n"
);
}
}
}
if ($exp_matched) {
return wantarray
? (
${*$exp_matched}{exp_Match_Number}, ${*$exp_matched}{exp_Error},
${*$exp_matched}{exp_Match}, ${*$exp_matched}{exp_Before},
${*$exp_matched}{exp_After}, $exp_matched,
)
: ${*$exp_matched}{exp_Match_Number};
}
return wantarray ? ( undef, $err, undef, $before, undef, undef ) : undef;
}
# Patterns are arrays that consist of
# [ $pattern_type, $pattern, $sub, @subparms ]
# optional $pattern_type is '-re' (RegExp, default) or '-ex' (exact);
# $sub is optional CODE ref, which is called as &{$sub}($exp, @subparms)
# if pattern matched;
# the $parm_nr gets unshifted onto the array for reporting purposes.
sub _add_patterns_to_list {
my ($listref, $timeoutlistref,$store_parm_nr, @params) = @_;
# $timeoutlistref gets timeout patterns
my $parm_nr = $store_parm_nr || 1;
foreach my $parm (@params) {
if ( not ref($parm) eq 'ARRAY' ) {
return "Parameter #$parm_nr is not an ARRAY ref.";
}
$parm = [@$parm]; # make copy
if ( $parm->[0] =~ m/\A-/ ) {
# it's an option
if ( $parm->[0] ne '-re'
and $parm->[0] ne '-ex' )
{
return "Unknown option $parm->[0] in pattern #$parm_nr";
}
} else {
if ( $parm->[0] eq 'timeout' ) {
if ( defined $timeoutlistref ) {
splice @$parm, 0, 1, ( "-$parm->[0]", undef );
unshift @$parm, $store_parm_nr ? $parm_nr : undef;
push @$timeoutlistref, $parm;
}
next;
} elsif ( $parm->[0] eq 'eof' ) {
splice @$parm, 0, 1, ( "-$parm->[0]", undef );
} else {
unshift @$parm, '-re'; # defaults to RegExp
}
}
if ( @$parm > 2 ) {
if ( ref( $parm->[2] ) ne 'CODE' ) {
croak(
"Pattern #$parm_nr doesn't have a CODE reference",
"after the pattern."
);
}
} else {
push @$parm, undef; # make sure we have three elements
}
unshift @$parm, $store_parm_nr ? $parm_nr : undef;
push @$listref, $parm;
$parm_nr++;
}
return;
}
######################################################################
# $process->interact([$in_handle],[$escape sequence])
# If you don't specify in_handle STDIN will be used.
sub interact {
my ($self, $infile, $escape_sequence) = @_;
my $outfile;
my @old_group = $self->set_group();
# If the handle is STDIN we'll
# $infile->fileno == 0 should be stdin.. follow stdin rules.
no strict 'subs'; # Allow bare word 'STDIN'
unless ( defined($infile) ) {
# We need a handle object Associated with STDIN.
$infile = IO::File->new;
$infile->IO::File::fdopen( STDIN, 'r' );
$outfile = IO::File->new;
$outfile->IO::File::fdopen( STDOUT, 'w' );
} elsif ( fileno($infile) == fileno(STDIN) ) {
# With STDIN we want output to go to stdout.
$outfile = IO::File->new;
$outfile->IO::File::fdopen( STDOUT, 'w' );
} else {
undef($outfile);
}
# Here we assure ourselves we have an Expect object.
my $in_object = Expect->exp_init($infile);
if ( defined($outfile) ) {
# as above.. we want output to go to stdout if we're given stdin.
my $out_object = Expect->exp_init($outfile);
$out_object->manual_stty(1);
$self->set_group($out_object);
} else {
$self->set_group($in_object);
}
$in_object->set_group($self);
$in_object->set_seq( $escape_sequence, undef ) if defined($escape_sequence);
# interconnect normally sets stty -echo raw. Interact really sort
# of implies we don't do that by default. If anyone wanted to they could
# set it before calling interact, of use interconnect directly.
my $old_manual_stty_val = $self->manual_stty();
$self->manual_stty(1);
# I think this is right. Don't send stuff from in_obj to stdout by default.
# in theory whatever 'self' is should echo what's going on.
my $old_log_stdout_val = $self->log_stdout();
$self->log_stdout(0);
$in_object->log_stdout(0);
# Allow for the setting of an optional EOF escape function.
# $in_object->set_seq('EOF',undef);
# $self->set_seq('EOF',undef);
Expect::interconnect( $self, $in_object );
$self->log_stdout($old_log_stdout_val);
$self->set_group(@old_group);
# If old_group was undef, make sure that occurs. This is a slight hack since
# it modifies the value directly.
# Normally an undef passed to set_group will return the current groups.
# It is possible that it may be of worth to make it possible to undef
# The current group without doing this.
unless (@old_group) {
@{ ${*$self}{exp_Listen_Group} } = ();
}
$self->manual_stty($old_manual_stty_val);
return;
}
sub interconnect {
my (@handles) = @_;
# my ($handle)=(shift); call as Expect::interconnect($spawn1,$spawn2,...)
my ( $nread );
my ( $rout, $emask, $eout );
my ( $escape_character_buffer );
my ( $read_mask, $temp_mask ) = ( '', '' );
# Get read/write handles
foreach my $handle (@handles) {
$temp_mask = '';
vec( $temp_mask, $handle->fileno(), 1 ) = 1;
# Under Linux w/ 5.001 the next line comes up w/ 'Uninit var.'.
# It appears to be impossible to make the warning go away.
# doing something like $temp_mask='' unless defined ($temp_mask)
# has no effect whatsoever. This may be a bug in 5.001.
$read_mask = $read_mask | $temp_mask;
}
if ($Expect::Debug) {
print STDERR "Read handles:\r\n";
foreach my $handle (@handles) {
print STDERR "\tRead handle: ";
print STDERR "'${*$handle}{exp_Pty_Handle}'\r\n";
print STDERR "\t\tListen Handles:";
foreach my $write_handle ( @{ ${*$handle}{exp_Listen_Group} } ) {
print STDERR " '${*$write_handle}{exp_Pty_Handle}'";
}
print STDERR ".\r\n";
}
}
# I think if we don't set raw/-echo here we may have trouble. We don't
# want a bunch of echoing crap making all the handles jabber at each other.
foreach my $handle (@handles) {
unless ( ${*$handle}{"exp_Manual_Stty"} ) {
# This is probably O/S specific.
${*$handle}{exp_Stored_Stty} = $handle->exp_stty('-g');
print STDERR "Setting tty for ${*$handle}{exp_Pty_Handle} to 'raw -echo'.\r\n"
if ${*$handle}{"exp_Debug"};
$handle->exp_stty("raw -echo");
}
foreach my $write_handle ( @{ ${*$handle}{exp_Listen_Group} } ) {
unless ( ${*$write_handle}{"exp_Manual_Stty"} ) {
${*$write_handle}{exp_Stored_Stty} =
$write_handle->exp_stty('-g');
print STDERR "Setting ${*$write_handle}{exp_Pty_Handle} to 'raw -echo'.\r\n"
if ${*$handle}{"exp_Debug"};
$write_handle->exp_stty("raw -echo");
}
}
}
print STDERR "Attempting interconnection\r\n" if $Expect::Debug;
# Wait until the process dies or we get EOF
# In the case of !${*$handle}{exp_Pid} it means
# the handle was exp_inited instead of spawned.
CONNECT_LOOP:
# Go until we have a reason to stop
while (1) {
# test each handle to see if it's still alive.
foreach my $read_handle (@handles) {
waitpid( ${*$read_handle}{exp_Pid}, WNOHANG )
if ( exists( ${*$read_handle}{exp_Pid} )
and ${*$read_handle}{exp_Pid} );
if ( exists( ${*$read_handle}{exp_Pid} )
and ( ${*$read_handle}{exp_Pid} )
and ( !kill( 0, ${*$read_handle}{exp_Pid} ) ) )
{
print STDERR
"Got EOF (${*$read_handle}{exp_Pty_Handle} died) reading ${*$read_handle}{exp_Pty_Handle}\r\n"
if ${*$read_handle}{"exp_Debug"};
last CONNECT_LOOP
unless defined( ${ ${*$read_handle}{exp_Function} }{"EOF"} );
last CONNECT_LOOP
unless &{ ${ ${*$read_handle}{exp_Function} }{"EOF"} }
( @{ ${ ${*$read_handle}{exp_Parameters} }{"EOF"} } );
}
}
# Every second? No, go until we get something from someone.
my $nfound = select( $rout = $read_mask, undef, $eout = $emask, undef );
# Is there anything to share? May be -1 if interrupted by a signal...
next CONNECT_LOOP if not defined $nfound or $nfound < 1;
# Which handles have stuff?
my @bits = split( //, unpack( 'b*', $rout ) );
$eout = 0 unless defined($eout);
my @ebits = split( //, unpack( 'b*', $eout ) );
# print "Ebits: $eout\r\n";
foreach my $read_handle (@handles) {
if ( $bits[ $read_handle->fileno() ] ) {
$nread = sysread(
$read_handle, ${*$read_handle}{exp_Pty_Buffer},
1024
);
# Appease perl -w
$nread = 0 unless defined($nread);
print STDERR "interconnect: read $nread byte(s) from ${*$read_handle}{exp_Pty_Handle}.\r\n"
if ${*$read_handle}{"exp_Debug"} > 1;
# Test for escape seq. before printing.
# Appease perl -w
$escape_character_buffer = ''
unless defined($escape_character_buffer);
$escape_character_buffer .= ${*$read_handle}{exp_Pty_Buffer};
foreach my $escape_sequence ( keys( %{ ${*$read_handle}{exp_Function} } ) ) {
print STDERR "Tested escape sequence $escape_sequence from ${*$read_handle}{exp_Pty_Handle}"
if ${*$read_handle}{"exp_Debug"} > 1;
# Make sure it doesn't grow out of bounds.
$escape_character_buffer = $read_handle->_trim_length(
$escape_character_buffer,
${*$read_handle}{"exp_Max_Accum"}
) if ( ${*$read_handle}{"exp_Max_Accum"} );
if ( $escape_character_buffer =~ /($escape_sequence)/ ) {
my $match = $1;
if ( ${*$read_handle}{"exp_Debug"} ) {
print STDERR
"\r\ninterconnect got escape sequence from ${*$read_handle}{exp_Pty_Handle}.\r\n";
# I'm going to make the esc. seq. pretty because it will
# probably contain unprintable characters.
print STDERR "\tEscape Sequence: '"
. _trim_length(
undef,
_make_readable($escape_sequence)
) . "'\r\n";
print STDERR "\tMatched by string: '" . _trim_length( undef, _make_readable($match) ) . "'\r\n";
}
# Print out stuff before the escape.
# Keep in mind that the sequence may have been split up
# over several reads.
# Let's get rid of it from this read. If part of it was
# in the last read there's not a lot we can do about it now.
if ( ${*$read_handle}{exp_Pty_Buffer} =~ /([\w\W]*)($escape_sequence)/ ) {
$read_handle->_print_handles($1);
} else {
$read_handle->_print_handles( ${*$read_handle}{exp_Pty_Buffer} );
}
# Clear the buffer so no more matches can be made and it will
# only be printed one time.
${*$read_handle}{exp_Pty_Buffer} = '';
$escape_character_buffer = '';
# Do the function here. Must return non-zero to continue.
# More cool syntax. Maybe I should turn these in to objects.
last CONNECT_LOOP
unless &{ ${ ${*$read_handle}{exp_Function} }{$escape_sequence} }
( @{ ${ ${*$read_handle}{exp_Parameters} }{$escape_sequence} } );
}
}
$nread = 0 unless defined($nread); # Appease perl -w?
waitpid( ${*$read_handle}{exp_Pid}, WNOHANG )
if ( defined( ${*$read_handle}{exp_Pid} )
&& ${*$read_handle}{exp_Pid} );
if ( $nread == 0 ) {
print STDERR "Got EOF reading ${*$read_handle}{exp_Pty_Handle}\r\n"
if ${*$read_handle}{"exp_Debug"};
last CONNECT_LOOP
unless defined( ${ ${*$read_handle}{exp_Function} }{"EOF"} );
last CONNECT_LOOP
unless &{ ${ ${*$read_handle}{exp_Function} }{"EOF"} }
( @{ ${ ${*$read_handle}{exp_Parameters} }{"EOF"} } );
}
last CONNECT_LOOP if ( $nread < 0 ); # This would be an error
$read_handle->_print_handles( ${*$read_handle}{exp_Pty_Buffer} );
}
# I'm removing this because I haven't determined what causes exceptions
# consistently.
if (0) #$ebits[$read_handle->fileno()])
{
print STDERR "Got Exception reading ${*$read_handle}{exp_Pty_Handle}\r\n"
if ${*$read_handle}{"exp_Debug"};
last CONNECT_LOOP
unless defined( ${ ${*$read_handle}{exp_Function} }{"EOF"} );
last CONNECT_LOOP
unless &{ ${ ${*$read_handle}{exp_Function} }{"EOF"} }
( @{ ${ ${*$read_handle}{exp_Parameters} }{"EOF"} } );
}
}
}
foreach my $handle (@handles) {
unless ( ${*$handle}{"exp_Manual_Stty"} ) {
$handle->exp_stty( ${*$handle}{exp_Stored_Stty} );
}
foreach my $write_handle ( @{ ${*$handle}{exp_Listen_Group} } ) {
unless ( ${*$write_handle}{"exp_Manual_Stty"} ) {
$write_handle->exp_stty( ${*$write_handle}{exp_Stored_Stty} );
}
}
}
return;
}
# user can decide if log output gets also sent to logfile
sub print_log_file {
my ($self, @params) = @_;
if ( ${*$self}{exp_Log_File} ) {
if ( ref( ${*$self}{exp_Log_File} ) eq 'CODE' ) {
${*$self}{exp_Log_File}->(@params);
} else {
${*$self}{exp_Log_File}->print(@params);
}
}
return;
}
# we provide our own print so we can debug what gets sent to the
# processes...
sub print {
my ( $self, @args ) = @_;
return if not defined $self->fileno(); # skip if closed
if ( ${*$self}{exp_Exp_Internal} ) {
my $args = _make_readable( join( '', @args ) );
cluck "Sending '$args' to ${*$self}{exp_Pty_Handle}\r\n";
}
foreach my $arg (@args) {
while ( length($arg) > 80 ) {
$self->SUPER::print( substr( $arg, 0, 80 ) );
$arg = substr( $arg, 80 );
}
$self->SUPER::print($arg);
}
return;
}
# make an alias for Tcl/Expect users for a DWIM experience...
*send = \&print;
# This is an Expect standard. It's nice for talking to modems and the like
# where from time to time they get unhappy if you send items too quickly.
sub send_slow {
my ($self, $sleep_time, @chunks) = @_;
return if not defined $self->fileno(); # skip if closed
# Flushing makes it so each character can be seen separately.
my $chunk;
while ( $chunk = shift @chunks ) {
my @linechars = split( '', $chunk );
foreach my $char (@linechars) {
# How slow?
select( undef, undef, undef, $sleep_time );
print $self $char;
print STDERR "Printed character \'" . _make_readable($char) . "\' to ${*$self}{exp_Pty_Handle}.\r\n"
if ${*$self}{"exp_Debug"} > 1;
# I think I can get away with this if I save it in accum
if ( ${*$self}{"exp_Log_Stdout"} || ${*$self}{exp_Log_Group} ) {
my $rmask = "";
vec( $rmask, $self->fileno(), 1 ) = 1;
# .01 sec granularity should work. If we miss something it will
# probably get flushed later, maybe in an expect call.
while ( select( $rmask, undef, undef, .01 ) ) {
my $ret = sysread( $self, ${*$self}{exp_Pty_Buffer}, 1024 );
last if not defined $ret or $ret == 0;
# Is this necessary to keep? Probably.. #
# if you need to expect it later.
${*$self}{exp_Accum} .= ${*$self}{exp_Pty_Buffer};
${*$self}{exp_Accum} = $self->_trim_length(
${*$self}{exp_Accum},
${*$self}{"exp_Max_Accum"}
) if ( ${*$self}{"exp_Max_Accum"} );
$self->_print_handles( ${*$self}{exp_Pty_Buffer} );
print STDERR "Received \'"
. $self->_trim_length( _make_readable($char) )
. "\' from ${*$self}{exp_Pty_Handle}\r\n"
if ${*$self}{"exp_Debug"} > 1;
}
}
}
}
return;
}
sub test_handles {
my ($timeout, @handle_list) = @_;
# This should be called by Expect::test_handles($timeout,@objects);
my ( $allmask, $rout );
foreach my $handle (@handle_list) {
my $rmask = '';
vec( $rmask, $handle->fileno(), 1 ) = 1;
$allmask = '' unless defined($allmask);
$allmask = $allmask | $rmask;
}
my $nfound = select( $rout = $allmask, undef, undef, $timeout );
return () unless $nfound;
# Which handles have stuff?
my @bits = split( //, unpack( 'b*', $rout ) );
my $handle_num = 0;
my @return_list = ();
foreach my $handle (@handle_list) {
# I go to great lengths to get perl -w to shut the hell up.
if ( defined( $bits[ $handle->fileno() ] )
and ( $bits[ $handle->fileno() ] ) )
{
push( @return_list, $handle_num );
}
} continue {
$handle_num++;
}
return @return_list;
}
# Be nice close. This should emulate what an interactive shell does after a
# command finishes... sort of. We're not as patient as a shell.
sub soft_close {
my ($self) = @_;
my ( $nfound, $nread, $rmask, $end_time, $temp_buffer );
# Give it 15 seconds to cough up an eof.
cluck "Closing ${*$self}{exp_Pty_Handle}.\r\n" if ${*$self}{exp_Debug};
return -1 if not defined $self->fileno(); # skip if handle already closed
unless ( exists ${*$self}{exp_Has_EOF} and ${*$self}{exp_Has_EOF} ) {
$end_time = time() + 15;
while ( $end_time > time() ) {
my $select_time = $end_time - time();
# Sanity check.
$select_time = 0 if $select_time < 0;
$rmask = '';
vec( $rmask, $self->fileno(), 1 ) = 1;
($nfound) = select( $rmask, undef, undef, $select_time );
last unless ( defined($nfound) && $nfound );
$nread = sysread( $self, $temp_buffer, 8096 );
# 0 = EOF.
unless ( defined($nread) && $nread ) {
print STDERR "Got EOF from ${*$self}{exp_Pty_Handle}.\r\n"
if ${*$self}{exp_Debug};
last;
}
$self->_print_handles($temp_buffer);
}
if ( ( $end_time <= time() ) && ${*$self}{exp_Debug} ) {
print STDERR "Timed out waiting for an EOF from ${*$self}{exp_Pty_Handle}.\r\n";
}
}
my $close_status = $self->close();
if ( $close_status && ${*$self}{exp_Debug} ) {
print STDERR "${*$self}{exp_Pty_Handle} closed.\r\n";
}
# quit now if it isn't a process.
return $close_status unless defined( ${*$self}{exp_Pid} );
# Now give it 15 seconds to die.
$end_time = time() + 15;
while ( $end_time > time() ) {
my $returned_pid = waitpid( ${*$self}{exp_Pid}, &WNOHANG );
# Stop here if the process dies.
if ( defined($returned_pid) && $returned_pid ) {
delete $Expect::Spawned_PIDs{$returned_pid};
if ( ${*$self}{exp_Debug} ) {
printf STDERR (
"Pid %d of %s exited, Status: 0x%02X\r\n",
${*$self}{exp_Pid},
${*$self}{exp_Pty_Handle}, $?
);
}
${*$self}{exp_Pid} = undef;
${*$self}{exp_Exit} = $?;
return ${*$self}{exp_Exit};
}
sleep 1; # Keep loop nice.
}
# Send it a term if it isn't dead.
if ( ${*$self}{exp_Debug} ) {
print STDERR "${*$self}{exp_Pty_Handle} not exiting, sending TERM.\r\n";
}
kill TERM => ${*$self}{exp_Pid};
# Now to be anal retentive.. wait 15 more seconds for it to die.
$end_time = time() + 15;
while ( $end_time > time() ) {
my $returned_pid = waitpid( ${*$self}{exp_Pid}, &WNOHANG );
if ( defined($returned_pid) && $returned_pid ) {
delete $Expect::Spawned_PIDs{$returned_pid};
if ( ${*$self}{exp_Debug} ) {
printf STDERR (
"Pid %d of %s terminated, Status: 0x%02X\r\n",
${*$self}{exp_Pid},
${*$self}{exp_Pty_Handle}, $?
);
}
${*$self}{exp_Pid} = undef;
${*$self}{exp_Exit} = $?;
return $?;
}
sleep 1;
}
# Since this is a 'soft' close, sending it a -9 would be inappropriate.
return;
}
# 'Make it go away' close.
sub hard_close {
my ($self) = @_;
cluck "Closing ${*$self}{exp_Pty_Handle}.\r\n" if ${*$self}{exp_Debug};
# Don't wait for an EOF.
my $close_status = $self->close();
if ( $close_status && ${*$self}{exp_Debug} ) {
print STDERR "${*$self}{exp_Pty_Handle} closed.\r\n";
}
# Return now if handle.
return $close_status unless defined( ${*$self}{exp_Pid} );
# Now give it 5 seconds to die. Less patience here if it won't die.
my $end_time = time() + 5;
while ( $end_time > time() ) {
my $returned_pid = waitpid( ${*$self}{exp_Pid}, &WNOHANG );
# Stop here if the process dies.
if ( defined($returned_pid) && $returned_pid ) {
delete $Expect::Spawned_PIDs{$returned_pid};
if ( ${*$self}{exp_Debug} ) {
printf STDERR (
"Pid %d of %s terminated, Status: 0x%02X\r\n",
${*$self}{exp_Pid},
${*$self}{exp_Pty_Handle}, $?
);
}
${*$self}{exp_Pid} = undef;
${*$self}{exp_Exit} = $?;
return ${*$self}{exp_Exit};
}
sleep 1; # Keep loop nice.
}
# Send it a term if it isn't dead.
if ( ${*$self}{exp_Debug} ) {
print STDERR "${*$self}{exp_Pty_Handle} not exiting, sending TERM.\r\n";
}
kill TERM => ${*$self}{exp_Pid};
# wait 15 more seconds for it to die.
$end_time = time() + 15;
while ( $end_time > time() ) {
my $returned_pid = waitpid( ${*$self}{exp_Pid}, &WNOHANG );
if ( defined($returned_pid) && $returned_pid ) {
delete $Expect::Spawned_PIDs{$returned_pid};
if ( ${*$self}{exp_Debug} ) {
printf STDERR (
"Pid %d of %s terminated, Status: 0x%02X\r\n",
${*$self}{exp_Pid},
${*$self}{exp_Pty_Handle}, $?
);
}
${*$self}{exp_Pid} = undef;
${*$self}{exp_Exit} = $?;
return ${*$self}{exp_Exit};
}
sleep 1;
}
kill KILL => ${*$self}{exp_Pid};
# wait 5 more seconds for it to die.
$end_time = time() + 5;
while ( $end_time > time() ) {
my $returned_pid = waitpid( ${*$self}{exp_Pid}, &WNOHANG );
if ( defined($returned_pid) && $returned_pid ) {
delete $Expect::Spawned_PIDs{$returned_pid};
if ( ${*$self}{exp_Debug} ) {
printf STDERR (
"Pid %d of %s killed, Status: 0x%02X\r\n",
${*$self}{exp_Pid},
${*$self}{exp_Pty_Handle}, $?
);
}
${*$self}{exp_Pid} = undef;
${*$self}{exp_Exit} = $?;
return ${*$self}{exp_Exit};
}
sleep 1;
}
warn "Pid ${*$self}{exp_Pid} of ${*$self}{exp_Pty_Handle} is HUNG.\r\n";
${*$self}{exp_Pid} = undef;
return;
}
# These should not be called externally.
sub _init_vars {
my ($self) = @_;
# for every spawned process or filehandle.
${*$self}{exp_Log_Stdout} = $Expect::Log_Stdout
if defined($Expect::Log_Stdout);
${*$self}{exp_Log_Group} = $Expect::Log_Group;
${*$self}{exp_Debug} = $Expect::Debug;
${*$self}{exp_Exp_Internal} = $Expect::Exp_Internal;
${*$self}{exp_Manual_Stty} = $Expect::Manual_Stty;
${*$self}{exp_Stored_Stty} = 'sane';
${*$self}{exp_Do_Soft_Close} = $Expect::Do_Soft_Close;
# sysread doesn't like my or local vars.
${*$self}{exp_Pty_Buffer} = '';
# Initialize accumulator.
${*$self}{exp_Max_Accum} = $Expect::Exp_Max_Accum;
${*$self}{exp_Accum} = '';
${*$self}{exp_NoTransfer} = 0;
# create empty expect_before & after lists
${*$self}{exp_expect_before_list} = [];
${*$self}{exp_expect_after_list} = [];
return;
}
sub _make_readable {
my ($s) = @_;
$s = '' if not defined($s);
study $s; # Speed things up?
$s =~ s/\\/\\\\/g; # So we can tell easily(?) what is a backslash
$s =~ s/\n/\\n/g;
$s =~ s/\r/\\r/g;
$s =~ s/\t/\\t/g;
$s =~ s/\'/\\\'/g; # So we can tell whassa quote and whassa notta quote.
$s =~ s/\"/\\\"/g;
# Formfeed (does anyone use formfeed?)
$s =~ s/\f/\\f/g;
$s =~ s/\010/\\b/g;
# escape control chars high/low, but allow ISO 8859-1 chars
$s =~ s/([\000-\037\177-\237\377])/sprintf("\\%03lo",ord($1))/ge;
return $s;
}
sub _trim_length {
my ($self, $string, $length) = @_;
# This is sort of a reverse truncation function
# Mostly so we don't have to see the full output when we're using
# Also used if Max_Accum gets set to limit the size of the accumulator
# for matching functions.
# exp_internal
croak('No string passed') if not defined $string;
# If we're not passed a length (_trim_length is being used for debugging
# purposes) AND debug >= 3, don't trim.
return ($string)
if (defined($self)
and ${*$self}{"exp_Debug"} >= 3
and ( !( defined($length) ) ) );
my $indicate_truncation = ($length ? '' : '...');
$length ||= 1021;
return $string if $length >= length $string;
# We wouldn't want the accumulator to begin with '...' if max_accum is passed
# This is because this funct. gets called internally w/ max_accum
# and is also used to print information back to the user.
return $indicate_truncation . substr( $string, ( length($string) - $length ), $length );
}
sub _print_handles {
my ($self, $print_this) = @_;
# Given crap from 'self' and the handles self wants to print to, print to
# them. these are indicated by the handle's 'group'
if ( ${*$self}{exp_Log_Group} ) {
foreach my $handle ( @{ ${*$self}{exp_Listen_Group} } ) {
$print_this = '' unless defined($print_this);
# Appease perl -w
print STDERR "Printed '"
. $self->_trim_length( _make_readable($print_this) )
. "' to ${*$handle}{exp_Pty_Handle} from ${*$self}{exp_Pty_Handle}.\r\n"
if ( ${*$handle}{"exp_Debug"} > 1 );
print $handle $print_this;
}
}
# If ${*$self}{exp_Pty_Handle} is STDIN this would make it echo.
print STDOUT $print_this
if ${*$self}{"exp_Log_Stdout"};
$self->print_log_file($print_this);
$| = 1; # This should not be necessary but autoflush() doesn't always work.
return;
}
sub _get_mode {
my ($handle) = @_;
my ($fcntl_flags) = '';
# What mode are we opening with? use fcntl to find out.
$fcntl_flags = fcntl( \*{$handle}, Fcntl::F_GETFL, $fcntl_flags );
die "fcntl returned undef during exp_init of $handle, $!\r\n"
unless defined($fcntl_flags);
if ( $fcntl_flags | (Fcntl::O_RDWR) ) {
return 'rw';
} elsif ( $fcntl_flags | (Fcntl::O_WRONLY) ) {
return 'w';
} else {
# Under Solaris (among others?) O_RDONLY is implemented as 0. so |O_RDONLY would fail.
return 'r';
}
}
sub _undef {
return undef;
# Seems a little retarded but &CORE::undef fails in interconnect.
# This is used for the default escape sequence function.
# w/out the leading & it won't compile.
}
# clean up child processes
sub DESTROY {
my ($self) = @_;
my $status = $?; # save this as it gets mangled by the terminating spawned children
if ( ${*$self}{exp_Do_Soft_Close} ) {
$self->soft_close();
}
$self->hard_close();
$? = $status; # restore it. otherwise deleting an Expect object may mangle $?, which is unintuitive
return;
}
1;
__END__
=head1 NAME
Expect - automate interactions with command line programs that expose a text terminal interface.
=head1 SYNOPSIS
use Expect;
# create an Expect object by spawning another process
my $exp = Expect->spawn($command, @params)
or die "Cannot spawn $command: $!\n";
# or by using an already opened filehandle (e.g. from Net::Telnet)
my $exp = Expect->exp_init(\*FILEHANDLE);
# if you prefer the OO mindset:
my $exp = Expect->new;
$exp->raw_pty(1);
$exp->spawn($command, @parameters)
or die "Cannot spawn $command: $!\n";
# send some string there:
$exp->send("string\n");
# or, for the filehandle mindset:
print $exp "string\n";
# then do some pattern matching with either the simple interface
$patidx = $exp->expect($timeout, @match_patterns);
# or multi-match on several spawned commands with callbacks,
# just like the Tcl version
$exp->expect($timeout,
[ qr/regex1/ => sub { my $exp = shift;
$exp->send("response\n");
exp_continue; } ],
[ "regexp2" , \&callback, @cbparms ],
);
# if no longer needed, do a soft_close to nicely shut down the command
$exp->soft_close();
# or be less patient with
$exp->hard_close();
Expect.pm is built to either spawn a process or take an existing filehandle
and interact with it such that normally interactive tasks can be done
without operator assistance. This concept makes more sense if you are
already familiar with the versatile Tcl version of Expect.
The public functions that make up Expect.pm are:
Expect->new()
Expect::interconnect(@objects_to_be_read_from)
Expect::test_handles($timeout, @objects_to_test)
Expect::version($version_requested | undef);
$object->spawn(@command)
$object->clear_accum()
$object->set_accum($value)
$object->debug($debug_level)
$object->exp_internal(0 | 1)
$object->notransfer(0 | 1)
$object->raw_pty(0 | 1)
$object->stty(@stty_modes) # See the IO::Stty docs
$object->slave()
$object->before();
$object->match();
$object->after();
$object->matchlist();
$object->match_number();
$object->error();
$object->command();
$object->exitstatus();
$object->pty_handle();
$object->do_soft_close();
$object->restart_timeout_upon_receive(0 | 1);
$object->interact($other_object, $escape_sequence)
$object->log_group(0 | 1 | undef)
$object->log_user(0 | 1 | undef)
$object->log_file("filename" | $filehandle | \&coderef | undef)
$object->manual_stty(0 | 1 | undef)
$object->match_max($max_buffersize or undef)
$object->pid();
$object->send_slow($delay, @strings_to_send)
$object->set_group(@listen_group_objects | undef)
$object->set_seq($sequence,\&function,\@parameters);
There are several configurable package variables that affect the behavior of Expect. They are:
$Expect::Debug;
$Expect::Exp_Internal;
$Expect::IgnoreEintr;
$Expect::Log_Group;
$Expect::Log_Stdout;
$Expect::Manual_Stty;
$Expect::Multiline_Matching;
$Expect::Do_Soft_Close;
=head1 DESCRIPTION
See an explanation of L<What is Expect|http://code-maven.com/expect>
The Expect module is a successor of Comm.pl and a descendent of Chat.pl. It
more closely resembles the Tcl Expect language than its predecessors. It
does not contain any of the networking code found in Comm.pl. I suspect this
would be obsolete anyway given the advent of IO::Socket and external tools
such as netcat.
Expect.pm is an attempt to have more of a switch() & case feeling to make
decision processing more fluid. Three separate types of debugging have
been implemented to make code production easier.
It is possible to interconnect multiple file handles (and processes) much
like Tcl's Expect. An attempt was made to enable all the features of Tcl's
Expect without forcing Tcl on the victim programmer :-) .
Please, before you consider using Expect, read the FAQs about
L</"I want to automate password entry for su/ssh/scp/rsh/..."> and
L</"I want to use Expect to automate [anything with a buzzword]...">
=head1 USAGE
=over 4
=item new
Creates a new Expect object, i.e. a pty. You can change parameters on
it before actually spawning a command. This is important if you want
to modify the terminal settings for the slave. See slave() below.
The object returned is actually a reblessed IO::Pty filehandle, so see
there for additional methods.
=item Expect->exp_init(\*FILEHANDLE) I<or>
=item Expect->init(\*FILEHANDLE)
Initializes $new_handle_object for use with other Expect functions. It must
be passed a B<_reference_> to FILEHANDLE if you want it to work properly.
IO::File objects are preferable. Returns a reference to the newly created
object.
You can use only real filehandles, certain tied filehandles
(e.g. Net::SSH2) that lack a fileno() will not work. Net::Telnet
objects can be used but have been reported to work only for certain
hosts. YMMV.
=item Expect->spawn($command, @parameters) I<or>
=item $object->spawn($command, @parameters) I<or>
=item Expect->new($command, @parameters)
Forks and execs $command. Returns an Expect object upon success or
C<undef> if the fork was unsuccessful or the command could not be
found. spawn() passes its parameters unchanged to Perls exec(), so
look there for detailed semantics.
Note that if spawn cannot exec() the given command, the Expect object
is still valid and the next expect() will see "Cannot exec", so you
can use that for error handling.
Also note that you cannot reuse an object with an already spawned
command, even if that command has exited. Sorry, but you have to
allocate a new object...
=item $object->debug(0 | 1 | 2 | 3 | undef)
Sets debug level for $object. 1 refers to general debugging
information, 2 refers to verbose debugging and 0 refers to no
debugging. If you call debug() with no parameters it will return the
current debugging level. When the object is created the debugging
level will match that $Expect::Debug, normally 0.
The '3' setting is new with 1.05, and adds the additional
functionality of having the _full_ accumulated buffer printed every
time data is read from an Expect object. This was implemented by
request. I recommend against using this unless you think you need it
as it can create quite a quantity of output under some circumstances..
=item $object->exp_internal(1 | 0)
Sets/unsets 'exp_internal' debugging. This is similar in nature to its Tcl
counterpart. It is extremely valuable when debugging expect() sequences.
When the object is created the exp_internal setting will match the value of
$Expect::Exp_Internal, normally 0. Returns the current setting if called
without parameters. It is highly recommended that you make use of the
debugging features lest you have angry code.
=item $object->raw_pty(1 | 0)
Set pty to raw mode before spawning. This disables echoing, CR->LF
translation and an ugly hack for broken Solaris TTYs (which send
<space><backspace> to slow things down) and thus gives a more
pipe-like behaviour (which is important if you want to transfer binary
content). Note that this must be set I<before> spawning the program.
=item $object->stty(qw(mode1 mode2...))
Sets the tty mode for $object's associated terminal to the given
modes. Note that on many systems the master side of the pty is not a
tty, so you have to modify the slave pty instead, see next item. This
needs IO::Stty installed, which is no longer required.
=item $object->slave()
Returns a filehandle to the slave part of the pty. Very useful in modifying
the terminal settings:
$object->slave->stty(qw(raw -echo));
Typical values are 'sane', 'raw', and 'raw -echo'. Note that I
recommend setting the terminal to 'raw' or 'raw -echo', as this avoids
a lot of hassle and gives pipe-like (i.e. transparent) behaviour
(without the buffering issue).
=item $object->print(@strings) I<or>
=item $object->send(@strings)
Sends the given strings to the spawned command. Note that the strings
are not logged in the logfile (see print_log_file) but will probably
be echoed back by the pty, depending on pty settings (default is echo)
and thus end up there anyway. This must also be taken into account
when expect()ing for an answer: the next string will be the command
just sent. I suggest setting the pty to raw, which disables echo and
makes the pty transparently act like a bidirectional pipe.
=item $object->expect($timeout, @match_patterns)
=over 4
=item Simple interface
Given $timeout in seconds Expect will wait for $object's handle to produce
one of the match_patterns, which are matched exactly by default. If you
want a regexp match, use a regexp object (C<qr//>) or prefix the pattern with '-re'.
$object->expect(15, 'match me exactly', qr/match\s+me\s+exactly/);
$object->expect(15, 'match me exactly','-re','match\s+me\s+exactly');
Due to o/s limitations $timeout should be a round number. If $timeout
is 0 Expect will check one time to see if $object's handle contains
any of the match_patterns. If $timeout is undef Expect
will wait forever for a pattern to match. If you don't want to
explicitly put the timeout on all calls to C<expect>, you can set
it via the C<timeout> method . If the first argument of C<expect>
doesn't look like a number, that value will be used.
$object->timeout(15);
$object->expect('match me exactly','-re','match\s+me\s+exactly');
If called in a scalar context, expect() will return the position of
the matched pattern within @matched_patterns, or undef if no pattern was
matched. This is a position starting from 1, so if you want to know
which of an array of @matched_patterns matched you should subtract one
from the return value.
If called in an array context expect() will return
($matched_pattern_position, $error, $successfully_matching_string,
$before_match, and $after_match).
C<$matched_pattern_position> will contain the value that would have been
returned if expect() had been called in a scalar context.
C<$error> is
the error that occurred that caused expect() to return. $error will
contain a number followed by a string equivalent expressing the nature
of the error. Possible values are undef, indicating no error,
'1:TIMEOUT' indicating that $timeout seconds had elapsed without a
match, '2:EOF' indicating an eof was read from $object, '3: spawn
id($fileno) died' indicating that the process exited before matching
and '4:$!' indicating whatever error was set in $ERRNO during the last
read on $object's handle or during select(). All handles indicated by
set_group plus STDOUT will have all data to come out of $object
printed to them during expect() if log_group and log_stdout are set.
C<$successfully_matching_string>
C<$before_match>
C<$after_match>
Changed from older versions is the regular expression handling. By
default now all strings passed to expect() are treated as literals. To
match a regular expression pass '-re' as a parameter in front of the
pattern you want to match as a regexp.
This change makes it possible to match literals and regular expressions
in the same expect() call.
Also new is multiline matching. ^ will now match the beginning of
lines. Unfortunately, because perl doesn't use $/ in determining where
lines break using $ to find the end of a line frequently doesn't work. This
is because your terminal is returning "\r\n" at the end of every line. One
way to check for a pattern at the end of a line would be to use \r?$ instead
of $.
Example: Spawning telnet to a host, you might look for the escape
character. telnet would return to you "\r\nEscape character is
'^]'.\r\n". To find this you might use $match='^Escape char.*\.\r?$';
$telnet->expect(10,'-re',$match);
=item New more Tcl/Expect-like interface
expect($timeout,
'-i', [ $obj1, $obj2, ... ],
[ $re_pattern, sub { ...; exp_continue; }, @subparms, ],
[ 'eof', sub { ... } ],
[ 'timeout', sub { ... }, \$subparm1 ],
'-i', [ $objn, ...],
'-ex', $exact_pattern, sub { ... },
$exact_pattern, sub { ...; exp_continue_timeout; },
'-re', $re_pattern, sub { ... },
'-i', \@object_list, @pattern_list,
...);
It's now possible to expect on more than one connection at a time by
specifying 'C<-i>' and a single Expect object or a ref to an array
containing Expect objects, e.g.
expect($timeout,
'-i', $exp1, @patterns_1,
'-i', [ $exp2, $exp3 ], @patterns_2_3,
)
Furthermore, patterns can now be specified as array refs containing
[$regexp, sub { ...}, @optional_subprams] . When the pattern matches,
the subroutine is called with parameters ($matched_expect_obj,
@optional_subparms). The subroutine can return the symbol
`exp_continue' to continue the expect matching with timeout starting
anew or return the symbol `exp_continue_timeout' for continuing expect
without resetting the timeout count.
$exp->expect($timeout,
[ qr/username: /i, sub { my $self = shift;
$self->send("$username\n");
exp_continue; }],
[ qr/password: /i, sub { my $self = shift;
$self->send("$password\n");
exp_continue; }],
$shell_prompt);
`expect' is now exported by default.
=back
=item $object->exp_before() I<or>
=item $object->before()
before() returns the 'before' part of the last expect() call. If the last
expect() call didn't match anything, exp_before() will return the entire
output of the object accumulated before the expect() call finished.
Note that this is something different than Tcl Expects before()!!
=item $object->exp_after() I<or>
=item $object->after()
returns the 'after' part of the last expect() call. If the last
expect() call didn't match anything, exp_after() will return undef().
=item $object->exp_match() I<or>
=item $object->match()
returns the string matched by the last expect() call, undef if
no string was matched.
=item $object->exp_match_number() I<or>
=item $object->match_number()
exp_match_number() returns the number of the pattern matched by the last
expect() call. Keep in mind that the first pattern in a list of patterns is 1,
not 0. Returns undef if no pattern was matched.
=item $object->exp_matchlist() I<or>
=item $object->matchlist()
exp_matchlist() returns a list of matched substrings from the brackets
() inside the regexp that last matched. ($object->matchlist)[0]
thus corresponds to $1, ($object->matchlist)[1] to $2, etc.
=item $object->exp_error() I<or>
=item $object->error()
exp_error() returns the error generated by the last expect() call if
no pattern was matched. It is typically useful to examine the value returned by
before() to find out what the output of the object was in determining
why it didn't match any of the patterns.
=item $object->clear_accum()
Clear the contents of the accumulator for $object. This gets rid of
any residual contents of a handle after expect() or send_slow() such
that the next expect() call will only see new data from $object. The
contents of the accumulator are returned.
=item $object->set_accum($value)
Sets the content of the accumulator for $object to $value. The
previous content of the accumulator is returned.
=item $object->exp_command() I<or>
=item $object->command()
exp_command() returns the string that was used to spawn the command. Helpful
for debugging and for reused patternmatch subroutines.
=item $object->exp_exitstatus() I<or>
=item $object->exitstatus()
Returns the exit status of $object (if it already exited).
=item $object->exp_pty_handle() I<or>
=item $object->pty_handle()
Returns a string representation of the attached pty, for example:
`spawn id(5)' (pty has fileno 5), `handle id(7)' (pty was initialized
from fileno 7) or `STDIN'. Useful for debugging.
=item $object->restart_timeout_upon_receive(0 | 1)
If this is set to 1, the expect timeout is retriggered whenever something
is received from the spawned command. This allows to perform some
aliveness testing and still expect for patterns.
$exp->restart_timeout_upon_receive(1);
$exp->expect($timeout,
[ timeout => \&report_timeout ],
[ qr/pattern/ => \&handle_pattern],
);
Now the timeout isn't triggered if the command produces any kind of output,
i.e. is still alive, but you can act upon patterns in the output.
=item $object->notransfer(1 | 0)
Do not truncate the content of the accumulator after a match.
Normally, the accumulator is set to the remains that come after the
matched string. Note that this setting is per object and not per
pattern, so if you want to have normal acting patterns that truncate
the accumulator, you have to add a
$exp->set_accum($exp->after);
to their callback, e.g.
$exp->notransfer(1);
$exp->expect($timeout,
# accumulator not truncated, pattern1 will match again
[ "pattern1" => sub { my $self = shift;
...
} ],
# accumulator truncated, pattern2 will not match again
[ "pattern2" => sub { my $self = shift;
...
$self->set_accum($self->after());
} ],
);
This is only a temporary fix until I can rewrite the pattern matching
part so it can take that additional -notransfer argument.
=item Expect::interconnect(@objects);
Read from @objects and print to their @listen_groups until an escape sequence
is matched from one of @objects and the associated function returns 0 or undef.
The special escape sequence 'EOF' is matched when an object's handle returns
an end of file. Note that it is not necessary to include objects that only
accept data in @objects since the escape sequence is _read_ from an object.
Further note that the listen_group for a write-only object is always empty.
Why would you want to have objects listening to STDOUT (for example)?
By default every member of @objects _as well as every member of its listen
group_ will be set to 'raw -echo' for the duration of interconnection.
Setting $object->manual_stty() will stop this behavior per object.
The original tty settings will be restored as interconnect exits.
For a generic way to interconnect processes, take a look at L<IPC::Run>.
=item Expect::test_handles(@objects)
Given a set of objects determines which objects' handles have data ready
to be read. B<Returns an array> who's members are positions in @objects that
have ready handles. Returns undef if there are no such handles ready.
=item Expect::version($version_requested or undef);
Returns current version of Expect. As of .99 earlier versions are not
supported. Too many things were changed to make versioning possible.
=item $object->interact( C<\*FILEHANDLE, $escape_sequence>)
interact() is essentially a macro for calling interconnect() for
connecting 2 processes together. \*FILEHANDLE defaults to \*STDIN and
$escape_sequence defaults to undef. Interaction ceases when $escape_sequence
is read from B<FILEHANDLE>, not $object. $object's listen group will
consist solely of \*FILEHANDLE for the duration of the interaction.
\*FILEHANDLE will not be echoed on STDOUT.
=item $object->log_group(0 | 1 | undef)
Set/unset logging of $object to its 'listen group'. If set all objects
in the listen group will have output from $object printed to them during
$object->expect(), $object->send_slow(), and C<Expect::interconnect($object
, ...)>. Default value is on. During creation of $object the setting will
match the value of $Expect::Log_Group, normally 1.
=item $object->log_user(0 | 1 | undef) I<or>
=item $object->log_stdout(0 | 1 | undef)
Set/unset logging of object's handle to STDOUT. This corresponds to Tcl's
log_user variable. Returns current setting if called without parameters.
Default setting is off for initialized handles. When a process object is
created (not a filehandle initialized with exp_init) the log_stdout setting
will match the value of $Expect::Log_Stdout variable, normally 1.
If/when you initialize STDIN it is usually associated with a tty which
will by default echo to STDOUT anyway, so be careful or you will have
multiple echoes.
=item $object->log_file("filename" | $filehandle | \&coderef | undef)
Log session to a file. All characters send to or received from the
spawned process are written to the file. Normally appends to the
logfile, but you can pass an additional mode of "w" to truncate the
file upon open():
$object->log_file("filename", "w");
Returns the logfilehandle.
If called with an undef value, stops logging and closes logfile:
$object->log_file(undef);
If called without argument, returns the logfilehandle:
$fh = $object->log_file();
Can be set to a code ref, which will be called instead of printing
to the logfile:
$object->log_file(\&myloggerfunc);
=item $object->print_log_file(@strings)
Prints to logfile (if opened) or calls the logfile hook function.
This allows the user to add arbitrary text to the logfile. Note that
this could also be done as $object->log_file->print() but would only
work for log files, not code hooks.
=item $object->set_seq($sequence, \&function, \@function_parameters)
During Expect->interconnect() if $sequence is read from $object &function
will be executed with parameters @function_parameters. It is B<_highly
recommended_> that the escape sequence be a single character since the
likelihood is great that the sequence will be broken into to separate reads
from the $object's handle, making it impossible to strip $sequence from
getting printed to $object's listen group. \&function should be something
like 'main::control_w_function' and @function_parameters should be an
array defined by the caller, passed by reference to set_seq().
Your function should return a non-zero value if execution of interconnect()
is to resume after the function returns, zero or undefined if interconnect()
should return after your function returns.
The special sequence 'EOF' matches the end of file being reached by $object.
See interconnect() for details.
=item $object->set_group(@listener_objects)
@listener_objects is the list of objects that should have their handles
printed to by $object when Expect::interconnect, $object->expect() or
$object->send_slow() are called. Calling w/out parameters will return
the current list of the listener objects.
=item $object->manual_stty(0 | 1 | undef)
Sets/unsets whether or not Expect should make reasonable guesses as to
when and how to set tty parameters for $object. Will match
$Expect::Manual_Stty value (normally 0) when $object is created. If called
without parameters manual_stty() will return the current manual_stty setting.
=item $object->match_max($maximum_buffer_length | undef) I<or>
=item $object->max_accum($maximum_buffer_length | undef)
Set the maximum accumulator size for object. This is useful if you think
that the accumulator will grow out of hand during expect() calls. Since
the buffer will be matched by every match_pattern it may get slow if the
buffer gets too large. Returns current value if called without parameters.
Not defined by default.
=item $object->notransfer(0 | 1)
If set, matched strings will not be deleted from the accumulator.
Returns current value if called without parameters. False by default.
=item $object->exp_pid() I<or>
=item $object->pid()
Return pid of $object, if one exists. Initialized filehandles will not have
pids (of course).
=item $object->send_slow($delay, @strings);
print each character from each string of @strings one at a time with $delay
seconds before each character. This is handy for devices such as modems
that can be annoying if you send them data too fast. After each character
$object will be checked to determine whether or not it has any new data ready
and if so update the accumulator for future expect() calls and print the
output to STDOUT and @listen_group if log_stdout and log_group are
appropriately set.
=back
=head2 Configurable Package Variables:
=over 4
=item $Expect::Debug
Defaults to 0. Newly created objects have a $object->debug() value
of $Expect::Debug. See $object->debug();
=item $Expect::Do_Soft_Close
Defaults to 0. When destroying objects, soft_close may take up to half
a minute to shut everything down. From now on, only hard_close will
be called, which is less polite but still gives the process a chance
to terminate properly. Set this to '1' for old behaviour.
=item $Expect::Exp_Internal
Defaults to 0. Newly created objects have a $object->exp_internal()
value of $Expect::Exp_Internal. See $object->exp_internal().
=item $Expect::IgnoreEintr
Defaults to 0. If set to 1, when waiting for new data, Expect will
ignore EINTR errors and restart the select() call instead.
=item $Expect::Log_Group
Defaults to 1. Newly created objects have a $object->log_group()
value of $Expect::Log_Group. See $object->log_group().
=item $Expect::Log_Stdout
Defaults to 1 for spawned commands, 0 for file handles
attached with exp_init(). Newly created objects have a
$object->log_stdout() value of $Expect::Log_Stdout. See
$object->log_stdout().
=item $Expect::Manual_Stty
Defaults to 0. Newly created objects have a $object->manual_stty()
value of $Expect::Manual_Stty. See $object->manual_stty().
=item $Expect::Multiline_Matching
Defaults to 1. Affects whether or not expect() uses the /m flag for
doing regular expression matching. If set to 1 /m is used.
This makes a difference when you are trying to match ^ and $. If
you have this on you can match lines in the middle of a page of output
using ^ and $ instead of it matching the beginning and end of the entire
expression. I think this is handy.
The $Expect::Multiline_Matching turns on and off Expect's multi-line
matching mode. But this only has an effect if you pass in a string, and
then use '-re' mode. If you pass in a regular expression value (via
qr//), then the qr//'s own flags are preserved irrespective of what it
gets interpolated into. There was a bug in Perl 5.8.x where interpolating
a regex without /m into a match with /m would incorrectly apply the /m
to the inner regex too, but this was fixed in Perl 5.10. The correct
behavior, as seen in Perl 5.10, is that if you pass in a regex (via
qr//), then $Expect::Multiline_Matching has no effect.
So if you pass in a regex, then you must use the qr's flags
to control whether it is multiline (which by default it is not, opposite
of the default behavior of Expect).
=back
=head1 CONTRIBUTIONS
Lee Eakin <leakin@japh.itg.ti.com> has ported the kibitz script
from Tcl/Expect to Perl/Expect.
Jeff Carr <jcarr@linuxmachines.com> provided a simple example of how
handle terminal window resize events (transmitted via the WINCH
signal) in a ssh session.
You can find both scripts in the examples/ subdir. Thanks to both!
Historical notes:
There are still a few lines of code dating back to the inspirational
Comm.pl and Chat.pl modules without which this would not have been possible.
Kudos to Eric Arnold <Eric.Arnold@Sun.com> and Randal 'Nuke your NT box with
one line of perl code' Schwartz<merlyn@stonehenge.com> for making these
available to the perl public.
As of .98 I think all the old code is toast. No way could this have been done
without it though. Special thanks to Graham Barr for helping make sense of
the IO::Handle stuff as well as providing the highly recommended IO::Tty
module.
=head1 REFERENCES
Mark Rogaski <rogaski@att.com> wrote:
"I figured that you'd like to know that Expect.pm has been very
useful to AT&T Labs over the past couple of years (since I first talked to
Austin about design decisions). We use Expect.pm for managing
the switches in our network via the telnet interface, and such automation
has significantly increased our reliability. So, you can honestly say that
one of the largest digital networks in existence (AT&T Frame Relay) uses
Expect.pm quite extensively."
=head1 FAQ - Frequently Asked Questions
This is a growing collection of things that might help.
Please send you questions that are not answered here to
RGiersig@cpan.org
=head2 What systems does Expect run on?
Expect itself doesn't have real system dependencies, but the underlying
IO::Tty needs pseudoterminals. IO::Stty uses POSIX.pm and Fcntl.pm.
I have used it on Solaris, Linux and AIX, others report *BSD and OSF
as working. Generally, any modern POSIX Unix should do, but there
are exceptions to every rule. Feedback is appreciated.
See L<IO::Tty> for a list of verified systems.
=head2 Can I use this module with ActivePerl on Windows?
Up to now, the answer was 'No', but this has changed.
You still cannot use ActivePerl, but if you use the Cygwin environment
(http://sources.redhat.com), which brings its own perl, and have
the latest IO::Tty (v0.05 or later) installed, it should work (feedback
appreciated).
=head2 The examples in the tutorial don't work!
The tutorial is hopelessly out of date and needs a serious overhaul.
I apologize for this, I have concentrated my efforts mainly on the
functionality. Volunteers welcomed.
=head2 How can I find out what Expect is doing?
If you set
$Expect::Exp_Internal = 1;
Expect will tell you very verbosely what it is receiving and sending,
what matching it is trying and what it found. You can do this on a
per-command base with
$exp->exp_internal(1);
You can also set
$Expect::Debug = 1; # or 2, 3 for more verbose output
or
$exp->debug(1);
which gives you even more output.
=head2 I am seeing the output of the command I spawned. Can I turn that off?
Yes, just set
$Expect::Log_Stdout = 0;
to globally disable it or
$exp->log_stdout(0);
for just that command. 'log_user' is provided as an alias so
Tcl/Expect user get a DWIM experience... :-)
=head2 No, I mean that when I send some text to the spawned process, it gets echoed back and I have to deal with it in the next expect.
This is caused by the pty, which has probably 'echo' enabled. A
solution would be to set the pty to raw mode, which in general is
cleaner for communication between two programs (no more unexpected
character translations). Unfortunately this would break a lot of old
code that sends "\r" to the program instead of "\n" (translating this
is also handled by the pty), so I won't add this to Expect just like that.
But feel free to experiment with C<$exp-E<gt>raw_pty(1)>.
=head2 How do I send control characters to a process?
A: You can send any characters to a process with the print command. To
represent a control character in Perl, use \c followed by the letter. For
example, control-G can be represented with "\cG" . Note that this will not
work if you single-quote your string. So, to send control-C to a process in
$exp, do:
print $exp "\cC";
Or, if you prefer:
$exp->send("\cC");
The ability to include control characters in a string like this is provided
by Perl, not by Expect.pm . Trying to learn Expect.pm without a thorough
grounding in Perl can be very daunting. We suggest you look into some of
the excellent Perl learning material, such as the books _Programming Perl_
and _Learning Perl_ by O'Reilly, as well as the extensive online Perl
documentation available through the perldoc command.
=head2 My script fails from time to time without any obvious reason. It seems that I am sometimes loosing output from the spawned program.
You could be exiting too fast without giving the spawned program
enough time to finish. Try adding $exp->soft_close() to terminate the
program gracefully or do an expect() for 'eof'.
Alternatively, try adding a 'sleep 1' after you spawn() the program.
It could be that pty creation on your system is just slow (but this is
rather improbable if you are using the latest IO-Tty).
=head2 I want to automate password entry for su/ssh/scp/rsh/...
You shouldn't use Expect for this. Putting passwords, especially
root passwords, into scripts in clear text can mean severe security
problems. I strongly recommend using other means. For 'su', consider
switching to 'sudo', which gives you root access on a per-command and
per-user basis without the need to enter passwords. 'ssh'/'scp' can be
set up with RSA authentication without passwords. 'rsh' can use
the .rhost mechanism, but I'd strongly suggest to switch to 'ssh'; to
mention 'rsh' and 'security' in the same sentence makes an oxymoron.
It will work for 'telnet', though, and there are valid uses for it,
but you still might want to consider using 'ssh', as keeping cleartext
passwords around is very insecure.
=head2 I want to use Expect to automate [anything with a buzzword]...
Are you sure there is no other, easier way? As a rule of thumb,
Expect is useful for automating things that expect to talk to a human,
where no formal standard applies. For other tasks that do follow a
well-defined protocol, there are often better-suited modules that
already can handle those protocols. Don't try to do HTTP requests by
spawning telnet to port 80, use LWP instead. To automate FTP, take a
look at L<Net::FTP> or C<ncftp> (http://www.ncftp.org). You don't use
a screwdriver to hammer in your nails either, or do you?
=head2 Is it possible to use threads with Expect?
Basically yes, with one restriction: you must spawn() your programs in
the main thread and then pass the Expect objects to the handling
threads. The reason is that spawn() uses fork(), and L<perlthrtut>:
"Thinking of mixing fork() and threads? Please lie down and wait until the feeling passes."
=head2 I want to log the whole session to a file.
Use
$exp->log_file("filename");
or
$exp->log_file($filehandle);
or even
$exp->log_file(\&log_procedure);
for maximum flexibility.
Note that the logfile is appended to by default, but you can
specify an optional mode "w" to truncate the logfile:
$exp->log_file("filename", "w");
To stop logging, just call it with a false argument:
$exp->log_file(undef);
=head2 How can I turn off multi-line matching for my regexps?
To globally unset multi-line matching for all regexps:
$Expect::Multiline_Matching = 0;
You can do that on a per-regexp basis by stating C<(?-m)> inside the regexp
(you need perl5.00503 or later for that).
=head2 How can I expect on multiple spawned commands?
You can use the B<-i> parameter to specify a single object or a list
of Expect objects. All following patterns will be evaluated against
that list.
You can specify B<-i> multiple times to create groups of objects
and patterns to match against within the same expect statement.
This works just like in Tcl/Expect.
See the source example below.
=head2 I seem to have problems with ptys!
Well, pty handling is really a black magic, as it is extremely system
dependent. I have extensively revised IO-Tty, so these problems
should be gone.
If your system is listed in the "verified" list of IO::Tty, you
probably have some non-standard setup, e.g. you compiled your
Linux-kernel yourself and disabled ptys. Please ask your friendly
sysadmin for help.
If your system is not listed, unpack the latest version of IO::Tty,
do a 'perl Makefile.PL; make; make test; uname C<-a>' and send me the
results and I'll see what I can deduce from that.
=head2 I just want to read the output of a process without expect()ing anything. How can I do this?
[ Are you sure you need Expect for this? How about qx() or open("prog|")? ]
By using expect without any patterns to match.
$process->expect(undef); # Forever until EOF
$process->expect($timeout); # For a few seconds
$process->expect(0); # Is there anything ready on the handle now?
=head2 Ok, so now how do I get what was read on the handle?
$read = $process->before();
=head2 Where's IO::Pty?
Find it on CPAN as IO-Tty, which provides both.
=head2 How come when I automate the passwd program to change passwords for me passwd dies before changing the password sometimes/every time?
What's happening is you are closing the handle before passwd exits.
When you close the handle to a process, it is sent a signal (SIGPIPE?)
telling it that STDOUT has gone away. The default behavior for
processes is to die in this circumstance. Two ways you can make this
not happen are:
$process->soft_close();
This will wait 15 seconds for a process to come up with an EOF by
itself before killing it.
$process->expect(undef);
This will wait forever for the process to match an empty set of
patterns. It will return when the process hits an EOF.
As a rule, you should always expect() the result of your transaction
before you continue with processing.
=head2 How come when I try to make a logfile with log_file() or set_group() it doesn't print anything after the last time I run expect()?
Output is only printed to the logfile/group when Expect reads from the
process, during expect(), send_slow() and interconnect().
One way you can force this is to make use of
$process->expect(undef);
and
$process->expect(0);
which will make expect() run with an empty pattern set forever or just
for an instant to capture the output of $process. The output is
available in the accumulator, so you can grab it using
$process->before().
=head2 I seem to have problems with terminal settings, double echoing, etc.
Tty settings are a major pain to keep track of. If you find unexpected
behavior such as double-echoing or a frozen session, doublecheck the
documentation for default settings. When in doubt, handle them
yourself using $exp->stty() and manual_stty() functions. As of .98
you shouldn't have to worry about stty settings getting fouled unless
you use interconnect or intentionally change them (like doing -echo to
get a password).
If you foul up your terminal's tty settings, kill any hung processes
and enter 'stty sane' at a shell prompt. This should make your
terminal manageable again.
Note that IO::Tty returns ptys with your systems default setting
regarding echoing, CRLF translation etc. and Expect does not change
them. I have considered setting the ptys to 'raw' without any
translation whatsoever, but this would break a lot of existing things,
as '\r' translation would not work anymore. On the other hand, a raw
pty works much like a pipe and is more WYGIWYE (what you get is what
you expect), so I suggest you set it to 'raw' by yourself:
$exp = Expect->new;
$exp->raw_pty(1);
$exp->spawn(...);
To disable echo:
$exp->slave->stty(qw(-echo));
=head2 I'm spawning a telnet/ssh session and then let the user interact with it. But screen-oriented applications on the other side don't work properly.
You have to set the terminal screen size for that. Luckily, IO::Pty
already has a method for that, so modify your code to look like this:
my $exp = Expect->new;
$exp->slave->clone_winsize_from(\*STDIN);
$exp->spawn("telnet somehost);
Also, some applications need the TERM shell variable set so they know
how to move the cursor across the screen. When logging in, the remote
shell sends a query (Ctrl-Z I think) and expects the terminal to
answer with a string, e.g. 'xterm'. If you really want to go that way
(be aware, madness lies at its end), you can handle that and send back
the value in $ENV{TERM}. This is only a hand-waving explanation,
please figure out the details by yourself.
=head2 I set the terminal size as explained above, but if I resize the window, the application does not notice this.
You have to catch the signal WINCH ("window size changed"), change the
terminal size and propagate the signal to the spawned application:
my $exp = Expect->new;
$exp->slave->clone_winsize_from(\*STDIN);
$exp->spawn("ssh somehost);
$SIG{WINCH} = \&winch;
sub winch {
$exp->slave->clone_winsize_from(\*STDIN);
kill WINCH => $exp->pid if $exp->pid;
$SIG{WINCH} = \&winch;
}
$exp->interact();
There is an example file ssh.pl in the examples/ subdir that shows how
this works with ssh. Please note that I do strongly object against
using Expect to automate ssh login, as there are better way to do that
(see L<ssh-keygen>).
=head2 I noticed that the test uses a string that resembles, but not exactly matches, a well-known sentence that contains every character. What does that mean?
That means you are anal-retentive. :-) [Gotcha there!]
=head2 I get a "Could not assign a pty" error when running as a non-root user on an IRIX box?
The OS may not be configured to grant additional pty's (pseudo terminals)
to non-root users. /usr/sbin/mkpts should be 4755, not 700 for this
to work. I don't know about security implications if you do this.
=head2 How come I don't notice when the spawned process closes its stdin/out/err??
You are probably on one of the systems where the master doesn't get an
EOF when the slave closes stdin/out/err.
One possible solution is when you spawn a process, follow it with a
unique string that would indicate the process is finished.
$process = Expect->spawn('telnet somehost; echo ____END____');
And then $process->expect($timeout,'____END____','other','patterns');
=head1 Source Examples
=head2 How to automate login
my $telnet = Net::Telnet->new("remotehost") # see Net::Telnet
or die "Cannot telnet to remotehost: $!\n";;
my $exp = Expect->exp_init($telnet);
# deprecated use of spawned telnet command
# my $exp = Expect->spawn("telnet localhost")
# or die "Cannot spawn telnet: $!\n";;
my $spawn_ok;
$exp->expect($timeout,
[
qr'login: $',
sub {
$spawn_ok = 1;
my $fh = shift;
$fh->send("$username\n");
exp_continue;
}
],
[
'Password: $',
sub {
my $fh = shift;
print $fh "$password\n";
exp_continue;
}
],
[
eof =>
sub {
if ($spawn_ok) {
die "ERROR: premature EOF in login.\n";
} else {
die "ERROR: could not spawn telnet.\n";
}
}
],
[
timeout =>
sub {
die "No login.\n";
}
],
'-re', qr'[#>:] $', #' wait for shell prompt, then exit expect
);
=head2 How to expect on multiple spawned commands
foreach my $cmd (@list_of_commands) {
push @commands, Expect->spawn($cmd);
}
expect($timeout,
'-i', \@commands,
[
qr"pattern", # find this pattern in output of all commands
sub {
my $obj = shift; # object that matched
print $obj "something\n";
exp_continue; # we don't want to terminate the expect call
}
],
'-i', $some_other_command,
[
"some other pattern",
sub {
my ($obj, $parmref) = @_;
# ...
# now we exit the expect command
},
\$parm
],
);
=head2 How to propagate terminal sizes
my $exp = Expect->new;
$exp->slave->clone_winsize_from(\*STDIN);
$exp->spawn("ssh somehost);
$SIG{WINCH} = \&winch;
sub winch {
$exp->slave->clone_winsize_from(\*STDIN);
kill WINCH => $exp->pid if $exp->pid;
$SIG{WINCH} = \&winch;
}
$exp->interact();
=head1 HOMEPAGE
L<http://sourceforge.net/projects/expectperl/> though the source code is now in GitHub: L<https://github.com/jacoby/expect.pm>
=head1 MAILING LISTS
There are two mailing lists available, expectperl-announce and
expectperl-discuss, at
http://lists.sourceforge.net/lists/listinfo/expectperl-announce
and
http://lists.sourceforge.net/lists/listinfo/expectperl-discuss
=head1 BUG TRACKING
You can use the CPAN Request Tracker http://rt.cpan.org/ and submit
new bugs under
http://rt.cpan.org/Ticket/Create.html?Queue=Expect
=head1 AUTHORS
(c) 1997 Austin Schutz E<lt>F<ASchutz@users.sourceforge.net>E<gt> (retired)
expect() interface & functionality enhancements (c) 1999-2006 Roland Giersig.
This module is now maintained by Dave Jacoby E<lt>F<jacoby@cpan.org>E<gt>
=head1 LICENSE
This module can be used under the same terms as Perl.
=head1 DISCLAIMER
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
In other words: Use at your own risk. Provided as is. Your mileage
may vary. Read the source, Luke!
And finally, just to be sure:
Any Use of This Product, in Any Manner Whatsoever, Will Increase the
Amount of Disorder in the Universe. Although No Liability Is Implied
Herein, the Consumer Is Warned That This Process Will Ultimately Lead
to the Heat Death of the Universe.
=cut
PK 1N%[P��Y�! �! perl5/Test/Needs.pmnu ��6�$ package Test::Needs;
use strict;
use warnings;
no warnings 'once';
our $VERSION = '0.002010';
$VERSION =~ tr/_//d;
BEGIN {
*_WORK_AROUND_HINT_LEAKAGE
= "$]" < 5.011 && !("$]" >= 5.009004 && "$]" < 5.010001)
? sub(){1} : sub(){0};
*_WORK_AROUND_BROKEN_MODULE_STATE
= "$]" < 5.009
? sub(){1} : sub(){0};
# this allows regexes to match wide characters in vstrings
if ("$]" >= 5.006001 && "$]" <= 5.006002) {
require utf8;
utf8->import;
}
}
our @EXPORT = qw(test_needs);
our $Level = 0;
sub _try_require {
local %^H
if _WORK_AROUND_HINT_LEAKAGE;
my ($module) = @_;
(my $file = "$module.pm") =~ s{::|'}{/}g;
my $err;
{
local $@;
eval { require $file }
or $err = $@;
}
if (defined $err) {
delete $INC{$file}
if _WORK_AROUND_BROKEN_MODULE_STATE;
die $err
unless $err =~ /\ACan't locate \Q$file\E/;
return !1;
}
!0;
}
sub _croak {
my $message = join '', @_;
my $i = 1;
while (my ($p, $f, $l) = caller($i++)) {
next
if $p =~ /\ATest::Needs(?:::|\z)/;
die "$message at $f line $l.\n";
}
die $message;
}
sub _try_version {
my ($module, $version) = @_;
local $@;
!!eval { $module->VERSION($version); 1 };
}
sub _numify_version {
for ($_[0]) {
return
!$_ ? 0
: /^[0-9]+(?:\.[0-9]+)?$/ ? sprintf('%.6f', $_)
: /^v?([0-9]+(?:\.[0-9]+)*)$/
? sprintf('%d.%03d%03d', ((split /\./, $1), 0, 0)[0..2])
: /^([\x05-\x07])(.*)$/s
? sprintf('%d.%03d%03d', ((map ord, /(.)/gs), 0, 0)[0..2])
: _croak qq{version "$_" does not look like a number};
}
}
sub _find_missing {
my @bad = map {
my ($module, $version) = @$_;
$module eq 'perl' ? do {
$version = _numify_version($version);
"$]" < $version ? (sprintf "perl %s (have %.6f)", $version, $]) : ()
}
: $module =~ /^\d|[^\w:]|:::|[^:]:[^:]|^:|:$/
? _croak sprintf qq{"%s" does not look like a module name}, $module
: _try_require($module) ? (
defined $version && !_try_version($module, $version)
? "$module $version (have ".(defined $module->VERSION ? $module->VERSION : 'undef').')'
: ()
)
: $version ? "$module $version"
: $module;
}
_pairs(@_);
@bad ? "Need " . join(', ', @bad) : undef;
}
sub import {
my $class = shift;
my $target = caller;
if (@_) {
local $Level = $Level + 1;
test_needs(@_);
}
no strict 'refs';
*{"${target}::$_"} = \&{"${class}::$_"}
for @{"${class}::EXPORT"};
}
sub test_needs {
my $missing = _find_missing(@_);
local $Level = $Level + 1;
if ($missing) {
if ($ENV{RELEASE_TESTING}) {
_fail("$missing due to RELEASE_TESTING");
}
else {
_skip($missing);
}
}
return 1;
}
sub _skip {
local $Level = $Level + 1;
_fail_or_skip($_[0], 0)
}
sub _fail {
local $Level = $Level + 1;
_fail_or_skip($_[0], 1)
}
sub _pairs {
map +(
ref eq 'HASH' ? do {
my $arg = $_;
map [ $_ => $arg->{$_} ], sort keys %$arg;
}
: ref eq 'ARRAY' ? do {
my $arg = $_;
map [ @{$arg}[$_*2,$_*2+1] ], 0 .. int($#$arg / 2);
}
: [ $_ ]
), @_;
}
sub _fail_or_skip {
my ($message, $fail) = @_;
if ($INC{'Test2/API.pm'}) {
my $ctx = Test2::API::context(level => $Level);
my $hub = $ctx->hub;
if ($fail) {
$ctx->ok(0, "Test::Needs modules available", [$message]);
}
else {
my $plan = $hub->plan;
my $tests = $hub->count;
if ($plan || $tests) {
my $skips
= $plan && $plan ne 'NO PLAN' ? $plan - $tests : 1;
$ctx->skip("Test::Needs modules not available") for 1 .. $skips;
$ctx->note($message);
}
else {
$ctx->plan(0, 'SKIP', $message);
}
}
$ctx->done_testing;
$ctx->release if $Test2::API::VERSION < 1.302053;
$ctx->send_event('+'._t2_terminate_event());
}
elsif ($INC{'Test/Builder.pm'}) {
local $Test::Builder::Level = $Test::Builder::Level + $Level;
my $tb = Test::Builder->new;
my $has_plan = Test::Builder->can('has_plan') ? 'has_plan'
: sub { $_[0]->expected_tests || eval { $_[0]->current_test($_[0]->current_test); 'no_plan' } };
my $tests = $tb->current_test;
if ($fail) {
$tb->plan(tests => 1)
unless $tb->$has_plan;
$tests++;
$tb->ok(0, "Test::Needs modules available");
$tb->diag($message);
}
else {
my $plan = $tb->$has_plan;
if ($plan || $tests) {
my $skips
= $plan && $plan ne 'no_plan' ? $plan - $tests : 1;
$tb->skip("Test::Needs modules not available")
for 1 .. $skips;
$tests += $skips;
Test::Builder->can('note') ? $tb->note($message) : print "# $message\n";
}
else {
$tb->skip_all($message);
}
}
$tb->done_testing($tests)
if Test::Builder->can('done_testing');
die bless {} => 'Test::Builder::Exception'
if Test::Builder->can('parent') && $tb->parent;
}
else {
if ($fail) {
print "1..1\n";
print "not ok 1 - Test::Needs modules available\n";
print STDERR "# $message\n";
exit 1;
}
else {
print "1..0 # SKIP $message\n";
}
}
exit 0;
}
my $terminate_event;
sub _t2_terminate_event () {
return $terminate_event
if $terminate_event;
local $@;
$terminate_event = eval sprintf <<'END_CODE', __LINE__+2, __FILE__ or die "$@";
#line %d "%s"
package # hide
Test::Needs::Event::Terminate;
use Test2::Event ();
our @ISA = qw(Test2::Event);
sub no_display { 1 }
sub terminate { 0 }
__PACKAGE__;
END_CODE
(my $pm = "$terminate_event.pm") =~ s{::}{/}g;
$INC{$pm} = __FILE__;
$terminate_event;
}
1;
__END__
=pod
=encoding utf-8
=head1 NAME
Test::Needs - Skip tests when modules not available
=head1 SYNOPSIS
# need one module
use Test::Needs 'Some::Module';
# need multiple modules
use Test::Needs 'Some::Module', 'Some::Other::Module';
# need a given version of a module
use Test::Needs {
'Some::Module' => '1.005',
};
# check later
use Test::Needs;
test_needs 'Some::Module';
# skips remainder of subtest
use Test::More;
use Test::Needs;
subtest 'my subtest' => sub {
test_needs 'Some::Module';
...
};
# check perl version
use Test::Needs { perl => 5.020 };
=head1 DESCRIPTION
Skip test scripts if modules are not available. The requested modules will be
loaded, and optionally have their versions checked. If the module is missing,
the test script will be skipped. Modules that are found but fail to compile
will exit with an error rather than skip.
If used in a subtest, the remainder of the subtest will be skipped.
Skipping will work even if some tests have already been run, or if a plan has
been declared.
Versions are checked via a C<< $module->VERSION($wanted_version) >> call.
Versions must be provided in a format that will be accepted. No extra
processing is done on them.
If C<perl> is used as a module, the version is checked against the running perl
version (L<$]|perlvar/$]>). The version can be specified as a number,
dotted-decimal string, v-string, or version object.
If the C<RELEASE_TESTING> environment variable is set, the tests will fail
rather than skip. Subtests will be aborted, but the test script will continue
running after that point.
=head1 EXPORTS
=head2 test_needs
Has the same interface as when using Test::Needs in a C<use>.
=head1 SEE ALSO
=over 4
=item L<Test::Requires>
A similar module, with some important differences. L<Test::Requires> will act
as a C<use> statement (despite its name), calling the import sub. Under
C<RELEASE_TESTING>, it will BAIL_OUT if a module fails to load rather than
using a normal test fail. It also doesn't distinguish between missing modules
and broken modules.
=item L<Test2::Require::Module>
Part of the L<Test2> ecosystem. Only supports running as a C<use> command to
skip an entire plan.
=item L<Test2::Require::Perl>
Part of the L<Test2> ecosystem. Only supports running as a C<use> command to
skip an entire plan. Checks perl versions.
=item L<Test::If>
Acts as a C<use> statement. Only supports running as a C<use> command to skip
an entire plan. Can skip based on subref results.
=back
=head1 AUTHORS
haarg - Graham Knop (cpan:HAARG) <haarg@haarg.org>
=head1 CONTRIBUTORS
None so far.
=head1 COPYRIGHT AND LICENSE
Copyright (c) 2016 the Test::Needs L</AUTHORS> and L</CONTRIBUTORS>
as listed above.
This library is free software and may be distributed under the same terms
as perl itself. See L<http://dev.perl.org/licenses/>.
=cut
PK 1N%[`�$�y y perl5/Test/RequiresInternet.pmnu ��6�$ use strict;
use warnings;
package Test::RequiresInternet;
$Test::RequiresInternet::VERSION = '0.05';
# ABSTRACT: Easily test network connectivity
use Socket;
sub import {
skip_all("NO_NETWORK_TESTING") if env("NO_NETWORK_TESTING");
my $namespace = shift;
my $argc = scalar @_;
if ( $argc == 0 ) {
push @_, 'www.google.com', 80;
}
elsif ( $argc % 2 != 0 ) {
die "Must supply server and a port pairs. You supplied " . (join ", ", @_) . "\n";
}
while ( @_ ) {
my $host = shift;
my $port = shift;
local $@;
eval {make_socket($host, $port)};
if ( $@ ) {
skip_all("$@");
}
}
}
sub make_socket {
my ($host, $port) = @_;
my $portnum;
if ($port =~ /\D/) {
$portnum = getservbyname($port, "tcp");
}
else {
$portnum = $port;
}
die "Could not find a port number for $port\n" if not $portnum;
my $iaddr = inet_aton($host) or die "no host: $host\n";
my $paddr = sockaddr_in($portnum, $iaddr);
my $proto = getprotobyname("tcp");
socket(my $sock, PF_INET, SOCK_STREAM, $proto) or die "socket: $!\n";
connect($sock, $paddr) or die "connect: $!\n";
close ($sock) or die "close: $!\n";
1;
}
sub env {
exists $ENV{$_[0]} && $ENV{$_[0]} eq '1'
}
sub skip_all {
my $reason = shift;
print "1..0 # Skipped: $reason";
exit 0;
}
1;
__END__
=pod
=encoding UTF-8
=head1 NAME
Test::RequiresInternet - Easily test network connectivity
=head1 VERSION
version 0.05
=head1 SYNOPSIS
use Test::More;
use Test::RequiresInternet ('www.example.com' => 80, 'foobar.io' => 25);
# if you reach here, sockets successfully connected to hosts/ports above
plan tests => 1;
ok(do_that_internet_thing());
=head1 OVERVIEW
This module is intended to easily test network connectivity before functional
tests begin to non-local Internet resources. It does not require any modules
beyond those supplied in core Perl.
If you do not specify a host/port pair, then the module defaults to using
C<www.google.com> on port C<80>.
You may optionally specify the port by its name, as in C<http> or C<ldap>.
If you do this, the test module will attempt to look up the port number
using C<getservbyname>.
If you do specify a host and port, they must be specified in B<pairs>. It is a
fatal error to omit one or the other.
If the environment variable C<NO_NETWORK_TESTING> is set, then the tests
will be skipped without attempting any socket connections.
If the sockets cannot connect to the specified hosts and ports, the exception
is caught, reported and the tests skipped.
=head1 AUTHOR
Mark Allen <mrallen1@yahoo.com>
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2014 by Mark Allen.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut
PK 1N%[��n�t �t perl5/Test/Alien.pmnu ��6�$ package Test::Alien;
use strict;
use warnings;
use 5.008004;
use Env qw( @PATH );
use File::Which 1.10 qw( which );
use Capture::Tiny qw( capture capture_merged );
use Alien::Build::Temp;
use File::Copy qw( move );
use Text::ParseWords qw( shellwords );
use Test2::API qw( context run_subtest );
use Exporter qw( import );
use Path::Tiny qw( path );
use Alien::Build::Util qw( _dump );
use Config;
our @EXPORT = qw( alien_ok run_ok xs_ok ffi_ok with_subtest synthetic helper_ok interpolate_template_is interpolate_run_ok plugin_ok );
# ABSTRACT: Testing tools for Alien modules
our $VERSION = '2.84'; # VERSION
our @aliens;
sub alien_ok ($;$)
{
my($alien, $message) = @_;
my $name = ref $alien ? ref($alien) . '[instance]' : $alien;
$name = 'undef' unless defined $name;
my @methods = qw( cflags libs dynamic_libs bin_dir );
$message ||= "$name responds to: @methods";
my $ok;
my @diag;
if(defined $alien)
{
my @missing = grep { ! $alien->can($_) } @methods;
$ok = !@missing;
push @diag, map { " missing method $_" } @missing;
if($ok)
{
push @aliens, $alien;
if($^O eq 'MSWin32' && $alien->isa('Alien::MSYS'))
{
unshift @PATH, Alien::MSYS::msys_path();
}
else
{
unshift @PATH, $alien->bin_dir;
}
}
if($alien->can('alien_helper'))
{
my($intr) = _interpolator();
my $help = eval { $alien->alien_helper };
if(my $error = $@)
{
$ok = 0;
push @diag, " error getting helpers: $error";
}
foreach my $name (keys %$help)
{
my $code = $help->{$name};
$intr->replace_helper($name, $code);
}
}
}
else
{
$ok = 0;
push @diag, " undefined alien";
}
my $ctx = context();
$ctx->ok($ok, $message);
$ctx->diag($_) for @diag;
$ctx->release;
$ok;
}
sub synthetic
{
my($opt) = @_;
$opt ||= {};
my %alien = %$opt;
require Test::Alien::Synthetic;
bless \%alien, 'Test::Alien::Synthetic',
}
sub run_ok
{
my($command, $message) = @_;
my(@command) = ref $command ? @$command : (do {
my $command = $command; # make a copy
# Double the backslashes so that when they are unescaped by shellwords(),
# they become a single backslash. This should be fine on Windows since
# backslashes are not used to escape metacharacters in cmd.exe.
$command =~ s/\\/\\\\/g if $^O eq 'MSWin32';
shellwords $command;
});
$message ||= ref $command ? "run @command" : "run $command";
require Test::Alien::Run;
my $run = bless {
out => '',
err => '',
exit => 0,
sig => 0,
cmd => [@command],
}, 'Test::Alien::Run';
my $ctx = context();
my $exe = which $command[0];
if(defined $exe)
{
if(ref $command)
{
shift @command;
$run->{cmd} = [$exe, @command];
}
else
{
$run->{cmd} = [$command];
}
my @diag;
my $ok = 1;
my($exit, $errno);
($run->{out}, $run->{err}, $exit, $errno) = capture {
if(ref $command)
{
system $exe, @command;
}
else
{
system $command;
}
($?,$!);
};
if($exit == -1)
{
$ok = 0;
$run->{fail} = "failed to execute: $errno";
push @diag, " failed to execute: $errno";
}
elsif($exit & 127)
{
$ok = 0;
push @diag, " killed with signal: @{[ $exit & 127 ]}";
$run->{sig} = $exit & 127;
}
else
{
$run->{exit} = $exit >> 8;
}
$ctx->ok($ok, $message);
$ok
? $ctx->note(" using $exe")
: $ctx->diag(" using $exe");
$ctx->diag(@diag) for @diag;
}
else
{
$ctx->ok(0, $message);
$ctx->diag(" command not found");
$run->{fail} = 'command not found';
}
unless(@aliens || $ENV{TEST_ALIEN_ALIENS_MISSING})
{
$ctx->diag("run_ok called without any aliens, you may want to call alien_ok");
}
$ctx->release;
$run;
}
sub _flags
{
my($class, $method) = @_;
my $static = "${method}_static";
$class->can($static) && $class->can('install_type') && $class->install_type eq 'share' && (!$class->can('xs_load'))
? $class->$static
: $class->$method;
}
sub xs_ok
{
my $cb;
$cb = pop if defined $_[-1] && ref $_[-1] eq 'CODE';
my($xs, $message) = @_;
$message ||= 'xs';
$xs = { xs => $xs } unless ref $xs;
# make sure this is a copy because we may
# modify it.
$xs->{xs} = "@{[ $xs->{xs} ]}";
$xs->{pxs} ||= {};
$xs->{cbuilder_check} ||= 'have_compiler';
$xs->{cbuilder_config} ||= {};
$xs->{cbuilder_compile} ||= {};
$xs->{cbuilder_link} ||= {};
require ExtUtils::CBuilder;
my $skip = do {
my $have_compiler = $xs->{cbuilder_check};
my %config = %{ $xs->{cbuilder_config} };
!ExtUtils::CBuilder->new( config => \%config )->$have_compiler;
};
if($skip)
{
my $ctx = context();
$ctx->skip($message, 'test requires a compiler');
$ctx->skip("$message subtest", 'test requires a compiler') if $cb;
$ctx->release;
return;
}
if($xs->{cpp} || $xs->{'C++'})
{
my $ctx = context();
$ctx->bail("The cpp and C++ options have been removed from xs_ok");
}
else
{
$xs->{c_ext} ||= 'c';
}
my $verbose = $xs->{verbose} || 0;
my $ok = 1;
my @diag;
my $dir = Alien::Build::Temp->newdir(
TEMPLATE => 'test-alien-XXXXXX',
CLEANUP => $^O =~ /^(MSWin32|cygwin|msys)$/ ? 0 : 1,
);
my $xs_filename = path($dir)->child('test.xs')->stringify;
my $c_filename = path($dir)->child("test.@{[ $xs->{c_ext} ]}")->stringify;
my $ctx = context();
my $module;
if($ENV{TEST_ALIEN_ALWAYS_KEEP})
{
$dir->unlink_on_destroy(0);
$ctx->note("keeping XS temporary directory $dir at user request");
}
if($xs->{xs} =~ /\bTA_MODULE\b/)
{
our $count;
$count = 0 unless defined $count;
my $name = sprintf "Test::Alien::XS::Mod%s%s", $count, chr(65 + $count % 26 ) x 4;
$count++;
my $code = $xs->{xs};
$code =~ s{\bTA_MODULE\b}{$name}g;
$xs->{xs} = $code;
}
# this regex copied shamefully from ExtUtils::ParseXS
# in part because we need the module name to do the bootstrap
# and also because if this regex doesn't match then ParseXS
# does an exit() which we don't want.
if($xs->{xs} =~ /^MODULE\s*=\s*([\w:]+)(?:\s+PACKAGE\s*=\s*([\w:]+))?(?:\s+PREFIX\s*=\s*(\S+))?\s*$/m)
{
$module = $1;
$ctx->note("detect module name $module") if $verbose;
}
else
{
$ok = 0;
push @diag, ' XS does not have a module decleration that we could find';
}
if($ok)
{
open my $fh, '>', $xs_filename;
print $fh $xs->{xs};
close $fh;
require ExtUtils::ParseXS;
my $pxs = ExtUtils::ParseXS->new;
my($out, $err) = capture_merged {
eval {
$pxs->process_file(
filename => $xs_filename,
output => $c_filename,
versioncheck => 0,
prototypes => 0,
%{ $xs->{pxs} },
);
};
$@;
};
$ctx->note("parse xs $xs_filename => $c_filename") if $verbose;
$ctx->note($out) if $verbose;
$ctx->note("error: $err") if $verbose && $err;
unless($pxs->report_error_count == 0)
{
$ok = 0;
push @diag, ' ExtUtils::ParseXS failed:';
push @diag, " $err" if $err;
push @diag, " $_" for split /\r?\n/, $out;
}
}
push @diag, "xs_ok called without any aliens, you may want to call alien_ok" unless @aliens || $ENV{TEST_ALIEN_ALIENS_MISSING};
if($ok)
{
my $cb = ExtUtils::CBuilder->new(
config => do {
my %config = %{ $xs->{cbuilder_config} };
my $lddlflags = join(' ', grep !/^-l/, shellwords map { _flags $_, 'libs' } @aliens) . " $Config{lddlflags}";
$config{lddlflags} = defined $config{lddlflags} ? "$lddlflags $config{lddlflags}" : $lddlflags;
\%config;
},
);
my %compile_options = (
source => $c_filename,
%{ $xs->{cbuilder_compile} },
);
if(defined $compile_options{extra_compiler_flags} && ref($compile_options{extra_compiler_flags}) eq '')
{
$compile_options{extra_compiler_flags} = [ shellwords $compile_options{extra_compiler_flags} ];
}
push @{ $compile_options{extra_compiler_flags} }, shellwords map { _flags $_, 'cflags' } @aliens;
my($out, $obj, $err) = capture_merged {
my $obj = eval {
$cb->compile(%compile_options);
};
($obj, $@);
};
$ctx->note("compile $c_filename") if $verbose;
$ctx->note($out) if $verbose;
$ctx->note($err) if $verbose && $err;
if($verbose > 1)
{
$ctx->note(_dump({ compile_options => \%compile_options }));
}
unless($obj)
{
$ok = 0;
push @diag, ' ExtUtils::CBuilder->compile failed';
push @diag, " $err" if $err;
push @diag, " $_" for split /\r?\n/, $out;
}
if($ok)
{
my %link_options = (
objects => [$obj],
module_name => $module,
%{ $xs->{cbuilder_link} },
);
if(defined $link_options{extra_linker_flags} && ref($link_options{extra_linker_flags}) eq '')
{
$link_options{extra_linker_flags} = [ shellwords $link_options{extra_linker_flags} ];
}
unshift @{ $link_options{extra_linker_flags} }, grep /^-l/, shellwords map { _flags $_, 'libs' } @aliens;
my($out, $lib, $err) = capture_merged {
my $lib = eval {
$cb->link(%link_options);
};
($lib, $@);
};
$ctx->note("link $obj") if $verbose;
$ctx->note($out) if $verbose;
$ctx->note($err) if $verbose && $err;
if($verbose > 1)
{
$ctx->note(_dump({ link_options => \%link_options }));
}
if($lib && -f $lib)
{
$ctx->note("created lib $lib") if $xs->{verbose};
}
else
{
$ok = 0;
push @diag, ' ExtUtils::CBuilder->link failed';
push @diag, " $err" if $err;
push @diag, " $_" for split /\r?\n/, $out;
}
if($ok)
{
my @modparts = split(/::/,$module);
my $dl_dlext = $Config{dlext};
my $modfname = $modparts[-1];
my $libpath = path($dir)->child('auto', @modparts, "$modfname.$dl_dlext");
$libpath->parent->mkpath;
move($lib, "$libpath") || die "unable to copy $lib => $libpath $!";
pop @modparts;
my $pmpath = path($dir)->child(@modparts, "$modfname.pm");
$pmpath->parent->mkpath;
open my $fh, '>', "$pmpath";
my($alien_with_xs_load, @rest) = grep { $_->can('xs_load') } @aliens;
if($alien_with_xs_load)
{
{
no strict 'refs';
@{join '::', $module, 'rest'} = @rest;
${join '::', $module, 'alien_with_xs_load'} = $alien_with_xs_load;
}
print $fh '# line '. __LINE__ . ' "' . __FILE__ . qq("\n) . qq{
package $module;
use strict;
use warnings;
our \$VERSION = '0.01';
our \@rest;
our \$alien_with_xs_load;
\$alien_with_xs_load->xs_load('$module', \$VERSION, \@rest);
1;
};
}
else
{
print $fh '# line '. __LINE__ . ' "' . __FILE__ . qq("\n) . qq{
package $module;
use strict;
use warnings;
require XSLoader;
our \$VERSION = '0.01';
XSLoader::load('$module',\$VERSION);
1;
};
}
close $fh;
{
local @INC = @INC;
unshift @INC, "$dir";
## no critic
eval '# line '. __LINE__ . ' "' . __FILE__ . qq("\n) . qq{
use $module;
};
## use critic
}
if(my $error = $@)
{
$ok = 0;
push @diag, ' XSLoader failed';
push @diag, " $error";
}
}
}
}
$ctx->ok($ok, $message);
$ctx->diag($_) for @diag;
$ctx->release;
unless($ok || defined $ENV{TEST_ALIEN_ALWAYS_KEEP})
{
$ctx->note("keeping XS temporary directory $dir due to failure");
$dir->unlink_on_destroy(0);
}
if($cb)
{
$cb = sub {
my $ctx = context();
$ctx->plan(0, 'SKIP', "subtest requires xs success");
$ctx->release;
} unless $ok;
@_ = ("$message subtest", $cb, 1, $module);
goto \&Test2::API::run_subtest;
}
$ok;
}
sub with_subtest (&)
{
my($code) = @_;
# it may be possible to catch a segmentation fault,
# but not with signal handlers apparently. See:
# https://feepingcreature.github.io/handling.html
return $code if $^O eq 'MSWin32';
# try to catch a segmentation fault and bail out
# with a useful diagnostic. prove test to swallow
# the diagnostic on such failures.
sub {
local $SIG{SEGV} = sub {
my $ctx = context();
$ctx->bail("Segmentation fault");
};
$code->(@_);
}
}
sub ffi_ok
{
my $cb;
$cb = pop if defined $_[-1] && ref $_[-1] eq 'CODE';
my($opt, $message) = @_;
$message ||= 'ffi';
my $ok = 1;
my $skip;
my $ffi;
my @diag;
{
my $min = '0.12'; # the first CPAN release
$min = '0.15' if $opt->{ignore_not_found};
$min = '0.18' if $opt->{lang};
$min = '0.99' if defined $opt->{api} && $opt->{api} > 0;
unless(eval { require FFI::Platypus; FFI::Platypus->VERSION($min) })
{
$ok = 0;
$skip = "Test requires FFI::Platypus $min";
}
}
if($ok && $opt->{lang})
{
my $class = "FFI::Platypus::Lang::@{[ $opt->{lang} ]}";
{
my $pm = "$class.pm";
$pm =~ s/::/\//g;
eval { require $pm };
}
if($@)
{
$ok = 0;
$skip = "Test requires FFI::Platypus::Lang::@{[ $opt->{lang} ]}";
}
}
unless(@aliens || $ENV{TEST_ALIEN_ALIENS_MISSING})
{
push @diag, 'ffi_ok called without any aliens, you may want to call alien_ok';
}
if($ok)
{
$ffi = FFI::Platypus->new(
do {
my @args = (
lib => [map { $_->dynamic_libs } @aliens],
ignore_not_found => $opt->{ignore_not_found},
lang => $opt->{lang},
);
push @args, api => $opt->{api} if defined $opt->{api};
@args;
}
);
foreach my $symbol (@{ $opt->{symbols} || [] })
{
unless($ffi->find_symbol($symbol))
{
$ok = 0;
push @diag, " $symbol not found"
}
}
}
my $ctx = context();
if($skip)
{
$ctx->skip($message, $skip);
}
else
{
$ctx->ok($ok, $message);
}
$ctx->diag($_) for @diag;
$ctx->release;
if($cb)
{
$cb = sub {
my $ctx = context();
$ctx->plan(0, 'SKIP', "subtest requires ffi success");
$ctx->release;
} unless $ok;
@_ = ("$message subtest", $cb, 1, $ffi);
goto \&Test2::API::run_subtest;
}
$ok;
}
{
my @ret;
sub _interpolator
{
return @ret if @ret;
require Alien::Build::Interpolate::Default;
my $intr = Alien::Build::Interpolate::Default->new;
require Alien::Build;
my $build = Alien::Build->new;
$build->meta->interpolator($intr);
@ret = ($intr, $build);
}
}
sub helper_ok
{
my($name, $message) = @_;
$message ||= "helper $name exists";
my($intr) = _interpolator;
my $code = $intr->has_helper($name);
my $ok = defined $code;
my $ctx = context();
$ctx->ok($ok, $message);
$ctx->diag("helper_ok called without any aliens, you may want to call alien_ok") unless @aliens || $ENV{TEST_ALIEN_ALIENS_MISSING};
$ctx->release;
$ok;
}
sub plugin_ok
{
my($name, $message) = @_;
my @args;
($name, @args) = @$name if ref $name;
$message ||= "plugin $name";
my($intr, $build) = _interpolator;
my $class = "Alien::Build::Plugin::$name";
my $pm = "$class.pm";
$pm =~ s/::/\//g;
my $ctx = context();
my $plugin = eval {
require $pm unless $class->can('new');
$class->new(@args);
};
if(my $error = $@)
{
$ctx->ok(0, $message, ['unable to create $name plugin', $error]);
$ctx->release;
return 0;
}
eval {
$plugin->init($build->meta);
};
if($^O eq 'MSWin32' && ($plugin->isa('Alien::Build::Plugin::Build::MSYS') || $plugin->isa('Alien::Build::Plugin::Build::Autoconf')))
{
require Alien::MSYS;
unshift @PATH, Alien::MSYS::msys_path();
}
if(my $error = $@)
{
$ctx->ok(0, $message, ['unable to initiate $name plugin', $error]);
$ctx->release;
return 0;
}
else
{
$ctx->ok(1, $message);
$ctx->release;
return 1;
}
}
sub interpolate_template_is
{
my($template, $pattern, $message) = @_;
$message ||= "template matches";
my($intr) = _interpolator;
my $value = eval { $intr->interpolate($template) };
my $error = $@;
my @diag;
my $ok;
if($error)
{
$ok = 0;
push @diag, "error in evaluation:";
push @diag, " $error";
}
elsif(ref($pattern) eq 'Regexp')
{
$ok = $value =~ $pattern;
push @diag, "value '$value' does not match $pattern'" unless $ok;
}
else
{
$ok = $value eq "$pattern";
push @diag, "value '$value' does not equal '$pattern'" unless $ok;
}
my $ctx = context();
$ctx->ok($ok, $message, [@diag]);
$ctx->diag('interpolate_template_is called without any aliens, you may want to call alien_ok') unless @aliens || $ENV{TEST_ALIEN_ALIENS_MISSING};
$ctx->release;
$ok;
}
sub interpolate_run_ok
{
my($template, $message) = @_;
my(@template) = ref $template ? @$template : ($template);
my($intr) = _interpolator;
my $ok = 1;
my @diag;
my @command;
foreach my $template (@template)
{
my $command = eval { $intr->interpolate($template) };
if(my $error = $@)
{
$ok = 0;
push @diag, "error in evaluation:";
push @diag, " $error";
}
else
{
push @command, $command;
}
}
my $ctx = context();
if($ok)
{
my $command = ref $template ? \@command : $command[0];
$ok = run_ok($command, $message);
}
else
{
$message ||= "run @template";
$ctx->ok($ok, $message, [@diag]);
$ctx->diag('interpolate_run_ok called without any aliens, you may want to call alien_ok') unless @aliens || $ENV{TEST_ALIEN_ALIENS_MISSING};
}
$ctx->release;
$ok;
}
1;
__END__
=pod
=encoding UTF-8
=head1 NAME
Test::Alien - Testing tools for Alien modules
=head1 VERSION
version 2.84
=head1 SYNOPSIS
Test commands that come with your Alien:
use Test2::V0;
use Test::Alien;
use Alien::patch;
alien_ok 'Alien::patch';
run_ok([ 'patch', '--version' ])
->success
# we only accept the version written
# by Larry ...
->out_like(qr{Larry Wall});
done_testing;
Test that your library works with C<XS>:
use Test2::V0;
use Test::Alien;
use Alien::Editline;
alien_ok 'Alien::Editline';
my $xs = do { local $/; <DATA> };
xs_ok $xs, with_subtest {
my($module) = @_;
ok $module->version;
};
done_testing;
__DATA__
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include <editline/readline.h>
const char *
version(const char *class)
{
return rl_library_version;
}
MODULE = TA_MODULE PACKAGE = TA_MODULE
const char *version(class);
const char *class;
Test that your library works with L<FFI::Platypus>:
use Test2::V0;
use Test::Alien;
use Alien::LibYAML;
alien_ok 'Alien::LibYAML';
ffi_ok { symbols => ['yaml_get_version'] }, with_subtest {
my($ffi) = @_;
my $get_version = $ffi->function(yaml_get_version => ['int*','int*','int*'] => 'void');
$get_version->call(\my $major, \my $minor, \my $patch);
like $major, qr{[0-9]+};
like $minor, qr{[0-9]+};
like $patch, qr{[0-9]+};
};
done_testing;
=head1 DESCRIPTION
This module provides tools for testing L<Alien> modules. It has hooks
to work easily with L<Alien::Base> based modules, but can also be used
via the synthetic interface to test non L<Alien::Base> based L<Alien>
modules. It has very modest prerequisites.
Prior to this module the best way to test a L<Alien> module was via L<Test::CChecker>.
The main downside to that module is that it is heavily influenced by and uses
L<ExtUtils::CChecker>, which is a tool for checking at install time various things
about your compiler. It was also written before L<Alien::Base> became as stable as it
is today. In particular, L<Test::CChecker> does its testing by creating an executable
and running it. Unfortunately Perl uses extensions by creating dynamic libraries
and linking them into the Perl process, which is different in subtle and error prone
ways. This module attempts to test the libraries in the way that they will actually
be used, via either C<XS> or L<FFI::Platypus>. It also provides a mechanism for
testing binaries that are provided by the various L<Alien> modules (for example
L<Alien::gmake> and L<Alien::patch>).
L<Alien> modules can actually be usable without a compiler, or without L<FFI::Platypus>
(for example, if the library is provided by the system, and you are using L<FFI::Platypus>,
or if you are building from source and you are using C<XS>), so tests with missing
prerequisites are automatically skipped. For example, L</xs_ok> will automatically skip
itself if a compiler is not found, and L</ffi_ok> will automatically skip itself
if L<FFI::Platypus> is not installed.
=head1 FUNCTIONS
=head2 alien_ok
alien_ok $alien, $message;
alien_ok $alien;
Load the given L<Alien> instance or class. Checks that the instance or class conforms to the same
interface as L<Alien::Base>. Will be used by subsequent tests. The C<$alien> module only needs to
provide these methods in order to conform to the L<Alien::Base> interface:
=over 4
=item cflags
String containing the compiler flags
=item libs
String containing the linker and library flags
=item dynamic_libs
List of dynamic libraries. Returns empty list if the L<Alien> module does not provide this.
=item bin_dir
Directory containing tool binaries. Returns empty list if the L<Alien> module does not provide
this.
=back
If your L<Alien> module does not conform to this interface then you can create a synthetic L<Alien>
module using the L</synthetic> function.
=head2 synthetic
my $alien = synthetic \%config;
Create a synthetic L<Alien> module which can be passed into L</alien_ok>. C<\%config>
can contain these keys (all of which are optional):
=over 4
=item cflags
String containing the compiler flags.
=item cflags_static
String containing the static compiler flags (optional).
=item libs
String containing the linker and library flags.
=item libs_static
String containing the static linker flags (optional).
=item dynamic_libs
List reference containing the dynamic libraries.
=item bin_dir
Tool binary directory.
=item runtime_prop
Runtime properties.
=back
See L<Test::Alien::Synthetic> for more details.
=head2 run_ok
my $run = run_ok $command;
my $run = run_ok $command, $message;
Runs the given command, falling back on any C<Alien::Base#bin_dir> methods provided by L<Alien> modules
specified with L</alien_ok>.
C<$command> can be either a string or an array reference.
Only fails if the command cannot be found, or if it is killed by a signal! Returns a L<Test::Alien::Run>
object, which you can use to test the exit status, output and standard error.
Always returns an instance of L<Test::Alien::Run>, even if the command could not be found.
=head2 xs_ok
xs_ok $xs;
xs_ok $xs, $message;
Compiles, links the given C<XS> code and attaches to Perl.
If you use the special module name C<TA_MODULE> in your C<XS>
code, it will be replaced by an automatically generated
package name. This can be useful if you want to pass the same
C<XS> code to multiple calls to C<xs_ok> without subsequent
calls replacing previous ones.
C<$xs> may be either a string containing the C<XS> code,
or a hash reference with these keys:
=over 4
=item xs
The XS code. This is the only required element.
=item pxs
Extra L<ExtUtils::ParseXS> arguments passed in as a hash reference.
=item cbuilder_check
The compile check that should be done prior to attempting to build.
Should be one of C<have_compiler> or C<have_cplusplus>. Defaults
to C<have_compiler>.
=item cbuilder_config
Hash to override values normally provided by C<Config>.
=item cbuilder_compile
Extra The L<ExtUtils::CBuilder> arguments passed in as a hash reference.
=item cbuilder_link
Extra The L<ExtUtils::CBuilder> arguments passed in as a hash reference.
=item verbose
Spew copious debug information via test note.
=back
You can use the C<with_subtest> keyword to conditionally
run a subtest if the C<xs_ok> call succeeds. If C<xs_ok>
does not work, then the subtest will automatically be
skipped. Example:
xs_ok $xs, with_subtest {
# skipped if $xs fails for some reason
my($module) = @_;
is $module->foo, 1;
};
The module name detected during the XS parsing phase will
be passed in to the subtest. This is helpful when you are
using a generated module name.
If you need to test XS C++ interfaces, see L<Test::Alien::CPP>.
Caveats: C<xs_ok> uses L<ExtUtils::ParseXS>, which may call C<exit>
under certain error conditions. While this is not really good
thing to happen in the middle of a test, it usually indicates
a real failure condition, and it should return a failure condition
so the test should still fail overall.
[version 2.53]
As of version 2.53, C<xs_ok> will only remove temporary generated files
if the test is successful by default. You can force either always
or never removing the temporary generated files using the
C<TEST_ALIEN_ALWAYS_KEEP> environment variable (see L</ENVIRONMENT> below).
=head2 ffi_ok
ffi_ok;
ffi_ok \%opt;
ffi_ok \%opt, $message;
Test that L<FFI::Platypus> works.
C<\%opt> is a hash reference with these keys (all optional):
=over 4
=item symbols
List references of symbols that must be found for the test to succeed.
=item ignore_not_found
Ignores symbols that aren't found. This affects functions accessed via
L<FFI::Platypus#attach> and L<FFI::Platypus#function> methods, and does
not influence the C<symbols> key above.
=item lang
Set the language. Used primarily for language specific native types.
=item api
Set the API. C<api = 1> requires FFI::Platypus 0.99 or later. This
option was added with Test::Alien version 1.90, so your use line should
include this version as a safeguard to make sure it works:
use Test::Alien 1.90;
...
ffi_ok ...;
=back
As with L</xs_ok> above, you can use the C<with_subtest> keyword to specify
a subtest to be run if C<ffi_ok> succeeds (it will skip otherwise). The
L<FFI::Platypus> instance is passed into the subtest as the first argument.
For example:
ffi_ok with_subtest {
my($ffi) = @_;
is $ffi->function(foo => [] => 'void')->call, 42;
};
=head2 helper_ok
helper_ok $name;
helper_ok $name, $message;
Tests that the given helper has been defined.
=head2 plugin_ok
[version 2.52]
plugin_ok $plugin_name, $message;
plugin_ok [$plugin_name, @args], $message;
This applies an L<Alien::Build::Plugin> to the interpolator used by L</helper_ok>, L</interpolate_template_is>
and L</interpolate_run_ok> so that you can test with any helpers that plugin provides. Useful,
for example for getting C<%{configure}> from L<Alien::Build::Plugin::Build::Autoconf>.
=head2 interpolate_template_is
interpolate_template_is $template, $string;
interpolate_template_is $template, $string, $message;
interpolate_template_is $template, $regex;
interpolate_template_is $template, $regex, $message;
Tests that the given template when evaluated with the appropriate helpers will match
either the given string or regular expression.
=head2 interpolate_run_ok
[version 2.52]
my $run = interpolate_run_ok $command;
my $run = interpolate_run_ok $command, $message;
This is the same as L</run_ok> except it runs the command through the interpolator first.
=head1 ENVIRONMENT
=over 4
=item C<TEST_ALIEN_ALWAYS_KEEP>
If this is defined then it will override the built in logic that decides if
the temporary files generated by L</xs_ok> should be kept when the test file
terminates. If set to true the generated files will always be kept. If
set to false, then they will always be removed.
=item C<TEST_ALIEN_ALIENS_MISSING>
By default, this module will warn you if some tools are used without first
invoking L</alien_ok>. This is usually a mistake, but if you really do
want to use one of these tools with no aliens loaded, you can set this
environment variable to false.
=back
=head1 SEE ALSO
=over 4
=item L<Alien>
=item L<Alien::Base>
=item L<Alien::Build>
=item L<alienfile>
=item L<Test2>
=item L<Test::Alien::Run>
=item L<Test::Alien::CanCompile>
=item L<Test::Alien::CanPlatypus>
=item L<Test::Alien::Synthetic>
=item L<Test::Alien::CPP>
=back
=head1 AUTHOR
Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>
Contributors:
Diab Jerius (DJERIUS)
Roy Storey (KIWIROY)
Ilya Pavlov
David Mertens (run4flat)
Mark Nunberg (mordy, mnunberg)
Christian Walde (Mithaldu)
Brian Wightman (MidLifeXis)
Zaki Mughal (zmughal)
mohawk (mohawk2, ETJ)
Vikas N Kumar (vikasnkumar)
Flavio Poletti (polettix)
Salvador Fandiño (salva)
Gianni Ceccarelli (dakkar)
Pavel Shaydo (zwon, trinitum)
Kang-min Liu (劉康民, gugod)
Nicholas Shipp (nshp)
Juan Julián Merelo Guervós (JJ)
Joel Berger (JBERGER)
Petr Písař (ppisar)
Lance Wicks (LANCEW)
Ahmad Fatoum (a3f, ATHREEF)
José Joaquín Atria (JJATRIA)
Duke Leto (LETO)
Shoichi Kaji (SKAJI)
Shawn Laffan (SLAFFAN)
Paul Evans (leonerd, PEVANS)
Håkon Hægland (hakonhagland, HAKONH)
nick nauwelaerts (INPHOBIA)
Florian Weimer
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2011-2022 by Graham Ollis.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut
PK 1N%[k��
perl5/Test/Alien/Diag.pmnu ��6�$ package Test::Alien::Diag;
use strict;
use warnings;
use 5.008004;
use Test2::API qw( context );
use Exporter qw( import );
our @EXPORT = qw( alien_diag );
our @EXPORT_OK = @EXPORT;
# ABSTRACT: Print out standard diagnostic for Aliens in the test step.
our $VERSION = '2.84'; # VERSION
my @default_scalar_properties = qw(
cflags cflags_static libs libs_static version install_type
);
my @default_list_properties = qw(
dynamic_libs bin_dir
);
sub alien_diag ($@)
{
my $ctx = context();
my %options = defined $_[-1] && ref($_[-1]) eq 'HASH' ? %{ pop @_ } : ();
my @extra_properties = @{ delete $options{properties} || [] };
my @extra_list_properties = @{ delete $options{list_properties} || [] };
my $max = 0;
foreach my $alien (@_)
{
foreach my $name (@default_scalar_properties, @default_list_properties, @extra_properties, @extra_list_properties)
{
if(eval { $alien->can($name) })
{
my $str = "$alien->$name";
if(length($str) > $max)
{
$max = length($str);
}
}
}
}
$ctx->diag('');
if(%options)
{
my @extra = sort keys %options;
$ctx->diag("warning: unknown option@{[ @extra > 1 ? 's' : '' ]} for alien_diag: @extra");
$ctx->diag("(you should check for typos or maybe upgrade to a newer version of Alien::Build)");
}
foreach my $alien (@_) {
$ctx->diag('') for 1..2;
my $found = 0;
foreach my $name (sort(@default_scalar_properties, @extra_properties))
{
if(eval { $alien->can($name) })
{
$found++;
my $value = $alien->$name;
$value = '[undef]' unless defined $value;
$ctx->diag(sprintf "%-${max}s = %s", "$alien->$name", $value);
}
}
foreach my $name (sort(@default_list_properties, @extra_list_properties))
{
if(eval { $alien->can($name) })
{
$found++;
my @list = eval { $alien->$name };
next if $@;
$ctx->diag(sprintf "%-${max}s = %s", "$alien->$name", $_) for @list;
}
}
$ctx->diag("no diagnostics found for $alien") unless $found;
}
$ctx->diag('') for 1..2;
$ctx->release;
}
1;
__END__
=pod
=encoding UTF-8
=head1 NAME
Test::Alien::Diag - Print out standard diagnostic for Aliens in the test step.
=head1 VERSION
version 2.84
=head1 SYNOPSIS
use Test2::V0;
use Test::Alien::Diag qw( alien_diag );
=head1 DESCRIPTION
This module provides an C<alien_diag> method that prints out diagnostics useful for
cpantesters and other bug reports that gives a quick summary of the important settings
like C<clfags> and C<libs>.
=head1 FUNCTIONS
=head2 alien_diag
alien_diag @aliens;
prints out diagnostics for each given alien. Each alien must be the class
name of an alien.
[version 2.68]
alien_diag @aliens, \%options;
Starting with L<Alien::Build> 2.68, you can provide an option hash to adjust the
behavior of C<alien_diag>. Valid options are:
=over 4
=item properties
Additional properties to display in the diagnostic. Useful when you have an L<Alien>
with custom properties defined in the subclass.
=item list_properties
Additional properties that are returned as a list to display in the diagnostic. Useful
when you have an L<Alien> with customer properties that return a list.
=back
=head1 AUTHOR
Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>
Contributors:
Diab Jerius (DJERIUS)
Roy Storey (KIWIROY)
Ilya Pavlov
David Mertens (run4flat)
Mark Nunberg (mordy, mnunberg)
Christian Walde (Mithaldu)
Brian Wightman (MidLifeXis)
Zaki Mughal (zmughal)
mohawk (mohawk2, ETJ)
Vikas N Kumar (vikasnkumar)
Flavio Poletti (polettix)
Salvador Fandiño (salva)
Gianni Ceccarelli (dakkar)
Pavel Shaydo (zwon, trinitum)
Kang-min Liu (劉康民, gugod)
Nicholas Shipp (nshp)
Juan Julián Merelo Guervós (JJ)
Joel Berger (JBERGER)
Petr Písař (ppisar)
Lance Wicks (LANCEW)
Ahmad Fatoum (a3f, ATHREEF)
José Joaquín Atria (JJATRIA)
Duke Leto (LETO)
Shoichi Kaji (SKAJI)
Shawn Laffan (SLAFFAN)
Paul Evans (leonerd, PEVANS)
Håkon Hægland (hakonhagland, HAKONH)
nick nauwelaerts (INPHOBIA)
Florian Weimer
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2011-2022 by Graham Ollis.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut
PK 1N%[�!m�d d perl5/Test/Alien/Run.pmnu ��6�$ package Test::Alien::Run;
use strict;
use warnings;
use 5.008004;
use Test2::API qw( context );
# ABSTRACT: Run object
our $VERSION = '2.84'; # VERSION
sub out { shift->{out} }
sub err { shift->{err} }
sub exit { shift->{exit} }
sub signal { shift->{sig} }
sub success
{
my($self, $message) = @_;
$message ||= 'command succeeded';
my $ok = $self->exit == 0 && $self->signal == 0;
$ok = 0 if $self->{fail};
my $ctx = context();
$ctx->ok($ok, $message);
unless($ok)
{
$ctx->diag(" command exited with @{[ $self->exit ]}") if $self->exit;
$ctx->diag(" command killed with @{[ $self->signal ]}") if $self->signal;
$ctx->diag(" @{[ $self->{fail} ]}") if $self->{fail};
}
$ctx->release;
$self;
}
sub exit_is
{
my($self, $exit, $message) = @_;
$message ||= "command exited with value $exit";
my $ok = $self->exit == $exit;
my $ctx = context();
$ctx->ok($ok, $message);
$ctx->diag(" actual exit value was: @{[ $self->exit ]}") unless $ok;
$ctx->release;
$self;
}
sub exit_isnt
{
my($self, $exit, $message) = @_;
$message ||= "command exited with value not $exit";
my $ok = $self->exit != $exit;
my $ctx = context();
$ctx->ok($ok, $message);
$ctx->diag(" actual exit value was: @{[ $self->exit ]}") unless $ok;
$ctx->release;
$self;
}
sub _like
{
my($self, $regex, $source, $not, $message) = @_;
my $ok = $self->{$source} =~ $regex;
$ok = !$ok if $not;
my $ctx = context();
$ctx->ok($ok, $message);
unless($ok)
{
$ctx->diag(" $source:");
$ctx->diag(" $_") for split /\r?\n/, $self->{$source};
$ctx->diag($not ? ' matches:' : ' does not match:');
$ctx->diag(" $regex");
}
$ctx->release;
$self;
}
sub out_like
{
my($self, $regex, $message) = @_;
$message ||= "output matches $regex";
$self->_like($regex, 'out', 0, $message);
}
sub out_unlike
{
my($self, $regex, $message) = @_;
$message ||= "output does not match $regex";
$self->_like($regex, 'out', 1, $message);
}
sub err_like
{
my($self, $regex, $message) = @_;
$message ||= "standard error matches $regex";
$self->_like($regex, 'err', 0, $message);
}
sub err_unlike
{
my($self, $regex, $message) = @_;
$message ||= "standard error does not match $regex";
$self->_like($regex, 'err', 1, $message);
}
sub note
{
my($self) = @_;
my $ctx = context();
$ctx->note("[cmd]");
$ctx->note(" @{$self->{cmd}}");
if($self->out ne '')
{
$ctx->note("[out]");
$ctx->note(" $_") for split /\r?\n/, $self->out;
}
if($self->err ne '')
{
$ctx->note("[err]");
$ctx->note(" $_") for split /\r?\n/, $self->err;
}
$ctx->release;
$self;
}
sub diag
{
my($self) = @_;
my $ctx = context();
$ctx->diag("[cmd]");
$ctx->diag(" @{$self->{cmd}}");
if($self->out ne '')
{
$ctx->diag("[out]");
$ctx->diag(" $_") for split /\r?\n/, $self->out;
}
if($self->err ne '')
{
$ctx->diag("[err]");
$ctx->diag(" $_") for split /\r?\n/, $self->err;
}
$ctx->release;
$self;
}
1;
__END__
=pod
=encoding UTF-8
=head1 NAME
Test::Alien::Run - Run object
=head1 VERSION
version 2.84
=head1 SYNOPSIS
use Test2::V0;
use Test::Alien;
run_ok([ $^X, -e => 'print "some output"; exit 22'])
->exit_is(22)
->out_like(qr{some});
=head1 DESCRIPTION
This class stores information about a process run as performed by
L<Test::Alien#run_ok>. That function is the I<ONLY> way to create
an instance of this class.
=head1 ATTRIBUTES
=head2 out
my $str = $run->out;
The standard output from the run.
=head2 err
my $str = $run->err;
The standard error from the run.
=head2 exit
my $int = $run->exit;
The exit value of the run.
=head2 signal
my $int = $run->signal;
The signal that killed the run, or zero if the process was terminated normally.
=head1 METHODS
These methods return the run object itself, so they can be chained,
as in the synopsis above.
=head2 success
$run->success;
$run->success($message);
Passes if the process terminated normally with an exit value of 0.
=head2 exit_is
$run->exit_is($exit);
$run->exit_is($exit, $message);
Passes if the process terminated with the given exit value.
=head2 exit_isnt
$run->exit_isnt($exit);
$run->exit_isnt($exit, $message);
Passes if the process terminated with an exit value of anything
but the given value.
=head2 out_like
$run->out_like($regex);
$run->out_like($regex, $message);
Passes if the output of the run matches the given pattern.
=head2 out_unlike
$run->out_unlike($regex);
$run->out_unlike($regex, $message);
Passes if the output of the run does not match the given pattern.
=head2 err_like
$run->err_like($regex);
$run->err_like($regex, $message);
Passes if the standard error of the run matches the given pattern.
=head2 err_unlike
$run->err_unlike($regex);
$run->err_unlike($regex, $message);
Passes if the standard error of the run does not match the given pattern.
=head2 note
$run->note;
Send the output and standard error as test note.
=head2 diag
$run->diag;
Send the output and standard error as test diagnostic.
=head1 SEE ALSO
=over 4
=item L<Test::Alien>
=back
=head1 AUTHOR
Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>
Contributors:
Diab Jerius (DJERIUS)
Roy Storey (KIWIROY)
Ilya Pavlov
David Mertens (run4flat)
Mark Nunberg (mordy, mnunberg)
Christian Walde (Mithaldu)
Brian Wightman (MidLifeXis)
Zaki Mughal (zmughal)
mohawk (mohawk2, ETJ)
Vikas N Kumar (vikasnkumar)
Flavio Poletti (polettix)
Salvador Fandiño (salva)
Gianni Ceccarelli (dakkar)
Pavel Shaydo (zwon, trinitum)
Kang-min Liu (劉康民, gugod)
Nicholas Shipp (nshp)
Juan Julián Merelo Guervós (JJ)
Joel Berger (JBERGER)
Petr Písař (ppisar)
Lance Wicks (LANCEW)
Ahmad Fatoum (a3f, ATHREEF)
José Joaquín Atria (JJATRIA)
Duke Leto (LETO)
Shoichi Kaji (SKAJI)
Shawn Laffan (SLAFFAN)
Paul Evans (leonerd, PEVANS)
Håkon Hægland (hakonhagland, HAKONH)
nick nauwelaerts (INPHOBIA)
Florian Weimer
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2011-2022 by Graham Ollis.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut
PK 1N%[�Ո� � perl5/Test/Alien/CanCompile.pmnu ��6�$ package Test::Alien::CanCompile;
use strict;
use warnings;
use 5.008004;
use Test2::API qw( context );
# ABSTRACT: Skip a test file unless a C compiler is available
our $VERSION = '2.84'; # VERSION
sub skip
{
require ExtUtils::CBuilder;
ExtUtils::CBuilder->new->have_compiler ? undef : 'This test requires a compiler.';
}
sub import
{
my $skip = __PACKAGE__->skip;
return unless defined $skip;
my $ctx = context();
$ctx->plan(0, SKIP => $skip);
$ctx->release;
}
1;
__END__
=pod
=encoding UTF-8
=head1 NAME
Test::Alien::CanCompile - Skip a test file unless a C compiler is available
=head1 VERSION
version 2.84
=head1 SYNOPSIS
use Test::Alien::CanCompile;
=head1 DESCRIPTION
This is just a L<Test2> plugin that requires that a compiler
be available. Otherwise the test will be skipped.
=head1 SEE ALSO
=over 4
=item L<Test::Alien>
=back
=head1 AUTHOR
Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>
Contributors:
Diab Jerius (DJERIUS)
Roy Storey (KIWIROY)
Ilya Pavlov
David Mertens (run4flat)
Mark Nunberg (mordy, mnunberg)
Christian Walde (Mithaldu)
Brian Wightman (MidLifeXis)
Zaki Mughal (zmughal)
mohawk (mohawk2, ETJ)
Vikas N Kumar (vikasnkumar)
Flavio Poletti (polettix)
Salvador Fandiño (salva)
Gianni Ceccarelli (dakkar)
Pavel Shaydo (zwon, trinitum)
Kang-min Liu (劉康民, gugod)
Nicholas Shipp (nshp)
Juan Julián Merelo Guervós (JJ)
Joel Berger (JBERGER)
Petr Písař (ppisar)
Lance Wicks (LANCEW)
Ahmad Fatoum (a3f, ATHREEF)
José Joaquín Atria (JJATRIA)
Duke Leto (LETO)
Shoichi Kaji (SKAJI)
Shawn Laffan (SLAFFAN)
Paul Evans (leonerd, PEVANS)
Håkon Hægland (hakonhagland, HAKONH)
nick nauwelaerts (INPHOBIA)
Florian Weimer
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2011-2022 by Graham Ollis.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut
PK 1N%[����p p perl5/Test/Alien/Synthetic.pmnu ��6�$ package Test::Alien::Synthetic;
use strict;
use warnings;
use 5.008004;
use Test2::API qw( context );
# ABSTRACT: A mock alien object for testing
our $VERSION = '2.84'; # VERSION
sub _def ($) { my($val) = @_; defined $val ? $val : '' }
sub cflags { _def shift->{cflags} }
sub libs { _def shift->{libs} }
sub dynamic_libs { @{ shift->{dynamic_libs} || [] } }
sub runtime_prop
{
my($self) = @_;
defined $self->{runtime_prop}
? $self->{runtime_prop}
: {};
}
sub cflags_static
{
my($self) = @_;
defined $self->{cflags_static}
? $self->{cflags_static}
: $self->cflags;
}
sub libs_static
{
my($self) = @_;
defined $self->{libs_static}
? $self->{libs_static}
: $self->libs;
}
sub bin_dir
{
my $dir = shift->{bin_dir};
defined $dir && -d $dir ? ($dir) : ();
}
1;
__END__
=pod
=encoding UTF-8
=head1 NAME
Test::Alien::Synthetic - A mock alien object for testing
=head1 VERSION
version 2.84
=head1 SYNOPSIS
use Test2::V0;
use Test::Alien;
my $alien = synthetic {
cflags => '-I/foo/bar/include',
libs => '-L/foo/bar/lib -lbaz',
};
alien_ok $alien;
done_testing;
=head1 DESCRIPTION
This class is used to model a synthetic L<Alien>
class that implements the minimum L<Alien::Base>
interface needed by L<Test::Alien>.
It can be useful if you have a non-L<Alien::Base>
based L<Alien> distribution that you need to test.
B<NOTE>: The name of this class may move in the
future, so do not refer to this class name directly.
Instead create instances of this class using the
L<Test::Alien#synthetic> function.
=head1 ATTRIBUTES
=head2 cflags
String containing the compiler flags
=head2 cflags_static
String containing the static compiler flags
=head2 libs
String containing the linker and library flags
=head2 libs_static
String containing the static linker and library flags
=head2 dynamic_libs
List reference containing the dynamic libraries.
=head2 bin_dir
Tool binary directory.
=head2 runtime_prop
Runtime properties.
=head1 EXAMPLE
Here is a complete example using L<Alien::Libarchive> which is a non-L<Alien::Base>
based L<Alien> distribution.
use strict;
use warnings;
use Test2::V0;
use Test::Alien;
use Alien::Libarchive;
my $real = Alien::Libarchive->new;
my $alien = synthetic {
cflags => scalar $real->cflags,
libs => scalar $real->libs,
dynamic_libs => [$real->dlls],
};
alien_ok $alien;
xs_ok do { local $/; <DATA> }, with_subtest {
my($module) = @_;
my $ptr = $module->archive_read_new;
like $ptr, qr{^[0-9]+$};
$module->archive_read_free($ptr);
};
ffi_ok { symbols => [qw( archive_read_new )] }, with_subtest {
my($ffi) = @_;
my $new = $ffi->function(archive_read_new => [] => 'opaque');
my $free = $ffi->function(archive_read_close => ['opaque'] => 'void');
my $ptr = $new->();
like $ptr, qr{^[0-9]+$};
$free->($ptr);
};
done_testing;
__DATA__
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include <archive.h>
MODULE = TA_MODULE PACKAGE = TA_MODULE
void *archive_read_new(class);
const char *class;
CODE:
RETVAL = (void*) archive_read_new();
OUTPUT:
RETVAL
void archive_read_free(class, ptr);
const char *class;
void *ptr;
CODE:
archive_read_free(ptr);
=head1 SEE ALSO
=over 4
=item L<Test::Alien>
=back
=head1 AUTHOR
Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>
Contributors:
Diab Jerius (DJERIUS)
Roy Storey (KIWIROY)
Ilya Pavlov
David Mertens (run4flat)
Mark Nunberg (mordy, mnunberg)
Christian Walde (Mithaldu)
Brian Wightman (MidLifeXis)
Zaki Mughal (zmughal)
mohawk (mohawk2, ETJ)
Vikas N Kumar (vikasnkumar)
Flavio Poletti (polettix)
Salvador Fandiño (salva)
Gianni Ceccarelli (dakkar)
Pavel Shaydo (zwon, trinitum)
Kang-min Liu (劉康民, gugod)
Nicholas Shipp (nshp)
Juan Julián Merelo Guervós (JJ)
Joel Berger (JBERGER)
Petr Písař (ppisar)
Lance Wicks (LANCEW)
Ahmad Fatoum (a3f, ATHREEF)
José Joaquín Atria (JJATRIA)
Duke Leto (LETO)
Shoichi Kaji (SKAJI)
Shawn Laffan (SLAFFAN)
Paul Evans (leonerd, PEVANS)
Håkon Hægland (hakonhagland, HAKONH)
nick nauwelaerts (INPHOBIA)
Florian Weimer
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2011-2022 by Graham Ollis.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut
PK 1N%[�\-�E E perl5/Test/Alien/Build.pmnu ��6�$ package Test::Alien::Build;
use strict;
use warnings;
use 5.008004;
use Exporter qw( import );
use Path::Tiny qw( path );
use Carp qw( croak );
use Test2::API qw( context run_subtest );
use Capture::Tiny qw( capture_merged );
use Alien::Build::Util qw( _mirror );
use List::Util 1.33 qw( any );
use Alien::Build::Temp;
our @EXPORT = qw(
alienfile
alienfile_ok
alienfile_skip_if_missing_prereqs
alien_download_ok
alien_extract_ok
alien_build_ok
alien_build_clean
alien_clean_install
alien_install_type_is
alien_checkpoint_ok
alien_resume_ok
alien_subtest
alien_rc
);
# ABSTRACT: Tools for testing Alien::Build + alienfile
our $VERSION = '2.84'; # VERSION
my $build;
my $build_alienfile;
my $build_root;
my $build_targ;
sub alienfile::targ
{
$build_targ;
}
sub alienfile
{
my($package, $filename, $line) = caller;
($package, $filename, $line) = caller(2) if $package eq __PACKAGE__;
$filename = path($filename)->absolute;
my %args = @_ == 0 ? (filename => 'alienfile') : @_ % 2 ? ( source => do { '# line '. $line . ' "' . path($filename)->absolute . qq("\n) . $_[0] }) : @_;
require alienfile;
push @alienfile::EXPORT, 'targ' unless any { /^targ$/ } @alienfile::EXPORT;
my $temp = Alien::Build::Temp->newdir;
my $get_temp_root = do{
my $root; # may be undef;
sub {
$root ||= Path::Tiny->new($temp);
if(@_)
{
my $path = $root->child(@_);
$path->mkpath;
$path;
}
else
{
return $root;
}
};
};
if($args{source})
{
my $file = $get_temp_root->()->child('alienfile');
$file->spew_utf8($args{source});
$args{filename} = $file->stringify;
}
else
{
unless(defined $args{filename})
{
croak "You must specify at least one of filename or source";
}
$args{filename} = path($args{filename})->absolute->stringify;
}
$args{stage} ||= $get_temp_root->('stage')->stringify;
$args{prefix} ||= $get_temp_root->('prefix')->stringify;
$args{root} ||= $get_temp_root->('root')->stringify;
require Alien::Build;
_alienfile_clear();
my $out = capture_merged {
$build_targ = $args{targ};
$build = Alien::Build->load($args{filename}, root => $args{root});
$build->set_stage($args{stage});
$build->set_prefix($args{prefix});
};
my $ctx = context();
$ctx->note($out) if $out;
$ctx->release;
$build_alienfile = $args{filename};
$build_root = $temp;
$build
}
sub _alienfile_clear
{
eval { defined $build_root && -d $build_root && path($build_root)->remove_tree };
undef $build;
undef $build_alienfile;
undef $build_root;
undef $build_targ;
}
sub alienfile_ok
{
my $build;
my $name;
my $error;
if(@_ == 1 && ! defined $_[0])
{
$build = $_[0];
$error = 'no alienfile given';
$name = 'alienfile compiled';
}
elsif(@_ == 1 && eval { $_[0]->isa('Alien::Build') })
{
$build = $_[0];
$name = 'alienfile compiled';
}
else
{
$build = eval { alienfile(@_) };
$error = $@;
$name = 'alienfile compiles';
}
my $ok = !! $build;
my $ctx = context();
$ctx->ok($ok, $name);
$ctx->diag("error: $error") if $error;
$ctx->release;
$build;
}
sub alienfile_skip_if_missing_prereqs
{
my($phase) = @_;
if($build)
{
eval { $build->load_requires('configure', 1) };
if(my $error = $@)
{
my $reason = "Missing configure prereq";
if($error =~ /Required (.*) (.*),/)
{
$reason .= ": $1 $2";
}
my $ctx = context();
$ctx->plan(0, SKIP => $reason);
$ctx->release;
return;
}
$phase ||= $build->install_type;
eval { $build->load_requires($phase, 1) };
if(my $error = $@)
{
my $reason = "Missing $phase prereq";
if($error =~ /Required (.*) (.*),/)
{
$reason .= ": $1 $2";
}
my $ctx = context();
$ctx->plan(0, SKIP => $reason);
$ctx->release;
return;
}
}
}
sub alien_install_type_is
{
my($type, $name) = @_;
croak "invalid install type" unless defined $type && $type =~ /^(system|share)$/;
$name ||= "alien install type is $type";
my $ok = 0;
my @diag;
if($build)
{
my($out, $actual) = capture_merged {
$build->load_requires('configure');
$build->install_type;
};
if($type eq $actual)
{
$ok = 1;
}
else
{
push @diag, "expected install type of $type, but got $actual";
}
}
else
{
push @diag, 'no alienfile'
}
my $ctx = context();
$ctx->ok($ok, $name);
$ctx->diag($_) for @diag;
$ctx->release;
$ok;
}
sub alien_download_ok
{
my($name) = @_;
$name ||= 'alien download';
my $ok;
my $file;
my @diag;
my @note;
if($build)
{
my($out, $error) = capture_merged {
eval {
$build->load_requires('configure');
$build->load_requires($build->install_type);
$build->download;
};
$@;
};
if($error)
{
$ok = 0;
push @diag, $out if defined $out;
push @diag, "extract threw exception: $error";
}
else
{
$file = $build->install_prop->{download};
if(-d $file || -f $file)
{
$ok = 1;
push @note, $out if defined $out;
}
else
{
$ok = 0;
push @diag, $out if defined $out;
push @diag, 'no file or directory';
}
}
}
else
{
$ok = 0;
push @diag, 'no alienfile';
}
my $ctx = context();
$ctx->ok($ok, $name);
$ctx->note($_) for @note;
$ctx->diag($_) for @diag;
$ctx->release;
$file;
}
sub alien_extract_ok
{
my($archive, $name) = @_;
$name ||= $archive ? "alien extraction of $archive" : 'alien extraction';
my $ok;
my $dir;
my @diag;
my @note;
if($build)
{
my($out, $error);
($out, $dir, $error) = capture_merged {
my $dir = eval {
$build->load_requires('configure');
$build->load_requires($build->install_type);
$build->download;
$build->extract($archive);
};
($dir, $@);
};
if($error)
{
$ok = 0;
push @diag, $out if defined $out;
push @diag, "extract threw exception: $error";
}
else
{
if(-d $dir)
{
$ok = 1;
push @note, $out if defined $out;
}
else
{
$ok = 0;
push @diag, $out if defined $out;
push @diag, 'no directory';
}
}
}
else
{
$ok = 0;
push @diag, 'no alienfile';
}
my $ctx = context();
$ctx->ok($ok, $name);
$ctx->note($_) for @note;
$ctx->diag($_) for @diag;
$ctx->release;
$dir;
}
my $count = 1;
sub alien_build_ok
{
my $opt = defined $_[0] && ref($_[0]) eq 'HASH'
? shift : { class => 'Alien::Base' };
my($name) = @_;
$name ||= 'alien builds okay';
my $ok;
my @diag;
my @note;
my $alien;
if($build)
{
my($out,$error) = capture_merged {
eval {
$build->load_requires('configure');
$build->load_requires($build->install_type);
$build->download;
$build->build;
};
$@;
};
if($error)
{
$ok = 0;
push @diag, $out if defined $out;
push @diag, "build threw exception: $error";
}
else
{
$ok = 1;
push @note, $out if defined $out;
require Alien::Base;
my $prefix = $build->runtime_prop->{prefix};
my $stage = $build->install_prop->{stage};
my %prop = %{ $build->runtime_prop };
$prop{distdir} = $prefix;
_mirror $stage, $prefix;
my $dist_dir = sub {
$prefix;
};
my $runtime_prop = sub {
\%prop;
};
$alien = sprintf 'Test::Alien::Build::Faux%04d', $count++;
{
no strict 'refs';
@{ "${alien}::ISA" } = $opt->{class};
*{ "${alien}::dist_dir" } = $dist_dir;
*{ "${alien}::runtime_prop" } = $runtime_prop;
}
}
}
else
{
$ok = 0;
push @diag, 'no alienfile';
}
my $ctx = context();
$ctx->ok($ok, $name);
$ctx->diag($_) for @diag;
$ctx->note($_) for @note;
$ctx->release;
$alien;
}
sub alien_build_clean
{
my $ctx = context();
if($build_root)
{
foreach my $child (path($build_root)->children)
{
next if $child->basename eq 'prefix';
$ctx->note("clean: rm: $child");
$child->remove_tree;
}
}
else
{
$ctx->note("no build to clean");
}
$ctx->release;
}
sub alien_clean_install
{
my($name) = @_;
$name ||= "run clean_install";
my $ok;
my @diag;
my @note;
if($build)
{
my($out,$error) = capture_merged {
eval {
$build->clean_install;
};
$@;
};
if($error)
{
$ok = 0;
push @diag, $out if defined $out && $out ne '';
push @diag, "build threw exception: $error";
}
else
{
$ok = 1;
push @note, $out if defined $out && $out ne '';
}
}
else
{
$ok = 0;
push @diag, 'no alienfile';
}
my $ctx = context();
$ctx->ok($ok, $name);
$ctx->diag($_) for @diag;
$ctx->note($_) for @note;
$ctx->release;
}
sub alien_checkpoint_ok
{
my($name) = @_;
$name ||= "alien checkpoint ok";
my $ok;
my @diag;
if($build)
{
eval { $build->checkpoint };
if($@)
{
push @diag, "error in checkpoint: $@";
$ok = 0;
}
else
{
$ok = 1;
}
undef $build;
}
else
{
push @diag, "no build to checkpoint";
$ok = 0;
}
my $ctx = context();
$ctx->ok($ok, $name);
$ctx->diag($_) for @diag;
$ctx->release;
$ok;
}
sub alien_resume_ok
{
my($name) = @_;
$name ||= "alien resume ok";
my $ok;
my @diag;
if($build_alienfile && $build_root && !defined $build)
{
$build = eval { Alien::Build->resume($build_alienfile, "$build_root/root") };
if($@)
{
push @diag, "error in resume: $@";
$ok = 0;
}
else
{
$ok = 1;
}
}
else
{
if($build)
{
push @diag, "build has not been checkpointed";
}
else
{
push @diag, "no build to resume";
}
$ok = 0;
}
my $ctx = context();
$ctx->ok($ok, $name);
$ctx->diag($_) for @diag;
$ctx->release;
($ok && $build) || $ok;
}
my $alien_rc_root;
sub alien_rc
{
my($code) = @_;
croak "passed in undef rc" unless defined $code;
croak "looks like you have already defined a rc.pl file" if $ENV{ALIEN_BUILD_RC} ne '-';
my(undef, $filename, $line) = caller;
my $code2 = "use strict; use warnings;\n" .
'# line ' . $line . ' "' . path($filename)->absolute . "\n$code";
$alien_rc_root ||= Alien::Build::Temp->newdir;
my $rc = path($alien_rc_root)->child('rc.pl');
$rc->spew_utf8($code2);
$ENV{ALIEN_BUILD_RC} = "$rc";
return 1;
}
sub alien_subtest
{
my($name, $code, @args) = @_;
_alienfile_clear;
my $ctx = context();
my $pass = run_subtest($name, $code, { buffered => 1 }, @args);
$ctx->release;
_alienfile_clear;
$pass;
}
delete $ENV{$_} for qw( ALIEN_BUILD_LOG ALIEN_BUILD_PRELOAD ALIEN_BUILD_POSTLOAD ALIEN_INSTALL_TYPE PKG_CONFIG_PATH ALIEN_BUILD_PKG_CONFIG );
$ENV{ALIEN_BUILD_RC} = '-';
1;
__END__
=pod
=encoding UTF-8
=head1 NAME
Test::Alien::Build - Tools for testing Alien::Build + alienfile
=head1 VERSION
version 2.84
=head1 SYNOPSIS
use Test2::V0;
use Test::Alien::Build;
# returns an instance of Alien::Build.
my $build = alienfile_ok q{
use alienfile;
plugin 'My::Plugin' => (
foo => 1,
bar => 'string',
...
);
};
alien_build_ok 'builds okay.';
done_testing;
=head1 DESCRIPTION
This module provides some tools for testing L<Alien::Build> and L<alienfile>. Outside of L<Alien::Build>
core development, It is probably most useful for L<Alien::Build::Plugin> developers.
This module also unsets a number of L<Alien::Build> specific environment variables, in order to make tests
reproducible even when overrides are set in different environments. So if you want to test those variables in
various states you should explicitly set them in your test script. These variables are unset if they defined:
C<ALIEN_BUILD_PRELOAD> C<ALIEN_BUILD_POSTLOAD> C<ALIEN_INSTALL_TYPE>.
=head1 FUNCTIONS
=head2 alienfile
my $build = alienfile;
my $build = alienfile q{ use alienfile ... };
my $build = alienfile filename => 'alienfile';
Create a Alien::Build instance from the given L<alienfile>. The first two forms are abbreviations.
my $build = alienfile;
# is the same as
my $build = alienfile filename => 'alienfile';
and
my $build = alienfile q{ use alienfile ... };
# is the same as
my $build = alienfile source => q{ use alienfile ... };
Except for the second abbreviated form sets the line number before feeding the source into L<Alien::Build>
so that you will get diagnostics with the correct line numbers.
=over 4
=item source
The source for the alienfile as a string. You must specify one of C<source> or C<filename>.
=item filename
The filename for the alienfile. You must specify one of C<source> or C<filename>.
=item root
The build root.
=item stage
The staging area for the build.
=item prefix
The install prefix for the build.
=back
=head2 alienfile_ok
my $build = alienfile_ok;
my $build = alienfile_ok q{ use alienfile ... };
my $build = alienfile_ok filename => 'alienfile';
my $build = alienfile_ok $build;
Same as C<alienfile> above, except that it runs as a test, and will not throw an exception
on failure (it will return undef instead).
[version 1.49]
As of version 1.49 you can also pass in an already formed instance of L<Alien::Build>. This
allows you to do something like this:
subtest 'a subtest' => sub {
my $build = alienfile q{ use alienfile; ... };
alienfile_skip_if_missing_prereqs; # skip if alienfile prereqs are missing
alienfile_ok $build; # delayed pass/fail for the compile of alienfile
};
=head2 alienfile_skip_if_missing_prereqs
alienfile_skip_if_missing_prereqs;
alienfile_skip_if_missing_prereqs $phase;
Skips the test or subtest if the prereqs for the alienfile are missing.
If C<$phase> is not given, then either C<share> or C<system> will be
detected.
=head2 alien_install_type_is
alien_install_type_is $type;
alien_install_type_is $type, $name;
Simple test to see if the install type is what you expect.
C<$type> should be one of C<system> or C<share>.
=head2 alien_download_ok
my $file = alien_download_ok;
my $file = alien_download_ok $name;
Makes a download attempt and test that a file or directory results. Returns
the file or directory if successful. Returns C<undef> otherwise.
=head2 alien_extract_ok
my $dir = alien_extract_ok;
my $dir = alien_extract_ok $archive;
my $dir = alien_extract_ok $archive, $name;
my $dir = alien_extract_ok undef, $name;
Makes an extraction attempt and test that a directory results. Returns
the directory if successful. Returns C<undef> otherwise.
=head2 alien_build_ok
my $alien = alien_build_ok;
my $alien = alien_build_ok $name;
my $alien = alien_build_ok { class => $class };
my $alien = alien_build_ok { class => $class }, $name;
Runs the download and build stages. Passes if the build succeeds. Returns an instance
of L<Alien::Base> which can be passed into C<alien_ok> from L<Test::Alien>. Returns
C<undef> if the test fails.
Options
=over 4
=item class
The base class to use for your alien. This is L<Alien::Base> by default. Should
be a subclass of L<Alien::Base>, or at least adhere to its API.
=back
=head2 alien_build_clean
alien_build_clean;
Removes all files with the current build, except for the runtime prefix.
This helps test that the final install won't depend on the build files.
=head2 alien_clean_install
alien_clean_install;
Runs C<$build-E<gt>clean_install>, and verifies it did not crash.
=head2 alien_checkpoint_ok
alien_checkpoint_ok;
alien_checkpoint_ok $test_name;
Test the checkpoint of a build.
=head2 alien_resume_ok
alien_resume_ok;
alien_resume_ok $test_name;
Test a resume a checkpointed build.
=head2 alien_rc
alien_rc $code;
Creates C<rc.pl> file in a temp directory and sets ALIEN_BUILD_RC. Useful for testing
plugins that should be called from C<~/.alienbuild/rc.pl>. Note that because of the
nature of how the C<~/.alienbuild/rc.pl> file works, you can only use this once!
=head2 alien_subtest
alien_subtest $test_name => sub {
...
};
Clear the build object and clear the build object before and after the subtest.
=head1 SEE ALSO
=over 4
=item L<Alien>
=item L<alienfile>
=item L<Alien::Build>
=item L<Test::Alien>
=back
=head1 AUTHOR
Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>
Contributors:
Diab Jerius (DJERIUS)
Roy Storey (KIWIROY)
Ilya Pavlov
David Mertens (run4flat)
Mark Nunberg (mordy, mnunberg)
Christian Walde (Mithaldu)
Brian Wightman (MidLifeXis)
Zaki Mughal (zmughal)
mohawk (mohawk2, ETJ)
Vikas N Kumar (vikasnkumar)
Flavio Poletti (polettix)
Salvador Fandiño (salva)
Gianni Ceccarelli (dakkar)
Pavel Shaydo (zwon, trinitum)
Kang-min Liu (劉康民, gugod)
Nicholas Shipp (nshp)
Juan Julián Merelo Guervós (JJ)
Joel Berger (JBERGER)
Petr Písař (ppisar)
Lance Wicks (LANCEW)
Ahmad Fatoum (a3f, ATHREEF)
José Joaquín Atria (JJATRIA)
Duke Leto (LETO)
Shoichi Kaji (SKAJI)
Shawn Laffan (SLAFFAN)
Paul Evans (leonerd, PEVANS)
Håkon Hægland (hakonhagland, HAKONH)
nick nauwelaerts (INPHOBIA)
Florian Weimer
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2011-2022 by Graham Ollis.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut
PK 1N%[���m� � perl5/Test/Alien/CanPlatypus.pmnu ��6�$ package Test::Alien::CanPlatypus;
use strict;
use warnings;
use 5.008004;
use Test2::API qw( context );
# ABSTRACT: Skip a test file unless FFI::Platypus is available
our $VERSION = '2.84'; # VERSION
sub skip
{
eval { require FFI::Platypus; 1 } ? undef : 'This test requires FFI::Platypus.';
}
sub import
{
my $skip = __PACKAGE__->skip;
return unless defined $skip;
my $ctx = context();
$ctx->plan(0, SKIP => $skip);
$ctx->release;
}
1;
__END__
=pod
=encoding UTF-8
=head1 NAME
Test::Alien::CanPlatypus - Skip a test file unless FFI::Platypus is available
=head1 VERSION
version 2.84
=head1 SYNOPSIS
use Test::Alien::CanPlatypus;
=head1 DESCRIPTION
This is just a L<Test2> plugin that requires that L<FFI::Platypus>
be available. Otherwise the test will be skipped.
=head1 SEE ALSO
=over 4
=item L<Test::Alien>
=item L<FFI::Platypus>
=back
=head1 AUTHOR
Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>
Contributors:
Diab Jerius (DJERIUS)
Roy Storey (KIWIROY)
Ilya Pavlov
David Mertens (run4flat)
Mark Nunberg (mordy, mnunberg)
Christian Walde (Mithaldu)
Brian Wightman (MidLifeXis)
Zaki Mughal (zmughal)
mohawk (mohawk2, ETJ)
Vikas N Kumar (vikasnkumar)
Flavio Poletti (polettix)
Salvador Fandiño (salva)
Gianni Ceccarelli (dakkar)
Pavel Shaydo (zwon, trinitum)
Kang-min Liu (劉康民, gugod)
Nicholas Shipp (nshp)
Juan Julián Merelo Guervós (JJ)
Joel Berger (JBERGER)
Petr Písař (ppisar)
Lance Wicks (LANCEW)
Ahmad Fatoum (a3f, ATHREEF)
José Joaquín Atria (JJATRIA)
Duke Leto (LETO)
Shoichi Kaji (SKAJI)
Shawn Laffan (SLAFFAN)
Paul Evans (leonerd, PEVANS)
Håkon Hægland (hakonhagland, HAKONH)
nick nauwelaerts (INPHOBIA)
Florian Weimer
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2011-2022 by Graham Ollis.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut
PK 1N%[o1D�� � perl5/Scope/Guard.pmnu ��6�$ package Scope::Guard;
use strict;
use warnings;
use Carp qw(confess);
use Exporter ();
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(guard scope_guard);
our $VERSION = '0.21';
sub new {
confess "Can't create a Scope::Guard in void context" unless (defined wantarray);
my $class = shift;
my $handler = shift() || die 'Scope::Guard::new: no handler supplied';
my $ref = ref $handler || '';
die "Scope::Guard::new: invalid handler - expected CODE ref, got: '$ref'"
unless ref($handler) eq 'CODE';
bless [ 0, $handler ], ref $class || $class;
}
sub dismiss {
my $self = shift;
my $dismiss = @_ ? shift : 1;
$self->[0] = $dismiss;
}
sub guard(&) { __PACKAGE__->new(shift) }
sub scope_guard($) { __PACKAGE__->new(shift) }
sub DESTROY {
my $self = shift;
my ($dismiss, $handler) = @$self;
$handler->() unless ($dismiss);
}
1;
__END__
=pod
=head1 NAME
Scope::Guard - lexically-scoped resource management
=head1 SYNOPSIS
my $guard = guard { ... };
# or
my $guard = scope_guard \&handler;
# or
my $guard = Scope::Guard->new(sub { ... });
$guard->dismiss(); # disable the handler
=head1 DESCRIPTION
This module provides a convenient way to perform cleanup or other forms of resource
management at the end of a scope. It is particularly useful when dealing with exceptions:
the C<Scope::Guard> constructor takes a reference to a subroutine that is guaranteed to
be called even if the thread of execution is aborted prematurely. This effectively allows
lexically-scoped "promises" to be made that are automatically honoured by perl's garbage
collector.
For more information, see: L<http://www.drdobbs.com/cpp/184403758>
=head1 METHODS
=head2 new
my $guard = Scope::Guard->new(sub { ... });
# or
my $guard = Scope::Guard->new(\&handler);
The C<new> method creates a new C<Scope::Guard> object which calls the supplied handler when its C<DESTROY> method is
called, typically at the end of the scope.
=head2 dismiss
$guard->dismiss();
# or
$guard->dismiss(1);
C<dismiss> detaches the handler from the C<Scope::Guard> object. This revokes the "promise" to call the
handler when the object is destroyed.
The handler can be re-enabled by calling:
$guard->dismiss(0);
=head1 EXPORTS
=head2 guard
C<guard> takes a block and returns a new C<Scope::Guard> object. It can be used
as a shorthand for:
Scope::Guard->new(...)
e.g.
my $guard = guard { ... };
Note: calling C<guard> anonymously, i.e. in void context, will raise an exception.
This is because anonymous guards are destroyed B<immediately>
(rather than at the end of the scope), which is unlikely to be the desired behaviour.
=head2 scope_guard
C<scope_guard> is the same as C<guard>, but it takes a code ref rather than a block.
e.g.
my $guard = scope_guard \&handler;
or:
my $guard = scope_guard sub { ... };
or:
my $guard = scope_guard $handler;
As with C<guard>, calling C<scope_guard> in void context will raise an exception.
=head1 VERSION
0.21
=head1 SEE ALSO
=over
=item * L<B::Hooks::EndOfScope|B::Hooks::EndOfScope>
=item * L<End|End>
=item * L<Guard|Guard>
=item * L<Hook::Scope|Hook::Scope>
=item * L<Object::Destroyer|Object::Destroyer>
=item * L<Perl::AtEndOfScope|Perl::AtEndOfScope>
=item * L<ReleaseAction|ReleaseAction>
=item * L<Scope::local_OnExit|Scope::local_OnExit>
=item * L<Scope::OnExit|Scope::OnExit>
=item * L<Sub::ScopeFinalizer|Sub::ScopeFinalizer>
=item * L<Value::Canary|Value::Canary>
=back
=head1 AUTHOR
chocolateboy <chocolate@cpan.org>
=head1 COPYRIGHT
Copyright (c) 2005-2015, chocolateboy.
This module is free software. It may be used, redistributed and/or modified under the same terms
as Perl itself.
=cut
PK 1N%[�lYH YH
perl5/CPAN.pmnu ��6�$ # -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*-
# vim: ts=4 sts=4 sw=4:
use strict;
package CPAN;
$CPAN::VERSION = '2.38';
$CPAN::VERSION =~ s/_//;
# we need to run chdir all over and we would get at wrong libraries
# there
use File::Spec ();
BEGIN {
if (File::Spec->can("rel2abs")) {
for my $inc (@INC) {
$inc = File::Spec->rel2abs($inc) unless ref $inc;
}
}
$SIG{WINCH} = 'IGNORE' if exists $SIG{WINCH};
}
use CPAN::Author;
use CPAN::HandleConfig;
use CPAN::Version;
use CPAN::Bundle;
use CPAN::CacheMgr;
use CPAN::Complete;
use CPAN::Debug;
use CPAN::Distribution;
use CPAN::Distrostatus;
use CPAN::FTP;
use CPAN::Index 1.93; # https://rt.cpan.org/Ticket/Display.html?id=43349
use CPAN::InfoObj;
use CPAN::Module;
use CPAN::Prompt;
use CPAN::URL;
use CPAN::Queue;
use CPAN::Tarzip;
use CPAN::DeferredCode;
use CPAN::Shell;
use CPAN::LWP::UserAgent;
use CPAN::Exception::RecursiveDependency;
use CPAN::Exception::yaml_not_installed;
use CPAN::Exception::yaml_process_error;
use Carp ();
use Config ();
use Cwd qw(chdir);
use DirHandle ();
use Exporter ();
use ExtUtils::MakeMaker qw(prompt); # for some unknown reason,
# 5.005_04 does not work without
# this
use File::Basename ();
use File::Copy ();
use File::Find;
use File::Path ();
use FileHandle ();
use Fcntl qw(:flock);
use Safe ();
use Sys::Hostname qw(hostname);
use Text::ParseWords ();
use Text::Wrap ();
# protect against "called too early"
sub find_perl ();
sub anycwd ();
sub _uniq;
no lib ".";
require Mac::BuildTools if $^O eq 'MacOS';
if ($ENV{PERL5_CPAN_IS_RUNNING} && $$ != $ENV{PERL5_CPAN_IS_RUNNING}) {
$ENV{PERL5_CPAN_IS_RUNNING_IN_RECURSION} ||= $ENV{PERL5_CPAN_IS_RUNNING};
my @rec = _uniq split(/,/, $ENV{PERL5_CPAN_IS_RUNNING_IN_RECURSION}), $$;
$ENV{PERL5_CPAN_IS_RUNNING_IN_RECURSION} = join ",", @rec;
# warn "# Note: Recursive call of CPAN.pm detected\n";
my $w = sprintf "# Note: CPAN.pm is running in process %d now", pop @rec;
my %sleep = (
5 => 30,
6 => 60,
7 => 120,
);
my $sleep = @rec > 7 ? 300 : ($sleep{scalar @rec}||0);
my $verbose = @rec >= 4;
while (@rec) {
$w .= sprintf " which has been called by process %d", pop @rec;
}
if ($sleep) {
$w .= ".\n\n# Sleeping $sleep seconds to protect other processes\n";
}
if ($verbose) {
warn $w;
}
local $| = 1;
my $have_been_sleeping = 0;
while ($sleep > 0) {
printf "\r#%5d", --$sleep;
sleep 1;
++$have_been_sleeping;
}
print "\n" if $have_been_sleeping;
}
$ENV{PERL5_CPAN_IS_RUNNING}=$$;
$ENV{PERL5_CPANPLUS_IS_RUNNING}=$$; # https://rt.cpan.org/Ticket/Display.html?id=23735
END { $CPAN::End++; &cleanup; }
$CPAN::Signal ||= 0;
$CPAN::Frontend ||= "CPAN::Shell";
unless (@CPAN::Defaultsites) {
@CPAN::Defaultsites = map {
CPAN::URL->new(TEXT => $_, FROM => "DEF")
}
"http://www.perl.org/CPAN/",
"ftp://ftp.perl.org/pub/CPAN/";
}
# $CPAN::iCwd (i for initial)
$CPAN::iCwd ||= CPAN::anycwd();
$CPAN::Perl ||= CPAN::find_perl();
$CPAN::Defaultdocs ||= "http://search.cpan.org/perldoc?";
$CPAN::Defaultrecent ||= "http://search.cpan.org/uploads.rdf";
$CPAN::Defaultrecent ||= "http://cpan.uwinnipeg.ca/htdocs/cpan.xml";
# our globals are getting a mess
use vars qw(
$AUTOLOAD
$Be_Silent
$CONFIG_DIRTY
$Defaultdocs
$Echo_readline
$Frontend
$GOTOSHELL
$HAS_USABLE
$Have_warned
$MAX_RECURSION
$META
$RUN_DEGRADED
$Signal
$SQLite
$Suppress_readline
$VERSION
$autoload_recursion
$term
@Defaultsites
@EXPORT
);
$MAX_RECURSION = 32;
@CPAN::ISA = qw(CPAN::Debug Exporter);
# note that these functions live in CPAN::Shell and get executed via
# AUTOLOAD when called directly
@EXPORT = qw(
autobundle
bundle
clean
cvs_import
expand
force
fforce
get
install
install_tested
is_tested
make
mkmyconfig
notest
perldoc
readme
recent
recompile
report
shell
smoke
test
upgrade
);
sub soft_chdir_with_alternatives ($);
{
$autoload_recursion ||= 0;
#-> sub CPAN::AUTOLOAD ;
sub AUTOLOAD { ## no critic
$autoload_recursion++;
my($l) = $AUTOLOAD;
$l =~ s/.*:://;
if ($CPAN::Signal) {
warn "Refusing to autoload '$l' while signal pending";
$autoload_recursion--;
return;
}
if ($autoload_recursion > 1) {
my $fullcommand = join " ", map { "'$_'" } $l, @_;
warn "Refusing to autoload $fullcommand in recursion\n";
$autoload_recursion--;
return;
}
my(%export);
@export{@EXPORT} = '';
CPAN::HandleConfig->load unless $CPAN::Config_loaded++;
if (exists $export{$l}) {
CPAN::Shell->$l(@_);
} else {
die(qq{Unknown CPAN command "$AUTOLOAD". }.
qq{Type ? for help.\n});
}
$autoload_recursion--;
}
}
{
my $x = *SAVEOUT; # avoid warning
open($x,">&STDOUT") or die "dup failed";
my $redir = 0;
sub _redirect(@) {
#die if $redir;
local $_;
push(@_,undef);
while(defined($_=shift)) {
if (s/^\s*>//){
my ($m) = s/^>// ? ">" : "";
s/\s+//;
$_=shift unless length;
die "no dest" unless defined;
open(STDOUT,">$m$_") or die "open:$_:$!\n";
$redir=1;
} elsif ( s/^\s*\|\s*// ) {
my $pipe="| $_";
while(defined($_[0])){
$pipe .= ' ' . shift;
}
open(STDOUT,$pipe) or die "open:$pipe:$!\n";
$redir=1;
} else {
push(@_,$_);
}
}
return @_;
}
sub _unredirect {
return unless $redir;
$redir = 0;
## redirect: unredirect and propagate errors. explicit close to wait for pipe.
close(STDOUT);
open(STDOUT,">&SAVEOUT");
die "$@" if "$@";
## redirect: done
}
}
sub _uniq {
my(@list) = @_;
my %seen;
return grep { !$seen{$_}++ } @list;
}
#-> sub CPAN::shell ;
sub shell {
my($self) = @_;
$Suppress_readline = ! -t STDIN unless defined $Suppress_readline;
CPAN::HandleConfig->load unless $CPAN::Config_loaded++;
my $oprompt = shift || CPAN::Prompt->new;
my $prompt = $oprompt;
my $commandline = shift || "";
$CPAN::CurrentCommandId ||= 1;
local($^W) = 1;
unless ($Suppress_readline) {
require Term::ReadLine;
if (! $term
or
$term->ReadLine eq "Term::ReadLine::Stub"
) {
$term = Term::ReadLine->new('CPAN Monitor');
}
if ($term->ReadLine eq "Term::ReadLine::Gnu") {
my $attribs = $term->Attribs;
$attribs->{attempted_completion_function} = sub {
&CPAN::Complete::gnu_cpl;
}
} else {
$readline::rl_completion_function =
$readline::rl_completion_function = 'CPAN::Complete::cpl';
}
if (my $histfile = $CPAN::Config->{'histfile'}) {{
unless ($term->can("AddHistory")) {
$CPAN::Frontend->mywarn("Terminal does not support AddHistory.\n");
unless ($CPAN::META->has_inst('Term::ReadLine::Perl')) {
$CPAN::Frontend->mywarn("\nTo fix that, maybe try> install Term::ReadLine::Perl\n\n");
}
last;
}
$META->readhist($term,$histfile);
}}
for ($CPAN::Config->{term_ornaments}) { # alias
local $Term::ReadLine::termcap_nowarn = 1;
$term->ornaments($_) if defined;
}
# $term->OUT is autoflushed anyway
my $odef = select STDERR;
$| = 1;
select STDOUT;
$| = 1;
select $odef;
}
$META->checklock();
my @cwd = grep { defined $_ and length $_ }
CPAN::anycwd(),
File::Spec->can("tmpdir") ? File::Spec->tmpdir() : (),
File::Spec->rootdir();
my $try_detect_readline;
$try_detect_readline = $term->ReadLine eq "Term::ReadLine::Stub" if $term;
unless ($CPAN::Config->{inhibit_startup_message}) {
my $rl_avail = $Suppress_readline ? "suppressed" :
($term->ReadLine ne "Term::ReadLine::Stub") ? "enabled" :
"available (maybe install Bundle::CPAN or Bundle::CPANxxl?)";
$CPAN::Frontend->myprint(
sprintf qq{
cpan shell -- CPAN exploration and modules installation (v%s)
Enter 'h' for help.
},
$CPAN::VERSION,
)
}
my($continuation) = "";
my $last_term_ornaments;
SHELLCOMMAND: while () {
if ($Suppress_readline) {
if ($Echo_readline) {
$|=1;
}
print $prompt;
last SHELLCOMMAND unless defined ($_ = <> );
if ($Echo_readline) {
# backdoor: I could not find a way to record sessions
print $_;
}
chomp;
} else {
last SHELLCOMMAND unless
defined ($_ = $term->readline($prompt, $commandline));
}
$_ = "$continuation$_" if $continuation;
s/^\s+//;
next SHELLCOMMAND if /^$/;
s/^\s*\?\s*/help /;
if (/^(?:q(?:uit)?|bye|exit)\s*$/i) {
last SHELLCOMMAND;
} elsif (s/\\$//s) {
chomp;
$continuation = $_;
$prompt = " > ";
} elsif (/^\!/) {
s/^\!//;
my($eval) = $_;
package
CPAN::Eval; # hide from the indexer
use strict;
use vars qw($import_done);
CPAN->import(':DEFAULT') unless $import_done++;
CPAN->debug("eval[$eval]") if $CPAN::DEBUG;
eval($eval);
warn $@ if $@;
$continuation = "";
$prompt = $oprompt;
} elsif (/./) {
my(@line);
eval { @line = Text::ParseWords::shellwords($_) };
warn($@), next SHELLCOMMAND if $@;
warn("Text::Parsewords could not parse the line [$_]"),
next SHELLCOMMAND unless @line;
$CPAN::META->debug("line[".join("|",@line)."]") if $CPAN::DEBUG;
my $command = shift @line;
eval {
local (*STDOUT)=*STDOUT;
@line = _redirect(@line);
CPAN::Shell->$command(@line)
};
my $command_error = $@;
_unredirect;
my $reported_error;
if ($command_error) {
my $err = $command_error;
if (ref $err and $err->isa('CPAN::Exception::blocked_urllist')) {
$CPAN::Frontend->mywarn("Client not fully configured, please proceed with configuring.$err");
$reported_error = ref $err;
} else {
# I'd prefer never to arrive here and make all errors exception objects
if ($err =~ /\S/) {
require Carp;
require Dumpvalue;
my $dv = Dumpvalue->new(tick => '"');
Carp::cluck(sprintf "Catching error: %s", $dv->stringify($err));
}
}
}
if ($command =~ /^(
# classic commands
make
|test
|install
|clean
# pragmas for classic commands
|ff?orce
|notest
# compounds
|report
|smoke
|upgrade
)$/x) {
# only commands that tell us something about failed distros
# eval necessary for people without an urllist
eval {CPAN::Shell->failed($CPAN::CurrentCommandId,1);};
if (my $err = $@) {
unless (ref $err and $reported_error eq ref $err) {
die $@;
}
}
}
soft_chdir_with_alternatives(\@cwd);
$CPAN::Frontend->myprint("\n");
$continuation = "";
$CPAN::CurrentCommandId++;
$prompt = $oprompt;
}
} continue {
$commandline = ""; # I do want to be able to pass a default to
# shell, but on the second command I see no
# use in that
$Signal=0;
CPAN::Queue->nullify_queue;
if ($try_detect_readline) {
if ($CPAN::META->has_inst("Term::ReadLine::Gnu")
||
$CPAN::META->has_inst("Term::ReadLine::Perl")
) {
delete $INC{"Term/ReadLine.pm"};
my $redef = 0;
local($SIG{__WARN__}) = CPAN::Shell::paintdots_onreload(\$redef);
require Term::ReadLine;
$CPAN::Frontend->myprint("\n$redef subroutines in ".
"Term::ReadLine redefined\n");
$GOTOSHELL = 1;
}
}
if ($term and $term->can("ornaments")) {
for ($CPAN::Config->{term_ornaments}) { # alias
if (defined $_) {
if (not defined $last_term_ornaments
or $_ != $last_term_ornaments
) {
local $Term::ReadLine::termcap_nowarn = 1;
$term->ornaments($_);
$last_term_ornaments = $_;
}
} else {
undef $last_term_ornaments;
}
}
}
for my $class (qw(Module Distribution)) {
# again unsafe meta access?
for my $dm (sort keys %{$CPAN::META->{readwrite}{"CPAN::$class"}}) {
next unless $CPAN::META->{readwrite}{"CPAN::$class"}{$dm}{incommandcolor};
CPAN->debug("BUG: $class '$dm' was in command state, resetting");
delete $CPAN::META->{readwrite}{"CPAN::$class"}{$dm}{incommandcolor};
}
}
if ($GOTOSHELL) {
$GOTOSHELL = 0; # not too often
$META->savehist if $CPAN::term && $CPAN::term->can("GetHistory");
@_ = ($oprompt,"");
goto &shell;
}
}
soft_chdir_with_alternatives(\@cwd);
}
#-> CPAN::soft_chdir_with_alternatives ;
sub soft_chdir_with_alternatives ($) {
my($cwd) = @_;
unless (@$cwd) {
my $root = File::Spec->rootdir();
$CPAN::Frontend->mywarn(qq{Warning: no good directory to chdir to!
Trying '$root' as temporary haven.
});
push @$cwd, $root;
}
while () {
if (chdir "$cwd->[0]") {
return;
} else {
if (@$cwd>1) {
$CPAN::Frontend->mywarn(qq{Could not chdir to "$cwd->[0]": $!
Trying to chdir to "$cwd->[1]" instead.
});
shift @$cwd;
} else {
$CPAN::Frontend->mydie(qq{Could not chdir to "$cwd->[0]": $!});
}
}
}
}
sub _flock {
my($fh,$mode) = @_;
if ( $Config::Config{d_flock} || $Config::Config{d_fcntl_can_lock} ) {
return flock $fh, $mode;
} elsif (!$Have_warned->{"d_flock"}++) {
$CPAN::Frontend->mywarn("Your OS does not seem to support locking; continuing and ignoring all locking issues\n");
$CPAN::Frontend->mysleep(5);
return 1;
} else {
return 1;
}
}
sub _yaml_module () {
my $yaml_module = $CPAN::Config->{yaml_module} || "YAML";
if (
$yaml_module ne "YAML"
&&
!$CPAN::META->has_inst($yaml_module)
) {
# $CPAN::Frontend->mywarn("'$yaml_module' not installed, falling back to 'YAML'\n");
$yaml_module = "YAML";
}
if ($yaml_module eq "YAML"
&&
$CPAN::META->has_inst($yaml_module)
&&
$YAML::VERSION < 0.60
&&
!$Have_warned->{"YAML"}++
) {
$CPAN::Frontend->mywarn("Warning: YAML version '$YAML::VERSION' is too low, please upgrade!\n".
"I'll continue but problems are *very* likely to happen.\n"
);
$CPAN::Frontend->mysleep(5);
}
return $yaml_module;
}
# CPAN::_yaml_loadfile
sub _yaml_loadfile {
my($self,$local_file,$opt) = @_;
return +[] unless -s $local_file;
my $opt_loadblessed = $opt->{loadblessed} || $CPAN::Config->{yaml_load_code} || 0;
my $yaml_module = _yaml_module;
if ($CPAN::META->has_inst($yaml_module)) {
# temporarily enable yaml code deserialisation
no strict 'refs';
# 5.6.2 could not do the local() with the reference
# so we do it manually instead
my $old_loadcode = ${"$yaml_module\::LoadCode"};
my $old_loadblessed = ${"$yaml_module\::LoadBlessed"};
${ "$yaml_module\::LoadCode" } = $CPAN::Config->{yaml_load_code} || 0;
${ "$yaml_module\::LoadBlessed" } = $opt_loadblessed ? 1 : 0;
my ($code, @yaml);
if ($code = UNIVERSAL::can($yaml_module, "LoadFile")) {
eval { @yaml = $code->($local_file); };
if ($@) {
# this shall not be done by the frontend
die CPAN::Exception::yaml_process_error->new($yaml_module,$local_file,"parse",$@);
}
} elsif ($code = UNIVERSAL::can($yaml_module, "Load")) {
local *FH;
if (open FH, $local_file) {
local $/;
my $ystream = <FH>;
eval { @yaml = $code->($ystream); };
if ($@) {
# this shall not be done by the frontend
die CPAN::Exception::yaml_process_error->new($yaml_module,$local_file,"parse",$@);
}
} else {
$CPAN::Frontend->mywarn("Could not open '$local_file': $!");
}
}
${"$yaml_module\::LoadCode"} = $old_loadcode;
${"$yaml_module\::LoadBlessed"} = $old_loadblessed;
return \@yaml;
} else {
# this shall not be done by the frontend
die CPAN::Exception::yaml_not_installed->new($yaml_module, $local_file, "parse");
}
return +[];
}
# CPAN::_yaml_dumpfile
sub _yaml_dumpfile {
my($self,$local_file,@what) = @_;
my $yaml_module = _yaml_module;
if ($CPAN::META->has_inst($yaml_module)) {
my $code;
if (UNIVERSAL::isa($local_file, "FileHandle")) {
$code = UNIVERSAL::can($yaml_module, "Dump");
eval { print $local_file $code->(@what) };
} elsif ($code = UNIVERSAL::can($yaml_module, "DumpFile")) {
eval { $code->($local_file,@what); };
} elsif ($code = UNIVERSAL::can($yaml_module, "Dump")) {
local *FH;
open FH, ">$local_file" or die "Could not open '$local_file': $!";
print FH $code->(@what);
}
if ($@) {
die CPAN::Exception::yaml_process_error->new($yaml_module,$local_file,"dump",$@);
}
} else {
if (UNIVERSAL::isa($local_file, "FileHandle")) {
# I think this case does not justify a warning at all
} else {
die CPAN::Exception::yaml_not_installed->new($yaml_module, $local_file, "dump");
}
}
}
sub _init_sqlite () {
unless ($CPAN::META->has_inst("CPAN::SQLite")) {
$CPAN::Frontend->mywarn(qq{CPAN::SQLite not installed, trying to work without\n})
unless $Have_warned->{"CPAN::SQLite"}++;
return;
}
require CPAN::SQLite::META; # not needed since CVS version of 2006-12-17
$CPAN::SQLite ||= CPAN::SQLite::META->new($CPAN::META);
}
{
my $negative_cache = {};
sub _sqlite_running {
if ($negative_cache->{time} && time < $negative_cache->{time} + 60) {
# need to cache the result, otherwise too slow
return $negative_cache->{fact};
} else {
$negative_cache = {}; # reset
}
my $ret = $CPAN::Config->{use_sqlite} && ($CPAN::SQLite || _init_sqlite());
return $ret if $ret; # fast anyway
$negative_cache->{time} = time;
return $negative_cache->{fact} = $ret;
}
}
$META ||= CPAN->new; # In case we re-eval ourselves we need the ||
# from here on only subs.
################################################################################
sub _perl_fingerprint {
my($self,$other_fingerprint) = @_;
my $dll = eval {OS2::DLLname()};
my $mtime_dll = 0;
if (defined $dll) {
$mtime_dll = (-f $dll ? (stat(_))[9] : '-1');
}
my $mtime_perl = (-f CPAN::find_perl ? (stat(_))[9] : '-1');
my $this_fingerprint = {
'$^X' => CPAN::find_perl,
sitearchexp => $Config::Config{sitearchexp},
'mtime_$^X' => $mtime_perl,
'mtime_dll' => $mtime_dll,
};
if ($other_fingerprint) {
if (exists $other_fingerprint->{'stat($^X)'}) { # repair fp from rev. 1.88_57
$other_fingerprint->{'mtime_$^X'} = $other_fingerprint->{'stat($^X)'}[9];
}
# mandatory keys since 1.88_57
for my $key (qw($^X sitearchexp mtime_dll mtime_$^X)) {
return unless $other_fingerprint->{$key} eq $this_fingerprint->{$key};
}
return 1;
} else {
return $this_fingerprint;
}
}
sub suggest_myconfig () {
SUGGEST_MYCONFIG: if(!$INC{'CPAN/MyConfig.pm'}) {
$CPAN::Frontend->myprint("You don't seem to have a user ".
"configuration (MyConfig.pm) yet.\n");
my $new = CPAN::Shell::colorable_makemaker_prompt("Do you want to create a ".
"user configuration now? (Y/n)",
"yes");
if($new =~ m{^y}i) {
CPAN::Shell->mkmyconfig();
return &checklock;
} else {
$CPAN::Frontend->mydie("OK, giving up.");
}
}
}
#-> sub CPAN::all_objects ;
sub all_objects {
my($mgr,$class) = @_;
CPAN::HandleConfig->load unless $CPAN::Config_loaded++;
CPAN->debug("mgr[$mgr] class[$class]") if $CPAN::DEBUG;
CPAN::Index->reload;
values %{ $META->{readwrite}{$class} }; # unsafe meta access, ok
}
# Called by shell, not in batch mode. In batch mode I see no risk in
# having many processes updating something as installations are
# continually checked at runtime. In shell mode I suspect it is
# unintentional to open more than one shell at a time
#-> sub CPAN::checklock ;
sub checklock {
my($self) = @_;
my $lockfile = File::Spec->catfile($CPAN::Config->{cpan_home},".lock");
if (-f $lockfile && -M _ > 0) {
my $fh = FileHandle->new($lockfile) or
$CPAN::Frontend->mydie("Could not open lockfile '$lockfile': $!");
my $otherpid = <$fh>;
my $otherhost = <$fh>;
$fh->close;
if (defined $otherpid && length $otherpid) {
chomp $otherpid;
}
if (defined $otherhost && length $otherhost) {
chomp $otherhost;
}
my $thishost = hostname();
my $ask_if_degraded_wanted = 0;
if (defined $otherhost && defined $thishost &&
$otherhost ne '' && $thishost ne '' &&
$otherhost ne $thishost) {
$CPAN::Frontend->mydie(sprintf("CPAN.pm panic: Lockfile '$lockfile'\n".
"reports other host $otherhost and other ".
"process $otherpid.\n".
"Cannot proceed.\n"));
} elsif ($RUN_DEGRADED) {
$CPAN::Frontend->mywarn("Running in downgraded mode (experimental)\n");
} elsif (defined $otherpid && $otherpid) {
return if $$ == $otherpid; # should never happen
$CPAN::Frontend->mywarn(
qq{
There seems to be running another CPAN process (pid $otherpid). Contacting...
});
if (kill 0, $otherpid or $!{EPERM}) {
$CPAN::Frontend->mywarn(qq{Other job is running.\n});
$ask_if_degraded_wanted = 1;
} elsif (-w $lockfile) {
my($ans) =
CPAN::Shell::colorable_makemaker_prompt
(qq{Other job not responding. Shall I overwrite }.
qq{the lockfile '$lockfile'? (Y/n)},"y");
$CPAN::Frontend->myexit("Ok, bye\n")
unless $ans =~ /^y/i;
} else {
Carp::croak(
qq{Lockfile '$lockfile' not writable by you. }.
qq{Cannot proceed.\n}.
qq{ On UNIX try:\n}.
qq{ rm '$lockfile'\n}.
qq{ and then rerun us.\n}
);
}
} elsif ($^O eq "MSWin32") {
$CPAN::Frontend->mywarn(
qq{
There seems to be running another CPAN process according to '$lockfile'.
});
$ask_if_degraded_wanted = 1;
} else {
$CPAN::Frontend->mydie(sprintf("CPAN.pm panic: Found invalid lockfile ".
"'$lockfile', please remove. Cannot proceed.\n"));
}
if ($ask_if_degraded_wanted) {
my($ans) =
CPAN::Shell::colorable_makemaker_prompt
(qq{Shall I try to run in downgraded }.
qq{mode? (Y/n)},"y");
if ($ans =~ /^y/i) {
$CPAN::Frontend->mywarn("Running in downgraded mode (experimental).
Please report if something unexpected happens\n");
$RUN_DEGRADED = 1;
for ($CPAN::Config) {
# XXX
# $_->{build_dir_reuse} = 0; # 2006-11-17 akoenig Why was that?
$_->{commandnumber_in_prompt} = 0; # visibility
$_->{histfile} = ""; # who should win otherwise?
$_->{cache_metadata} = 0; # better would be a lock?
$_->{use_sqlite} = 0; # better would be a write lock!
$_->{auto_commit} = 0; # we are violent, do not persist
$_->{test_report} = 0; # Oliver Paukstadt had sent wrong reports in degraded mode
}
} else {
my $msg = "You may want to kill the other job and delete the lockfile.";
if (defined $otherpid) {
$msg .= " Something like:
kill $otherpid
rm $lockfile
";
}
$CPAN::Frontend->mydie("\n$msg");
}
}
}
my $dotcpan = $CPAN::Config->{cpan_home};
eval { File::Path::mkpath($dotcpan);};
if ($@) {
# A special case at least for Jarkko.
my $firsterror = $@;
my $seconderror;
my $symlinkcpan;
if (-l $dotcpan) {
$symlinkcpan = readlink $dotcpan;
die "readlink $dotcpan failed: $!" unless defined $symlinkcpan;
eval { File::Path::mkpath($symlinkcpan); };
if ($@) {
$seconderror = $@;
} else {
$CPAN::Frontend->mywarn(qq{
Working directory $symlinkcpan created.
});
}
}
unless (-d $dotcpan) {
my $mess = qq{
Your configuration suggests "$dotcpan" as your
CPAN.pm working directory. I could not create this directory due
to this error: $firsterror\n};
$mess .= qq{
As "$dotcpan" is a symlink to "$symlinkcpan",
I tried to create that, but I failed with this error: $seconderror
} if $seconderror;
$mess .= qq{
Please make sure the directory exists and is writable.
};
$CPAN::Frontend->mywarn($mess);
return suggest_myconfig;
}
} # $@ after eval mkpath $dotcpan
if (0) { # to test what happens when a race condition occurs
for (reverse 1..10) {
print $_, "\n";
sleep 1;
}
}
# locking
if (!$RUN_DEGRADED && !$self->{LOCKFH}) {
my $fh;
unless ($fh = FileHandle->new("+>>$lockfile")) {
$CPAN::Frontend->mywarn(qq{
Your configuration suggests that CPAN.pm should use a working
directory of
$CPAN::Config->{cpan_home}
Unfortunately we could not create the lock file
$lockfile
due to '$!'.
Please make sure that the configuration variable
\$CPAN::Config->{cpan_home}
points to a directory where you can write a .lock file. You can set
this variable in either a CPAN/MyConfig.pm or a CPAN/Config.pm in your
\@INC path;
});
return suggest_myconfig;
}
my $sleep = 1;
while (!CPAN::_flock($fh, LOCK_EX|LOCK_NB)) {
my $err = $! || "unknown error";
if ($sleep>3) {
$CPAN::Frontend->mydie("Could not lock '$lockfile' with flock: $err; giving up\n");
}
$CPAN::Frontend->mysleep($sleep+=0.1);
$CPAN::Frontend->mywarn("Could not lock '$lockfile' with flock: $err; retrying\n");
}
seek $fh, 0, 0;
truncate $fh, 0;
$fh->autoflush(1);
$fh->print($$, "\n");
$fh->print(hostname(), "\n");
$self->{LOCK} = $lockfile;
$self->{LOCKFH} = $fh;
}
$SIG{TERM} = sub {
my $sig = shift;
&cleanup;
$CPAN::Frontend->mydie("Got SIG$sig, leaving");
};
$SIG{INT} = sub {
# no blocks!!!
my $sig = shift;
&cleanup if $Signal;
die "Got yet another signal" if $Signal > 1;
$CPAN::Frontend->mydie("Got another SIG$sig") if $Signal;
$CPAN::Frontend->mywarn("Caught SIG$sig, trying to continue\n");
$Signal++;
};
# From: Larry Wall <larry@wall.org>
# Subject: Re: deprecating SIGDIE
# To: perl5-porters@perl.org
# Date: Thu, 30 Sep 1999 14:58:40 -0700 (PDT)
#
# The original intent of __DIE__ was only to allow you to substitute one
# kind of death for another on an application-wide basis without respect
# to whether you were in an eval or not. As a global backstop, it should
# not be used any more lightly (or any more heavily :-) than class
# UNIVERSAL. Any attempt to build a general exception model on it should
# be politely squashed. Any bug that causes every eval {} to have to be
# modified should be not so politely squashed.
#
# Those are my current opinions. It is also my opinion that polite
# arguments degenerate to personal arguments far too frequently, and that
# when they do, it's because both people wanted it to, or at least didn't
# sufficiently want it not to.
#
# Larry
# global backstop to cleanup if we should really die
$SIG{__DIE__} = \&cleanup;
$self->debug("Signal handler set.") if $CPAN::DEBUG;
}
#-> sub CPAN::DESTROY ;
sub DESTROY {
&cleanup; # need an eval?
}
#-> sub CPAN::anycwd ;
sub anycwd () {
my $getcwd;
$getcwd = $CPAN::Config->{'getcwd'} || 'cwd';
CPAN->$getcwd();
}
#-> sub CPAN::cwd ;
sub cwd {Cwd::cwd();}
#-> sub CPAN::getcwd ;
sub getcwd {Cwd::getcwd();}
#-> sub CPAN::fastcwd ;
sub fastcwd {Cwd::fastcwd();}
#-> sub CPAN::getdcwd ;
sub getdcwd {Cwd::getdcwd();}
#-> sub CPAN::backtickcwd ;
sub backtickcwd {my $cwd = `cwd`; chomp $cwd; $cwd}
# Adapted from Probe::Perl
#-> sub CPAN::_perl_is_same
sub _perl_is_same {
my ($perl) = @_;
return MM->maybe_command($perl)
&& `$perl -MConfig=myconfig -e print -e myconfig` eq Config->myconfig;
}
# Adapted in part from Probe::Perl
#-> sub CPAN::find_perl ;
sub find_perl () {
if ( File::Spec->file_name_is_absolute($^X) ) {
return $^X;
}
else {
my $exe = $Config::Config{exe_ext};
my @candidates = (
File::Spec->catfile($CPAN::iCwd,$^X),
$Config::Config{'perlpath'},
);
for my $perl_name ($^X, 'perl', 'perl5', "perl$]") {
for my $path (File::Spec->path(), $Config::Config{'binexp'}) {
if ( defined($path) && length $path && -d $path ) {
my $perl = File::Spec->catfile($path,$perl_name);
push @candidates, $perl;
# try with extension if not provided already
if ($^O eq 'VMS') {
# VMS might have a file version at the end
push @candidates, $perl . $exe
unless $perl =~ m/$exe(;\d+)?$/i;
} elsif (defined $exe && length $exe) {
push @candidates, $perl . $exe
unless $perl =~ m/$exe$/i;
}
}
}
}
for my $perl ( @candidates ) {
if (MM->maybe_command($perl) && _perl_is_same($perl)) {
$^X = $perl;
return $perl;
}
}
}
return $^X; # default fall back
}
#-> sub CPAN::exists ;
sub exists {
my($mgr,$class,$id) = @_;
CPAN::HandleConfig->load unless $CPAN::Config_loaded++;
CPAN::Index->reload;
### Carp::croak "exists called without class argument" unless $class;
$id ||= "";
$id =~ s/:+/::/g if $class eq "CPAN::Module";
my $exists;
if (CPAN::_sqlite_running) {
$exists = (exists $META->{readonly}{$class}{$id} or
$CPAN::SQLite->set($class, $id));
} else {
$exists = exists $META->{readonly}{$class}{$id};
}
$exists ||= exists $META->{readwrite}{$class}{$id}; # unsafe meta access, ok
}
#-> sub CPAN::delete ;
sub delete {
my($mgr,$class,$id) = @_;
delete $META->{readonly}{$class}{$id}; # unsafe meta access, ok
delete $META->{readwrite}{$class}{$id}; # unsafe meta access, ok
}
#-> sub CPAN::has_usable
# has_inst is sometimes too optimistic, we should replace it with this
# has_usable whenever a case is given
sub has_usable {
my($self,$mod,$message) = @_;
return 1 if $HAS_USABLE->{$mod};
my $has_inst = $self->has_inst($mod,$message);
return unless $has_inst;
my $usable;
$usable = {
#
# most of these subroutines warn on the frontend, then
# die if the installed version is unusable for some
# reason; has_usable() then returns false when it caught
# an exception, otherwise returns true and caches that;
#
'CPAN::Meta' => [
sub {
require CPAN::Meta;
unless (CPAN::Version->vge(CPAN::Meta->VERSION, 2.110350)) {
for ("Will not use CPAN::Meta, need version 2.110350\n") {
$CPAN::Frontend->mywarn($_);
die $_;
}
}
},
],
'CPAN::Meta::Requirements' => [
sub {
if (defined $CPAN::Meta::Requirements::VERSION
&& CPAN::Version->vlt($CPAN::Meta::Requirements::VERSION, "2.120920")
) {
delete $INC{"CPAN/Meta/Requirements.pm"};
}
require CPAN::Meta::Requirements;
unless (CPAN::Version->vge(CPAN::Meta::Requirements->VERSION, 2.120920)) {
for ("Will not use CPAN::Meta::Requirements, need version 2.120920\n") {
$CPAN::Frontend->mywarn($_);
die $_;
}
}
},
],
'CPAN::Reporter' => [
sub {
if (defined $CPAN::Reporter::VERSION
&& CPAN::Version->vlt($CPAN::Reporter::VERSION, "1.2011")
) {
delete $INC{"CPAN/Reporter.pm"};
}
require CPAN::Reporter;
unless (CPAN::Version->vge(CPAN::Reporter->VERSION, "1.2011")) {
for ("Will not use CPAN::Reporter, need version 1.2011\n") {
$CPAN::Frontend->mywarn($_);
die $_;
}
}
},
],
LWP => [ # we frequently had "Can't locate object
# method "new" via package "LWP::UserAgent" at
# (eval 69) line 2006
sub {require LWP},
sub {require LWP::UserAgent},
sub {require HTTP::Request},
sub {require URI::URL;
unless (CPAN::Version->vge(URI::URL::->VERSION,0.08)) {
for ("Will not use URI::URL, need 0.08\n") {
$CPAN::Frontend->mywarn($_);
die $_;
}
}
},
],
'Net::FTP' => [
sub {
my $var = $CPAN::Config->{ftp_proxy} || $ENV{ftp_proxy};
if ($var and $var =~ /^http:/i) {
# rt #110833
for ("Net::FTP cannot handle http proxy") {
$CPAN::Frontend->mywarn($_);
die $_;
}
}
},
sub {require Net::FTP},
sub {require Net::Config},
],
'IO::Socket::SSL' => [
sub {
require IO::Socket::SSL;
unless (CPAN::Version->vge(IO::Socket::SSL::->VERSION,1.56)) {
for ("Will not use IO::Socket::SSL, need 1.56\n") {
$CPAN::Frontend->mywarn($_);
die $_;
}
}
}
],
'Net::SSLeay' => [
sub {
require Net::SSLeay;
unless (CPAN::Version->vge(Net::SSLeay::->VERSION,1.49)) {
for ("Will not use Net::SSLeay, need 1.49\n") {
$CPAN::Frontend->mywarn($_);
die $_;
}
}
}
],
'HTTP::Tiny' => [
sub {
require HTTP::Tiny;
unless (CPAN::Version->vge(HTTP::Tiny->VERSION, 0.005)) {
for ("Will not use HTTP::Tiny, need version 0.005\n") {
$CPAN::Frontend->mywarn($_);
die $_;
}
}
},
],
'File::HomeDir' => [
sub {require File::HomeDir;
unless (CPAN::Version->vge(File::HomeDir::->VERSION, 0.52)) {
for ("Will not use File::HomeDir, need 0.52\n") {
$CPAN::Frontend->mywarn($_);
die $_;
}
}
},
],
'Archive::Tar' => [
sub {require Archive::Tar;
my $demand = "1.50";
unless (CPAN::Version->vge(Archive::Tar::->VERSION, $demand)) {
my $atv = Archive::Tar->VERSION;
for ("You have Archive::Tar $atv, but $demand or later is recommended. Please upgrade.\n") {
$CPAN::Frontend->mywarn($_);
# don't die, because we may need
# Archive::Tar to upgrade
}
}
},
],
'File::Temp' => [
# XXX we should probably delete from
# %INC too so we can load after we
# installed a new enough version --
# I'm not sure.
sub {require File::Temp;
unless (CPAN::Version->vge(File::Temp::->VERSION,0.16)) {
for ("Will not use File::Temp, need 0.16\n") {
$CPAN::Frontend->mywarn($_);
die $_;
}
}
},
]
};
if ($usable->{$mod}) {
local @INC = @INC;
pop @INC if $INC[-1] eq '.';
for my $c (0..$#{$usable->{$mod}}) {
my $code = $usable->{$mod}[$c];
my $ret = eval { &$code() };
$ret = "" unless defined $ret;
if ($@) {
# warn "DEBUG: c[$c]\$\@[$@]ret[$ret]";
return;
}
}
}
return $HAS_USABLE->{$mod} = 1;
}
sub frontend {
shift;
$CPAN::Frontend = shift if @_;
$CPAN::Frontend;
}
sub use_inst {
my ($self, $module) = @_;
unless ($self->has_inst($module)) {
$self->frontend->mydie("$module not installed, cannot continue");
}
}
#-> sub CPAN::has_inst
sub has_inst {
my($self,$mod,$message) = @_;
Carp::croak("CPAN->has_inst() called without an argument")
unless defined $mod;
my %dont = map { $_ => 1 } keys %{$CPAN::META->{dontload_hash}||{}},
keys %{$CPAN::Config->{dontload_hash}||{}},
@{$CPAN::Config->{dontload_list}||[]};
if (defined $message && $message eq "no" # as far as I remember only used by Nox
||
$dont{$mod}
) {
$CPAN::META->{dontload_hash}{$mod}||=1; # unsafe meta access, ok
return 0;
}
local @INC = @INC;
pop @INC if $INC[-1] eq '.';
my $file = $mod;
my $obj;
$file =~ s|::|/|g;
$file .= ".pm";
if ($INC{$file}) {
# checking %INC is wrong, because $INC{LWP} may be true
# although $INC{"URI/URL.pm"} may have failed. But as
# I really want to say "blah loaded OK", I have to somehow
# cache results.
### warn "$file in %INC"; #debug
return 1;
} elsif (eval { require $file }) {
# eval is good: if we haven't yet read the database it's
# perfect and if we have installed the module in the meantime,
# it tries again. The second require is only a NOOP returning
# 1 if we had success, otherwise it's retrying
my $mtime = (stat $INC{$file})[9];
# privileged files loaded by has_inst; Note: we use $mtime
# as a proxy for a checksum.
$CPAN::Shell::reload->{$file} = $mtime;
my $v = eval "\$$mod\::VERSION";
$v = $v ? " (v$v)" : "";
CPAN::Shell->optprint("load_module","CPAN: $mod loaded ok$v\n");
if ($mod eq "CPAN::WAIT") {
push @CPAN::Shell::ISA, 'CPAN::WAIT';
}
return 1;
} elsif ($mod eq "Net::FTP") {
$CPAN::Frontend->mywarn(qq{
Please, install Net::FTP as soon as possible. CPAN.pm installs it for you
if you just type
install Bundle::libnet
}) unless $Have_warned->{"Net::FTP"}++;
$CPAN::Frontend->mysleep(3);
} elsif ($mod eq "Digest::SHA") {
if ($Have_warned->{"Digest::SHA"}++) {
$CPAN::Frontend->mywarn(qq{CPAN: checksum security checks disabled }.
qq{because Digest::SHA not installed.\n});
} else {
$CPAN::Frontend->mywarn(qq{
CPAN: checksum security checks disabled because Digest::SHA not installed.
Please consider installing the Digest::SHA module.
});
$CPAN::Frontend->mysleep(2);
}
} elsif ($mod eq "Module::Signature") {
# NOT prefs_lookup, we are not a distro
my $check_sigs = $CPAN::Config->{check_sigs};
if (not $check_sigs) {
# they do not want us:-(
} elsif (not $Have_warned->{"Module::Signature"}++) {
# No point in complaining unless the user can
# reasonably install and use it.
if (eval { require Crypt::OpenPGP; 1 } ||
(
defined $CPAN::Config->{'gpg'}
&&
$CPAN::Config->{'gpg'} =~ /\S/
)
) {
$CPAN::Frontend->mywarn(qq{
CPAN: Module::Signature security checks disabled because Module::Signature
not installed. Please consider installing the Module::Signature module.
You may also need to be able to connect over the Internet to the public
key servers like pool.sks-keyservers.net or pgp.mit.edu.
});
$CPAN::Frontend->mysleep(2);
}
}
} else {
delete $INC{$file}; # if it inc'd LWP but failed during, say, URI
}
return 0;
}
#-> sub CPAN::instance ;
sub instance {
my($mgr,$class,$id) = @_;
CPAN::Index->reload;
$id ||= "";
# unsafe meta access, ok?
return $META->{readwrite}{$class}{$id} if exists $META->{readwrite}{$class}{$id};
$META->{readwrite}{$class}{$id} ||= $class->new(ID => $id);
}
#-> sub CPAN::new ;
sub new {
bless {}, shift;
}
#-> sub CPAN::_exit_messages ;
sub _exit_messages {
my ($self) = @_;
$self->{exit_messages} ||= [];
}
#-> sub CPAN::cleanup ;
sub cleanup {
# warn "cleanup called with arg[@_] End[$CPAN::End] Signal[$Signal]";
local $SIG{__DIE__} = '';
my($message) = @_;
my $i = 0;
my $ineval = 0;
my($subroutine);
while ((undef,undef,undef,$subroutine) = caller(++$i)) {
$ineval = 1, last if
$subroutine eq '(eval)';
}
return if $ineval && !$CPAN::End;
return unless defined $META->{LOCK};
return unless -f $META->{LOCK};
$META->savehist;
$META->{cachemgr} ||= CPAN::CacheMgr->new('atexit');
close $META->{LOCKFH};
unlink $META->{LOCK};
# require Carp;
# Carp::cluck("DEBUGGING");
if ( $CPAN::CONFIG_DIRTY ) {
$CPAN::Frontend->mywarn("Warning: Configuration not saved.\n");
}
$CPAN::Frontend->myprint("Lockfile removed.\n");
for my $msg ( @{ $META->_exit_messages } ) {
$CPAN::Frontend->myprint($msg);
}
}
#-> sub CPAN::readhist
sub readhist {
my($self,$term,$histfile) = @_;
my $histsize = $CPAN::Config->{'histsize'} || 100;
$term->Attribs->{'MaxHistorySize'} = $histsize if (defined($term->Attribs->{'MaxHistorySize'}));
my($fh) = FileHandle->new;
open $fh, "<$histfile" or return;
local $/ = "\n";
while (<$fh>) {
chomp;
$term->AddHistory($_);
}
close $fh;
}
#-> sub CPAN::savehist
sub savehist {
my($self) = @_;
my($histfile,$histsize);
unless ($histfile = $CPAN::Config->{'histfile'}) {
$CPAN::Frontend->mywarn("No history written (no histfile specified).\n");
return;
}
$histsize = $CPAN::Config->{'histsize'} || 100;
if ($CPAN::term) {
unless ($CPAN::term->can("GetHistory")) {
$CPAN::Frontend->mywarn("Terminal does not support GetHistory.\n");
return;
}
} else {
return;
}
my @h = $CPAN::term->GetHistory;
splice @h, 0, @h-$histsize if @h>$histsize;
my($fh) = FileHandle->new;
open $fh, ">$histfile" or $CPAN::Frontend->mydie("Couldn't open >$histfile: $!");
local $\ = local $, = "\n";
print $fh @h;
close $fh;
}
#-> sub CPAN::is_tested
sub is_tested {
my($self,$what,$when) = @_;
unless ($what) {
Carp::cluck("DEBUG: empty what");
return;
}
$self->{is_tested}{$what} = $when;
}
#-> sub CPAN::reset_tested
# forget all distributions tested -- resets what gets included in PERL5LIB
sub reset_tested {
my ($self) = @_;
$self->{is_tested} = {};
}
#-> sub CPAN::is_installed
# unsets the is_tested flag: as soon as the thing is installed, it is
# not needed in set_perl5lib anymore
sub is_installed {
my($self,$what) = @_;
delete $self->{is_tested}{$what};
}
sub _list_sorted_descending_is_tested {
my($self) = @_;
my $foul = 0;
my @sorted = sort
{ ($self->{is_tested}{$b}||0) <=> ($self->{is_tested}{$a}||0) }
grep
{ if ($foul){ 0 } elsif (-e) { 1 } else { $foul = $_; 0 } }
keys %{$self->{is_tested}};
if ($foul) {
$CPAN::Frontend->mywarn("Lost build_dir detected ($foul), giving up all cached test results of currently running session.\n");
for my $dbd (sort keys %{$self->{is_tested}}) { # distro-build-dir
SEARCH: for my $d (sort { $a->id cmp $b->id } $CPAN::META->all_objects("CPAN::Distribution")) {
if ($d->{build_dir} && $d->{build_dir} eq $dbd) {
$CPAN::Frontend->mywarn(sprintf "Flushing cache for %s\n", $d->pretty_id);
$d->fforce("");
last SEARCH;
}
}
delete $self->{is_tested}{$dbd};
}
return ();
} else {
return @sorted;
}
}
#-> sub CPAN::set_perl5lib
# Notes on max environment variable length:
# - Win32 : XP or later, 8191; Win2000 or NT4, 2047
{
my $fh;
sub set_perl5lib {
my($self,$for) = @_;
unless ($for) {
(undef,undef,undef,$for) = caller(1);
$for =~ s/.*://;
}
$self->{is_tested} ||= {};
return unless %{$self->{is_tested}};
my $env = $ENV{PERL5LIB};
$env = $ENV{PERLLIB} unless defined $env;
my @env;
push @env, split /\Q$Config::Config{path_sep}\E/, $env if defined $env and length $env;
#my @dirs = map {("$_/blib/arch", "$_/blib/lib")} keys %{$self->{is_tested}};
#$CPAN::Frontend->myprint("Prepending @dirs to PERL5LIB.\n");
my @dirs = map {("$_/blib/arch", "$_/blib/lib")} $self->_list_sorted_descending_is_tested;
return if !@dirs;
if (@dirs < 12) {
$CPAN::Frontend->optprint('perl5lib', "Prepending @dirs to PERL5LIB for '$for'\n");
$ENV{PERL5LIB} = join $Config::Config{path_sep}, @dirs, @env;
} elsif (@dirs < 24 ) {
my @d = map {my $cp = $_;
$cp =~ s/^\Q$CPAN::Config->{build_dir}\E/%BUILDDIR%/;
$cp
} @dirs;
$CPAN::Frontend->optprint('perl5lib', "Prepending @d to PERL5LIB; ".
"%BUILDDIR%=$CPAN::Config->{build_dir} ".
"for '$for'\n"
);
$ENV{PERL5LIB} = join $Config::Config{path_sep}, @dirs, @env;
} else {
my $cnt = keys %{$self->{is_tested}};
my $newenv = join $Config::Config{path_sep}, @dirs, @env;
$CPAN::Frontend->optprint('perl5lib', sprintf ("Prepending blib/arch and blib/lib of ".
"%d build dirs to PERL5LIB, reaching size %d; ".
"for '%s'\n", $cnt, length($newenv), $for)
);
$ENV{PERL5LIB} = $newenv;
}
}}
1;
__END__
=head1 NAME
CPAN - query, download and build perl modules from CPAN sites
=head1 SYNOPSIS
Interactive mode:
perl -MCPAN -e shell
--or--
cpan
Basic commands:
# Modules:
cpan> install Acme::Meta # in the shell
CPAN::Shell->install("Acme::Meta"); # in perl
# Distributions:
cpan> install NWCLARK/Acme-Meta-0.02.tar.gz # in the shell
CPAN::Shell->
install("NWCLARK/Acme-Meta-0.02.tar.gz"); # in perl
# module objects:
$mo = CPAN::Shell->expandany($mod);
$mo = CPAN::Shell->expand("Module",$mod); # same thing
# distribution objects:
$do = CPAN::Shell->expand("Module",$mod)->distribution;
$do = CPAN::Shell->expandany($distro); # same thing
$do = CPAN::Shell->expand("Distribution",
$distro); # same thing
=head1 DESCRIPTION
The CPAN module automates or at least simplifies the make and install
of perl modules and extensions. It includes some primitive searching
capabilities and knows how to use LWP, HTTP::Tiny, Net::FTP and certain
external download clients to fetch distributions from the net.
These are fetched from one or more mirrored CPAN (Comprehensive
Perl Archive Network) sites and unpacked in a dedicated directory.
The CPAN module also supports named and versioned
I<bundles> of modules. Bundles simplify handling of sets of
related modules. See Bundles below.
The package contains a session manager and a cache manager. The
session manager keeps track of what has been fetched, built, and
installed in the current session. The cache manager keeps track of the
disk space occupied by the make processes and deletes excess space
using a simple FIFO mechanism.
All methods provided are accessible in a programmer style and in an
interactive shell style.
=head2 CPAN::shell([$prompt, $command]) Starting Interactive Mode
Enter interactive mode by running
perl -MCPAN -e shell
or
cpan
which puts you into a readline interface. If C<Term::ReadKey> and
either of C<Term::ReadLine::Perl> or C<Term::ReadLine::Gnu> are installed,
history and command completion are supported.
Once at the command line, type C<h> for one-page help
screen; the rest should be self-explanatory.
The function call C<shell> takes two optional arguments: one the
prompt, the second the default initial command line (the latter
only works if a real ReadLine interface module is installed).
The most common uses of the interactive modes are
=over 2
=item Searching for authors, bundles, distribution files and modules
There are corresponding one-letter commands C<a>, C<b>, C<d>, and C<m>
for each of the four categories and another, C<i> for any of the
mentioned four. Each of the four entities is implemented as a class
with slightly differing methods for displaying an object.
Arguments to these commands are either strings exactly matching
the identification string of an object, or regular expressions
matched case-insensitively against various attributes of the
objects. The parser only recognizes a regular expression when you
enclose it with slashes.
The principle is that the number of objects found influences how an
item is displayed. If the search finds one item, the result is
displayed with the rather verbose method C<as_string>, but if
more than one is found, each object is displayed with the terse method
C<as_glimpse>.
Examples:
cpan> m Acme::MetaSyntactic
Module id = Acme::MetaSyntactic
CPAN_USERID BOOK (Philippe Bruhat (BooK) <[...]>)
CPAN_VERSION 0.99
CPAN_FILE B/BO/BOOK/Acme-MetaSyntactic-0.99.tar.gz
UPLOAD_DATE 2006-11-06
MANPAGE Acme::MetaSyntactic - Themed metasyntactic variables names
INST_FILE /usr/local/lib/perl/5.10.0/Acme/MetaSyntactic.pm
INST_VERSION 0.99
cpan> a BOOK
Author id = BOOK
EMAIL [...]
FULLNAME Philippe Bruhat (BooK)
cpan> d BOOK/Acme-MetaSyntactic-0.99.tar.gz
Distribution id = B/BO/BOOK/Acme-MetaSyntactic-0.99.tar.gz
CPAN_USERID BOOK (Philippe Bruhat (BooK) <[...]>)
CONTAINSMODS Acme::MetaSyntactic Acme::MetaSyntactic::Alias [...]
UPLOAD_DATE 2006-11-06
cpan> m /lorem/
Module = Acme::MetaSyntactic::loremipsum (BOOK/Acme-MetaSyntactic-0.99.tar.gz)
Module Text::Lorem (ADEOLA/Text-Lorem-0.3.tar.gz)
Module Text::Lorem::More (RKRIMEN/Text-Lorem-More-0.12.tar.gz)
Module Text::Lorem::More::Source (RKRIMEN/Text-Lorem-More-0.12.tar.gz)
cpan> i /berlin/
Distribution BEATNIK/Filter-NumberLines-0.02.tar.gz
Module = DateTime::TimeZone::Europe::Berlin (DROLSKY/DateTime-TimeZone-0.7904.tar.gz)
Module Filter::NumberLines (BEATNIK/Filter-NumberLines-0.02.tar.gz)
Author [...]
The examples illustrate several aspects: the first three queries
target modules, authors, or distros directly and yield exactly one
result. The last two use regular expressions and yield several
results. The last one targets all of bundles, modules, authors, and
distros simultaneously. When more than one result is available, they
are printed in one-line format.
=item C<get>, C<make>, C<test>, C<install>, C<clean> modules or distributions
These commands take any number of arguments and investigate what is
necessary to perform the action. Argument processing is as follows:
known module name in format Foo/Bar.pm module
other embedded slash distribution
- with trailing slash dot directory
enclosing slashes regexp
known module name in format Foo::Bar module
If the argument is a distribution file name (recognized by embedded
slashes), it is processed. If it is a module, CPAN determines the
distribution file in which this module is included and processes that,
following any dependencies named in the module's META.yml or
Makefile.PL (this behavior is controlled by the configuration
parameter C<prerequisites_policy>). If an argument is enclosed in
slashes it is treated as a regular expression: it is expanded and if
the result is a single object (distribution, bundle or module), this
object is processed.
Example:
install Dummy::Perl # installs the module
install AUXXX/Dummy-Perl-3.14.tar.gz # installs that distribution
install /Dummy-Perl-3.14/ # same if the regexp is unambiguous
C<get> downloads a distribution file and untars or unzips it, C<make>
builds it, C<test> runs the test suite, and C<install> installs it.
Any C<make> or C<test> is run unconditionally. An
install <distribution_file>
is also run unconditionally. But for
install <module>
CPAN checks whether an install is needed and prints
I<module up to date> if the distribution file containing
the module doesn't need updating.
CPAN also keeps track of what it has done within the current session
and doesn't try to build a package a second time regardless of whether it
succeeded or not. It does not repeat a test run if the test
has been run successfully before. Same for install runs.
The C<force> pragma may precede another command (currently: C<get>,
C<make>, C<test>, or C<install>) to execute the command from scratch
and attempt to continue past certain errors. See the section below on
the C<force> and the C<fforce> pragma.
The C<notest> pragma skips the test part in the build
process.
Example:
cpan> notest install Tk
A C<clean> command results in a
make clean
being executed within the distribution file's working directory.
=item C<readme>, C<perldoc>, C<look> module or distribution
C<readme> displays the README file of the associated distribution.
C<Look> gets and untars (if not yet done) the distribution file,
changes to the appropriate directory and opens a subshell process in
that directory. C<perldoc> displays the module's pod documentation
in html or plain text format.
=item C<ls> author
=item C<ls> globbing_expression
The first form lists all distribution files in and below an author's
CPAN directory as stored in the CHECKSUMS files distributed on
CPAN. The listing recurses into subdirectories.
The second form limits or expands the output with shell
globbing as in the following examples:
ls JV/make*
ls GSAR/*make*
ls */*make*
The last example is very slow and outputs extra progress indicators
that break the alignment of the result.
Note that globbing only lists directories explicitly asked for, for
example FOO/* will not list FOO/bar/Acme-Sthg-n.nn.tar.gz. This may be
regarded as a bug that may be changed in some future version.
=item C<failed>
The C<failed> command reports all distributions that failed on one of
C<make>, C<test> or C<install> for some reason in the currently
running shell session.
=item Persistence between sessions
If the C<YAML> or the C<YAML::Syck> module is installed a record of
the internal state of all modules is written to disk after each step.
The files contain a signature of the currently running perl version
for later perusal.
If the configurations variable C<build_dir_reuse> is set to a true
value, then CPAN.pm reads the collected YAML files. If the stored
signature matches the currently running perl, the stored state is
loaded into memory such that persistence between sessions
is effectively established.
=item The C<force> and the C<fforce> pragma
To speed things up in complex installation scenarios, CPAN.pm keeps
track of what it has already done and refuses to do some things a
second time. A C<get>, a C<make>, and an C<install> are not repeated.
A C<test> is repeated only if the previous test was unsuccessful. The
diagnostic message when CPAN.pm refuses to do something a second time
is one of I<Has already been >C<unwrapped|made|tested successfully> or
something similar. Another situation where CPAN refuses to act is an
C<install> if the corresponding C<test> was not successful.
In all these cases, the user can override this stubborn behaviour by
prepending the command with the word force, for example:
cpan> force get Foo
cpan> force make AUTHOR/Bar-3.14.tar.gz
cpan> force test Baz
cpan> force install Acme::Meta
Each I<forced> command is executed with the corresponding part of its
memory erased.
The C<fforce> pragma is a variant that emulates a C<force get> which
erases the entire memory followed by the action specified, effectively
restarting the whole get/make/test/install procedure from scratch.
=item Lockfile
Interactive sessions maintain a lockfile, by default C<~/.cpan/.lock>.
Batch jobs can run without a lockfile and not disturb each other.
The shell offers to run in I<downgraded mode> when another process is
holding the lockfile. This is an experimental feature that is not yet
tested very well. This second shell then does not write the history
file, does not use the metadata file, and has a different prompt.
=item Signals
CPAN.pm installs signal handlers for SIGINT and SIGTERM. While you are
in the cpan-shell, it is intended that you can press C<^C> anytime and
return to the cpan-shell prompt. A SIGTERM will cause the cpan-shell
to clean up and leave the shell loop. You can emulate the effect of a
SIGTERM by sending two consecutive SIGINTs, which usually means by
pressing C<^C> twice.
CPAN.pm ignores SIGPIPE. If the user sets C<inactivity_timeout>, a
SIGALRM is used during the run of the C<perl Makefile.PL> or C<perl
Build.PL> subprocess. A SIGALRM is also used during module version
parsing, and is controlled by C<version_timeout>.
=back
=head2 CPAN::Shell
The commands available in the shell interface are methods in
the package CPAN::Shell. If you enter the shell command, your
input is split by the Text::ParseWords::shellwords() routine, which
acts like most shells do. The first word is interpreted as the
method to be invoked, and the rest of the words are treated as the method's arguments.
Continuation lines are supported by ending a line with a
literal backslash.
=head2 autobundle
C<autobundle> writes a bundle file into the
C<$CPAN::Config-E<gt>{cpan_home}/Bundle> directory. The file contains
a list of all modules that are both available from CPAN and currently
installed within @INC. Duplicates of each distribution are suppressed.
The name of the bundle file is based on the current date and a
counter, e.g. F<Bundle/Snapshot_2012_05_21_00.pm>. This is installed
again by running C<cpan Bundle::Snapshot_2012_05_21_00>, or installing
C<Bundle::Snapshot_2012_05_21_00> from the CPAN shell.
Return value: path to the written file.
=head2 hosts
Note: this feature is still in alpha state and may change in future
versions of CPAN.pm
This commands provides a statistical overview over recent download
activities. The data for this is collected in the YAML file
C<FTPstats.yml> in your C<cpan_home> directory. If no YAML module is
configured or YAML not installed, or if C<ftpstats_size> is set to a
value C<< <=0 >>, no stats are provided.
=head2 install_tested
Install all distributions that have been tested successfully but have
not yet been installed. See also C<is_tested>.
=head2 is_tested
List all build directories of distributions that have been tested
successfully but have not yet been installed. See also
C<install_tested>.
=head2 mkmyconfig
mkmyconfig() writes your own CPAN::MyConfig file into your C<~/.cpan/>
directory so that you can save your own preferences instead of the
system-wide ones.
=head2 r [Module|/Regexp/]...
scans current perl installation for modules that have a newer version
available on CPAN and provides a list of them. If called without
argument, all potential upgrades are listed; if called with arguments
the list is filtered to the modules and regexps given as arguments.
The listing looks something like this:
Package namespace installed latest in CPAN file
CPAN 1.94_64 1.9600 ANDK/CPAN-1.9600.tar.gz
CPAN::Reporter 1.1801 1.1902 DAGOLDEN/CPAN-Reporter-1.1902.tar.gz
YAML 0.70 0.73 INGY/YAML-0.73.tar.gz
YAML::Syck 1.14 1.17 AVAR/YAML-Syck-1.17.tar.gz
YAML::Tiny 1.44 1.50 ADAMK/YAML-Tiny-1.50.tar.gz
CGI 3.43 3.55 MARKSTOS/CGI.pm-3.55.tar.gz
Module::Build::YAML 1.40 1.41 DAGOLDEN/Module-Build-0.3800.tar.gz
TAP::Parser::Result::YAML 3.22 3.23 ANDYA/Test-Harness-3.23.tar.gz
YAML::XS 0.34 0.35 INGY/YAML-LibYAML-0.35.tar.gz
It suppresses duplicates in the column C<in CPAN file> such that
distributions with many upgradeable modules are listed only once.
Note that the list is not sorted.
=head2 recent ***EXPERIMENTAL COMMAND***
The C<recent> command downloads a list of recent uploads to CPAN and
displays them I<slowly>. While the command is running, a $SIG{INT}
exits the loop after displaying the current item.
B<Note>: This command requires XML::LibXML installed.
B<Note>: This whole command currently is just a hack and will
probably change in future versions of CPAN.pm, but the general
approach will likely remain.
B<Note>: See also L<smoke>
=head2 recompile
recompile() is a special command that takes no argument and
runs the make/test/install cycle with brute force over all installed
dynamically loadable extensions (a.k.a. XS modules) with 'force' in
effect. The primary purpose of this command is to finish a network
installation. Imagine you have a common source tree for two different
architectures. You decide to do a completely independent fresh
installation. You start on one architecture with the help of a Bundle
file produced earlier. CPAN installs the whole Bundle for you, but
when you try to repeat the job on the second architecture, CPAN
responds with a C<"Foo up to date"> message for all modules. So you
invoke CPAN's recompile on the second architecture and you're done.
Another popular use for C<recompile> is to act as a rescue in case your
perl breaks binary compatibility. If one of the modules that CPAN uses
is in turn depending on binary compatibility (so you cannot run CPAN
commands), then you should try the CPAN::Nox module for recovery.
=head2 report Bundle|Distribution|Module
The C<report> command temporarily turns on the C<test_report> config
variable, then runs the C<force test> command with the given
arguments. The C<force> pragma reruns the tests and repeats
every step that might have failed before.
=head2 smoke ***EXPERIMENTAL COMMAND***
B<*** WARNING: this command downloads and executes software from CPAN to
your computer of completely unknown status. You should never do
this with your normal account and better have a dedicated well
separated and secured machine to do this. ***>
The C<smoke> command takes the list of recent uploads to CPAN as
provided by the C<recent> command and tests them all. While the
command is running $SIG{INT} is defined to mean that the current item
shall be skipped.
B<Note>: This whole command currently is just a hack and will
probably change in future versions of CPAN.pm, but the general
approach will likely remain.
B<Note>: See also L<recent>
=head2 upgrade [Module|/Regexp/]...
The C<upgrade> command first runs an C<r> command with the given
arguments and then installs the newest versions of all modules that
were listed by that.
=head2 The four C<CPAN::*> Classes: Author, Bundle, Module, Distribution
Although it may be considered internal, the class hierarchy does matter
for both users and programmer. CPAN.pm deals with the four
classes mentioned above, and those classes all share a set of methods. Classical
single polymorphism is in effect. A metaclass object registers all
objects of all kinds and indexes them with a string. The strings
referencing objects have a separated namespace (well, not completely
separated):
Namespace Class
words containing a "/" (slash) Distribution
words starting with Bundle:: Bundle
everything else Module or Author
Modules know their associated Distribution objects. They always refer
to the most recent official release. Developers may mark their releases
as unstable development versions (by inserting an underscore into the
module version number which will also be reflected in the distribution
name when you run 'make dist'), so the really hottest and newest
distribution is not always the default. If a module Foo circulates
on CPAN in both version 1.23 and 1.23_90, CPAN.pm offers a convenient
way to install version 1.23 by saying
install Foo
This would install the complete distribution file (say
BAR/Foo-1.23.tar.gz) with all accompanying material. But if you would
like to install version 1.23_90, you need to know where the
distribution file resides on CPAN relative to the authors/id/
directory. If the author is BAR, this might be BAR/Foo-1.23_90.tar.gz;
so you would have to say
install BAR/Foo-1.23_90.tar.gz
The first example will be driven by an object of the class
CPAN::Module, the second by an object of class CPAN::Distribution.
=head2 Integrating local directories
Note: this feature is still in alpha state and may change in future
versions of CPAN.pm
Distribution objects are normally distributions from the CPAN, but
there is a slightly degenerate case for Distribution objects, too, of
projects held on the local disk. These distribution objects have the
same name as the local directory and end with a dot. A dot by itself
is also allowed for the current directory at the time CPAN.pm was
used. All actions such as C<make>, C<test>, and C<install> are applied
directly to that directory. This gives the command C<cpan .> an
interesting touch: while the normal mantra of installing a CPAN module
without CPAN.pm is one of
perl Makefile.PL perl Build.PL
( go and get prerequisites )
make ./Build
make test ./Build test
make install ./Build install
the command C<cpan .> does all of this at once. It figures out which
of the two mantras is appropriate, fetches and installs all
prerequisites, takes care of them recursively, and finally finishes the
installation of the module in the current directory, be it a CPAN
module or not.
The typical usage case is for private modules or working copies of
projects from remote repositories on the local disk.
=head2 Redirection
The usual shell redirection symbols C< | > and C<< > >> are recognized
by the cpan shell B<only when surrounded by whitespace>. So piping to
pager or redirecting output into a file works somewhat as in a normal
shell, with the stipulation that you must type extra spaces.
=head2 Plugin support ***EXPERIMENTAL***
Plugins are objects that implement any of currently eight methods:
pre_get
post_get
pre_make
post_make
pre_test
post_test
pre_install
post_install
The C<plugin_list> configuration parameter holds a list of strings of
the form
Modulename=arg0,arg1,arg2,arg3,...
eg:
CPAN::Plugin::Flurb=dir,/opt/pkgs/flurb/raw,verbose,1
At run time, each listed plugin is instantiated as a singleton object
by running the equivalent of this pseudo code:
my $plugin = <string representation from config>;
<generate Modulename and arguments from $plugin>;
my $p = $instance{$plugin} ||= Modulename->new($arg0,$arg1,...);
The generated singletons are kept around from instantiation until the
end of the shell session. <plugin_list> can be reconfigured at any
time at run time. While the cpan shell is running, it checks all
activated plugins at each of the 8 reference points listed above and
runs the respective method if it is implemented for that object. The
method is called with the active CPAN::Distribution object passed in
as an argument.
=head1 CONFIGURATION
When the CPAN module is used for the first time, a configuration
dialogue tries to determine a couple of site specific options. The
result of the dialog is stored in a hash reference C< $CPAN::Config >
in a file CPAN/Config.pm.
Default values defined in the CPAN/Config.pm file can be
overridden in a user specific file: CPAN/MyConfig.pm. Such a file is
best placed in C<$HOME/.cpan/CPAN/MyConfig.pm>, because C<$HOME/.cpan> is
added to the search path of the CPAN module before the use() or
require() statements. The mkmyconfig command writes this file for you.
If you want to keep your own CPAN/MyConfig.pm somewhere else, you
should load it before loading CPAN.pm, e.g.:
perl -I/tmp/somewhere -MCPAN::MyConfig -MCPAN -eshell
--or--
perl -I/tmp/somewhere -MCPAN::MyConfig -S cpan
Once you are in the shell you can change your configuration as follows.
The C<o conf> command has various bells and whistles:
=over
=item completion support
If you have a ReadLine module installed, you can hit TAB at any point
of the commandline and C<o conf> will offer you completion for the
built-in subcommands and/or config variable names.
=item displaying some help: o conf help
Displays a short help
=item displaying current values: o conf [KEY]
Displays the current value(s) for this config variable. Without KEY,
displays all subcommands and config variables.
Example:
o conf shell
If KEY starts and ends with a slash, the string in between is
treated as a regular expression and only keys matching this regexp
are displayed
Example:
o conf /color/
=item changing of scalar values: o conf KEY VALUE
Sets the config variable KEY to VALUE. The empty string can be
specified as usual in shells, with C<''> or C<"">
Example:
o conf wget /usr/bin/wget
=item changing of list values: o conf KEY SHIFT|UNSHIFT|PUSH|POP|SPLICE|LIST
If a config variable name ends with C<list>, it is a list. C<o conf
KEY shift> removes the first element of the list, C<o conf KEY pop>
removes the last element of the list. C<o conf KEYS unshift LIST>
prepends a list of values to the list, C<o conf KEYS push LIST>
appends a list of valued to the list.
Likewise, C<o conf KEY splice LIST> passes the LIST to the corresponding
splice command.
Finally, any other list of arguments is taken as a new list value for
the KEY variable discarding the previous value.
Examples:
o conf urllist unshift http://cpan.dev.local/CPAN
o conf urllist splice 3 1
o conf urllist http://cpan1.local http://cpan2.local ftp://ftp.perl.org
=item reverting to saved: o conf defaults
Reverts all config variables to the state in the saved config file.
=item saving the config: o conf commit
Saves all config variables to the current config file (CPAN/Config.pm
or CPAN/MyConfig.pm that was loaded at start).
=back
The configuration dialog can be started any time later again by
issuing the command C< o conf init > in the CPAN shell. A subset of
the configuration dialog can be run by issuing C<o conf init WORD>
where WORD is any valid config variable or a regular expression.
=head2 Config Variables
The following keys in the hash reference $CPAN::Config are
currently defined:
allow_installing_module_downgrades
allow or disallow installing module downgrades
allow_installing_outdated_dists
allow or disallow installing modules that are
indexed in the cpan index pointing to a distro
with a higher distro-version number
applypatch path to external prg
auto_commit commit all changes to config variables to disk
build_cache size of cache for directories to build modules
build_dir locally accessible directory to build modules
build_dir_reuse boolean if distros in build_dir are persistent
build_requires_install_policy
to install or not to install when a module is
only needed for building. yes|no|ask/yes|ask/no
bzip2 path to external prg
cache_metadata use serializer to cache metadata
check_sigs if signatures should be verified
cleanup_after_install
remove build directory immediately after a
successful install and remember that for the
duration of the session
colorize_debug Term::ANSIColor attributes for debugging output
colorize_output boolean if Term::ANSIColor should colorize output
colorize_print Term::ANSIColor attributes for normal output
colorize_warn Term::ANSIColor attributes for warnings
commandnumber_in_prompt
boolean if you want to see current command number
commands_quote preferred character to use for quoting external
commands when running them. Defaults to double
quote on Windows, single tick everywhere else;
can be set to space to disable quoting
connect_to_internet_ok
whether to ask if opening a connection is ok before
urllist is specified
cpan_home local directory reserved for this package
curl path to external prg
dontload_hash DEPRECATED
dontload_list arrayref: modules in the list will not be
loaded by the CPAN::has_inst() routine
ftp path to external prg
ftp_passive if set, the environment variable FTP_PASSIVE is set
for downloads
ftp_proxy proxy host for ftp requests
ftpstats_period max number of days to keep download statistics
ftpstats_size max number of items to keep in the download statistics
getcwd see below
gpg path to external prg
gzip location of external program gzip
halt_on_failure stop processing after the first failure of queued
items or dependencies
histfile file to maintain history between sessions
histsize maximum number of lines to keep in histfile
http_proxy proxy host for http requests
inactivity_timeout breaks interactive Makefile.PLs or Build.PLs
after this many seconds inactivity. Set to 0 to
disable timeouts.
index_expire refetch index files after this many days
inhibit_startup_message
if true, suppress the startup message
keep_source_where directory in which to keep the source (if we do)
load_module_verbosity
report loading of optional modules used by CPAN.pm
lynx path to external prg
make location of external make program
make_arg arguments that should always be passed to 'make'
make_install_make_command
the make command for running 'make install', for
example 'sudo make'
make_install_arg same as make_arg for 'make install'
makepl_arg arguments passed to 'perl Makefile.PL'
mbuild_arg arguments passed to './Build'
mbuild_install_arg arguments passed to './Build install'
mbuild_install_build_command
command to use instead of './Build' when we are
in the install stage, for example 'sudo ./Build'
mbuildpl_arg arguments passed to 'perl Build.PL'
ncftp path to external prg
ncftpget path to external prg
no_proxy don't proxy to these hosts/domains (comma separated list)
pager location of external program more (or any pager)
password your password if you CPAN server wants one
patch path to external prg
patches_dir local directory containing patch files
perl5lib_verbosity verbosity level for PERL5LIB additions
plugin_list list of active hooks (see Plugin support above
and the CPAN::Plugin module)
prefer_external_tar
per default all untar operations are done with
Archive::Tar; by setting this variable to true
the external tar command is used if available
prefer_installer legal values are MB and EUMM: if a module comes
with both a Makefile.PL and a Build.PL, use the
former (EUMM) or the latter (MB); if the module
comes with only one of the two, that one will be
used no matter the setting
prerequisites_policy
what to do if you are missing module prerequisites
('follow' automatically, 'ask' me, or 'ignore')
For 'follow', also sets PERL_AUTOINSTALL and
PERL_EXTUTILS_AUTOINSTALL for "--defaultdeps" if
not already set
prefs_dir local directory to store per-distro build options
proxy_user username for accessing an authenticating proxy
proxy_pass password for accessing an authenticating proxy
pushy_https use https to cpan.org when possible, otherwise use http
to cpan.org and issue a warning
randomize_urllist add some randomness to the sequence of the urllist
recommends_policy whether recommended prerequisites should be included
scan_cache controls scanning of cache ('atstart', 'atexit' or 'never')
shell your favorite shell
show_unparsable_versions
boolean if r command tells which modules are versionless
show_upload_date boolean if commands should try to determine upload date
show_zero_versions boolean if r command tells for which modules $version==0
suggests_policy whether suggested prerequisites should be included
tar location of external program tar
tar_verbosity verbosity level for the tar command
term_is_latin deprecated: if true Unicode is translated to ISO-8859-1
(and nonsense for characters outside latin range)
term_ornaments boolean to turn ReadLine ornamenting on/off
test_report email test reports (if CPAN::Reporter is installed)
trust_test_report_history
skip testing when previously tested ok (according to
CPAN::Reporter history)
unzip location of external program unzip
urllist arrayref to nearby CPAN sites (or equivalent locations)
urllist_ping_external
use external ping command when autoselecting mirrors
urllist_ping_verbose
increase verbosity when autoselecting mirrors
use_prompt_default set PERL_MM_USE_DEFAULT for configure/make/test/install
use_sqlite use CPAN::SQLite for metadata storage (fast and lean)
username your username if you CPAN server wants one
version_timeout stops version parsing after this many seconds.
Default is 15 secs. Set to 0 to disable.
wait_list arrayref to a wait server to try (See CPAN::WAIT)
wget path to external prg
yaml_load_code enable YAML code deserialisation via CPAN::DeferredCode
yaml_module which module to use to read/write YAML files
You can set and query each of these options interactively in the cpan
shell with the C<o conf> or the C<o conf init> command as specified below.
=over 2
=item C<o conf E<lt>scalar optionE<gt>>
prints the current value of the I<scalar option>
=item C<o conf E<lt>scalar optionE<gt> E<lt>valueE<gt>>
Sets the value of the I<scalar option> to I<value>
=item C<o conf E<lt>list optionE<gt>>
prints the current value of the I<list option> in MakeMaker's
neatvalue format.
=item C<o conf E<lt>list optionE<gt> [shift|pop]>
shifts or pops the array in the I<list option> variable
=item C<o conf E<lt>list optionE<gt> [unshift|push|splice] E<lt>listE<gt>>
works like the corresponding perl commands.
=item interactive editing: o conf init [MATCH|LIST]
Runs an interactive configuration dialog for matching variables.
Without argument runs the dialog over all supported config variables.
To specify a MATCH the argument must be enclosed by slashes.
Examples:
o conf init ftp_passive ftp_proxy
o conf init /color/
Note: this method of setting config variables often provides more
explanation about the functioning of a variable than the manpage.
=back
=head2 CPAN::anycwd($path): Note on config variable getcwd
CPAN.pm changes the current working directory often and needs to
determine its own current working directory. By default it uses
Cwd::cwd, but if for some reason this doesn't work on your system,
configure alternatives according to the following table:
=over 4
=item cwd
Calls Cwd::cwd
=item getcwd
Calls Cwd::getcwd
=item fastcwd
Calls Cwd::fastcwd
=item getdcwd
Calls Cwd::getdcwd
=item backtickcwd
Calls the external command cwd.
=back
=head2 Note on the format of the urllist parameter
urllist parameters are URLs according to RFC 1738. We do a little
guessing if your URL is not compliant, but if you have problems with
C<file> URLs, please try the correct format. Either:
file://localhost/whatever/ftp/pub/CPAN/
or
file:///home/ftp/pub/CPAN/
=head2 The urllist parameter has CD-ROM support
The C<urllist> parameter of the configuration table contains a list of
URLs used for downloading. If the list contains any
C<file> URLs, CPAN always tries there first. This
feature is disabled for index files. So the recommendation for the
owner of a CD-ROM with CPAN contents is: include your local, possibly
outdated CD-ROM as a C<file> URL at the end of urllist, e.g.
o conf urllist push file://localhost/CDROM/CPAN
CPAN.pm will then fetch the index files from one of the CPAN sites
that come at the beginning of urllist. It will later check for each
module to see whether there is a local copy of the most recent version.
Another peculiarity of urllist is that the site that we could
successfully fetch the last file from automatically gets a preference
token and is tried as the first site for the next request. So if you
add a new site at runtime it may happen that the previously preferred
site will be tried another time. This means that if you want to disallow
a site for the next transfer, it must be explicitly removed from
urllist.
=head2 Maintaining the urllist parameter
If you have YAML.pm (or some other YAML module configured in
C<yaml_module>) installed, CPAN.pm collects a few statistical data
about recent downloads. You can view the statistics with the C<hosts>
command or inspect them directly by looking into the C<FTPstats.yml>
file in your C<cpan_home> directory.
To get some interesting statistics, it is recommended that
C<randomize_urllist> be set; this introduces some amount of
randomness into the URL selection.
=head2 The C<requires> and C<build_requires> dependency declarations
Since CPAN.pm version 1.88_51 modules declared as C<build_requires> by
a distribution are treated differently depending on the config
variable C<build_requires_install_policy>. By setting
C<build_requires_install_policy> to C<no>, such a module is not
installed. It is only built and tested, and then kept in the list of
tested but uninstalled modules. As such, it is available during the
build of the dependent module by integrating the path to the
C<blib/arch> and C<blib/lib> directories in the environment variable
PERL5LIB. If C<build_requires_install_policy> is set to C<yes>, then
both modules declared as C<requires> and those declared as
C<build_requires> are treated alike. By setting to C<ask/yes> or
C<ask/no>, CPAN.pm asks the user and sets the default accordingly.
=head2 Configuration of the allow_installing_* parameters
The C<allow_installing_*> parameters are evaluated during
the C<make> phase. If set to C<yes>, they allow the testing and the installation of
the current distro and otherwise have no effect. If set to C<no>, they
may abort the build (preventing testing and installing), depending on the contents of the
C<blib/> directory. The C<blib/> directory is the directory that holds
all the files that would usually be installed in the C<install> phase.
C<allow_installing_outdated_dists> compares the C<blib/> directory with the CPAN index.
If it finds something there that belongs, according to the index, to a different
dist, it aborts the current build.
C<allow_installing_module_downgrades> compares the C<blib/> directory
with already installed modules, actually their version numbers, as
determined by ExtUtils::MakeMaker or equivalent. If a to-be-installed
module would downgrade an already installed module, the current build
is aborted.
An interesting twist occurs when a distroprefs document demands the
installation of an outdated dist via goto while
C<allow_installing_outdated_dists> forbids it. Without additional
provisions, this would let the C<allow_installing_outdated_dists>
win and the distroprefs lose. So the proper arrangement in such a case
is to write a second distroprefs document for the distro that C<goto>
points to and overrule the C<cpanconfig> there. E.g.:
---
match:
distribution: "^MAUKE/Keyword-Simple-0.04.tar.gz"
goto: "MAUKE/Keyword-Simple-0.03.tar.gz"
---
match:
distribution: "^MAUKE/Keyword-Simple-0.03.tar.gz"
cpanconfig:
allow_installing_outdated_dists: yes
=head2 Configuration for individual distributions (I<Distroprefs>)
(B<Note:> This feature has been introduced in CPAN.pm 1.8854)
Distributions on CPAN usually behave according to what we call the
CPAN mantra. Or since the advent of Module::Build we should talk about
two mantras:
perl Makefile.PL perl Build.PL
make ./Build
make test ./Build test
make install ./Build install
But some modules cannot be built with this mantra. They try to get
some extra data from the user via the environment, extra arguments, or
interactively--thus disturbing the installation of large bundles like
Phalanx100 or modules with many dependencies like Plagger.
The distroprefs system of C<CPAN.pm> addresses this problem by
allowing the user to specify extra informations and recipes in YAML
files to either
=over
=item
pass additional arguments to one of the four commands,
=item
set environment variables
=item
instantiate an Expect object that reads from the console, waits for
some regular expressions and enters some answers
=item
temporarily override assorted C<CPAN.pm> configuration variables
=item
specify dependencies the original maintainer forgot
=item
disable the installation of an object altogether
=back
See the YAML and Data::Dumper files that come with the C<CPAN.pm>
distribution in the C<distroprefs/> directory for examples.
=head2 Filenames
The YAML files themselves must have the C<.yml> extension; all other
files are ignored (for two exceptions see I<Fallback Data::Dumper and
Storable> below). The containing directory can be specified in
C<CPAN.pm> in the C<prefs_dir> config variable. Try C<o conf init
prefs_dir> in the CPAN shell to set and activate the distroprefs
system.
Every YAML file may contain arbitrary documents according to the YAML
specification, and every document is treated as an entity that
can specify the treatment of a single distribution.
Filenames can be picked arbitrarily; C<CPAN.pm> always reads
all files (in alphabetical order) and takes the key C<match> (see
below in I<Language Specs>) as a hashref containing match criteria
that determine if the current distribution matches the YAML document
or not.
=head2 Fallback Data::Dumper and Storable
If neither your configured C<yaml_module> nor YAML.pm is installed,
CPAN.pm falls back to using Data::Dumper and Storable and looks for
files with the extensions C<.dd> or C<.st> in the C<prefs_dir>
directory. These files are expected to contain one or more hashrefs.
For Data::Dumper generated files, this is expected to be done with by
defining C<$VAR1>, C<$VAR2>, etc. The YAML shell would produce these
with the command
ysh < somefile.yml > somefile.dd
For Storable files the rule is that they must be constructed such that
C<Storable::retrieve(file)> returns an array reference and the array
elements represent one distropref object each. The conversion from
YAML would look like so:
perl -MYAML=LoadFile -MStorable=nstore -e '
@y=LoadFile(shift);
nstore(\@y, shift)' somefile.yml somefile.st
In bootstrapping situations it is usually sufficient to translate only
a few YAML files to Data::Dumper for crucial modules like
C<YAML::Syck>, C<YAML.pm> and C<Expect.pm>. If you prefer Storable
over Data::Dumper, remember to pull out a Storable version that writes
an older format than all the other Storable versions that will need to
read them.
=head2 Blueprint
The following example contains all supported keywords and structures
with the exception of C<eexpect> which can be used instead of
C<expect>.
---
comment: "Demo"
match:
module: "Dancing::Queen"
distribution: "^CHACHACHA/Dancing-"
not_distribution: "\.zip$"
perl: "/usr/local/cariba-perl/bin/perl"
perlconfig:
archname: "freebsd"
not_cc: "gcc"
env:
DANCING_FLOOR: "Shubiduh"
disabled: 1
cpanconfig:
make: gmake
pl:
args:
- "--somearg=specialcase"
env: {}
expect:
- "Which is your favorite fruit"
- "apple\n"
make:
args:
- all
- extra-all
env: {}
expect: []
commandline: "echo SKIPPING make"
test:
args: []
env: {}
expect: []
install:
args: []
env:
WANT_TO_INSTALL: YES
expect:
- "Do you really want to install"
- "y\n"
patches:
- "ABCDE/Fedcba-3.14-ABCDE-01.patch"
depends:
configure_requires:
LWP: 5.8
build_requires:
Test::Exception: 0.25
requires:
Spiffy: 0.30
=head2 Language Specs
Every YAML document represents a single hash reference. The valid keys
in this hash are as follows:
=over
=item comment [scalar]
A comment
=item cpanconfig [hash]
Temporarily override assorted C<CPAN.pm> configuration variables.
Supported are: C<build_requires_install_policy>, C<check_sigs>,
C<make>, C<make_install_make_command>, C<prefer_installer>,
C<test_report>. Please report as a bug when you need another one
supported.
=item depends [hash] *** EXPERIMENTAL FEATURE ***
All three types, namely C<configure_requires>, C<build_requires>, and
C<requires> are supported in the way specified in the META.yml
specification. The current implementation I<merges> the specified
dependencies with those declared by the package maintainer. In a
future implementation this may be changed to override the original
declaration.
=item disabled [boolean]
Specifies that this distribution shall not be processed at all.
=item features [array] *** EXPERIMENTAL FEATURE ***
Experimental implementation to deal with optional_features from
META.yml. Still needs coordination with installer software and
currently works only for META.yml declaring C<dynamic_config=0>. Use
with caution.
=item goto [string]
The canonical name of a delegate distribution to install
instead. Useful when a new version, although it tests OK itself,
breaks something else or a developer release or a fork is already
uploaded that is better than the last released version.
=item install [hash]
Processing instructions for the C<make install> or C<./Build install>
phase of the CPAN mantra. See below under I<Processing Instructions>.
=item make [hash]
Processing instructions for the C<make> or C<./Build> phase of the
CPAN mantra. See below under I<Processing Instructions>.
=item match [hash]
A hashref with one or more of the keys C<distribution>, C<module>,
C<perl>, C<perlconfig>, and C<env> that specify whether a document is
targeted at a specific CPAN distribution or installation.
Keys prefixed with C<not_> negates the corresponding match.
The corresponding values are interpreted as regular expressions. The
C<distribution> related one will be matched against the canonical
distribution name, e.g. "AUTHOR/Foo-Bar-3.14.tar.gz".
The C<module> related one will be matched against I<all> modules
contained in the distribution until one module matches.
The C<perl> related one will be matched against C<$^X> (but with the
absolute path).
The value associated with C<perlconfig> is itself a hashref that is
matched against corresponding values in the C<%Config::Config> hash
living in the C<Config.pm> module.
Keys prefixed with C<not_> negates the corresponding match.
The value associated with C<env> is itself a hashref that is
matched against corresponding values in the C<%ENV> hash.
Keys prefixed with C<not_> negates the corresponding match.
If more than one restriction of C<module>, C<distribution>, etc. is
specified, the results of the separately computed match values must
all match. If so, the hashref represented by the
YAML document is returned as the preference structure for the current
distribution.
=item patches [array]
An array of patches on CPAN or on the local disk to be applied in
order via an external patch program. If the value for the C<-p>
parameter is C<0> or C<1> is determined by reading the patch
beforehand. The path to each patch is either an absolute path on the
local filesystem or relative to a patch directory specified in the
C<patches_dir> configuration variable or in the format of a canonical
distro name. For examples please consult the distroprefs/ directory in
the CPAN.pm distribution (these examples are not installed by
default).
Note: if the C<applypatch> program is installed and C<CPAN::Config>
knows about it B<and> a patch is written by the C<makepatch> program,
then C<CPAN.pm> lets C<applypatch> apply the patch. Both C<makepatch>
and C<applypatch> are available from CPAN in the C<JV/makepatch-*>
distribution.
=item pl [hash]
Processing instructions for the C<perl Makefile.PL> or C<perl
Build.PL> phase of the CPAN mantra. See below under I<Processing
Instructions>.
=item test [hash]
Processing instructions for the C<make test> or C<./Build test> phase
of the CPAN mantra. See below under I<Processing Instructions>.
=back
=head2 Processing Instructions
=over
=item args [array]
Arguments to be added to the command line
=item commandline
A full commandline to run via C<system()>.
During execution, the environment variable PERL is set
to $^X (but with an absolute path). If C<commandline> is specified,
C<args> is not used.
=item eexpect [hash]
Extended C<expect>. This is a hash reference with four allowed keys,
C<mode>, C<timeout>, C<reuse>, and C<talk>.
You must install the C<Expect> module to use C<eexpect>. CPAN.pm
does not install it for you.
C<mode> may have the values C<deterministic> for the case where all
questions come in the order written down and C<anyorder> for the case
where the questions may come in any order. The default mode is
C<deterministic>.
C<timeout> denotes a timeout in seconds. Floating-point timeouts are
OK. With C<mode=deterministic>, the timeout denotes the
timeout per question; with C<mode=anyorder> it denotes the
timeout per byte received from the stream or questions.
C<talk> is a reference to an array that contains alternating questions
and answers. Questions are regular expressions and answers are literal
strings. The Expect module watches the stream from the
execution of the external program (C<perl Makefile.PL>, C<perl
Build.PL>, C<make>, etc.).
For C<mode=deterministic>, the CPAN.pm injects the
corresponding answer as soon as the stream matches the regular expression.
For C<mode=anyorder> CPAN.pm answers a question as soon
as the timeout is reached for the next byte in the input stream. In
this mode you can use the C<reuse> parameter to decide what will
happen with a question-answer pair after it has been used. In the
default case (reuse=0) it is removed from the array, avoiding being
used again accidentally. If you want to answer the
question C<Do you really want to do that> several times, then it must
be included in the array at least as often as you want this answer to
be given. Setting the parameter C<reuse> to 1 makes this repetition
unnecessary.
=item env [hash]
Environment variables to be set during the command
=item expect [array]
You must install the C<Expect> module to use C<expect>. CPAN.pm
does not install it for you.
C<< expect: <array> >> is a short notation for this C<eexpect>:
eexpect:
mode: deterministic
timeout: 15
talk: <array>
=back
=head2 Schema verification with C<Kwalify>
If you have the C<Kwalify> module installed (which is part of the
Bundle::CPANxxl), then all your distroprefs files are checked for
syntactic correctness.
=head2 Example Distroprefs Files
C<CPAN.pm> comes with a collection of example YAML files. Note that these
are really just examples and should not be used without care because
they cannot fit everybody's purpose. After all, the authors of the
packages that ask questions had a need to ask, so you should watch
their questions and adjust the examples to your environment and your
needs. You have been warned:-)
=head1 PROGRAMMER'S INTERFACE
If you do not enter the shell, shell commands are
available both as methods (C<CPAN::Shell-E<gt>install(...)>) and as
functions in the calling package (C<install(...)>). Before calling low-level
commands, it makes sense to initialize components of CPAN you need, e.g.:
CPAN::HandleConfig->load;
CPAN::Shell::setup_output;
CPAN::Index->reload;
High-level commands do such initializations automatically.
There's currently only one class that has a stable interface -
CPAN::Shell. All commands that are available in the CPAN shell are
methods of the class CPAN::Shell. The arguments on the commandline are
passed as arguments to the method.
So if you take for example the shell command
notest install A B C
the actually executed command is
CPAN::Shell->notest("install","A","B","C");
Each of the commands that produce listings of modules (C<r>,
C<autobundle>, C<u>) also return a list of the IDs of all modules
within the list.
=over 2
=item expand($type,@things)
The IDs of all objects available within a program are strings that can
be expanded to the corresponding real objects with the
C<CPAN::Shell-E<gt>expand("Module",@things)> method. Expand returns a
list of CPAN::Module objects according to the C<@things> arguments
given. In scalar context, it returns only the first element of the
list.
=item expandany(@things)
Like expand, but returns objects of the appropriate type, i.e.
CPAN::Bundle objects for bundles, CPAN::Module objects for modules, and
CPAN::Distribution objects for distributions. Note: it does not expand
to CPAN::Author objects.
=item Programming Examples
This enables the programmer to do operations that combine
functionalities that are available in the shell.
# install everything that is outdated on my disk:
perl -MCPAN -e 'CPAN::Shell->install(CPAN::Shell->r)'
# install my favorite programs if necessary:
for $mod (qw(Net::FTP Digest::SHA Data::Dumper)) {
CPAN::Shell->install($mod);
}
# list all modules on my disk that have no VERSION number
for $mod (CPAN::Shell->expand("Module","/./")) {
next unless $mod->inst_file;
# MakeMaker convention for undefined $VERSION:
next unless $mod->inst_version eq "undef";
print "No VERSION in ", $mod->id, "\n";
}
# find out which distribution on CPAN contains a module:
print CPAN::Shell->expand("Module","Apache::Constants")->cpan_file
Or if you want to schedule a I<cron> job to watch CPAN, you could list
all modules that need updating. First a quick and dirty way:
perl -e 'use CPAN; CPAN::Shell->r;'
If you don't want any output should all modules be
up to date, parse the output of above command for the regular
expression C</modules are up to date/> and decide to mail the output
only if it doesn't match.
If you prefer to do it more in a programmerish style in one single
process, something like this may better suit you:
# list all modules on my disk that have newer versions on CPAN
for $mod (CPAN::Shell->expand("Module","/./")) {
next unless $mod->inst_file;
next if $mod->uptodate;
printf "Module %s is installed as %s, could be updated to %s from CPAN\n",
$mod->id, $mod->inst_version, $mod->cpan_version;
}
If that gives too much output every day, you may want to
watch only for three modules. You can write
for $mod (CPAN::Shell->expand("Module","/Apache|LWP|CGI/")) {
as the first line instead. Or you can combine some of the above
tricks:
# watch only for a new mod_perl module
$mod = CPAN::Shell->expand("Module","mod_perl");
exit if $mod->uptodate;
# new mod_perl arrived, let me know all update recommendations
CPAN::Shell->r;
=back
=head2 Methods in the other Classes
=over 4
=item CPAN::Author::as_glimpse()
Returns a one-line description of the author
=item CPAN::Author::as_string()
Returns a multi-line description of the author
=item CPAN::Author::email()
Returns the author's email address
=item CPAN::Author::fullname()
Returns the author's name
=item CPAN::Author::name()
An alias for fullname
=item CPAN::Bundle::as_glimpse()
Returns a one-line description of the bundle
=item CPAN::Bundle::as_string()
Returns a multi-line description of the bundle
=item CPAN::Bundle::clean()
Recursively runs the C<clean> method on all items contained in the bundle.
=item CPAN::Bundle::contains()
Returns a list of objects' IDs contained in a bundle. The associated
objects may be bundles, modules or distributions.
=item CPAN::Bundle::force($method,@args)
Forces CPAN to perform a task that it normally would have refused to
do. Force takes as arguments a method name to be called and any number
of additional arguments that should be passed to the called method.
The internals of the object get the needed changes so that CPAN.pm
does not refuse to take the action. The C<force> is passed recursively
to all contained objects. See also the section above on the C<force>
and the C<fforce> pragma.
=item CPAN::Bundle::get()
Recursively runs the C<get> method on all items contained in the bundle
=item CPAN::Bundle::inst_file()
Returns the highest installed version of the bundle in either @INC or
C<< $CPAN::Config->{cpan_home} >>. Note that this is different from
CPAN::Module::inst_file.
=item CPAN::Bundle::inst_version()
Like CPAN::Bundle::inst_file, but returns the $VERSION
=item CPAN::Bundle::uptodate()
Returns 1 if the bundle itself and all its members are up-to-date.
=item CPAN::Bundle::install()
Recursively runs the C<install> method on all items contained in the bundle
=item CPAN::Bundle::make()
Recursively runs the C<make> method on all items contained in the bundle
=item CPAN::Bundle::readme()
Recursively runs the C<readme> method on all items contained in the bundle
=item CPAN::Bundle::test()
Recursively runs the C<test> method on all items contained in the bundle
=item CPAN::Distribution::as_glimpse()
Returns a one-line description of the distribution
=item CPAN::Distribution::as_string()
Returns a multi-line description of the distribution
=item CPAN::Distribution::author
Returns the CPAN::Author object of the maintainer who uploaded this
distribution
=item CPAN::Distribution::pretty_id()
Returns a string of the form "AUTHORID/TARBALL", where AUTHORID is the
author's PAUSE ID and TARBALL is the distribution filename.
=item CPAN::Distribution::base_id()
Returns the distribution filename without any archive suffix. E.g
"Foo-Bar-0.01"
=item CPAN::Distribution::clean()
Changes to the directory where the distribution has been unpacked and
runs C<make clean> there.
=item CPAN::Distribution::containsmods()
Returns a list of IDs of modules contained in a distribution file.
Works only for distributions listed in the 02packages.details.txt.gz
file. This typically means that just most recent version of a
distribution is covered.
=item CPAN::Distribution::cvs_import()
Changes to the directory where the distribution has been unpacked and
runs something like
cvs -d $cvs_root import -m $cvs_log $cvs_dir $userid v$version
there.
=item CPAN::Distribution::dir()
Returns the directory into which this distribution has been unpacked.
=item CPAN::Distribution::force($method,@args)
Forces CPAN to perform a task that it normally would have refused to
do. Force takes as arguments a method name to be called and any number
of additional arguments that should be passed to the called method.
The internals of the object get the needed changes so that CPAN.pm
does not refuse to take the action. See also the section above on the
C<force> and the C<fforce> pragma.
=item CPAN::Distribution::get()
Downloads the distribution from CPAN and unpacks it. Does nothing if
the distribution has already been downloaded and unpacked within the
current session.
=item CPAN::Distribution::install()
Changes to the directory where the distribution has been unpacked and
runs the external command C<make install> there. If C<make> has not
yet been run, it will be run first. A C<make test> is issued in
any case and if this fails, the install is cancelled. The
cancellation can be avoided by letting C<force> run the C<install> for
you.
This install method only has the power to install the distribution if
there are no dependencies in the way. To install an object along with all
its dependencies, use CPAN::Shell->install.
Note that install() gives no meaningful return value. See uptodate().
=item CPAN::Distribution::isa_perl()
Returns 1 if this distribution file seems to be a perl distribution.
Normally this is derived from the file name only, but the index from
CPAN can contain a hint to achieve a return value of true for other
filenames too.
=item CPAN::Distribution::look()
Changes to the directory where the distribution has been unpacked and
opens a subshell there. Exiting the subshell returns.
=item CPAN::Distribution::make()
First runs the C<get> method to make sure the distribution is
downloaded and unpacked. Changes to the directory where the
distribution has been unpacked and runs the external commands C<perl
Makefile.PL> or C<perl Build.PL> and C<make> there.
=item CPAN::Distribution::perldoc()
Downloads the pod documentation of the file associated with a
distribution (in HTML format) and runs it through the external
command I<lynx> specified in C<< $CPAN::Config->{lynx} >>. If I<lynx>
isn't available, it converts it to plain text with the external
command I<html2text> and runs it through the pager specified
in C<< $CPAN::Config->{pager} >>.
=item CPAN::Distribution::prefs()
Returns the hash reference from the first matching YAML file that the
user has deposited in the C<prefs_dir/> directory. The first
succeeding match wins. The files in the C<prefs_dir/> are processed
alphabetically, and the canonical distro name (e.g.
AUTHOR/Foo-Bar-3.14.tar.gz) is matched against the regular expressions
stored in the $root->{match}{distribution} attribute value.
Additionally all module names contained in a distribution are matched
against the regular expressions in the $root->{match}{module} attribute
value. The two match values are ANDed together. Each of the two
attributes are optional.
=item CPAN::Distribution::prereq_pm()
Returns the hash reference that has been announced by a distribution
as the C<requires> and C<build_requires> elements. These can be
declared either by the C<META.yml> (if authoritative) or can be
deposited after the run of C<Build.PL> in the file C<./_build/prereqs>
or after the run of C<Makfile.PL> written as the C<PREREQ_PM> hash in
a comment in the produced C<Makefile>. I<Note>: this method only works
after an attempt has been made to C<make> the distribution. Returns
undef otherwise.
=item CPAN::Distribution::readme()
Downloads the README file associated with a distribution and runs it
through the pager specified in C<< $CPAN::Config->{pager} >>.
=item CPAN::Distribution::reports()
Downloads report data for this distribution from www.cpantesters.org
and displays a subset of them.
=item CPAN::Distribution::read_yaml()
Returns the content of the META.yml of this distro as a hashref. Note:
works only after an attempt has been made to C<make> the distribution.
Returns undef otherwise. Also returns undef if the content of META.yml
is not authoritative. (The rules about what exactly makes the content
authoritative are still in flux.)
=item CPAN::Distribution::test()
Changes to the directory where the distribution has been unpacked and
runs C<make test> there.
=item CPAN::Distribution::uptodate()
Returns 1 if all the modules contained in the distribution are
up-to-date. Relies on containsmods.
=item CPAN::Index::force_reload()
Forces a reload of all indices.
=item CPAN::Index::reload()
Reloads all indices if they have not been read for more than
C<< $CPAN::Config->{index_expire} >> days.
=item CPAN::InfoObj::dump()
CPAN::Author, CPAN::Bundle, CPAN::Module, and CPAN::Distribution
inherit this method. It prints the data structure associated with an
object. Useful for debugging. Note: the data structure is considered
internal and thus subject to change without notice.
=item CPAN::Module::as_glimpse()
Returns a one-line description of the module in four columns: The
first column contains the word C<Module>, the second column consists
of one character: an equals sign if this module is already installed
and up-to-date, a less-than sign if this module is installed but can be
upgraded, and a space if the module is not installed. The third column
is the name of the module and the fourth column gives maintainer or
distribution information.
=item CPAN::Module::as_string()
Returns a multi-line description of the module
=item CPAN::Module::clean()
Runs a clean on the distribution associated with this module.
=item CPAN::Module::cpan_file()
Returns the filename on CPAN that is associated with the module.
=item CPAN::Module::cpan_version()
Returns the latest version of this module available on CPAN.
=item CPAN::Module::cvs_import()
Runs a cvs_import on the distribution associated with this module.
=item CPAN::Module::description()
Returns a 44 character description of this module. Only available for
modules listed in The Module List (CPAN/modules/00modlist.long.html
or 00modlist.long.txt.gz)
=item CPAN::Module::distribution()
Returns the CPAN::Distribution object that contains the current
version of this module.
=item CPAN::Module::dslip_status()
Returns a hash reference. The keys of the hash are the letters C<D>,
C<S>, C<L>, C<I>, and <P>, for development status, support level,
language, interface and public licence respectively. The data for the
DSLIP status are collected by pause.perl.org when authors register
their namespaces. The values of the 5 hash elements are one-character
words whose meaning is described in the table below. There are also 5
hash elements C<DV>, C<SV>, C<LV>, C<IV>, and <PV> that carry a more
verbose value of the 5 status variables.
Where the 'DSLIP' characters have the following meanings:
D - Development Stage (Note: *NO IMPLIED TIMESCALES*):
i - Idea, listed to gain consensus or as a placeholder
c - under construction but pre-alpha (not yet released)
a/b - Alpha/Beta testing
R - Released
M - Mature (no rigorous definition)
S - Standard, supplied with Perl 5
S - Support Level:
m - Mailing-list
d - Developer
u - Usenet newsgroup comp.lang.perl.modules
n - None known, try comp.lang.perl.modules
a - abandoned; volunteers welcome to take over maintenance
L - Language Used:
p - Perl-only, no compiler needed, should be platform independent
c - C and perl, a C compiler will be needed
h - Hybrid, written in perl with optional C code, no compiler needed
+ - C++ and perl, a C++ compiler will be needed
o - perl and another language other than C or C++
I - Interface Style
f - plain Functions, no references used
h - hybrid, object and function interfaces available
n - no interface at all (huh?)
r - some use of unblessed References or ties
O - Object oriented using blessed references and/or inheritance
P - Public License
p - Standard-Perl: user may choose between GPL and Artistic
g - GPL: GNU General Public License
l - LGPL: "GNU Lesser General Public License" (previously known as
"GNU Library General Public License")
b - BSD: The BSD License
a - Artistic license alone
2 - Artistic license 2.0 or later
o - open source: approved by www.opensource.org
d - allows distribution without restrictions
r - restricted distribution
n - no license at all
=item CPAN::Module::force($method,@args)
Forces CPAN to perform a task it would normally refuse to
do. Force takes as arguments a method name to be invoked and any number
of additional arguments to pass that method.
The internals of the object get the needed changes so that CPAN.pm
does not refuse to take the action. See also the section above on the
C<force> and the C<fforce> pragma.
=item CPAN::Module::get()
Runs a get on the distribution associated with this module.
=item CPAN::Module::inst_file()
Returns the filename of the module found in @INC. The first file found
is reported, just as perl itself stops searching @INC once it finds a
module.
=item CPAN::Module::available_file()
Returns the filename of the module found in PERL5LIB or @INC. The
first file found is reported. The advantage of this method over
C<inst_file> is that modules that have been tested but not yet
installed are included because PERL5LIB keeps track of tested modules.
=item CPAN::Module::inst_version()
Returns the version number of the installed module in readable format.
=item CPAN::Module::available_version()
Returns the version number of the available module in readable format.
=item CPAN::Module::install()
Runs an C<install> on the distribution associated with this module.
=item CPAN::Module::look()
Changes to the directory where the distribution associated with this
module has been unpacked and opens a subshell there. Exiting the
subshell returns.
=item CPAN::Module::make()
Runs a C<make> on the distribution associated with this module.
=item CPAN::Module::manpage_headline()
If module is installed, peeks into the module's manpage, reads the
headline, and returns it. Moreover, if the module has been downloaded
within this session, does the equivalent on the downloaded module even
if it hasn't been installed yet.
=item CPAN::Module::perldoc()
Runs a C<perldoc> on this module.
=item CPAN::Module::readme()
Runs a C<readme> on the distribution associated with this module.
=item CPAN::Module::reports()
Calls the reports() method on the associated distribution object.
=item CPAN::Module::test()
Runs a C<test> on the distribution associated with this module.
=item CPAN::Module::uptodate()
Returns 1 if the module is installed and up-to-date.
=item CPAN::Module::userid()
Returns the author's ID of the module.
=back
=head2 Cache Manager
Currently the cache manager only keeps track of the build directory
($CPAN::Config->{build_dir}). It is a simple FIFO mechanism that
deletes complete directories below C<build_dir> as soon as the size of
all directories there gets bigger than $CPAN::Config->{build_cache}
(in MB). The contents of this cache may be used for later
re-installations that you intend to do manually, but will never be
trusted by CPAN itself. This is due to the fact that the user might
use these directories for building modules on different architectures.
There is another directory ($CPAN::Config->{keep_source_where}) where
the original distribution files are kept. This directory is not
covered by the cache manager and must be controlled by the user. If
you choose to have the same directory as build_dir and as
keep_source_where directory, then your sources will be deleted with
the same fifo mechanism.
=head2 Bundles
A bundle is just a perl module in the namespace Bundle:: that does not
define any functions or methods. It usually only contains documentation.
It starts like a perl module with a package declaration and a $VERSION
variable. After that the pod section looks like any other pod with the
only difference being that I<one special pod section> exists starting with
(verbatim):
=head1 CONTENTS
In this pod section each line obeys the format
Module_Name [Version_String] [- optional text]
The only required part is the first field, the name of a module
(e.g. Foo::Bar, i.e. I<not> the name of the distribution file). The rest
of the line is optional. The comment part is delimited by a dash just
as in the man page header.
The distribution of a bundle should follow the same convention as
other distributions.
Bundles are treated specially in the CPAN package. If you say 'install
Bundle::Tkkit' (assuming such a bundle exists), CPAN will install all
the modules in the CONTENTS section of the pod. You can install your
own Bundles locally by placing a conformant Bundle file somewhere into
your @INC path. The autobundle() command which is available in the
shell interface does that for you by including all currently installed
modules in a snapshot bundle file.
=head1 PREREQUISITES
The CPAN program is trying to depend on as little as possible so the
user can use it in hostile environment. It works better the more goodies
the environment provides. For example if you try in the CPAN shell
install Bundle::CPAN
or
install Bundle::CPANxxl
you will find the shell more convenient than the bare shell before.
If you have a local mirror of CPAN and can access all files with
"file:" URLs, then you only need a perl later than perl5.003 to run
this module. Otherwise Net::FTP is strongly recommended. LWP may be
required for non-UNIX systems, or if your nearest CPAN site is
associated with a URL that is not C<ftp:>.
If you have neither Net::FTP nor LWP, there is a fallback mechanism
implemented for an external ftp command or for an external lynx
command.
=head1 UTILITIES
=head2 Finding packages and VERSION
This module presumes that all packages on CPAN
=over 2
=item *
declare their $VERSION variable in an easy to parse manner. This
prerequisite can hardly be relaxed because it consumes far too much
memory to load all packages into the running program just to determine
the $VERSION variable. Currently all programs that are dealing with
version use something like this
perl -MExtUtils::MakeMaker -le \
'print MM->parse_version(shift)' filename
If you are author of a package and wonder if your $VERSION can be
parsed, please try the above method.
=item *
come as compressed or gzipped tarfiles or as zip files and contain a
C<Makefile.PL> or C<Build.PL> (well, we try to handle a bit more, but
with little enthusiasm).
=back
=head2 Debugging
Debugging this module is more than a bit complex due to interference from
the software producing the indices on CPAN, the mirroring process on CPAN,
packaging, configuration, synchronicity, and even (gasp!) due to bugs
within the CPAN.pm module itself.
For debugging the code of CPAN.pm itself in interactive mode, some
debugging aid can be turned on for most packages within
CPAN.pm with one of
=over 2
=item o debug package...
sets debug mode for packages.
=item o debug -package...
unsets debug mode for packages.
=item o debug all
turns debugging on for all packages.
=item o debug number
=back
which sets the debugging packages directly. Note that C<o debug 0>
turns debugging off.
What seems a successful strategy is the combination of C<reload
cpan> and the debugging switches. Add a new debug statement while
running in the shell and then issue a C<reload cpan> and see the new
debugging messages immediately without losing the current context.
C<o debug> without an argument lists the valid package names and the
current set of packages in debugging mode. C<o debug> has built-in
completion support.
For debugging of CPAN data there is the C<dump> command which takes
the same arguments as make/test/install and outputs each object's
Data::Dumper dump. If an argument looks like a perl variable and
contains one of C<$>, C<@> or C<%>, it is eval()ed and fed to
Data::Dumper directly.
=head2 Floppy, Zip, Offline Mode
CPAN.pm works nicely without network access, too. If you maintain machines
that are not networked at all, you should consider working with C<file:>
URLs. You'll have to collect your modules somewhere first. So
you might use CPAN.pm to put together all you need on a networked
machine. Then copy the $CPAN::Config->{keep_source_where} (but not
$CPAN::Config->{build_dir}) directory on a floppy. This floppy is kind
of a personal CPAN. CPAN.pm on the non-networked machines works nicely
with this floppy. See also below the paragraph about CD-ROM support.
=head2 Basic Utilities for Programmers
=over 2
=item has_inst($module)
Returns true if the module is installed. Used to load all modules into
the running CPAN.pm that are considered optional. The config variable
C<dontload_list> intercepts the C<has_inst()> call such
that an optional module is not loaded despite being available. For
example, the following command will prevent C<YAML.pm> from being
loaded:
cpan> o conf dontload_list push YAML
See the source for details.
=item use_inst($module)
Similary to L<has_inst()> tries to load optional library but also dies if
library is not available
=item has_usable($module)
Returns true if the module is installed and in a usable state. Only
useful for a handful of modules that are used internally. See the
source for details.
=item instance($module)
The constructor for all the singletons used to represent modules,
distributions, authors, and bundles. If the object already exists, this
method returns the object; otherwise, it calls the constructor.
=item frontend()
=item frontend($new_frontend)
Getter/setter for frontend object. Method just allows to subclass CPAN.pm.
=back
=head1 SECURITY
There's no strong security layer in CPAN.pm. CPAN.pm helps you to
install foreign, unmasked, unsigned code on your machine. We compare
to a checksum that comes from the net just as the distribution file
itself. But we try to make it easy to add security on demand:
=head2 Cryptographically signed modules
Since release 1.77, CPAN.pm has been able to verify cryptographically
signed module distributions using Module::Signature. The CPAN modules
can be signed by their authors, thus giving more security. The simple
unsigned MD5 checksums that were used before by CPAN protect mainly
against accidental file corruption.
You will need to have Module::Signature installed, which in turn
requires that you have at least one of Crypt::OpenPGP module or the
command-line F<gpg> tool installed.
You will also need to be able to connect over the Internet to the public
key servers, like pgp.mit.edu, and their port 11731 (the HKP protocol).
The configuration parameter check_sigs is there to turn signature
checking on or off.
=head1 EXPORT
Most functions in package CPAN are exported by default. The reason
for this is that the primary use is intended for the cpan shell or for
one-liners.
=head1 ENVIRONMENT
When the CPAN shell enters a subshell via the look command, it sets
the environment CPAN_SHELL_LEVEL to 1, or increments that variable if it is
already set.
When CPAN runs, it sets the environment variable PERL5_CPAN_IS_RUNNING
to the ID of the running process. It also sets
PERL5_CPANPLUS_IS_RUNNING to prevent runaway processes which could
happen with older versions of Module::Install.
When running C<perl Makefile.PL>, the environment variable
C<PERL5_CPAN_IS_EXECUTING> is set to the full path of the
C<Makefile.PL> that is being executed. This prevents runaway processes
with newer versions of Module::Install.
When the config variable ftp_passive is set, all downloads will be run
with the environment variable FTP_PASSIVE set to this value. This is
in general a good idea as it influences both Net::FTP and LWP based
connections. The same effect can be achieved by starting the cpan
shell with this environment variable set. For Net::FTP alone, one can
also always set passive mode by running libnetcfg.
=head1 POPULATE AN INSTALLATION WITH LOTS OF MODULES
Populating a freshly installed perl with one's favorite modules is pretty
easy if you maintain a private bundle definition file. To get a useful
blueprint of a bundle definition file, the command autobundle can be used
on the CPAN shell command line. This command writes a bundle definition
file for all modules installed for the current perl
interpreter. It's recommended to run this command once only, and from then
on maintain the file manually under a private name, say
Bundle/my_bundle.pm. With a clever bundle file you can then simply say
cpan> install Bundle::my_bundle
then answer a few questions and go out for coffee (possibly
even in a different city).
Maintaining a bundle definition file means keeping track of two
things: dependencies and interactivity. CPAN.pm sometimes fails on
calculating dependencies because not all modules define all MakeMaker
attributes correctly, so a bundle definition file should specify
prerequisites as early as possible. On the other hand, it's
annoying that so many distributions need some interactive configuring. So
what you can try to accomplish in your private bundle file is to have the
packages that need to be configured early in the file and the gentle
ones later, so you can go out for coffee after a few minutes and leave CPAN.pm
to churn away unattended.
=head1 WORKING WITH CPAN.pm BEHIND FIREWALLS
Thanks to Graham Barr for contributing the following paragraphs about
the interaction between perl, and various firewall configurations. For
further information on firewalls, it is recommended to consult the
documentation that comes with the I<ncftp> program. If you are unable to
go through the firewall with a simple Perl setup, it is likely
that you can configure I<ncftp> so that it works through your firewall.
=head2 Three basic types of firewalls
Firewalls can be categorized into three basic types.
=over 4
=item http firewall
This is when the firewall machine runs a web server, and to access the
outside world, you must do so via that web server. If you set environment
variables like http_proxy or ftp_proxy to values beginning with http://,
or in your web browser you've proxy information set, then you know
you are running behind an http firewall.
To access servers outside these types of firewalls with perl (even for
ftp), you need LWP or HTTP::Tiny.
=item ftp firewall
This where the firewall machine runs an ftp server. This kind of
firewall will only let you access ftp servers outside the firewall.
This is usually done by connecting to the firewall with ftp, then
entering a username like "user@outside.host.com".
To access servers outside these type of firewalls with perl, you
need Net::FTP.
=item One-way visibility
One-way visibility means these firewalls try to make themselves
invisible to users inside the firewall. An FTP data connection is
normally created by sending your IP address to the remote server and then
listening for the return connection. But the remote server will not be able to
connect to you because of the firewall. For these types of firewall,
FTP connections need to be done in a passive mode.
There are two that I can think off.
=over 4
=item SOCKS
If you are using a SOCKS firewall, you will need to compile perl and link
it with the SOCKS library. This is what is normally called a 'socksified'
perl. With this executable you will be able to connect to servers outside
the firewall as if it were not there.
=item IP Masquerade
This is when the firewall implemented in the kernel (via NAT, or networking
address translation), it allows you to hide a complete network behind one
IP address. With this firewall no special compiling is needed as you can
access hosts directly.
For accessing ftp servers behind such firewalls you usually need to
set the environment variable C<FTP_PASSIVE> or the config variable
ftp_passive to a true value.
=back
=back
=head2 Configuring lynx or ncftp for going through a firewall
If you can go through your firewall with e.g. lynx, presumably with a
command such as
/usr/local/bin/lynx -pscott:tiger
then you would configure CPAN.pm with the command
o conf lynx "/usr/local/bin/lynx -pscott:tiger"
That's all. Similarly for ncftp or ftp, you would configure something
like
o conf ncftp "/usr/bin/ncftp -f /home/scott/ncftplogin.cfg"
Your mileage may vary...
=head1 FAQ
=over 4
=item 1)
I installed a new version of module X but CPAN keeps saying,
I have the old version installed
Probably you B<do> have the old version installed. This can
happen if a module installs itself into a different directory in the
@INC path than it was previously installed. This is not really a
CPAN.pm problem, you would have the same problem when installing the
module manually. The easiest way to prevent this behaviour is to add
the argument C<UNINST=1> to the C<make install> call, and that is why
many people add this argument permanently by configuring
o conf make_install_arg UNINST=1
=item 2)
So why is UNINST=1 not the default?
Because there are people who have their precise expectations about who
may install where in the @INC path and who uses which @INC array. In
fine tuned environments C<UNINST=1> can cause damage.
=item 3)
I want to clean up my mess, and install a new perl along with
all modules I have. How do I go about it?
Run the autobundle command for your old perl and optionally rename the
resulting bundle file (e.g. Bundle/mybundle.pm), install the new perl
with the Configure option prefix, e.g.
./Configure -Dprefix=/usr/local/perl-5.6.78.9
Install the bundle file you produced in the first step with something like
cpan> install Bundle::mybundle
and you're done.
=item 4)
When I install bundles or multiple modules with one command
there is too much output to keep track of.
You may want to configure something like
o conf make_arg "| tee -ai /root/.cpan/logs/make.out"
o conf make_install_arg "| tee -ai /root/.cpan/logs/make_install.out"
so that STDOUT is captured in a file for later inspection.
=item 5)
I am not root, how can I install a module in a personal directory?
As of CPAN 1.9463, if you do not have permission to write the default perl
library directories, CPAN's configuration process will ask you whether
you want to bootstrap <local::lib>, which makes keeping a personal
perl library directory easy.
Another thing you should bear in mind is that the UNINST parameter can
be dangerous when you are installing into a private area because you
might accidentally remove modules that other people depend on that are
not using the private area.
=item 6)
How to get a package, unwrap it, and make a change before building it?
Have a look at the C<look> (!) command.
=item 7)
I installed a Bundle and had a couple of fails. When I
retried, everything resolved nicely. Can this be fixed to work
on first try?
The reason for this is that CPAN does not know the dependencies of all
modules when it starts out. To decide about the additional items to
install, it just uses data found in the META.yml file or the generated
Makefile. An undetected missing piece breaks the process. But it may
well be that your Bundle installs some prerequisite later than some
depending item and thus your second try is able to resolve everything.
Please note, CPAN.pm does not know the dependency tree in advance and
cannot sort the queue of things to install in a topologically correct
order. It resolves perfectly well B<if> all modules declare the
prerequisites correctly with the PREREQ_PM attribute to MakeMaker or
the C<requires> stanza of Module::Build. For bundles which fail and
you need to install often, it is recommended to sort the Bundle
definition file manually.
=item 8)
In our intranet, we have many modules for internal use. How
can I integrate these modules with CPAN.pm but without uploading
the modules to CPAN?
Have a look at the CPAN::Site module.
=item 9)
When I run CPAN's shell, I get an error message about things in my
C</etc/inputrc> (or C<~/.inputrc>) file.
These are readline issues and can only be fixed by studying readline
configuration on your architecture and adjusting the referenced file
accordingly. Please make a backup of the C</etc/inputrc> or C<~/.inputrc>
and edit them. Quite often harmless changes like uppercasing or
lowercasing some arguments solves the problem.
=item 10)
Some authors have strange characters in their names.
Internally CPAN.pm uses the UTF-8 charset. If your terminal is
expecting ISO-8859-1 charset, a converter can be activated by setting
term_is_latin to a true value in your config file. One way of doing so
would be
cpan> o conf term_is_latin 1
If other charset support is needed, please file a bug report against
CPAN.pm at rt.cpan.org and describe your needs. Maybe we can extend
the support or maybe UTF-8 terminals become widely available.
Note: this config variable is deprecated and will be removed in a
future version of CPAN.pm. It will be replaced with the conventions
around the family of $LANG and $LC_* environment variables.
=item 11)
When an install fails for some reason and then I correct the error
condition and retry, CPAN.pm refuses to install the module, saying
C<Already tried without success>.
You could use the force pragma like so
force install Foo::Bar
Or, to avoid a force install (which would install even if the tests
fail), you can force only the test and then install:
force test Foo::Bar
install Foo::Bar
Or you can use
look Foo::Bar
and then C<make install> directly in the subshell.
=item 12)
How do I install a "DEVELOPER RELEASE" of a module?
By default, CPAN will install the latest non-developer release of a
module. If you want to install a dev release, you have to specify the
partial path starting with the author id to the tarball you wish to
install, like so:
cpan> install KWILLIAMS/Module-Build-0.27_07.tar.gz
Note that you can use the C<ls> command to get this path listed.
=item 13)
How do I install a module and all its dependencies from the commandline,
without being prompted for anything, despite my CPAN configuration
(or lack thereof)?
CPAN uses ExtUtils::MakeMaker's prompt() function to ask its questions, so
if you set the PERL_MM_USE_DEFAULT environment variable, you shouldn't be
asked any questions at all (assuming the modules you are installing are
nice about obeying that variable as well):
% PERL_MM_USE_DEFAULT=1 perl -MCPAN -e 'install My::Module'
=item 14)
How do I create a Module::Build based Build.PL derived from an
ExtUtils::MakeMaker focused Makefile.PL?
http://search.cpan.org/dist/Module-Build-Convert/
=item 15)
I'm frequently irritated with the CPAN shell's inability to help me
select a good mirror.
CPAN can now help you select a "good" mirror, based on which ones have the
lowest 'ping' round-trip times. From the shell, use the command 'o conf init
urllist' and allow CPAN to automatically select mirrors for you.
Beyond that help, the urllist config parameter is yours. You can add and remove
sites at will. You should find out which sites have the best up-to-dateness,
bandwidth, reliability, etc. and are topologically close to you. Some people
prefer fast downloads, others up-to-dateness, others reliability. You decide
which to try in which order.
Henk P. Penning maintains a site that collects data about CPAN sites:
http://mirrors.cpan.org/
Also, feel free to play with experimental features. Run
o conf init randomize_urllist ftpstats_period ftpstats_size
and choose your favorite parameters. After a few downloads running the
C<hosts> command will probably assist you in choosing the best mirror
sites.
=item 16)
Why do I get asked the same questions every time I start the shell?
You can make your configuration changes permanent by calling the
command C<o conf commit>. Alternatively set the C<auto_commit>
variable to true by running C<o conf init auto_commit> and answering
the following question with yes.
=item 17)
Older versions of CPAN.pm had the original root directory of all
tarballs in the build directory. Now there are always random
characters appended to these directory names. Why was this done?
The random characters are provided by File::Temp and ensure that each
module's individual build directory is unique. This makes running
CPAN.pm in concurrent processes simultaneously safe.
=item 18)
Speaking of the build directory. Do I have to clean it up myself?
You have the choice to set the config variable C<scan_cache> to
C<never>. Then you must clean it up yourself. The other possible
values, C<atstart> and C<atexit> clean up the build directory when you
start (or more precisely, after the first extraction into the build
directory) or exit the CPAN shell, respectively. If you never start up
the CPAN shell, you probably also have to clean up the build directory
yourself.
=item 19)
How can I switch to sudo instead of local::lib?
The following 5 environment veriables need to be reset to the previous
values: PATH, PERL5LIB, PERL_LOCAL_LIB_ROOT, PERL_MB_OPT, PERL_MM_OPT;
and these two CPAN.pm config variables must be reconfigured:
make_install_make_command and mbuild_install_build_command. The five
env variables have probably been overwritten in your $HOME/.bashrc or
some equivalent. You either find them there and delete their traces
and logout/login or you override them temporarily, depending on your
exact desire. The two cpanpm config variables can be set with:
o conf init /install_.*_command/
probably followed by
o conf commit
=item 20)
How do recommends_policy and suggests_policy work, exactly?
The terms C<recommends> and C<suggests> have been standardized in
https://metacpan.org/pod/CPAN::Meta::Spec
In CPAN.pm, if you set C<recommands_policy> to a true value, that
means: if you then install a distribution C<Foo> that I<recommends> a
module C<Bar>, both C<Foo> and C<Bar> will be tested and potentially
installed.
Similarly, if you set C<suggests_policy> to a true value, it means: if
you install a distribution C<Foo> that I<suggests> a module C<Bar>,
both C<Foo> and C<Bar> will be tested and potentially installed.
In either case, when C<Foo> passes its tests and C<Bar> does not pass
its tests, C<Foo> will be installed nontheless. But if C<Foo> does not
pass its tests, neither will be installed.
This also works recursively for all recommends and suggests of the
module C<Bar>.
This has also been illustrated by a cpan tester, who wrote:
I just tested Starlink-AST-3.03 which recommends Tk::Zinc;
Tk-Zinc-3.306 fails with
http://www.cpantesters.org/cpan/report/a2de7c38-810d-11ee-9ad4-e2167316189a
; nonetheless Starlink-AST-3.03 succeeds with
http://www.cpantesters.org/cpan/report/9352e754-810d-11ee-90e9-46117316189a
=back
=head1 COMPATIBILITY
=head2 OLD PERL VERSIONS
CPAN.pm is regularly tested to run under 5.005 and assorted
newer versions. It is getting more and more difficult to get the
minimal prerequisites working on older perls. It is close to
impossible to get the whole Bundle::CPAN working there. If you're in
the position to have only these old versions, be advised that CPAN is
designed to work fine without the Bundle::CPAN installed.
To get things going, note that GBARR/Scalar-List-Utils-1.18.tar.gz is
compatible with ancient perls and that File::Temp is listed as a
prerequisite but CPAN has reasonable workarounds if it is missing.
=head2 CPANPLUS
This module and its competitor, the CPANPLUS module, are both much
cooler than the other. CPAN.pm is older. CPANPLUS was designed to be
more modular, but it was never intended to be compatible with CPAN.pm.
=head2 CPANMINUS
In the year 2010 App::cpanminus was launched as a new approach to a
cpan shell with a considerably smaller footprint. Very cool stuff.
=head1 SECURITY ADVICE
This software enables you to upgrade software on your computer and so
is inherently dangerous because the newly installed software may
contain bugs and may alter the way your computer works or even make it
unusable. Please consider backing up your data before every upgrade.
=head1 BUGS
Please report bugs via L<http://rt.cpan.org/>
Before submitting a bug, please make sure that the traditional method
of building a Perl module package from a shell by following the
installation instructions of that package still works in your
environment.
=head1 AUTHOR
Andreas Koenig C<< <andk@cpan.org> >>
=head1 LICENSE
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
See L<http://www.perl.com/perl/misc/Artistic.html>
=head1 TRANSLATIONS
Kawai,Takanori provides a Japanese translation of a very old version
of this manpage at
L<http://homepage3.nifty.com/hippo2000/perltips/CPAN.htm>
=head1 SEE ALSO
Many people enter the CPAN shell by running the L<cpan> utility
program which is installed in the same directory as perl itself. So if
you have this directory in your PATH variable (or some equivalent in
your operating system) then typing C<cpan> in a console window will
work for you as well. Above that the utility provides several
commandline shortcuts.
melezhik (Alexey) sent me a link where he published a chef recipe to
work with CPAN.pm: http://community.opscode.com/cookbooks/cpan.
=cut
PK 1N%[���/�T �T perl5/LWP.pmnu ��6�$ package LWP;
our $VERSION = '6.78';
require LWP::UserAgent; # this should load everything you need
1;
__END__
=pod
=encoding utf-8
=head1 NAME
LWP - The World-Wide Web library for Perl
=head1 SYNOPSIS
use LWP;
print "This is libwww-perl-$LWP::VERSION\n";
=head1 DESCRIPTION
The libwww-perl collection is a set of Perl modules which provides a
simple and consistent application programming interface (API) to the
World-Wide Web. The main focus of the library is to provide classes
and functions that allow you to write WWW clients. The library also
contain modules that are of more general use and even classes that
help you implement simple HTTP servers.
Most modules in this library provide an object oriented API. The user
agent, requests sent and responses received from the WWW server are
all represented by objects. This makes a simple and powerful
interface to these services. The interface is easy to extend
and customize for your own needs.
The main features of the library are:
=over 3
=item *
Contains various reusable components (modules) that can be
used separately or together.
=item *
Provides an object oriented model of HTTP-style communication. Within
this framework we currently support access to C<http>, C<https>, C<gopher>,
C<ftp>, C<news>, C<file>, and C<mailto> resources.
=item *
Provides a full object oriented interface or
a very simple procedural interface.
=item *
Supports the basic and digest authorization schemes.
=item *
Supports transparent redirect handling.
=item *
Supports access through proxy servers.
=item *
Provides parser for F<robots.txt> files and a framework for constructing robots.
=item *
Supports parsing of HTML forms.
=item *
Implements HTTP content negotiation algorithm that can
be used both in protocol modules and in server scripts (like CGI
scripts).
=item *
Supports HTTP cookies.
=item *
Some simple command line clients, for instance C<lwp-request> and C<lwp-download>.
=back
=head1 HTTP STYLE COMMUNICATION
The libwww-perl library is based on HTTP style communication. This
section tries to describe what that means.
Let us start with this quote from the HTTP specification document
L<http://www.w3.org/Protocols/>:
=over 3
=item *
The HTTP protocol is based on a request/response paradigm. A client
establishes a connection with a server and sends a request to the
server in the form of a request method, URI, and protocol version,
followed by a MIME-like message containing request modifiers, client
information, and possible body content. The server responds with a
status line, including the message's protocol version and a success or
error code, followed by a MIME-like message containing server
information, entity meta-information, and possible body content.
=back
What this means to libwww-perl is that communication always take place
through these steps: First a I<request> object is created and
configured. This object is then passed to a server and we get a
I<response> object in return that we can examine. A request is always
independent of any previous requests, i.e. the service is stateless.
The same simple model is used for any kind of service we want to
access.
For example, if we want to fetch a document from a remote file server,
then we send it a request that contains a name for that document and
the response will contain the document itself. If we access a search
engine, then the content of the request will contain the query
parameters and the response will contain the query result. If we want
to send a mail message to somebody then we send a request object which
contains our message to the mail server and the response object will
contain an acknowledgment that tells us that the message has been
accepted and will be forwarded to the recipient(s).
It is as simple as that!
=head2 The Request Object
The libwww-perl request object has the class name L<HTTP::Request>.
The fact that the class name uses C<HTTP::> as a
prefix only implies that we use the HTTP model of communication. It
does not limit the kind of services we can try to pass this I<request>
to. For instance, we will send L<HTTP::Request>s both to ftp and
gopher servers, as well as to the local file system.
The main attributes of the request objects are:
=over 3
=item *
B<method> is a short string that tells what kind of
request this is. The most common methods are B<GET>, B<PUT>,
B<POST> and B<HEAD>.
=item *
B<uri> is a string denoting the protocol, server and
the name of the "document" we want to access. The B<uri> might
also encode various other parameters.
=item *
B<headers> contains additional information about the
request and can also used to describe the content. The headers
are a set of keyword/value pairs.
=item *
B<content> is an arbitrary amount of data.
=back
=head2 The Response Object
The libwww-perl response object has the class name L<HTTP::Response>.
The main attributes of objects of this class are:
=over 3
=item *
B<code> is a numerical value that indicates the overall
outcome of the request.
=item *
B<message> is a short, human readable string that
corresponds to the I<code>.
=item *
B<headers> contains additional information about the
response and describe the content.
=item *
B<content> is an arbitrary amount of data.
=back
Since we don't want to handle all possible I<code> values directly in
our programs, a libwww-perl response object has methods that can be
used to query what kind of response this is. The most commonly used
response classification methods are:
=over 3
=item is_success()
The request was successfully received, understood or accepted.
=item is_error()
The request failed. The server or the resource might not be
available, access to the resource might be denied or other things might
have failed for some reason.
=back
=head2 The User Agent
Let us assume that we have created a I<request> object. What do we
actually do with it in order to receive a I<response>?
The answer is that you pass it to a I<user agent> object and this
object takes care of all the things that need to be done
(like low-level communication and error handling) and returns
a I<response> object. The user agent represents your
application on the network and provides you with an interface that
can accept I<requests> and return I<responses>.
The user agent is an interface layer between
your application code and the network. Through this interface you are
able to access the various servers on the network.
The class name for the user agent is L<LWP::UserAgent>. Every
libwww-perl application that wants to communicate should create at
least one object of this class. The main method provided by this
object is request(). This method takes an L<HTTP::Request> object as
argument and (eventually) returns a L<HTTP::Response> object.
The user agent has many other attributes that let you
configure how it will interact with the network and with your
application.
=over 3
=item *
B<timeout> specifies how much time we give remote servers to
respond before the library disconnects and creates an
internal I<timeout> response.
=item *
B<agent> specifies the name that your application uses when it
presents itself on the network.
=item *
B<from> can be set to the e-mail address of the person
responsible for running the application. If this is set, then the
address will be sent to the servers with every request.
=item *
B<parse_head> specifies whether we should initialize response
headers from the C<< <head> >> section of HTML documents.
=item *
B<proxy> and B<no_proxy> specify if and when to go through
a proxy server. L<http://www.w3.org/History/1994/WWW/Proxies/>
=item *
B<credentials> provides a way to set up user names and
passwords needed to access certain services.
=back
Many applications want even more control over how they interact
with the network and they get this by sub-classing
L<LWP::UserAgent>. The library includes a
sub-class, L<LWP::RobotUA>, for robot applications.
=head2 An Example
This example shows how the user agent, a request and a response are
represented in actual perl code:
# Create a user agent object
use LWP::UserAgent;
my $ua = LWP::UserAgent->new;
$ua->agent("MyApp/0.1 ");
# Create a request
my $req = HTTP::Request->new(POST => 'http://search.cpan.org/search');
$req->content_type('application/x-www-form-urlencoded');
$req->content('query=libwww-perl&mode=dist');
# Pass request to the user agent and get a response back
my $res = $ua->request($req);
# Check the outcome of the response
if ($res->is_success) {
print $res->content;
}
else {
print $res->status_line, "\n";
}
The C<$ua> is created once when the application starts up. New request
objects should normally created for each request sent.
=head1 NETWORK SUPPORT
This section discusses the various protocol schemes and
the HTTP style methods that headers may be used for each.
For all requests, a "User-Agent" header is added and initialized from
the C<< $ua->agent >> attribute before the request is handed to the network
layer. In the same way, a "From" header is initialized from the
$ua->from attribute.
For all responses, the library adds a header called "Client-Date".
This header holds the time when the response was received by
your application. The format and semantics of the header are the
same as the server created "Date" header. You may also encounter other
"Client-XXX" headers. They are all generated by the library
internally and are not received from the servers.
=head2 HTTP Requests
HTTP requests are just handed off to an HTTP server and it
decides what happens. Few servers implement methods beside the usual
"GET", "HEAD", "POST" and "PUT", but CGI-scripts may implement
any method they like.
If the server is not available then the library will generate an
internal error response.
The library automatically adds a "Host" and a "Content-Length" header
to the HTTP request before it is sent over the network.
For a GET request you might want to add an "If-Modified-Since" or
"If-None-Match" header to make the request conditional.
For a POST request you should add the "Content-Type" header. When you
try to emulate HTML E<lt>FORM> handling you should usually let the value
of the "Content-Type" header be "application/x-www-form-urlencoded".
See L<lwpcook> for examples of this.
The libwww-perl HTTP implementation currently support the HTTP/1.1
and HTTP/1.0 protocol.
The library allows you to access proxy server through HTTP. This
means that you can set up the library to forward all types of request
through the HTTP protocol module. See L<LWP::UserAgent> for
documentation of this.
=head2 HTTPS Requests
HTTPS requests are HTTP requests over an encrypted network connection
using the SSL protocol developed by Netscape. Everything about HTTP
requests above also apply to HTTPS requests. In addition the library
will add the headers "Client-SSL-Cipher", "Client-SSL-Cert-Subject" and
"Client-SSL-Cert-Issuer" to the response. These headers denote the
encryption method used and the name of the server owner.
The request can contain the header "If-SSL-Cert-Subject" in order to
make the request conditional on the content of the server certificate.
If the certificate subject does not match, no request is sent to the
server and an internally generated error response is returned. The
value of the "If-SSL-Cert-Subject" header is interpreted as a Perl
regular expression.
=head2 FTP Requests
The library currently supports GET, HEAD and PUT requests. GET
retrieves a file or a directory listing from an FTP server. PUT
stores a file on a ftp server.
You can specify a ftp account for servers that want this in addition
to user name and password. This is specified by including an "Account"
header in the request.
User name/password can be specified using basic authorization or be
encoded in the URL. Failed logins return an UNAUTHORIZED response with
"WWW-Authenticate: Basic" and can be treated like basic authorization
for HTTP.
The library supports ftp ASCII transfer mode by specifying the "type=a"
parameter in the URL. It also supports transfer of ranges for FTP transfers
using the "Range" header.
Directory listings are by default returned unprocessed (as returned
from the ftp server) with the content media type reported to be
"text/ftp-dir-listing". The L<File::Listing> module provides methods
for parsing of these directory listing.
The ftp module is also able to convert directory listings to HTML and
this can be requested via the standard HTTP content negotiation
mechanisms (add an "Accept: text/html" header in the request if you
want this).
For normal file retrievals, the "Content-Type" is guessed based on the
file name suffix. See L<LWP::MediaTypes>.
The "If-Modified-Since" request header works for servers that implement
the C<MDTM> command. It will probably not work for directory listings though.
Example:
$req = HTTP::Request->new(GET => 'ftp://me:passwd@ftp.some.where.com/');
$req->header(Accept => "text/html, */*;q=0.1");
=head2 News Requests
Access to the USENET News system is implemented through the NNTP
protocol. The name of the news server is obtained from the
NNTP_SERVER environment variable and defaults to "news". It is not
possible to specify the hostname of the NNTP server in news: URLs.
The library supports GET and HEAD to retrieve news articles through the
NNTP protocol. You can also post articles to newsgroups by using
(surprise!) the POST method.
GET on newsgroups is not implemented yet.
Examples:
$req = HTTP::Request->new(GET => 'news:abc1234@a.sn.no');
$req = HTTP::Request->new(POST => 'news:comp.lang.perl.test');
$req->header(Subject => 'This is a test',
From => 'me@some.where.org');
$req->content(<<EOT);
This is the content of the message that we are sending to
the world.
EOT
=head2 Gopher Request
The library supports the GET and HEAD methods for gopher requests. All
request header values are ignored. HEAD cheats and returns a
response without even talking to server.
Gopher menus are always converted to HTML.
The response "Content-Type" is generated from the document type
encoded (as the first letter) in the request URL path itself.
Example:
$req = HTTP::Request->new(GET => 'gopher://gopher.sn.no/');
=head2 File Request
The library supports GET and HEAD methods for file requests. The
"If-Modified-Since" header is supported. All other headers are
ignored. The I<host> component of the file URL must be empty or set
to "localhost". Any other I<host> value will be treated as an error.
Directories are always converted to an HTML document. For normal
files, the "Content-Type" and "Content-Encoding" in the response are
guessed based on the file suffix.
Example:
$req = HTTP::Request->new(GET => 'file:/etc/passwd');
=head2 Mailto Request
You can send (aka "POST") mail messages using the library. All
headers specified for the request are passed on to the mail system.
The "To" header is initialized from the mail address in the URL.
Example:
$req = HTTP::Request->new(POST => 'mailto:libwww@perl.org');
$req->header(Subject => "subscribe");
$req->content("Please subscribe me to the libwww-perl mailing list!\n");
=head2 CPAN Requests
URLs with scheme C<cpan:> are redirected to a suitable CPAN
mirror. If you have your own local mirror of CPAN you might tell LWP
to use it for C<cpan:> URLs by an assignment like this:
$LWP::Protocol::cpan::CPAN = "file:/local/CPAN/";
Suitable CPAN mirrors are also picked up from the configuration for
the CPAN.pm, so if you have used that module a suitable mirror should
be picked automatically. If neither of these apply, then a redirect
to the generic CPAN http location is issued.
Example request to download the newest perl:
$req = HTTP::Request->new(GET => "cpan:src/latest.tar.gz");
=head1 OVERVIEW OF CLASSES AND PACKAGES
This table should give you a quick overview of the classes provided by the
library. Indentation shows class inheritance.
LWP::MemberMixin -- Access to member variables of Perl5 classes
LWP::UserAgent -- WWW user agent class
LWP::RobotUA -- When developing a robot applications
LWP::Protocol -- Interface to various protocol schemes
LWP::Protocol::http -- http:// access
LWP::Protocol::file -- file:// access
LWP::Protocol::ftp -- ftp:// access
...
LWP::Authen::Basic -- Handle 401 and 407 responses
LWP::Authen::Digest
HTTP::Headers -- MIME/RFC822 style header (used by HTTP::Message)
HTTP::Message -- HTTP style message
HTTP::Request -- HTTP request
HTTP::Response -- HTTP response
HTTP::Daemon -- A HTTP server class
WWW::RobotRules -- Parse robots.txt files
WWW::RobotRules::AnyDBM_File -- Persistent RobotRules
Net::HTTP -- Low level HTTP client
The following modules provide various functions and definitions.
LWP -- This file. Library version number and documentation.
LWP::MediaTypes -- MIME types configuration (text/html etc.)
LWP::Simple -- Simplified procedural interface for common functions
HTTP::Status -- HTTP status code (200 OK etc)
HTTP::Date -- Date parsing module for HTTP date formats
HTTP::Negotiate -- HTTP content negotiation calculation
File::Listing -- Parse directory listings
HTML::Form -- Processing for <form>s in HTML documents
=head1 MORE DOCUMENTATION
All modules contain detailed information on the interfaces they
provide. The L<lwpcook> manpage is the libwww-perl cookbook that contain
examples of typical usage of the library. You might want to take a
look at how the scripts L<lwp-request>, L<lwp-download>, L<lwp-dump>
and L<lwp-mirror> are implemented.
=head1 ENVIRONMENT
The following environment variables are used by LWP:
=over
=item HOME
The L<LWP::MediaTypes> functions will look for the F<.media.types> and
F<.mime.types> files relative to you home directory.
=item http_proxy
=item ftp_proxy
=item xxx_proxy
=item no_proxy
These environment variables can be set to enable communication through
a proxy server. See the description of the C<env_proxy> method in
L<LWP::UserAgent>.
=item PERL_LWP_ENV_PROXY
If set to a TRUE value, then the L<LWP::UserAgent> will by default call
C<env_proxy> during initialization. This makes LWP honor the proxy variables
described above.
=item PERL_LWP_SSL_VERIFY_HOSTNAME
The default C<verify_hostname> setting for L<LWP::UserAgent>. If
not set the default will be 1. Set it as 0 to disable hostname
verification (the default prior to libwww-perl 5.840.
=item PERL_LWP_SSL_CA_FILE
=item PERL_LWP_SSL_CA_PATH
The file and/or directory
where the trusted Certificate Authority certificates
is located. See L<LWP::UserAgent> for details.
=item PERL_HTTP_URI_CLASS
Used to decide what URI objects to instantiate. The default is L<URI>.
You might want to set it to L<URI::URL> for compatibility with old times.
=back
=head1 AUTHORS
LWP was made possible by contributions from Adam Newby, Albert
Dvornik, Alexandre Duret-Lutz, Andreas Gustafsson, Andreas König,
Andrew Pimlott, Andy Lester, Ben Coleman, Benjamin Low, Ben Low, Ben
Tilly, Blair Zajac, Bob Dalgleish, BooK, Brad Hughes, Brian
J. Murrell, Brian McCauley, Charles C. Fu, Charles Lane, Chris Nandor,
Christian Gilmore, Chris W. Unger, Craig Macdonald, Dale Couch, Dan
Kubb, Dave Dunkin, Dave W. Smith, David Coppit, David Dick, David
D. Kilzer, Doug MacEachern, Edward Avis, erik, Gary Shea, Gisle Aas,
Graham Barr, Gurusamy Sarathy, Hans de Graaff, Harald Joerg, Harry
Bochner, Hugo, Ilya Zakharevich, INOUE Yoshinari, Ivan Panchenko, Jack
Shirazi, James Tillman, Jan Dubois, Jared Rhine, Jim Stern, Joao
Lopes, John Klar, Johnny Lee, Josh Kronengold, Josh Rai, Joshua
Chamas, Joshua Hoblitt, Kartik Subbarao, Keiichiro Nagano, Ken
Williams, KONISHI Katsuhiro, Lee T Lindley, Liam Quinn, Marc Hedlund,
Marc Langheinrich, Mark D. Anderson, Marko Asplund, Mark Stosberg,
Markus B Krüger, Markus Laker, Martijn Koster, Martin Thurn, Matthew
Eldridge, Matthew.van.Eerde, Matt Sergeant, Michael A. Chase, Michael
Quaranta, Michael Thompson, Mike Schilli, Moshe Kaminsky, Nathan
Torkington, Nicolai Langfeldt, Norton Allen, Olly Betts, Paul
J. Schinder, peterm, Philip Guenther, Daniel Buenzli, Pon Hwa Lin,
Radoslaw Zielinski, Radu Greab, Randal L. Schwartz, Richard Chen,
Robin Barker, Roy Fielding, Sander van Zoest, Sean M. Burke,
shildreth, Slaven Rezic, Steve A Fink, Steve Hay, Steven Butler,
Steve_Kilbane, Takanori Ugai, Thomas Lotterer, Tim Bunce, Tom Hughes,
Tony Finch, Ville Skyttä, Ward Vandewege, William York, Yale Huang,
and Yitzchak Scott-Thoennes.
LWP owes a lot in motivation, design, and code, to the libwww-perl
library for Perl4 by Roy Fielding, which included work from Alberto
Accomazzi, James Casey, Brooks Cutter, Martijn Koster, Oscar
Nierstrasz, Mel Melchner, Gertjan van Oosten, Jared Rhine, Jack
Shirazi, Gene Spafford, Marc VanHeyningen, Steven E. Brenner, Marion
Hakanson, Waldemar Kebsch, Tony Sanders, and Larry Wall; see the
libwww-perl-0.40 library for details.
=head1 COPYRIGHT
Copyright 1995-2009, Gisle Aas
Copyright 1995, Martijn Koster
This library is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
=head1 AVAILABILITY
The latest version of this library is likely to be available from CPAN
as well as:
http://github.com/libwww-perl/libwww-perl
The best place to discuss this code is on the <libwww@perl.org>
mailing list.
=cut
PK 1N%[av+ �+ perl5/WWW/RobotRules.pmnu ��6�$ package WWW::RobotRules;
$VERSION = "6.02";
sub Version { $VERSION; }
use strict;
use URI ();
sub new {
my($class, $ua) = @_;
# This ugly hack is needed to ensure backwards compatibility.
# The "WWW::RobotRules" class is now really abstract.
$class = "WWW::RobotRules::InCore" if $class eq "WWW::RobotRules";
my $self = bless { }, $class;
$self->agent($ua);
$self;
}
sub parse {
my($self, $robot_txt_uri, $txt, $fresh_until) = @_;
$robot_txt_uri = URI->new("$robot_txt_uri");
my $netloc = $robot_txt_uri->host . ":" . $robot_txt_uri->port;
$self->clear_rules($netloc);
$self->fresh_until($netloc, $fresh_until || (time + 365*24*3600));
my $ua;
my $is_me = 0; # 1 iff this record is for me
my $is_anon = 0; # 1 iff this record is for *
my $seen_disallow = 0; # watch for missing record separators
my @me_disallowed = (); # rules disallowed for me
my @anon_disallowed = (); # rules disallowed for *
# blank lines are significant, so turn CRLF into LF to avoid generating
# false ones
$txt =~ s/\015\012/\012/g;
# split at \012 (LF) or \015 (CR) (Mac text files have just CR for EOL)
for(split(/[\012\015]/, $txt)) {
# Lines containing only a comment are discarded completely, and
# therefore do not indicate a record boundary.
next if /^\s*\#/;
s/\s*\#.*//; # remove comments at end-of-line
if (/^\s*$/) { # blank line
last if $is_me; # That was our record. No need to read the rest.
$is_anon = 0;
$seen_disallow = 0;
}
elsif (/^\s*User-Agent\s*:\s*(.*)/i) {
$ua = $1;
$ua =~ s/\s+$//;
if ($seen_disallow) {
# treat as start of a new record
$seen_disallow = 0;
last if $is_me; # That was our record. No need to read the rest.
$is_anon = 0;
}
if ($is_me) {
# This record already had a User-agent that
# we matched, so just continue.
}
elsif ($ua eq '*') {
$is_anon = 1;
}
elsif($self->is_me($ua)) {
$is_me = 1;
}
}
elsif (/^\s*Disallow\s*:\s*(.*)/i) {
unless (defined $ua) {
warn "RobotRules <$robot_txt_uri>: Disallow without preceding User-agent\n" if $^W;
$is_anon = 1; # assume that User-agent: * was intended
}
my $disallow = $1;
$disallow =~ s/\s+$//;
$seen_disallow = 1;
if (length $disallow) {
my $ignore;
eval {
my $u = URI->new_abs($disallow, $robot_txt_uri);
$ignore++ if $u->scheme ne $robot_txt_uri->scheme;
$ignore++ if lc($u->host) ne lc($robot_txt_uri->host);
$ignore++ if $u->port ne $robot_txt_uri->port;
$disallow = $u->path_query;
$disallow = "/" unless length $disallow;
};
next if $@;
next if $ignore;
}
if ($is_me) {
push(@me_disallowed, $disallow);
}
elsif ($is_anon) {
push(@anon_disallowed, $disallow);
}
}
elsif (/\S\s*:/) {
# ignore
}
else {
warn "RobotRules <$robot_txt_uri>: Malformed record: <$_>\n" if $^W;
}
}
if ($is_me) {
$self->push_rules($netloc, @me_disallowed);
}
else {
$self->push_rules($netloc, @anon_disallowed);
}
}
#
# Returns TRUE if the given name matches the
# name of this robot
#
sub is_me {
my($self, $ua_line) = @_;
my $me = $self->agent;
# See whether my short-name is a substring of the
# "User-Agent: ..." line that we were passed:
if(index(lc($me), lc($ua_line)) >= 0) {
return 1;
}
else {
return '';
}
}
sub allowed {
my($self, $uri) = @_;
$uri = URI->new("$uri");
return 1 unless $uri->scheme eq 'http' or $uri->scheme eq 'https';
# Robots.txt applies to only those schemes.
my $netloc = $uri->host . ":" . $uri->port;
my $fresh_until = $self->fresh_until($netloc);
return -1 if !defined($fresh_until) || $fresh_until < time;
my $str = $uri->path_query;
my $rule;
for $rule ($self->rules($netloc)) {
return 1 unless length $rule;
return 0 if index($str, $rule) == 0;
}
return 1;
}
# The following methods must be provided by the subclass.
sub agent;
sub visit;
sub no_visits;
sub last_visits;
sub fresh_until;
sub push_rules;
sub clear_rules;
sub rules;
sub dump;
package WWW::RobotRules::InCore;
use vars qw(@ISA);
@ISA = qw(WWW::RobotRules);
sub agent {
my ($self, $name) = @_;
my $old = $self->{'ua'};
if ($name) {
# Strip it so that it's just the short name.
# I.e., "FooBot" => "FooBot"
# "FooBot/1.2" => "FooBot"
# "FooBot/1.2 [http://foobot.int; foo@bot.int]" => "FooBot"
$name = $1 if $name =~ m/(\S+)/; # get first word
$name =~ s!/.*!!; # get rid of version
unless ($old && $old eq $name) {
delete $self->{'loc'}; # all old info is now stale
$self->{'ua'} = $name;
}
}
$old;
}
sub visit {
my($self, $netloc, $time) = @_;
return unless $netloc;
$time ||= time;
$self->{'loc'}{$netloc}{'last'} = $time;
my $count = \$self->{'loc'}{$netloc}{'count'};
if (!defined $$count) {
$$count = 1;
}
else {
$$count++;
}
}
sub no_visits {
my ($self, $netloc) = @_;
$self->{'loc'}{$netloc}{'count'};
}
sub last_visit {
my ($self, $netloc) = @_;
$self->{'loc'}{$netloc}{'last'};
}
sub fresh_until {
my ($self, $netloc, $fresh_until) = @_;
my $old = $self->{'loc'}{$netloc}{'fresh'};
if (defined $fresh_until) {
$self->{'loc'}{$netloc}{'fresh'} = $fresh_until;
}
$old;
}
sub push_rules {
my($self, $netloc, @rules) = @_;
push (@{$self->{'loc'}{$netloc}{'rules'}}, @rules);
}
sub clear_rules {
my($self, $netloc) = @_;
delete $self->{'loc'}{$netloc}{'rules'};
}
sub rules {
my($self, $netloc) = @_;
if (defined $self->{'loc'}{$netloc}{'rules'}) {
return @{$self->{'loc'}{$netloc}{'rules'}};
}
else {
return ();
}
}
sub dump
{
my $self = shift;
for (keys %$self) {
next if $_ eq 'loc';
print "$_ = $self->{$_}\n";
}
for (keys %{$self->{'loc'}}) {
my @rules = $self->rules($_);
print "$_: ", join("; ", @rules), "\n";
}
}
1;
__END__
# Bender: "Well, I don't have anything else
# planned for today. Let's get drunk!"
=head1 NAME
WWW::RobotRules - database of robots.txt-derived permissions
=head1 SYNOPSIS
use WWW::RobotRules;
my $rules = WWW::RobotRules->new('MOMspider/1.0');
use LWP::Simple qw(get);
{
my $url = "http://some.place/robots.txt";
my $robots_txt = get $url;
$rules->parse($url, $robots_txt) if defined $robots_txt;
}
{
my $url = "http://some.other.place/robots.txt";
my $robots_txt = get $url;
$rules->parse($url, $robots_txt) if defined $robots_txt;
}
# Now we can check if a URL is valid for those servers
# whose "robots.txt" files we've gotten and parsed:
if($rules->allowed($url)) {
$c = get $url;
...
}
=head1 DESCRIPTION
This module parses F</robots.txt> files as specified in
"A Standard for Robot Exclusion", at
<http://www.robotstxt.org/wc/norobots.html>
Webmasters can use the F</robots.txt> file to forbid conforming
robots from accessing parts of their web site.
The parsed files are kept in a WWW::RobotRules object, and this object
provides methods to check if access to a given URL is prohibited. The
same WWW::RobotRules object can be used for one or more parsed
F</robots.txt> files on any number of hosts.
The following methods are provided:
=over 4
=item $rules = WWW::RobotRules->new($robot_name)
This is the constructor for WWW::RobotRules objects. The first
argument given to new() is the name of the robot.
=item $rules->parse($robot_txt_url, $content, $fresh_until)
The parse() method takes as arguments the URL that was used to
retrieve the F</robots.txt> file, and the contents of the file.
=item $rules->allowed($uri)
Returns TRUE if this robot is allowed to retrieve this URL.
=item $rules->agent([$name])
Get/set the agent name. NOTE: Changing the agent name will clear the robots.txt
rules and expire times out of the cache.
=back
=head1 ROBOTS.TXT
The format and semantics of the "/robots.txt" file are as follows
(this is an edited abstract of
<http://www.robotstxt.org/wc/norobots.html>):
The file consists of one or more records separated by one or more
blank lines. Each record contains lines of the form
<field-name>: <value>
The field name is case insensitive. Text after the '#' character on a
line is ignored during parsing. This is used for comments. The
following <field-names> can be used:
=over 3
=item User-Agent
The value of this field is the name of the robot the record is
describing access policy for. If more than one I<User-Agent> field is
present the record describes an identical access policy for more than
one robot. At least one field needs to be present per record. If the
value is '*', the record describes the default access policy for any
robot that has not not matched any of the other records.
The I<User-Agent> fields must occur before the I<Disallow> fields. If a
record contains a I<User-Agent> field after a I<Disallow> field, that
constitutes a malformed record. This parser will assume that a blank
line should have been placed before that I<User-Agent> field, and will
break the record into two. All the fields before the I<User-Agent> field
will constitute a record, and the I<User-Agent> field will be the first
field in a new record.
=item Disallow
The value of this field specifies a partial URL that is not to be
visited. This can be a full path, or a partial path; any URL that
starts with this value will not be retrieved
=back
Unrecognized records are ignored.
=head1 ROBOTS.TXT EXAMPLES
The following example "/robots.txt" file specifies that no robots
should visit any URL starting with "/cyberworld/map/" or "/tmp/":
User-agent: *
Disallow: /cyberworld/map/ # This is an infinite virtual URL space
Disallow: /tmp/ # these will soon disappear
This example "/robots.txt" file specifies that no robots should visit
any URL starting with "/cyberworld/map/", except the robot called
"cybermapper":
User-agent: *
Disallow: /cyberworld/map/ # This is an infinite virtual URL space
# Cybermapper knows where to go.
User-agent: cybermapper
Disallow:
This example indicates that no robots should visit this site further:
# go away
User-agent: *
Disallow: /
This is an example of a malformed robots.txt file.
# robots.txt for ancientcastle.example.com
# I've locked myself away.
User-agent: *
Disallow: /
# The castle is your home now, so you can go anywhere you like.
User-agent: Belle
Disallow: /west-wing/ # except the west wing!
# It's good to be the Prince...
User-agent: Beast
Disallow:
This file is missing the required blank lines between records.
However, the intention is clear.
=head1 SEE ALSO
L<LWP::RobotUA>, L<WWW::RobotRules::AnyDBM_File>
=head1 COPYRIGHT
Copyright 1995-2009, Gisle Aas
Copyright 1995, Martijn Koster
This library is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
PK 1N%[�<��! ! # perl5/WWW/RobotRules/AnyDBM_File.pmnu ��6�$ package WWW::RobotRules::AnyDBM_File;
require WWW::RobotRules;
@ISA = qw(WWW::RobotRules);
$VERSION = "6.00";
use Carp ();
use AnyDBM_File;
use Fcntl;
use strict;
=head1 NAME
WWW::RobotRules::AnyDBM_File - Persistent RobotRules
=head1 SYNOPSIS
require WWW::RobotRules::AnyDBM_File;
require LWP::RobotUA;
# Create a robot useragent that uses a diskcaching RobotRules
my $rules = WWW::RobotRules::AnyDBM_File->new( 'my-robot/1.0', 'cachefile' );
my $ua = WWW::RobotUA->new( 'my-robot/1.0', 'me@foo.com', $rules );
# Then just use $ua as usual
$res = $ua->request($req);
=head1 DESCRIPTION
This is a subclass of I<WWW::RobotRules> that uses the AnyDBM_File
package to implement persistent diskcaching of F<robots.txt> and host
visit information.
The constructor (the new() method) takes an extra argument specifying
the name of the DBM file to use. If the DBM file already exists, then
you can specify undef as agent name as the name can be obtained from
the DBM database.
=cut
sub new
{
my ($class, $ua, $file) = @_;
Carp::croak('WWW::RobotRules::AnyDBM_File filename required') unless $file;
my $self = bless { }, $class;
$self->{'filename'} = $file;
tie %{$self->{'dbm'}}, 'AnyDBM_File', $file, O_CREAT|O_RDWR, 0640
or Carp::croak("Can't open $file: $!");
if ($ua) {
$self->agent($ua);
}
else {
# Try to obtain name from DBM file
$ua = $self->{'dbm'}{"|ua-name|"};
Carp::croak("No agent name specified") unless $ua;
}
$self;
}
sub agent {
my($self, $newname) = @_;
my $old = $self->{'dbm'}{"|ua-name|"};
if (defined $newname) {
$newname =~ s!/?\s*\d+.\d+\s*$!!; # loose version
unless ($old && $old eq $newname) {
# Old info is now stale.
my $file = $self->{'filename'};
untie %{$self->{'dbm'}};
tie %{$self->{'dbm'}}, 'AnyDBM_File', $file, O_TRUNC|O_RDWR, 0640;
%{$self->{'dbm'}} = ();
$self->{'dbm'}{"|ua-name|"} = $newname;
}
}
$old;
}
sub no_visits {
my ($self, $netloc) = @_;
my $t = $self->{'dbm'}{"$netloc|vis"};
return 0 unless $t;
(split(/;\s*/, $t))[0];
}
sub last_visit {
my ($self, $netloc) = @_;
my $t = $self->{'dbm'}{"$netloc|vis"};
return undef unless $t;
(split(/;\s*/, $t))[1];
}
sub fresh_until {
my ($self, $netloc, $fresh) = @_;
my $old = $self->{'dbm'}{"$netloc|exp"};
if ($old) {
$old =~ s/;.*//; # remove cleartext
}
if (defined $fresh) {
$fresh .= "; " . localtime($fresh);
$self->{'dbm'}{"$netloc|exp"} = $fresh;
}
$old;
}
sub visit {
my($self, $netloc, $time) = @_;
$time ||= time;
my $count = 0;
my $old = $self->{'dbm'}{"$netloc|vis"};
if ($old) {
my $last;
($count,$last) = split(/;\s*/, $old);
$time = $last if $last > $time;
}
$count++;
$self->{'dbm'}{"$netloc|vis"} = "$count; $time; " . localtime($time);
}
sub push_rules {
my($self, $netloc, @rules) = @_;
my $cnt = 1;
$cnt++ while $self->{'dbm'}{"$netloc|r$cnt"};
foreach (@rules) {
$self->{'dbm'}{"$netloc|r$cnt"} = $_;
$cnt++;
}
}
sub clear_rules {
my($self, $netloc) = @_;
my $cnt = 1;
while ($self->{'dbm'}{"$netloc|r$cnt"}) {
delete $self->{'dbm'}{"$netloc|r$cnt"};
$cnt++;
}
}
sub rules {
my($self, $netloc) = @_;
my @rules = ();
my $cnt = 1;
while (1) {
my $rule = $self->{'dbm'}{"$netloc|r$cnt"};
last unless $rule;
push(@rules, $rule);
$cnt++;
}
@rules;
}
sub dump
{
}
1;
=head1 SEE ALSO
L<WWW::RobotRules>, L<LWP::RobotUA>
=head1 AUTHORS
Hakan Ardo E<lt>hakan@munin.ub2.lu.se>, Gisle Aas E<lt>aas@sn.no>
=cut
PK 1N%[���\� � perl5/AppConfig/Args.pmnu ��6�$ #============================================================================
#
# AppConfig::Args.pm
#
# Perl5 module to read command line argument and update the variable
# values in an AppConfig::State object accordingly.
#
# Written by Andy Wardley <abw@wardley.org>
#
# Copyright (C) 1997-2007 Andy Wardley. All Rights Reserved.
# Copyright (C) 1997,1998 Canon Research Centre Europe Ltd.
#============================================================================
package AppConfig::Args;
use 5.006;
use strict;
use warnings;
use AppConfig::State;
our $VERSION = '1.71';
#------------------------------------------------------------------------
# new($state, \@args)
#
# Module constructor. The first, mandatory parameter should be a
# reference to an AppConfig::State object to which all actions should
# be applied. The second parameter may be a reference to a list of
# command line arguments. This list reference is passed to args() for
# processing.
#
# Returns a reference to a newly created AppConfig::Args object.
#------------------------------------------------------------------------
sub new {
my $class = shift;
my $state = shift;
my $self = {
STATE => $state, # AppConfig::State ref
DEBUG => $state->_debug(), # store local copy of debug
PEDANTIC => $state->_pedantic, # and pedantic flags
};
bless $self, $class;
# call parse() to parse any arg list passed
$self->parse(shift)
if @_;
return $self;
}
#------------------------------------------------------------------------
# parse(\@args)
#
# Examines the argument list and updates the contents of the
# AppConfig::State referenced by $self->{ STATE } accordingly. If
# no argument list is provided then the method defaults to examining
# @ARGV. The method reports any warning conditions (such as undefined
# variables) by calling $self->{ STATE }->_error() and then continues to
# examine the rest of the list. If the PEDANTIC option is set in the
# AppConfig::State object, this behaviour is overridden and the method
# returns 0 immediately on any parsing error.
#
# Returns 1 on success or 0 if one or more warnings were raised.
#------------------------------------------------------------------------
sub parse {
my $self = shift;
my $argv = shift || \@ARGV;
my $warnings = 0;
my ($arg, $nargs, $variable, $value);
# take a local copy of the state to avoid much hash dereferencing
my ($state, $debug, $pedantic) = @$self{ qw( STATE DEBUG PEDANTIC ) };
# loop around arguments
ARG: while (@$argv && $argv->[0] =~ /^-/) {
$arg = shift(@$argv);
# '--' indicates the end of the options
last if $arg eq '--';
# strip leading '-';
($variable = $arg) =~ s/^-(-)?//;
# test for '--' prefix and push back any '=value' item
if (defined $1) {
($variable, $value) = split(/=/, $variable);
unshift(@$argv, $value) if defined $value;
}
# check the variable exists
if ($state->_exists($variable)) {
# see if it expects any mandatory arguments
$nargs = $state->_argcount($variable);
if ($nargs) {
# check there's another arg and it's not another '-opt'
if(defined($argv->[0])) {
$value = shift(@$argv);
}
else {
$state->_error("$arg expects an argument");
$warnings++;
last ARG if $pedantic;
next;
}
}
else {
# set a value of 1 if option doesn't expect an argument
$value = 1;
}
# set the variable with the new value
$state->set($variable, $value);
}
else {
$state->_error("$arg: invalid option");
$warnings++;
last ARG if $pedantic;
}
}
# return status
return $warnings ? 0 : 1;
}
1;
__END__
=head1 NAME
AppConfig::Args - Perl5 module for reading command line arguments.
=head1 SYNOPSIS
use AppConfig::Args;
my $state = AppConfig::State->new(\%cfg);
my $cfgargs = AppConfig::Args->new($state);
$cfgargs->parse(\@args); # read args
=head1 OVERVIEW
AppConfig::Args is a Perl5 module which reads command line arguments and
uses the options therein to update variable values in an AppConfig::State
object.
AppConfig::File is distributed as part of the AppConfig bundle.
=head1 DESCRIPTION
=head2 USING THE AppConfig::Args MODULE
To import and use the AppConfig::Args module the following line should appear
in your Perl script:
use AppConfig::Args;
AppConfig::Args is used automatically if you use the AppConfig module
and create an AppConfig::Args object through the parse() method.
AppConfig::File is implemented using object-oriented methods. A new
AppConfig::Args object is created and initialised using the new() method.
This returns a reference to a new AppConfig::File object. A reference to
an AppConfig::State object should be passed in as the first parameter:
my $state = AppConfig::State->new();
my $cfgargs = AppConfig::Args->new($state);
This will create and return a reference to a new AppConfig::Args object.
=head2 PARSING COMMAND LINE ARGUMENTS
The C<parse()> method is used to read a list of command line arguments and
update the STATE accordingly. A reference to the list of arguments should
be passed in.
$cfgargs->parse(\@ARGV);
If the method is called without a reference to an argument list then it
will examine and manipulate @ARGV.
If the PEDANTIC option is turned off in the AppConfig::State object, any
parsing errors (invalid variables, unvalidated values, etc) will generate
warnings, but not cause the method to return. Having processed all
arguments, the method will return 1 if processed without warning or 0 if
one or more warnings were raised. When the PEDANTIC option is turned on,
the method generates a warning and immediately returns a value of 0 as soon
as it encounters any parsing error.
The method continues parsing arguments until it detects the first one that
does not start with a leading dash, '-'. Arguments that constitute values
for other options are not examined in this way.
=head1 FUTURE DEVELOPMENT
This module was developed to provide backwards compatibility (to some
degree) with the preceeding App::Config module. The argument parsing
it provides is basic but offers a quick and efficient solution for those
times when simple option handling is all that is required.
If you require more flexibility in parsing command line arguments, then
you should consider using the AppConfig::Getopt module. This is loaded
and used automatically by calling the AppConfig getopt() method.
The AppConfig::Getopt module provides considerably extended functionality
over the AppConfig::Args module by delegating out the task of argument
parsing to Johan Vromans' Getopt::Long module. For advanced command-line
parsing, this module (either Getopt::Long by itself, or in conjunction with
AppConfig::Getopt) is highly recommended.
=head1 AUTHOR
Andy Wardley, E<lt>abw@wardley.orgE<gt>
=head1 COPYRIGHT
Copyright (C) 1997-2007 Andy Wardley. All Rights Reserved.
Copyright (C) 1997,1998 Canon Research Centre Europe Ltd.
This module is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
=head1 SEE ALSO
AppConfig, AppConfig::State, AppConfig::Getopt, Getopt::Long
=cut
PK 1N%[���L perl5/AppConfig/CGI.pmnu ��6�$ #============================================================================
#
# AppConfig::CGI.pm
#
# Perl5 module to provide a CGI interface to AppConfig. Internal variables
# may be set through the CGI "arguments" appended to a URL.
#
# Written by Andy Wardley <abw@wardley.org>
#
# Copyright (C) 1997-2003 Andy Wardley. All Rights Reserved.
# Copyright (C) 1997,1998 Canon Research Centre Europe Ltd.
#
#============================================================================
package AppConfig::CGI;
use 5.006;
use strict;
use warnings;
use AppConfig::State;
our $VERSION = '1.71';
#------------------------------------------------------------------------
# new($state, $query)
#
# Module constructor. The first, mandatory parameter should be a
# reference to an AppConfig::State object to which all actions should
# be applied. The second parameter may be a string containing a CGI
# QUERY_STRING which is then passed to parse() to process. If no second
# parameter is specifiied then the parse() process is skipped.
#
# Returns a reference to a newly created AppConfig::CGI object.
#------------------------------------------------------------------------
sub new {
my $class = shift;
my $state = shift;
my $self = {
STATE => $state, # AppConfig::State ref
DEBUG => $state->_debug(), # store local copy of debug
PEDANTIC => $state->_pedantic, # and pedantic flags
};
bless $self, $class;
# call parse(@_) to parse any arg list passed
$self->parse(@_)
if @_;
return $self;
}
#------------------------------------------------------------------------
# parse($query)
#
# Method used to parse a CGI QUERY_STRING and set internal variable
# values accordingly. If a query is not passed as the first parameter,
# then _get_cgi_query() is called to try to determine the query by
# examing the environment as per CGI protocol.
#
# Returns 0 if one or more errors or warnings were raised or 1 if the
# string parsed successfully.
#------------------------------------------------------------------------
sub parse {
my $self = shift;
my $query = shift;
my $warnings = 0;
my ($variable, $value, $nargs);
# take a local copy of the state to avoid much hash dereferencing
my ($state, $debug, $pedantic) = @$self{ qw( STATE DEBUG PEDANTIC ) };
# get the cgi query if not defined
$query = $ENV{ QUERY_STRING }
unless defined $query;
# no query to process
return 1 unless defined $query;
# we want to install a custom error handler into the AppConfig::State
# which appends filename and line info to error messages and then
# calls the previous handler; we start by taking a copy of the
# current handler..
my $errhandler = $state->_ehandler();
# install a closure as a new error handler
$state->_ehandler(
sub {
# modify the error message
my $format = shift;
$format =~ s/</</g;
$format =~ s/>/>/g;
$format = "<p>\n<b>[ AppConfig::CGI error: </b>$format<b> ] </b>\n<p>\n";
# send error to stdout for delivery to web client
printf($format, @_);
}
);
PARAM: foreach (split('&', $query)) {
# extract parameter and value from query token
($variable, $value) = map { _unescape($_) } split('=');
# check an argument was provided if one was expected
if ($nargs = $state->_argcount($variable)) {
unless (defined $value) {
$state->_error("$variable expects an argument");
$warnings++;
last PARAM if $pedantic;
next;
}
}
# default an undefined value to 1 if ARGCOUNT_NONE
else {
$value = 1 unless defined $value;
}
# set the variable, noting any error
unless ($state->set($variable, $value)) {
$warnings++;
last PARAM if $pedantic;
}
}
# restore original error handler
$state->_ehandler($errhandler);
# return $warnings => 0, $success => 1
return $warnings ? 0 : 1;
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# The following sub-routine was lifted from Lincoln Stein's CGI.pm
# module, version 2.36. Name has been prefixed by a '_'.
# unescape URL-encoded data
sub _unescape {
my($todecode) = @_;
$todecode =~ tr/+/ /; # pluses become spaces
$todecode =~ s/%([0-9a-fA-F]{2})/pack("c",hex($1))/ge;
return $todecode;
}
#
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1;
__END__
=head1 NAME
AppConfig::CGI - Perl5 module for processing CGI script parameters.
=head1 SYNOPSIS
use AppConfig::CGI;
my $state = AppConfig::State->new(\%cfg);
my $cgi = AppConfig::CGI->new($state);
$cgi->parse($cgi_query);
$cgi->parse(); # looks for CGI query in environment
=head1 OVERVIEW
AppConfig::CGI is a Perl5 module which implements a CGI interface to
AppConfig. It examines the QUERY_STRING environment variable, or a string
passed explicitly by parameter, which represents the additional parameters
passed to a CGI query. This is then used to update variable values in an
AppConfig::State object accordingly.
AppConfig::CGI is distributed as part of the AppConfig bundle.
=head1 DESCRIPTION
=head2 USING THE AppConfig::CGI MODULE
To import and use the AppConfig::CGI module the following line should appear
in your Perl script:
use AppConfig::CGI;
AppConfig::CGI is used automatically if you use the AppConfig module
and create an AppConfig::CGI object through the cgi() method.
AppConfig::CGI is implemented using object-oriented methods. A new
AppConfig::CGI object is created and initialised using the new()
method. This returns a reference to a new AppConfig::CGI object. A
reference to an AppConfig::State object should be passed in as the
first parameter:
my $state = AppConfig::State->new();
my $cgi = AppConfig::CGI->new($state);
This will create and return a reference to a new AppConfig::CGI object.
=head2 PARSING CGI QUERIES
The C<parse()> method is used to parse a CGI query which can be specified
explicitly, or is automatically extracted from the "QUERY_STRING" CGI
environment variable. This currently limits the module to only supporting
the GET method.
See AppConfig for information about using the AppConfig::CGI
module via the cgi() method.
=head1 AUTHOR
Andy Wardley, C<E<lt>abw@wardley.org<gt>>
=head1 COPYRIGHT
Copyright (C) 1997-2007 Andy Wardley. All Rights Reserved.
Copyright (C) 1997,1998 Canon Research Centre Europe Ltd.
This module is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
=head1 SEE ALSO
AppConfig, AppConfig::State
=cut
PK 1N%[�k��) ) perl5/AppConfig/Sys.pmnu ��6�$ #============================================================================
#
# AppConfig::Sys.pm
#
# Perl5 module providing platform-specific information and operations as
# required by other AppConfig::* modules.
#
# Written by Andy Wardley <abw@wardley.org>
#
# Copyright (C) 1997-2003 Andy Wardley. All Rights Reserved.
# Copyright (C) 1997,1998 Canon Research Centre Europe Ltd.
#
# $Id: Sys.pm,v 1.61 2004/02/04 10:11:23 abw Exp $
#
#============================================================================
package AppConfig::Sys;
use 5.006;
use strict;
use warnings;
use POSIX qw( getpwnam getpwuid );
our $VERSION = '1.71';
our ($AUTOLOAD, $OS, %CAN, %METHOD);
BEGIN {
# define the methods that may be available
if($^O =~ m/win32/i) {
$METHOD{ getpwuid } = sub {
return wantarray()
? ( (undef) x 7, getlogin() )
: getlogin();
};
$METHOD{ getpwnam } = sub {
die("Can't getpwnam on win32");
};
}
else
{
$METHOD{ getpwuid } = sub {
getpwuid( defined $_[0] ? shift : $< );
};
$METHOD{ getpwnam } = sub {
getpwnam( defined $_[0] ? shift : '' );
};
}
# try out each METHOD to see if it's supported on this platform;
# it's important we do this before defining AUTOLOAD which would
# otherwise catch the unresolved call
foreach my $method (keys %METHOD) {
eval { &{ $METHOD{ $method } }() };
$CAN{ $method } = ! $@;
}
}
#------------------------------------------------------------------------
# new($os)
#
# Module constructor. An optional operating system string may be passed
# to explicitly define the platform type.
#
# Returns a reference to a newly created AppConfig::Sys object.
#------------------------------------------------------------------------
sub new {
my $class = shift;
my $self = {
METHOD => \%METHOD,
CAN => \%CAN,
};
bless $self, $class;
$self->_configure(@_);
return $self;
}
#------------------------------------------------------------------------
# AUTOLOAD
#
# Autoload function called whenever an unresolved object method is
# called. If the method name relates to a METHODS entry, then it is
# called iff the corresponding CAN_$method is set true. If the
# method name relates to a CAN_$method value then that is returned.
#------------------------------------------------------------------------
sub AUTOLOAD {
my $self = shift;
my $method;
# splat the leading package name
($method = $AUTOLOAD) =~ s/.*:://;
# ignore destructor
$method eq 'DESTROY' && return;
# can_method()
if ($method =~ s/^can_//i && exists $self->{ CAN }->{ $method }) {
return $self->{ CAN }->{ $method };
}
# method()
elsif (exists $self->{ METHOD }->{ $method }) {
if ($self->{ CAN }->{ $method }) {
return &{ $self->{ METHOD }->{ $method } }(@_);
}
else {
return undef;
}
}
# variable
elsif (exists $self->{ uc $method }) {
return $self->{ uc $method };
}
else {
warn("AppConfig::Sys->", $method, "(): no such method or variable\n");
}
return undef;
}
#------------------------------------------------------------------------
# _configure($os)
#
# Uses the first parameter, $os, the package variable $AppConfig::Sys::OS,
# the value of $^O, or as a last resort, the value of
# $Config::Config('osname') to determine the current operating
# system/platform. Sets internal variables accordingly.
#------------------------------------------------------------------------
sub _configure {
my $self = shift;
# operating system may be defined as a parameter or in $OS
my $os = shift || $OS;
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# The following was lifted (and adapated slightly) from Lincoln Stein's
# CGI.pm module, version 2.36...
#
# FIGURE OUT THE OS WE'RE RUNNING UNDER
# Some systems support the $^O variable. If not
# available then require() the Config library
unless ($os) {
unless ($os = $^O) {
require Config;
$os = $Config::Config{'osname'};
}
}
if ($os =~ /win32/i) {
$os = 'WINDOWS';
} elsif ($os =~ /vms/i) {
$os = 'VMS';
} elsif ($os =~ /mac/i) {
$os = 'MACINTOSH';
} elsif ($os =~ /os2/i) {
$os = 'OS2';
} else {
$os = 'UNIX';
}
# The path separator is a slash, backslash or semicolon, depending
# on the platform.
my $ps = {
UNIX => '/',
OS2 => '\\',
WINDOWS => '\\',
MACINTOSH => ':',
VMS => '\\'
}->{ $os };
#
# Thanks Lincoln!
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
$self->{ OS } = $os;
$self->{ PATHSEP } = $ps;
}
#------------------------------------------------------------------------
# _dump()
#
# Dump internals for debugging.
#------------------------------------------------------------------------
sub _dump {
my $self = shift;
print "=" x 71, "\n";
print "Status of AppConfig::Sys (Version $VERSION) object: $self\n";
print " Operating System : ", $self->{ OS }, "\n";
print " Path Separator : ", $self->{ PATHSEP }, "\n";
print " Available methods :\n";
foreach my $can (keys %{ $self->{ CAN } }) {
printf "%20s : ", $can;
print $self->{ CAN }->{ $can } ? "yes" : "no", "\n";
}
print "=" x 71, "\n";
}
1;
__END__
=pod
=head1 NAME
AppConfig::Sys - Perl5 module defining platform-specific information and methods for other AppConfig::* modules.
=head1 SYNOPSIS
use AppConfig::Sys;
my $sys = AppConfig::Sys->new();
@fields = $sys->getpwuid($userid);
@fields = $sys->getpwnam($username);
=head1 OVERVIEW
AppConfig::Sys is a Perl5 module provides platform-specific information and
operations as required by other AppConfig::* modules.
AppConfig::Sys is distributed as part of the AppConfig bundle.
=head1 DESCRIPTION
=head2 USING THE AppConfig::Sys MODULE
To import and use the AppConfig::Sys module the following line should
appear in your Perl script:
use AppConfig::Sys;
AppConfig::Sys is implemented using object-oriented methods. A new
AppConfig::Sys object is created and initialised using the
AppConfig::Sys->new() method. This returns a reference to a new
AppConfig::Sys object.
my $sys = AppConfig::Sys->new();
This will attempt to detect your operating system and create a reference to
a new AppConfig::Sys object that is applicable to your platform. You may
explicitly specify an operating system name to override this automatic
detection:
$unix_sys = AppConfig::Sys->new("Unix");
Alternatively, the package variable $AppConfig::Sys::OS can be set to an
operating system name. The valid operating system names are: Win32, VMS,
Mac, OS2 and Unix. They are not case-specific.
=head2 AppConfig::Sys METHODS
AppConfig::Sys defines the following methods:
=over 4
=item getpwnam()
Calls the system function getpwnam() if available and returns the result.
Returns undef if not available. The can_getpwnam() method can be called to
determine if this function is available.
=item getpwuid()
Calls the system function getpwuid() if available and returns the result.
Returns undef if not available. The can_getpwuid() method can be called to
determine if this function is available.
=back
=head1 AUTHOR
Andy Wardley, E<lt>abw@wardley.orgE<gt>
=head1 COPYRIGHT
Copyright (C) 1997-2007 Andy Wardley. All Rights Reserved.
Copyright (C) 1997,1998 Canon Research Centre Europe Ltd.
This module is free software; you can redistribute it and/or modify it under
the term of the Perl Artistic License.
=head1 SEE ALSO
AppConfig, AppConfig::File
=cut
PK 1N%[��f�� � perl5/AppConfig/State.pmnu ��6�$ #============================================================================
#
# AppConfig::State.pm
#
# Perl5 module in which configuration information for an application can
# be stored and manipulated. AppConfig::State objects maintain knowledge
# about variables; their identities, options, aliases, targets, callbacks
# and so on. This module is used by a number of other AppConfig::* modules.
#
# Written by Andy Wardley <abw@wardley.org>
#
# Copyright (C) 1997-2007 Andy Wardley. All Rights Reserved.
# Copyright (C) 1997,1998 Canon Research Centre Europe Ltd.
#
#----------------------------------------------------------------------------
#
# TODO
#
# * Change varlist() to varhash() and provide another varlist() method
# which returns a list. Multiple parameters passed implies a hash
# slice/list grep, a single parameter should indicate a regex.
#
# * Perhaps allow a callback to be installed which is called *instead* of
# the get() and set() methods (or rather, is called by them).
#
# * Maybe CMDARG should be in there to specify extra command-line only
# options that get added to the AppConfig::GetOpt alias construction,
# but not applied in config files, general usage, etc. The GLOBAL
# CMDARG might be specified as a format, e.g. "-%c" where %s = name,
# %c = first character, %u - first unique sequence(?). Will
# GetOpt::Long handle --long to -l application automagically?
#
# * ..and an added thought is that CASE sensitivity may be required for the
# command line (-v vs -V, -r vs -R, for example), but not for parsing
# config files where you may wish to treat "Name", "NAME" and "name" alike.
#
#============================================================================
package AppConfig::State;
use 5.006;
use strict;
use warnings;
our $VERSION = '1.71';
our $DEBUG = 0;
our $AUTOLOAD;
# need access to AppConfig::ARGCOUNT_*
use AppConfig ':argcount';
# internal per-variable hashes that AUTOLOAD should provide access to
my %METHVARS;
@METHVARS{ qw( EXPAND ARGS ARGCOUNT ) } = ();
# internal values that AUTOLOAD should provide access to
my %METHFLAGS;
@METHFLAGS{ qw( PEDANTIC ) } = ();
# variable attributes that may be specified in GLOBAL;
my @GLOBAL_OK = qw( DEFAULT EXPAND VALIDATE ACTION ARGS ARGCOUNT );
#------------------------------------------------------------------------
# new(\%config, @vars)
#
# Module constructor. A reference to a hash array containing
# configuration options may be passed as the first parameter. This is
# passed off to _configure() for processing. See _configure() for
# information about configurarion options. The remaining parameters
# may be variable definitions and are passed en masse to define() for
# processing.
#
# Returns a reference to a newly created AppConfig::State object.
#------------------------------------------------------------------------
sub new {
my $class = shift;
my $self = {
# internal hash arrays to store variable specification information
VARIABLE => { }, # variable values
DEFAULT => { }, # default values
ALIAS => { }, # known aliases ALIAS => VARIABLE
ALIASES => { }, # reverse alias lookup VARIABLE => ALIASES
ARGCOUNT => { }, # arguments expected
ARGS => { }, # specific argument pattern (AppConfig::Getopt)
EXPAND => { }, # variable expansion (AppConfig::File)
VALIDATE => { }, # validation regexen or functions
ACTION => { }, # callback functions for when variable is set
GLOBAL => { }, # default global settings for new variables
# other internal data
CREATE => 0, # auto-create variables when set
CASE => 0, # case sensitivity flag (1 = sensitive)
PEDANTIC => 0, # return immediately on parse warnings
EHANDLER => undef, # error handler (let's hope we don't need it!)
ERROR => '', # error message
};
bless $self, $class;
# configure if first param is a config hash ref
$self->_configure(shift)
if ref($_[0]) eq 'HASH';
# call define(@_) to handle any variables definitions
$self->define(@_)
if @_;
return $self;
}
#------------------------------------------------------------------------
# define($variable, \%cfg, [$variable, \%cfg, ...])
#
# Defines one or more variables. The first parameter specifies the
# variable name. The following parameter may reference a hash of
# configuration options for the variable. Further variables and
# configuration hashes may follow and are processed in turn. If the
# parameter immediately following a variable name isn't a hash reference
# then it is ignored and the variable is defined without a specific
# configuration, although any default parameters as specified in the
# GLOBAL option will apply.
#
# The $variable value may contain an alias/args definition in compact
# format, such as "Foo|Bar=1".
#
# A warning is issued (via _error()) if an invalid option is specified.
#------------------------------------------------------------------------
sub define {
my $self = shift;
my ($var, $args, $count, $opt, $val, $cfg, @names);
while (@_) {
$var = shift;
$cfg = ref($_[0]) eq 'HASH' ? shift : { };
# variable may be specified in compact format, 'foo|bar=i@'
if ($var =~ s/(.+?)([!+=:].*)/$1/) {
# anything coming after the name|alias list is the ARGS
$cfg->{ ARGS } = $2
if length $2;
}
# examine any ARGS option
if (defined ($args = $cfg->{ ARGS })) {
ARGGCOUNT: {
$count = ARGCOUNT_NONE, last if $args =~ /^!/;
$count = ARGCOUNT_LIST, last if $args =~ /@/;
$count = ARGCOUNT_HASH, last if $args =~ /%/;
$count = ARGCOUNT_ONE;
}
$cfg->{ ARGCOUNT } = $count;
}
# split aliases out
@names = split(/\|/, $var);
$var = shift @names;
$cfg->{ ALIAS } = [ @names ] if @names;
# variable name gets folded to lower unless CASE sensitive
$var = lc $var unless $self->{ CASE };
# activate $variable (so it does 'exist()')
$self->{ VARIABLE }->{ $var } = undef;
# merge GLOBAL and variable-specific configurations
$cfg = { %{ $self->{ GLOBAL } }, %$cfg };
# examine each variable configuration parameter
while (($opt, $val) = each %$cfg) {
$opt = uc $opt;
# DEFAULT, VALIDATE, EXPAND, ARGS and ARGCOUNT are stored as
# they are;
$opt =~ /^DEFAULT|VALIDATE|EXPAND|ARGS|ARGCOUNT$/ && do {
$self->{ $opt }->{ $var } = $val;
next;
};
# CMDARG has been deprecated
$opt eq 'CMDARG' && do {
$self->_error("CMDARG has been deprecated. "
. "Please use an ALIAS if required.");
next;
};
# ACTION should be a code ref
$opt eq 'ACTION' && do {
unless (ref($val) eq 'CODE') {
$self->_error("'$opt' value is not a code reference");
next;
};
# store code ref, forcing keyword to upper case
$self->{ ACTION }->{ $var } = $val;
next;
};
# ALIAS creates alias links to the variable name
$opt eq 'ALIAS' && do {
# coerce $val to an array if not already so
$val = [ split(/\|/, $val) ]
unless ref($val) eq 'ARRAY';
# fold to lower case unless CASE sensitivity set
unless ($self->{ CASE }) {
@$val = map { lc } @$val;
}
# store list of aliases...
$self->{ ALIASES }->{ $var } = $val;
# ...and create ALIAS => VARIABLE lookup hash entries
foreach my $a (@$val) {
$self->{ ALIAS }->{ $a } = $var;
}
next;
};
# default
$self->_error("$opt is not a valid configuration item");
}
# set variable to default value
$self->_default($var);
# DEBUG: dump new variable definition
if ($DEBUG) {
print STDERR "Variable defined:\n";
$self->_dump_var($var);
}
}
}
#------------------------------------------------------------------------
# get($variable)
#
# Returns the value of the variable specified, $variable. Returns undef
# if the variable does not exists or is undefined and send a warning
# message to the _error() function.
#------------------------------------------------------------------------
sub get {
my $self = shift;
my $variable = shift;
my $negate = 0;
my $value;
# _varname returns variable name after aliasing and case conversion
# $negate indicates if the name got converted from "no<var>" to "<var>"
$variable = $self->_varname($variable, \$negate);
# check the variable has been defined
unless (exists($self->{ VARIABLE }->{ $variable })) {
$self->_error("$variable: no such variable");
return undef;
}
# DEBUG
print STDERR "$self->get($variable) => ",
defined $self->{ VARIABLE }->{ $variable }
? $self->{ VARIABLE }->{ $variable }
: "<undef>",
"\n"
if $DEBUG;
# return variable value, possibly negated if the name was "no<var>"
$value = $self->{ VARIABLE }->{ $variable };
return $negate ? !$value : $value;
}
#------------------------------------------------------------------------
# set($variable, $value)
#
# Assigns the value, $value, to the variable specified.
#
# Returns 1 if the variable is successfully updated or 0 if the variable
# does not exist. If an ACTION sub-routine exists for the variable, it
# will be executed and its return value passed back.
#------------------------------------------------------------------------
sub set {
my $self = shift;
my $variable = shift;
my $value = shift;
my $negate = 0;
my $create;
# _varname returns variable name after aliasing and case conversion
# $negate indicates if the name got converted from "no<var>" to "<var>"
$variable = $self->_varname($variable, \$negate);
# check the variable exists
if (exists($self->{ VARIABLE }->{ $variable })) {
# variable found, so apply any value negation
$value = $value ? 0 : 1 if $negate;
}
else {
# auto-create variable if CREATE is 1 or a pattern matching
# the variable name (real name, not an alias)
$create = $self->{ CREATE };
if (defined $create
&& ($create eq '1' || $variable =~ /$create/)) {
$self->define($variable);
print STDERR "Auto-created $variable\n" if $DEBUG;
}
else {
$self->_error("$variable: no such variable");
return 0;
}
}
# call the validate($variable, $value) method to perform any validation
unless ($self->_validate($variable, $value)) {
$self->_error("$variable: invalid value: $value");
return 0;
}
# DEBUG
print STDERR "$self->set($variable, ",
defined $value
? $value
: "<undef>",
")\n"
if $DEBUG;
# set the variable value depending on its ARGCOUNT
my $argcount = $self->{ ARGCOUNT }->{ $variable };
$argcount = AppConfig::ARGCOUNT_ONE unless defined $argcount;
if ($argcount eq AppConfig::ARGCOUNT_LIST) {
# push value onto the end of the list
push(@{ $self->{ VARIABLE }->{ $variable } }, $value);
}
elsif ($argcount eq AppConfig::ARGCOUNT_HASH) {
# insert "<key>=<value>" data into hash
my ($k, $v) = split(/\s*=\s*/, $value, 2);
# strip quoting
$v =~ s/^(['"])(.*)\1$/$2/ if defined $v;
$self->{ VARIABLE }->{ $variable }->{ $k } = $v;
}
else {
# set simple variable
$self->{ VARIABLE }->{ $variable } = $value;
}
# call any ACTION function bound to this variable
return &{ $self->{ ACTION }->{ $variable } }($self, $variable, $value)
if (exists($self->{ ACTION }->{ $variable }));
# ...or just return 1 (ok)
return 1;
}
#------------------------------------------------------------------------
# varlist($criteria, $filter)
#
# Returns a hash array of all variables and values whose real names
# match the $criteria regex pattern passed as the first parameter.
# If $filter is set to any true value, the keys of the hash array
# (variable names) will have the $criteria part removed. This allows
# the caller to specify the variables from one particular [block] and
# have the "block_" prefix removed, for example.
#
# TODO: This should be changed to varhash(). varlist() should return a
# list. Also need to consider specification by list rather than regex.
#
#------------------------------------------------------------------------
sub varlist {
my $self = shift;
my $criteria = shift;
my $strip = shift;
$criteria = "" unless defined $criteria;
# extract relevant keys and slice out corresponding values
my @keys = grep(/$criteria/, keys %{ $self->{ VARIABLE } });
my @vals = @{ $self->{ VARIABLE } }{ @keys };
my %set;
# clean off the $criteria part if $strip is set
@keys = map { s/$criteria//; $_ } @keys if $strip;
# slice values into the target hash
@set{ @keys } = @vals;
return %set;
}
#------------------------------------------------------------------------
# AUTOLOAD
#
# Autoload function called whenever an unresolved object method is
# called. If the method name relates to a defined VARIABLE, we patch
# in $self->get() and $self->set() to magically update the varaiable
# (if a parameter is supplied) and return the previous value.
#
# Thus the function can be used in the folowing ways:
# $state->variable(123); # set a new value
# $foo = $state->variable(); # get the current value
#
# Returns the current value of the variable, taken before any new value
# is set. Prints a warning if the variable isn't defined (i.e. doesn't
# exist rather than exists with an undef value) and returns undef.
#------------------------------------------------------------------------
sub AUTOLOAD {
my $self = shift;
my ($variable, $attrib);
# splat the leading package name
($variable = $AUTOLOAD) =~ s/.*:://;
# ignore destructor
$variable eq 'DESTROY' && return;
# per-variable attributes and internal flags listed as keys in
# %METHFLAGS and %METHVARS respectively can be accessed by a
# method matching the attribute or flag name in lower case with
# a leading underscore_
if (($attrib = $variable) =~ s/_//g) {
$attrib = uc $attrib;
if (exists $METHFLAGS{ $attrib }) {
return $self->{ $attrib };
}
if (exists $METHVARS{ $attrib }) {
# next parameter should be variable name
$variable = shift;
$variable = $self->_varname($variable);
# check we've got a valid variable
# $self->_error("$variable: no such variable or method"),
# return undef
# unless exists($self->{ VARIABLE }->{ $variable });
# return attribute
return $self->{ $attrib }->{ $variable };
}
}
# set a new value if a parameter was supplied or return the old one
return defined($_[0])
? $self->set($variable, shift)
: $self->get($variable);
}
#========================================================================
# ----- PRIVATE METHODS -----
#========================================================================
#------------------------------------------------------------------------
# _configure(\%cfg)
#
# Sets the various configuration options using the values passed in the
# hash array referenced by $cfg.
#------------------------------------------------------------------------
sub _configure {
my $self = shift;
my $cfg = shift || return;
# construct a regex to match values which are ok to be found in GLOBAL
my $global_ok = join('|', @GLOBAL_OK);
foreach my $opt (keys %$cfg) {
# GLOBAL must be a hash ref
$opt =~ /^GLOBALS?$/i && do {
unless (ref($cfg->{ $opt }) eq 'HASH') {
$self->_error("\U$opt\E parameter is not a hash ref");
next;
}
# we check each option is ok to be in GLOBAL, but we don't do
# any error checking on the values they contain (but should?).
foreach my $global ( keys %{ $cfg->{ $opt } } ) {
# continue if the attribute is ok to be GLOBAL
next if ($global =~ /(^$global_ok$)/io);
$self->_error( "\U$global\E parameter cannot be GLOBAL");
}
$self->{ GLOBAL } = $cfg->{ $opt };
next;
};
# CASE, CREATE and PEDANTIC are stored as they are
$opt =~ /^CASE|CREATE|PEDANTIC$/i && do {
$self->{ uc $opt } = $cfg->{ $opt };
next;
};
# ERROR triggers $self->_ehandler()
$opt =~ /^ERROR$/i && do {
$self->_ehandler($cfg->{ $opt });
next;
};
# DEBUG triggers $self->_debug()
$opt =~ /^DEBUG$/i && do {
$self->_debug($cfg->{ $opt });
next;
};
# warn about invalid options
$self->_error("\U$opt\E is not a valid configuration option");
}
}
#------------------------------------------------------------------------
# _varname($variable, \$negated)
#
# Variable names are treated case-sensitively or insensitively, depending
# on the value of $self->{ CASE }. When case-insensitive ($self->{ CASE }
# != 0), all variable names are converted to lower case. Variable values
# are not converted. This function simply converts the parameter
# (variable) to lower case if $self->{ CASE } isn't set. _varname() also
# expands a variable alias to the name of the target variable.
#
# Variables with an ARGCOUNT of ARGCOUNT_ZERO may be specified as
# "no<var>" in which case, the intended value should be negated. The
# leading "no" part is stripped from the variable name. A reference to
# a scalar value can be passed as the second parameter and if the
# _varname() method identified such a variable, it will negate the value.
# This allows the intended value or a simple negate flag to be passed by
# reference and be updated to indicate any negation activity taking place.
#
# The (possibly modified) variable name is returned.
#------------------------------------------------------------------------
sub _varname {
my $self = shift;
my $variable = shift;
my $negated = shift;
# convert to lower case if case insensitive
$variable = $self->{ CASE } ? $variable : lc $variable;
# get the actual name if this is an alias
$variable = $self->{ ALIAS }->{ $variable }
if (exists($self->{ ALIAS }->{ $variable }));
# if the variable doesn't exist, we can try to chop off a leading
# "no" and see if the remainder matches an ARGCOUNT_ZERO variable
unless (exists($self->{ VARIABLE }->{ $variable })) {
# see if the variable is specified as "no<var>"
if ($variable =~ /^no(.*)/) {
# see if the real variable (minus "no") exists and it
# has an ARGOUNT of ARGCOUNT_NONE (or no ARGCOUNT at all)
my $novar = $self->_varname($1);
if (exists($self->{ VARIABLE }->{ $novar })
&& ! $self->{ ARGCOUNT }->{ $novar }) {
# set variable name and negate value
$variable = $novar;
$$negated = ! $$negated if defined $negated;
}
}
}
# return the variable name
$variable;
}
#------------------------------------------------------------------------
# _default($variable)
#
# Sets the variable specified to the default value or undef if it doesn't
# have a default. The default value is returned.
#------------------------------------------------------------------------
sub _default {
my $self = shift;
my $variable = shift;
# _varname returns variable name after aliasing and case conversion
$variable = $self->_varname($variable);
# check the variable exists
if (exists($self->{ VARIABLE }->{ $variable })) {
# set variable value to the default scalar, an empty list or empty
# hash array, depending on its ARGCOUNT value
my $argcount = $self->{ ARGCOUNT }->{ $variable };
$argcount = AppConfig::ARGCOUNT_ONE unless defined $argcount;
if ($argcount == AppConfig::ARGCOUNT_NONE) {
return $self->{ VARIABLE }->{ $variable }
= $self->{ DEFAULT }->{ $variable } || 0;
}
elsif ($argcount == AppConfig::ARGCOUNT_LIST) {
my $deflist = $self->{ DEFAULT }->{ $variable };
return $self->{ VARIABLE }->{ $variable } =
[ ref $deflist eq 'ARRAY' ? @$deflist : ( ) ];
}
elsif ($argcount == AppConfig::ARGCOUNT_HASH) {
my $defhash = $self->{ DEFAULT }->{ $variable };
return $self->{ VARIABLE }->{ $variable } =
{ ref $defhash eq 'HASH' ? %$defhash : () };
}
else {
return $self->{ VARIABLE }->{ $variable }
= $self->{ DEFAULT }->{ $variable };
}
}
else {
$self->_error("$variable: no such variable");
return 0;
}
}
#------------------------------------------------------------------------
# _exists($variable)
#
# Returns 1 if the variable specified exists or 0 if not.
#------------------------------------------------------------------------
sub _exists {
my $self = shift;
my $variable = shift;
# _varname returns variable name after aliasing and case conversion
$variable = $self->_varname($variable);
# check the variable has been defined
return exists($self->{ VARIABLE }->{ $variable });
}
#------------------------------------------------------------------------
# _validate($variable, $value)
#
# Uses any validation rules or code defined for the variable to test if
# the specified value is acceptable.
#
# Returns 1 if the value passed validation checks, 0 if not.
#------------------------------------------------------------------------
sub _validate {
my $self = shift;
my $variable = shift;
my $value = shift;
my $validator;
# _varname returns variable name after aliasing and case conversion
$variable = $self->_varname($variable);
# return OK unless there is a validation function
return 1 unless defined($validator = $self->{ VALIDATE }->{ $variable });
#
# the validation performed is based on the validator type;
#
# CODE ref: code executed, returning 1 (ok) or 0 (failed)
# SCALAR : a regex which should match the value
#
# CODE ref
ref($validator) eq 'CODE' && do {
# run the validation function and return the result
return &$validator($variable, $value);
};
# non-ref (i.e. scalar)
ref($validator) || do {
# not a ref - assume it's a regex
return $value =~ /$validator/;
};
# validation failed
return 0;
}
#------------------------------------------------------------------------
# _error($format, @params)
#
# Checks for the existence of a user defined error handling routine and
# if defined, passes all variable straight through to that. The routine
# is expected to handle a string format and optional parameters as per
# printf(3C). If no error handler is defined, the message is formatted
# and passed to warn() which prints it to STDERR.
#------------------------------------------------------------------------
sub _error {
my $self = shift;
my $format = shift;
# user defined error handler?
if (ref($self->{ EHANDLER }) eq 'CODE') {
&{ $self->{ EHANDLER } }($format, @_);
}
else {
warn(sprintf("$format\n", @_));
}
}
#------------------------------------------------------------------------
# _ehandler($handler)
#
# Allows a new error handler to be installed. The current value of
# the error handler is returned.
#
# This is something of a kludge to allow other AppConfig::* modules to
# install their own error handlers to format error messages appropriately.
# For example, AppConfig::File appends a message of the form
# "at $file line $line" to each error message generated while parsing
# configuration files. The previous handler is returned (and presumably
# stored by the caller) to allow new error handlers to chain control back
# to any user-defined handler, and also restore the original handler when
# done.
#------------------------------------------------------------------------
sub _ehandler {
my $self = shift;
my $handler = shift;
# save previous value
my $previous = $self->{ EHANDLER };
# update internal reference if a new handler vas provide
if (defined $handler) {
# check this is a code reference
if (ref($handler) eq 'CODE') {
$self->{ EHANDLER } = $handler;
# DEBUG
print STDERR "installed new ERROR handler: $handler\n" if $DEBUG;
}
else {
$self->_error("ERROR handler parameter is not a code ref");
}
}
return $previous;
}
#------------------------------------------------------------------------
# _debug($debug)
#
# Sets the package debugging variable, $AppConfig::State::DEBUG depending
# on the value of the $debug parameter. 1 turns debugging on, 0 turns
# debugging off.
#
# May be called as an object method, $state->_debug(1), or as a package
# function, AppConfig::State::_debug(1). Returns the previous value of
# $DEBUG, before any new value was applied.
#------------------------------------------------------------------------
sub _debug {
# object reference may not be present if called as a package function
my $self = shift if ref($_[0]);
my $newval = shift;
# save previous value
my $oldval = $DEBUG;
# update $DEBUG if a new value was provided
$DEBUG = $newval if defined $newval;
# return previous value
$oldval;
}
#------------------------------------------------------------------------
# _dump_var($var)
#
# Displays the content of the specified variable, $var.
#------------------------------------------------------------------------
sub _dump_var {
my $self = shift;
my $var = shift;
return unless defined $var;
# $var may be an alias, so we resolve the real variable name
my $real = $self->_varname($var);
if ($var eq $real) {
print STDERR "$var\n";
}
else {
print STDERR "$real ('$var' is an alias)\n";
$var = $real;
}
# for some bizarre reason, the variable VALUE is stored in VARIABLE
# (it made sense at some point in time)
printf STDERR " VALUE => %s\n",
defined($self->{ VARIABLE }->{ $var })
? $self->{ VARIABLE }->{ $var }
: "<undef>";
# the rest of the values can be read straight out of their hashes
foreach my $param (qw( DEFAULT ARGCOUNT VALIDATE ACTION EXPAND )) {
printf STDERR " %-12s => %s\n", $param,
defined($self->{ $param }->{ $var })
? $self->{ $param }->{ $var }
: "<undef>";
}
# summarise all known aliases for this variable
print STDERR " ALIASES => ",
join(", ", @{ $self->{ ALIASES }->{ $var } }), "\n"
if defined $self->{ ALIASES }->{ $var };
}
#------------------------------------------------------------------------
# _dump()
#
# Dumps the contents of the Config object and all stored variables.
#------------------------------------------------------------------------
sub _dump {
my $self = shift;
my $var;
print STDERR "=" x 71, "\n";
print STDERR
"Status of AppConfig::State (version $VERSION) object:\n\t$self\n";
print STDERR "- " x 36, "\nINTERNAL STATE:\n";
foreach (qw( CREATE CASE PEDANTIC EHANDLER ERROR )) {
printf STDERR " %-12s => %s\n", $_,
defined($self->{ $_ }) ? $self->{ $_ } : "<undef>";
}
print STDERR "- " x 36, "\nVARIABLES:\n";
foreach $var (keys %{ $self->{ VARIABLE } }) {
$self->_dump_var($var);
}
print STDERR "- " x 36, "\n", "ALIASES:\n";
foreach $var (keys %{ $self->{ ALIAS } }) {
printf(" %-12s => %s\n", $var, $self->{ ALIAS }->{ $var });
}
print STDERR "=" x 72, "\n";
}
1;
__END__
=head1 NAME
AppConfig::State - application configuration state
=head1 SYNOPSIS
use AppConfig::State;
my $state = AppConfig::State->new(\%cfg);
$state->define("foo"); # very simple variable definition
$state->define("bar", \%varcfg); # variable specific configuration
$state->define("foo|bar=i@"); # compact format
$state->set("foo", 123); # trivial set/get examples
$state->get("foo");
$state->foo(); # shortcut variable access
$state->foo(456); # shortcut variable update
=head1 OVERVIEW
AppConfig::State is a Perl5 module to handle global configuration variables
for perl programs. It maintains the state of any number of variables,
handling default values, aliasing, validation, update callbacks and
option arguments for use by other AppConfig::* modules.
AppConfig::State is distributed as part of the AppConfig bundle.
=head1 DESCRIPTION
=head2 USING THE AppConfig::State MODULE
To import and use the AppConfig::State module the following line should
appear in your Perl script:
use AppConfig::State;
The AppConfig::State module is loaded automatically by the new()
constructor of the AppConfig module.
AppConfig::State is implemented using object-oriented methods. A
new AppConfig::State object is created and initialised using the
new() method. This returns a reference to a new AppConfig::State
object.
my $state = AppConfig::State->new();
This will create a reference to a new AppConfig::State with all
configuration options set to their default values. You can initialise
the object by passing a reference to a hash array containing
configuration options:
$state = AppConfig::State->new( {
CASE => 1,
ERROR => \&my_error,
} );
The new() constructor of the AppConfig module automatically passes all
parameters to the AppConfig::State new() constructor. Thus, any global
configuration values and variable definitions for AppConfig::State are
also applicable to AppConfig.
The following configuration options may be specified.
=over 4
=item CASE
Determines if the variable names are treated case sensitively. Any non-zero
value makes case significant when naming variables. By default, CASE is set
to 0 and thus "Variable", "VARIABLE" and "VaRiAbLe" are all treated as
"variable".
=item CREATE
By default, CREATE is turned off meaning that all variables accessed via
set() (which includes access via shortcut such as
C<$state-E<gt>variable($value)> which delegates to set()) must previously
have been defined via define(). When CREATE is set to 1, calling
set($variable, $value) on a variable that doesn't exist will cause it
to be created automatically.
When CREATE is set to any other non-zero value, it is assumed to be a
regular expression pattern. If the variable name matches the regex, the
variable is created. This can be used to specify configuration file
blocks in which variables should be created, for example:
$state = AppConfig::State->new( {
CREATE => '^define_',
} );
In a config file:
[define]
name = fred # define_name gets created automatically
[other]
name = john # other_name doesn't - warning raised
Note that a regex pattern specified in CREATE is applied to the real
variable name rather than any alias by which the variables may be
accessed.
=item PEDANTIC
The PEDANTIC option determines what action the configuration file
(AppConfig::File) or argument parser (AppConfig::Args) should take
on encountering a warning condition (typically caused when trying to set an
undeclared variable). If PEDANTIC is set to any true value, the parsing
methods will immediately return a value of 0 on encountering such a
condition. If PEDANTIC is not set, the method will continue to parse the
remainder of the current file(s) or arguments, returning 0 when complete.
If no warnings or errors are encountered, the method returns 1.
In the case of a system error (e.g. unable to open a file), the method
returns undef immediately, regardless of the PEDANTIC option.
=item ERROR
Specifies a user-defined error handling routine. When the handler is
called, a format string is passed as the first parameter, followed by
any additional values, as per printf(3C).
=item DEBUG
Turns debugging on or off when set to 1 or 0 accordingly. Debugging may
also be activated by calling _debug() as an object method
(C<$state-E<gt>_debug(1)>) or as a package function
(C<AppConfig::State::_debug(1)>), passing in a true/false value to
set the debugging state accordingly. The package variable
$AppConfig::State::DEBUG can also be set directly.
The _debug() method returns the current debug value. If a new value
is passed in, the internal value is updated, but the previous value is
returned.
Note that any AppConfig::File or App::Config::Args objects that are
instantiated with a reference to an App::State will inherit the
DEBUG (and also PEDANTIC) values of the state at that time. Subsequent
changes to the AppConfig::State debug value will not affect them.
=item GLOBAL
The GLOBAL option allows default values to be set for the DEFAULT, ARGCOUNT,
EXPAND, VALIDATE and ACTION options for any subsequently defined variables.
$state = AppConfig::State->new({
GLOBAL => {
DEFAULT => '<undef>', # default value for new vars
ARGCOUNT => 1, # vars expect an argument
ACTION => \&my_set_var, # callback when vars get set
}
});
Any attributes specified explicitly when a variable is defined will
override any GLOBAL values.
See L<DEFINING VARIABLES> below which describes these options in detail.
=back
=head2 DEFINING VARIABLES
The C<define()> function is used to pre-declare a variable and specify
its configuration.
$state->define("foo");
In the simple example above, a new variable called "foo" is defined. A
reference to a hash array may also be passed to specify configuration
information for the variable:
$state->define("foo", {
DEFAULT => 99,
ALIAS => 'metavar1',
});
Any variable-wide GLOBAL values passed to the new() constructor in the
configuration hash will also be applied. Values explicitly specified
in a variable's define() configuration will override the respective GLOBAL
values.
The following configuration options may be specified
=over 4
=item DEFAULT
The DEFAULT value is used to initialise the variable.
$state->define("drink", {
DEFAULT => 'coffee',
});
print $state->drink(); # prints "coffee"
=item ALIAS
The ALIAS option allows a number of alternative names to be specified for
this variable. A single alias should be specified as a string. Multiple
aliases can be specified as a reference to an array of alternatives or as
a string of names separated by vertical bars, '|'. e.g.:
# either
$state->define("name", {
ALIAS => 'person',
});
# or
$state->define("name", {
ALIAS => [ 'person', 'user', 'uid' ],
});
# or
$state->define("name", {
ALIAS => 'person|user|uid',
});
$state->user('abw'); # equivalent to $state->name('abw');
=item ARGCOUNT
The ARGCOUNT option specifies the number of arguments that should be
supplied for this variable. By default, no additional arguments are
expected for variables (ARGCOUNT_NONE).
The ARGCOUNT_* constants can be imported from the AppConfig module:
use AppConfig ':argcount';
$state->define('foo', { ARGCOUNT => ARGCOUNT_ONE });
or can be accessed directly from the AppConfig package:
use AppConfig;
$state->define('foo', { ARGCOUNT => AppConfig::ARGCOUNT_ONE });
The following values for ARGCOUNT may be specified.
=over 4
=item ARGCOUNT_NONE (0)
Indicates that no additional arguments are expected. If the variable is
identified in a confirguration file or in the command line arguments, it
is set to a value of 1 regardless of whatever arguments follow it.
=item ARGCOUNT_ONE (1)
Indicates that the variable expects a single argument to be provided.
The variable value will be overwritten with a new value each time it
is encountered.
=item ARGCOUNT_LIST (2)
Indicates that the variable expects multiple arguments. The variable
value will be appended to the list of previous values each time it is
encountered.
=item ARGCOUNT_HASH (3)
Indicates that the variable expects multiple arguments and that each
argument is of the form "key=value". The argument will be split into
a key/value pair and inserted into the hash of values each time it
is encountered.
=back
=item ARGS
The ARGS option can also be used to specify advanced command line options
for use with AppConfig::Getopt, which itself delegates to Getopt::Long.
See those two modules for more information on the format and meaning of
these options.
$state->define("name", {
ARGS => "=i@",
});
=item EXPAND
The EXPAND option specifies how the AppConfig::File processor should
expand embedded variables in the configuration file values it reads.
By default, EXPAND is turned off (EXPAND_NONE) and no expansion is made.
The EXPAND_* constants can be imported from the AppConfig module:
use AppConfig ':expand';
$state->define('foo', { EXPAND => EXPAND_VAR });
or can be accessed directly from the AppConfig package:
use AppConfig;
$state->define('foo', { EXPAND => AppConfig::EXPAND_VAR });
The following values for EXPAND may be specified. Multiple values should
be combined with vertical bars , '|', e.g. C<EXPAND_UID | EXPAND_VAR>).
=over 4
=item EXPAND_NONE
Indicates that no variable expansion should be attempted.
=item EXPAND_VAR
Indicates that variables embedded as $var or $(var) should be expanded
to the values of the relevant AppConfig::State variables.
=item EXPAND_UID
Indicates that '~' or '~uid' patterns in the string should be
expanded to the current users ($<), or specified user's home directory.
In the first case, C<~> is expanded to the value of the C<HOME>
environment variable. In the second case, the C<getpwnam()> method
is used if it is available on your system (which it isn't on Win32).
=item EXPAND_ENV
Inidicates that variables embedded as ${var} should be expanded to the
value of the relevant environment variable.
=item EXPAND_ALL
Equivalent to C<EXPAND_VARS | EXPAND_UIDS | EXPAND_ENVS>).
=item EXPAND_WARN
Indicates that embedded variables that are not defined should raise a
warning. If PEDANTIC is set, this will cause the read() method to return 0
immediately.
=back
=item VALIDATE
Each variable may have a sub-routine or regular expression defined which
is used to validate the intended value for a variable before it is set.
If VALIDATE is defined as a regular expression, it is applied to the
value and deemed valid if the pattern matches. In this case, the
variable is then set to the new value. A warning message is generated
if the pattern match fails.
VALIDATE may also be defined as a reference to a sub-routine which takes
as its arguments the name of the variable and its intended value. The
sub-routine should return 1 or 0 to indicate that the value is valid
or invalid, respectively. An invalid value will cause a warning error
message to be generated.
If the GLOBAL VALIDATE variable is set (see GLOBAL in L<DESCRIPTION>
above) then this value will be used as the default VALIDATE for each
variable unless otherwise specified.
$state->define("age", {
VALIDATE => '\d+',
});
$state->define("pin", {
VALIDATE => \&check_pin,
});
=item ACTION
The ACTION option allows a sub-routine to be bound to a variable as a
callback that is executed whenever the variable is set. The ACTION is
passed a reference to the AppConfig::State object, the name of the
variable and the value of the variable.
The ACTION routine may be used, for example, to post-process variable
data, update the value of some other dependant variable, generate a
warning message, etc.
Example:
$state->define("foo", { ACTION => \&my_notify });
sub my_notify {
my $state = shift;
my $var = shift;
my $val = shift;
print "$variable set to $value";
}
$state->foo(42); # prints "foo set to 42"
Be aware that calling C<$state-E<gt>set()> to update the same variable
from within the ACTION function will cause a recursive loop as the
ACTION function is repeatedly called.
=back
=head2 DEFINING VARIABLES USING THE COMPACT FORMAT
Variables may be defined in a compact format which allows any ALIAS and
ARGS values to be specified as part of the variable name. This is designed
to mimic the behaviour of Johan Vromans' Getopt::Long module.
Aliases for a variable should be specified after the variable name,
separated by vertical bars, '|'. Any ARGS parameter should be appended
after the variable name(s) and/or aliases.
The following examples are equivalent:
$state->define("foo", {
ALIAS => [ 'bar', 'baz' ],
ARGS => '=i',
});
$state->define("foo|bar|baz=i");
=head2 READING AND MODIFYING VARIABLE VALUES
AppConfig::State defines two methods to manipulate variable values:
set($variable, $value);
get($variable);
Both functions take the variable name as the first parameter and
C<set()> takes an additional parameter which is the new value for the
variable. C<set()> returns 1 or 0 to indicate successful or
unsuccessful update of the variable value. If there is an ACTION
routine associated with the named variable, the value returned will be
passed back from C<set()>. The C<get()> function returns the current
value of the variable.
Once defined, variables may be accessed directly as object methods where
the method name is the same as the variable name. i.e.
$state->set("verbose", 1);
is equivalent to
$state->verbose(1);
Without parameters, the current value of the variable is returned. If
a parameter is specified, the variable is set to that value and the
result of the set() operation is returned.
$state->age(29); # sets 'age' to 29, returns 1 (ok)
=head2 VARLIST
The varlist() method can be used to extract a number of variables into
a hash array. The first parameter should be a regular expression
used for matching against the variable names.
my %vars = $state->varlist("^file"); # all "file*" variables
A second parameter may be specified (any true value) to indicate that
the part of the variable name matching the regex should be removed
when copied to the target hash.
$state->file_name("/tmp/file");
$state->file_path("/foo:/bar:/baz");
my %vars = $state->varlist("^file_", 1);
# %vars:
# name => /tmp/file
# path => "/foo:/bar:/baz"
=head2 INTERNAL METHODS
The interal (private) methods of the AppConfig::State class are listed
below.
They aren't intended for regular use and potential users should consider
the fact that nothing about the internal implementation is guaranteed to
remain the same. Having said that, the AppConfig::State class is
intended to co-exist and work with a number of other modules and these
are considered "friend" classes. These methods are provided, in part,
as services to them. With this acknowledged co-operation in mind, it is
safe to assume some stability in this core interface.
The _varname() method can be used to determine the real name of a variable
from an alias:
$varname->_varname($alias);
Note that all methods that take a variable name, including those listed
below, can accept an alias and automatically resolve it to the correct
variable name. There is no need to call _varname() explicitly to do
alias expansion. The _varname() method will fold all variables names
to lower case unless CASE sensititvity is set.
The _exists() method can be used to check if a variable has been
defined:
$state->_exists($varname);
The _default() method can be used to reset a variable to its default value:
$state->_default($varname);
The _expand() method can be used to determine the EXPAND value for a
variable:
print "$varname EXPAND: ", $state->_expand($varname), "\n";
The _argcount() method returns the value of the ARGCOUNT attribute for a
variable:
print "$varname ARGCOUNT: ", $state->_argcount($varname), "\n";
The _validate() method can be used to determine if a new value for a variable
meets any validation criteria specified for it. The variable name and
intended value should be passed in. The methods returns a true/false value
depending on whether or not the validation succeeded:
print "OK\n" if $state->_validate($varname, $value);
The _pedantic() method can be called to determine the current value of the
PEDANTIC option.
print "pedantic mode is ", $state->_pedantic() ? "on" ; "off", "\n";
The _debug() method can be used to turn debugging on or off (pass 1 or 0
as a parameter). It can also be used to check the debug state,
returning the current internal value of $AppConfig::State::DEBUG. If a
new debug value is provided, the debug state is updated and the previous
state is returned.
$state->_debug(1); # debug on, returns previous value
The _dump_var($varname) and _dump() methods may also be called for
debugging purposes.
$state->_dump_var($varname); # show variable state
$state->_dump(); # show internal state and all vars
=head1 AUTHOR
Andy Wardley, E<lt>abw@wardley.orgE<gt>
=head1 COPYRIGHT
Copyright (C) 1997-2007 Andy Wardley. All Rights Reserved.
Copyright (C) 1997,1998 Canon Research Centre Europe Ltd.
This module is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
=head1 SEE ALSO
AppConfig, AppConfig::File, AppConfig::Args, AppConfig::Getopt
=cut
PK 1N%[f�OM^ ^ perl5/AppConfig/File.pmnu ��6�$ #============================================================================
#
# AppConfig::File.pm
#
# Perl5 module to read configuration files and use the contents therein
# to update variable values in an AppConfig::State object.
#
# Written by Andy Wardley <abw@wardley.org>
#
# Copyright (C) 1997-2007 Andy Wardley. All Rights Reserved.
# Copyright (C) 1997,1998 Canon Research Centre Europe Ltd.
#
#============================================================================
package AppConfig::File;
use 5.006;
use strict;
use warnings;
use AppConfig;
use AppConfig::State;
our $VERSION = '1.71';
#------------------------------------------------------------------------
# new($state, $file, [$file, ...])
#
# Module constructor. The first, mandatory parameter should be a
# reference to an AppConfig::State object to which all actions should
# be applied. The remaining parameters are assumed to be file names or
# file handles for reading and are passed to parse().
#
# Returns a reference to a newly created AppConfig::File object.
#------------------------------------------------------------------------
sub new {
my $class = shift;
my $state = shift;
my $self = {
STATE => $state, # AppConfig::State ref
DEBUG => $state->_debug(), # store local copy of debug
PEDANTIC => $state->_pedantic, # and pedantic flags
};
bless $self, $class;
# call parse(@_) to parse any files specified as further params
$self->parse(@_) if @_;
return $self;
}
#------------------------------------------------------------------------
# parse($file, [file, ...])
#
# Reads and parses a config file, updating the contents of the
# AppConfig::State referenced by $self->{ STATE } according to the
# contents of the file. Multiple files may be specified and are
# examined in turn. The method reports any error condition via
# $self->{ STATE }->_error() and immediately returns undef if it
# encounters a system error (i.e. cannot open one of the files.
# Parsing errors such as unknown variables or unvalidated values will
# also cause warnings to be raised vi the same _error(), but parsing
# continues to the end of the current file and through any subsequent
# files. If the PEDANTIC option is set in the $self->{ STATE } object,
# the behaviour is overridden and the method returns 0 immediately on
# any system or parsing error.
#
# The EXPAND option for each variable determines how the variable
# value should be expanded.
#
# Returns undef on system error, 0 if all files were parsed but generated
# one or more warnings, 1 if all files parsed without warnings.
#------------------------------------------------------------------------
sub parse {
my $self = shift;
my $warnings = 0;
my $prefix; # [block] defines $prefix
my $file;
my $flag;
# take a local copy of the state to avoid much hash dereferencing
my ($state, $debug, $pedantic) = @$self{ qw( STATE DEBUG PEDANTIC ) };
# we want to install a custom error handler into the AppConfig::State
# which appends filename and line info to error messages and then
# calls the previous handler; we start by taking a copy of the
# current handler..
my $errhandler = $state->_ehandler();
# ...and if it doesn't exist, we craft a default handler
$errhandler = sub { warn(sprintf(shift, @_), "\n") }
unless defined $errhandler;
# install a closure as a new error handler
$state->_ehandler(
sub {
# modify the error message
my $format = shift;
$format .= ref $file
? " at line $."
: " at $file line $.";
# chain call to prevous handler
&$errhandler($format, @_);
}
);
# trawl through all files passed as params
FILE: while ($file = shift) {
# local/lexical vars ensure opened files get closed
my $handle;
local *FH;
# if the file is a reference, we assume it's a file handle, if
# not, we assume it's a filename and attempt to open it
$handle = $file;
if (ref($file)) {
$handle = $file;
# DEBUG
print STDERR "reading from file handle: $file\n" if $debug;
}
else {
# open and read config file
open(FH, $file) or do {
# restore original error handler and report error
$state->_ehandler($errhandler);
$state->_error("$file: $!");
return undef;
};
$handle = \*FH;
# DEBUG
print STDERR "reading file: $file\n" if $debug;
}
# initialise $prefix to nothing (no [block])
$prefix = '';
local $_;
while (<$handle>) {
chomp;
# Throw away everything from an unescaped # to EOL
s/(^|\s+)#.*/$1/;
# add next line if there is one and this is a continuation
if (s/\\$// && !eof($handle)) {
$_ .= <$handle>;
redo;
}
# Convert \# -> #
s/\\#/#/g;
# ignore blank lines
next if /^\s*$/;
# strip leading and trailing whitespace
s/^\s+//;
s/\s+$//;
# look for a [block] to set $prefix
if (/^\[([^\]]+)\]$/) {
$prefix = $1;
print STDERR "Entering [$prefix] block\n" if $debug;
next;
}
# split line up by whitespace (\s+) or "equals" (\s*=\s*)
if (/^([^\s=]+)(?:(?:(?:\s*=\s*)|\s+)(.*))?/) {
my ($variable, $value) = ($1, $2);
if (defined $value) {
# here document
if ($value =~ /^([^\s=]+\s*=)?\s*<<(['"]?)(\S+)\2$/) { # '<<XX' or 'hashkey =<<XX'
my $boundary = "$3\n";
$value = defined($1) ? $1 : '';
while (<$handle>) {
last if $_ eq $boundary;
$value .= $_;
};
$value =~ s/[\r\n]$//;
} else {
# strip any quoting from the variable value
$value =~ s/^(['"])(.*)\1$/$2/;
};
};
# strip any leading '+/-' from the variable
$variable =~ s/^([\-+]?)//;
$flag = $1;
# $variable gets any $prefix
$variable = $prefix . '_' . $variable
if length $prefix;
# if the variable doesn't exist, we call set() to give
# AppConfig::State a chance to auto-create it
unless ($state->_exists($variable)
|| $state->set($variable, 1)) {
$warnings++;
last FILE if $pedantic;
next;
}
my $nargs = $state->_argcount($variable);
# variables prefixed '-' are reset to their default values
if ($flag eq '-') {
$state->_default($variable);
next;
}
# those prefixed '+' get set to 1
elsif ($flag eq '+') {
$value = 1 unless defined $value;
}
# determine if any extra arguments were expected
if ($nargs) {
if (defined $value && length $value) {
# expand any embedded variables, ~uids or
# environment variables, testing the return value
# for errors; we pass in any variable-specific
# EXPAND value
unless ($self->_expand(\$value,
$state->_expand($variable), $prefix)) {
print STDERR "expansion of [$value] failed\n"
if $debug;
$warnings++;
last FILE if $pedantic;
}
}
else {
$state->_error("$variable expects an argument");
$warnings++;
last FILE if $pedantic;
next;
}
}
# $nargs = 0
else {
# default value to 1 unless it is explicitly defined
# as '0' or "off"
if (defined $value) {
# "off" => 0
$value = 0 if $value =~ /off/i;
# any value => 1
$value = 1 if $value;
}
else {
# assume 1 unless explicitly defined off/0
$value = 1;
}
print STDERR "$variable => $value (no expansion)\n"
if $debug;
}
# set the variable, noting any failure from set()
unless ($state->set($variable, $value)) {
$warnings++;
last FILE if $pedantic;
}
}
else {
$state->_error("parse error");
$warnings++;
}
}
}
# restore original error handler
$state->_ehandler($errhandler);
# return $warnings => 0, $success => 1
return $warnings ? 0 : 1;
}
#========================================================================
# ----- PRIVATE METHODS -----
#========================================================================
#------------------------------------------------------------------------
# _expand(\$value, $expand, $prefix)
#
# The variable value string, referenced by $value, is examined and any
# embedded variables, environment variables or tilde globs (home
# directories) are replaced with their respective values, depending on
# the value of the second parameter, $expand. The third paramter may
# specify the name of the current [block] in which the parser is
# parsing. This prefix is prepended to any embedded variable name that
# can't otherwise be resolved. This allows the following to work:
#
# [define]
# home = /home/abw
# html = $define_home/public_html
# html = $home/public_html # same as above, 'define' is prefix
#
# Modifications are made directly into the variable referenced by $value.
# The method returns 1 on success or 0 if any warnings (undefined
# variables) were encountered.
#------------------------------------------------------------------------
sub _expand {
my ($self, $value, $expand, $prefix) = @_;
my $warnings = 0;
my ($sys, $var, $val);
# ensure prefix contains something (nothing!) valid for length()
$prefix = "" unless defined $prefix;
# take a local copy of the state to avoid much hash dereferencing
my ($state, $debug, $pedantic) = @$self{ qw( STATE DEBUG PEDANTIC ) };
# bail out if there's nothing to do
return 1 unless $expand && defined($$value);
# create an AppConfig::Sys instance, or re-use a previous one,
# to handle platform dependant functions: getpwnam(), getpwuid()
unless ($sys = $self->{ SYS }) {
require AppConfig::Sys;
$sys = $self->{ SYS } = AppConfig::Sys->new();
}
print STDERR "Expansion of [$$value] " if $debug;
EXPAND: {
#
# EXPAND_VAR
# expand $(var) and $var as AppConfig::State variables
#
if ($expand & AppConfig::EXPAND_VAR) {
$$value =~ s{
(?<!\\)\$ (?: \((\w+)\) | (\w+) ) # $2 => $(var) | $3 => $var
} {
# embedded variable name will be one of $2 or $3
$var = defined $1 ? $1 : $2;
# expand the variable if defined
if ($state->_exists($var)) {
$val = $state->get($var);
}
elsif (length $prefix
&& $state->_exists($prefix . '_' . $var)) {
print STDERR "(\$$var => \$${prefix}_$var) "
if $debug;
$var = $prefix . '_' . $var;
$val = $state->get($var);
}
else {
# raise a warning if EXPAND_WARN set
if ($expand & AppConfig::EXPAND_WARN) {
$state->_error("$var: no such variable");
$warnings++;
}
# replace variable with nothing
$val = '';
}
# $val gets substituted back into the $value string
$val;
}gex;
$$value =~ s/\\\$/\$/g;
# bail out now if we need to
last EXPAND if $warnings && $pedantic;
}
#
# EXPAND_UID
# expand ~uid as home directory (for $< if uid not specified)
#
if ($expand & AppConfig::EXPAND_UID) {
$$value =~ s{
~(\w+)? # $1 => username (optional)
} {
$val = undef;
# embedded user name may be in $1
if (defined ($var = $1)) {
# try and get user's home directory
if ($sys->can_getpwnam()) {
$val = ($sys->getpwnam($var))[7];
}
} else {
# determine home directory
$val = $ENV{ HOME };
}
# catch-all for undefined $dir
unless (defined $val) {
# raise a warning if EXPAND_WARN set
if ($expand & AppConfig::EXPAND_WARN) {
$state->_error("cannot determine home directory%s",
defined $var ? " for $var" : "");
$warnings++;
}
# replace variable with nothing
$val = '';
}
# $val gets substituted back into the $value string
$val;
}gex;
# bail out now if we need to
last EXPAND if $warnings && $pedantic;
}
#
# EXPAND_ENV
# expand ${VAR} as environment variables
#
if ($expand & AppConfig::EXPAND_ENV) {
$$value =~ s{
( \$ \{ (\w+) \} )
} {
$var = $2;
# expand the variable if defined
if (exists $ENV{ $var }) {
$val = $ENV{ $var };
} elsif ( $var eq 'HOME' ) {
# In the special case of HOME, if not set
# use the internal version
$val = $self->{ HOME };
} else {
# raise a warning if EXPAND_WARN set
if ($expand & AppConfig::EXPAND_WARN) {
$state->_error("$var: no such environment variable");
$warnings++;
}
# replace variable with nothing
$val = '';
}
# $val gets substituted back into the $value string
$val;
}gex;
# bail out now if we need to
last EXPAND if $warnings && $pedantic;
}
}
print STDERR "=> [$$value] (EXPAND = $expand)\n" if $debug;
# return status
return $warnings ? 0 : 1;
}
#------------------------------------------------------------------------
# _dump()
#
# Dumps the contents of the Config object.
#------------------------------------------------------------------------
sub _dump {
my $self = shift;
foreach my $key (keys %$self) {
printf("%-10s => %s\n", $key,
defined($self->{ $key }) ? $self->{ $key } : "<undef>");
}
}
1;
__END__
=head1 NAME
AppConfig::File - Perl5 module for reading configuration files.
=head1 SYNOPSIS
use AppConfig::File;
my $state = AppConfig::State->new(\%cfg1);
my $cfgfile = AppConfig::File->new($state, $file);
$cfgfile->parse($file); # read config file
=head1 OVERVIEW
AppConfig::File is a Perl5 module which reads configuration files and use
the contents therein to update variable values in an AppConfig::State
object.
AppConfig::File is distributed as part of the AppConfig bundle.
=head1 DESCRIPTION
=head2 USING THE AppConfig::File MODULE
To import and use the AppConfig::File module the following line should appear
in your Perl script:
use AppConfig::File;
AppConfig::File is used automatically if you use the AppConfig module
and create an AppConfig::File object through the file() method.
AppConfig::File is implemented using object-oriented methods. A new
AppConfig::File object is created and initialised using the
AppConfig::File->new() method. This returns a reference to a new
AppConfig::File object. A reference to an AppConfig::State object
should be passed in as the first parameter:
my $state = AppConfig::State->new();
my $cfgfile = AppConfig::File->new($state);
This will create and return a reference to a new AppConfig::File object.
=head2 READING CONFIGURATION FILES
The C<parse()> method is used to read a configuration file and have the
contents update the STATE accordingly.
$cfgfile->parse($file);
Multiple files maye be specified and will be read in turn.
$cfgfile->parse($file1, $file2, $file3);
The method will return an undef value if it encounters any errors opening
the files. It will return immediately without processing any further files.
By default, the PEDANTIC option in the AppConfig::State object,
$self->{ STATE }, is turned off and any parsing errors (invalid variables,
unvalidated values, etc) will generated warnings, but not cause the method
to return. Having processed all files, the method will return 1 if all
files were processed without warning or 0 if one or more warnings were
raised. When the PEDANTIC option is turned on, the method generates a
warning and immediately returns a value of 0 as soon as it encounters any
parsing error.
Variables values in the configuration files may be expanded depending on
the value of their EXPAND option, as determined from the App::State object.
See L<AppConfig::State> for more information on variable expansion.
=head2 CONFIGURATION FILE FORMAT
A configuration file may contain blank lines and comments which are
ignored. Comments begin with a '#' as the first character on a line
or following one or more whitespace tokens, and continue to the end of
the line.
# this is a comment
foo = bar # so is this
url = index.html#hello # this too, but not the '#welcome'
Notice how the '#welcome' part of the URL is not treated as a comment
because a whitespace character doesn't precede it.
Long lines can be continued onto the next line by ending the first
line with a '\'.
callsign = alpha bravo camel delta echo foxtrot golf hipowls \
india juliet kilo llama mike november oscar papa \
quebec romeo sierra tango umbrella victor whiskey \
x-ray yankee zebra
Variables that are simple flags and do not expect an argument (ARGCOUNT =
ARGCOUNT_NONE) can be specified without any value. They will be set with
the value 1, with any value explicitly specified (except "0" and "off")
being ignored. The variable may also be specified with a "no" prefix to
implicitly set the variable to 0.
verbose # on (1)
verbose = 1 # on (1)
verbose = 0 # off (0)
verbose off # off (0)
verbose on # on (1)
verbose mumble # on (1)
noverbose # off (0)
Variables that expect an argument (ARGCOUNT = ARGCOUNT_ONE) will be set to
whatever follows the variable name, up to the end of the current line. An
equals sign may be inserted between the variable and value for clarity.
room = /home/kitchen
room /home/bedroom
Each subsequent re-definition of the variable value overwrites the previous
value.
print $config->room(); # prints "/home/bedroom"
Variables may be defined to accept multiple values (ARGCOUNT = ARGCOUNT_LIST).
Each subsequent definition of the variable adds the value to the list of
previously set values for the variable.
drink = coffee
drink = tea
A reference to a list of values is returned when the variable is requested.
my $beverages = $config->drinks();
print join(", ", @$beverages); # prints "coffee, tea"
Variables may also be defined as hash lists (ARGCOUNT = ARGCOUNT_HASH).
Each subsequent definition creates a new key and value in the hash array.
alias l="ls -CF"
alias h="history"
A reference to the hash is returned when the variable is requested.
my $aliases = $config->alias();
foreach my $k (keys %$aliases) {
print "$k => $aliases->{ $k }\n";
}
A large chunk of text can be defined using Perl's "heredoc" quoting
style.
scalar = <<BOUNDARY_STRING
line 1
line 2: Space/linebreaks within a HERE document are kept.
line 3: The last linebreak (\n) is stripped.
BOUNDARY_STRING
hash key1 = <<'FOO'
* Quotes (['"]) around the boundary string are simply ignored.
* Whether the variables in HERE document are expanded depends on
the EXPAND option of the variable or global setting.
FOO
hash = key2 = <<"_bar_"
Text within HERE document are kept as is.
# comments are treated as a normal text.
The same applies to line continuation. \
_bar_
Note that you cannot use HERE document as a key in a hash or a name
of a variable.
The '-' prefix can be used to reset a variable to its default value and
the '+' prefix can be used to set it to 1
-verbose
+debug
Variable, environment variable and tilde (home directory) expansions
Variable values may contain references to other AppConfig variables,
environment variables and/or users' home directories. These will be
expanded depending on the EXPAND value for each variable or the GLOBAL
EXPAND value.
Three different expansion types may be applied:
bin = ~/bin # expand '~' to home dir if EXPAND_UID
tmp = ~abw/tmp # as above, but home dir for user 'abw'
perl = $bin/perl # expand value of 'bin' variable if EXPAND_VAR
ripl = $(bin)/ripl # as above with explicit parens
home = ${HOME} # expand HOME environment var if EXPAND_ENV
See L<AppConfig::State> for more information on expanding variable values.
The configuration files may have variables arranged in blocks. A block
header, consisting of the block name in square brackets, introduces a
configuration block. The block name and an underscore are then prefixed
to the names of all variables subsequently referenced in that block. The
block continues until the next block definition or to the end of the current
file.
[block1]
foo = 10 # block1_foo = 10
[block2]
foo = 20 # block2_foo = 20
=head1 AUTHOR
Andy Wardley, E<lt>abw@wardley.orgE<gt>
=head1 COPYRIGHT
Copyright (C) 1997-2007 Andy Wardley. All Rights Reserved.
This module is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
=head1 SEE ALSO
AppConfig, AppConfig::State
=cut
PK 1N%[���3 3 perl5/AppConfig/Getopt.pmnu ��6�$ #============================================================================
#
# AppConfig::Getopt.pm
#
# Perl5 module to interface AppConfig::* to Johan Vromans' Getopt::Long
# module. Getopt::Long implements the POSIX standard for command line
# options, with GNU extensions, and also traditional one-letter options.
# AppConfig::Getopt constructs the necessary Getopt:::Long configuration
# from the internal AppConfig::State and delegates the parsing of command
# line arguments to it. Internal variable values are updated by callback
# from GetOptions().
#
# Written by Andy Wardley <abw@wardley.org>
#
# Copyright (C) 1997-2007 Andy Wardley. All Rights Reserved.
# Copyright (C) 1997,1998 Canon Research Centre Europe Ltd.
#
#============================================================================
package AppConfig::Getopt;
use 5.006;
use strict;
use warnings;
use AppConfig::State;
use Getopt::Long 2.17;
our $VERSION = '1.71';
#------------------------------------------------------------------------
# new($state, \@args)
#
# Module constructor. The first, mandatory parameter should be a
# reference to an AppConfig::State object to which all actions should
# be applied. The second parameter may be a reference to a list of
# command line arguments. This list reference is passed to parse() for
# processing.
#
# Returns a reference to a newly created AppConfig::Getopt object.
#------------------------------------------------------------------------
sub new {
my $class = shift;
my $state = shift;
my $self = {
STATE => $state,
};
bless $self, $class;
# call parse() to parse any arg list passed
$self->parse(@_)
if @_;
return $self;
}
#------------------------------------------------------------------------
# parse(@$config, \@args)
#
# Constructs the appropriate configuration information and then delegates
# the task of processing command line options to Getopt::Long.
#
# Returns 1 on success or 0 if one or more warnings were raised.
#------------------------------------------------------------------------
sub parse {
my $self = shift;
my $state = $self->{ STATE };
my (@config, $args, $getopt);
local $" = ', ';
# we trap $SIG{__WARN__} errors and patch them into AppConfig::State
local $SIG{__WARN__} = sub {
my $msg = shift;
# AppConfig::State doesn't expect CR terminated error messages
# and it uses printf, so we protect any embedded '%' chars
chomp($msg);
$state->_error("%s", $msg);
};
# slurp all config items into @config
push(@config, shift) while defined $_[0] && ! ref($_[0]);
# add debug status if appropriate (hmm...can't decide about this)
# push(@config, 'debug') if $state->_debug();
# next parameter may be a reference to a list of args
$args = shift;
# copy any args explicitly specified into @ARGV
@ARGV = @$args if defined $args;
# we enclose in an eval block because constructor may die()
eval {
# configure Getopt::Long
Getopt::Long::Configure(@config);
# construct options list from AppConfig::State variables
my @opts = $self->{ STATE }->_getopt_state();
# DEBUG
if ($state->_debug()) {
print STDERR "Calling GetOptions(@opts)\n";
print STDERR "\@ARGV = (@ARGV)\n";
};
# call GetOptions() with specifications constructed from the state
$getopt = GetOptions(@opts);
};
if ($@) {
chomp($@);
$state->_error("%s", $@);
return 0;
}
# udpdate any args reference passed to include only that which is left
# in @ARGV
@$args = @ARGV if defined $args;
return $getopt;
}
#========================================================================
# AppConfig::State
#========================================================================
package AppConfig::State;
#------------------------------------------------------------------------
# _getopt_state()
#
# Constructs option specs in the Getopt::Long format for each variable
# definition.
#
# Returns a list of specification strings.
#------------------------------------------------------------------------
sub _getopt_state {
my $self = shift;
my ($var, $spec, $args, $argcount, @specs);
my $linkage = sub { $self->set(@_) };
foreach $var (keys %{ $self->{ VARIABLE } }) {
$spec = join('|', $var, @{ $self->{ ALIASES }->{ $var } || [ ] });
# an ARGS value is used, if specified
unless (defined ($args = $self->{ ARGS }->{ $var })) {
# otherwise, construct a basic one from ARGCOUNT
ARGCOUNT: {
last ARGCOUNT unless
defined ($argcount = $self->{ ARGCOUNT }->{ $var });
$args = "=s", last ARGCOUNT if $argcount eq ARGCOUNT_ONE;
$args = "=s@", last ARGCOUNT if $argcount eq ARGCOUNT_LIST;
$args = "=s%", last ARGCOUNT if $argcount eq ARGCOUNT_HASH;
$args = "!";
}
}
$spec .= $args if defined $args;
push(@specs, $spec, $linkage);
}
return @specs;
}
1;
__END__
=head1 NAME
AppConfig::Getopt - Perl5 module for processing command line arguments via delegation to Getopt::Long.
=head1 SYNOPSIS
use AppConfig::Getopt;
my $state = AppConfig::State->new(\%cfg);
my $getopt = AppConfig::Getopt->new($state);
$getopt->parse(\@args); # read args
=head1 OVERVIEW
AppConfig::Getopt is a Perl5 module which delegates to Johan Vroman's
Getopt::Long module to parse command line arguments and update values
in an AppConfig::State object accordingly.
AppConfig::Getopt is distributed as part of the AppConfig bundle.
=head1 DESCRIPTION
=head2 USING THE AppConfig::Getopt MODULE
To import and use the AppConfig::Getopt module the following line should appear
in your Perl script:
use AppConfig::Getopt;
AppConfig::Getopt is used automatically if you use the AppConfig module
and create an AppConfig::Getopt object through the getopt() method.
AppConfig::Getopt is implemented using object-oriented methods. A new
AppConfig::Getopt object is created and initialised using the new() method.
This returns a reference to a new AppConfig::Getopt object. A reference to
an AppConfig::State object should be passed in as the first parameter:
my $state = AppConfig::State->new();
my $getopt = AppConfig::Getopt->new($state);
This will create and return a reference to a new AppConfig::Getopt object.
=head2 PARSING COMMAND LINE ARGUMENTS
The C<parse()> method is used to read a list of command line arguments and
update the state accordingly.
The first (non-list reference) parameters may contain a number of
configuration strings to pass to Getopt::Long::Configure. A reference
to a list of arguments may additionally be passed or @ARGV is used by
default.
$getopt->parse(); # uses @ARGV
$getopt->parse(\@myargs);
$getopt->parse(qw(auto_abbrev debug)); # uses @ARGV
$getopt->parse(qw(debug), \@myargs);
See Getopt::Long for details of the configuartion options available.
A Getopt::Long specification string is constructed for each variable
defined in the AppConfig::State. This consists of the name, any aliases
and the ARGS value for the variable.
These specification string are then passed to Getopt::Long, the arguments
are parsed and the values in the AppConfig::State updated.
See AppConfig for information about using the AppConfig::Getopt
module via the getopt() method.
=head1 AUTHOR
Andy Wardley, E<lt>abw@wardley.orgE<gt>
=head1 COPYRIGHT
Copyright (C) 1997-2007 Andy Wardley. All Rights Reserved.
Copyright (C) 1997,1998 Canon Research Centre Europe Ltd.
This module is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
=head1 ACKNOWLEDGMENTS
Many thanks are due to Johan Vromans for the Getopt::Long module. He was
kind enough to offer assistance and access to early releases of his code to
enable this module to be written.
=head1 SEE ALSO
AppConfig, AppConfig::State, AppConfig::Args, Getopt::Long
=cut
PK 1N%[��E�1$ 1$ perl5/lwpcook.podnu ��6�$ =head1 NAME
lwpcook - The libwww-perl cookbook
=head1 DESCRIPTION
This document contain some examples that show typical usage of the
libwww-perl library. You should consult the documentation for the
individual modules for more detail.
All examples should be runnable programs. You can, in most cases, test
the code sections by piping the program text directly to perl.
=head1 GET
It is very easy to use this library to just fetch documents from the
net. The LWP::Simple module provides the get() function that return
the document specified by its URL argument:
use LWP::Simple;
$doc = get 'http://search.cpan.org/dist/libwww-perl/';
or, as a perl one-liner using the getprint() function:
perl -MLWP::Simple -e 'getprint "http://search.cpan.org/dist/libwww-perl/"'
or, how about fetching the latest perl by running this command:
perl -MLWP::Simple -e '
getstore "ftp://ftp.sunet.se/pub/lang/perl/CPAN/src/latest.tar.gz",
"perl.tar.gz"'
You will probably first want to find a CPAN site closer to you by
running something like the following command:
perl -MLWP::Simple -e 'getprint "http://www.cpan.org/SITES.html"'
Enough of this simple stuff! The LWP object oriented interface gives
you more control over the request sent to the server. Using this
interface you have full control over headers sent and how you want to
handle the response returned.
use LWP::UserAgent;
$ua = LWP::UserAgent->new;
$ua->agent("$0/0.1 " . $ua->agent);
# $ua->agent("Mozilla/8.0") # pretend we are very capable browser
$req = HTTP::Request->new(
GET => 'http://search.cpan.org/dist/libwww-perl/');
$req->header('Accept' => 'text/html');
# send request
$res = $ua->request($req);
# check the outcome
if ($res->is_success) {
print $res->decoded_content;
}
else {
print "Error: " . $res->status_line . "\n";
}
The lwp-request program (alias GET) that is distributed with the
library can also be used to fetch documents from WWW servers.
=head1 HEAD
If you just want to check if a document is present (i.e. the URL is
valid) try to run code that looks like this:
use LWP::Simple;
if (head($url)) {
# ok document exists
}
The head() function really returns a list of meta-information about
the document. The first three values of the list returned are the
document type, the size of the document, and the age of the document.
More control over the request or access to all header values returned
require that you use the object oriented interface described for GET
above. Just s/GET/HEAD/g.
=head1 POST
There is no simple procedural interface for posting data to a WWW server. You
must use the object oriented interface for this. The most common POST
operation is to access a WWW form application:
use LWP::UserAgent;
$ua = LWP::UserAgent->new;
my $req = HTTP::Request->new(
POST => 'https://rt.cpan.org/Public/Dist/Display.html');
$req->content_type('application/x-www-form-urlencoded');
$req->content('Status=Active&Name=libwww-perl');
my $res = $ua->request($req);
print $res->as_string;
Lazy people use the HTTP::Request::Common module to set up a suitable
POST request message (it handles all the escaping issues) and has a
suitable default for the content_type:
use HTTP::Request::Common qw(POST);
use LWP::UserAgent;
$ua = LWP::UserAgent->new;
my $req = POST 'https://rt.cpan.org/Public/Dist/Display.html',
[ Status => 'Active', Name => 'libwww-perl' ];
print $ua->request($req)->as_string;
The lwp-request program (alias POST) that is distributed with the
library can also be used for posting data.
=head1 PROXIES
Some sites use proxies to go through fire wall machines, or just as
cache in order to improve performance. Proxies can also be used for
accessing resources through protocols not supported directly (or
supported badly :-) by the libwww-perl library.
You should initialize your proxy setting before you start sending
requests:
use LWP::UserAgent;
$ua = LWP::UserAgent->new;
$ua->env_proxy; # initialize from environment variables
# or
$ua->proxy(ftp => 'http://proxy.myorg.com');
$ua->proxy(wais => 'http://proxy.myorg.com');
$ua->no_proxy(qw(no se fi));
my $req = HTTP::Request->new(GET => 'wais://xxx.com/');
print $ua->request($req)->as_string;
The LWP::Simple interface will call env_proxy() for you automatically.
Applications that use the $ua->env_proxy() method will normally not
use the $ua->proxy() and $ua->no_proxy() methods.
Some proxies also require that you send it a username/password in
order to let requests through. You should be able to add the
required header, with something like this:
use LWP::UserAgent;
$ua = LWP::UserAgent->new;
$ua->proxy(['http', 'ftp'] => 'http://username:password@proxy.myorg.com');
$req = HTTP::Request->new('GET',"http://www.perl.com");
$res = $ua->request($req);
print $res->decoded_content if $res->is_success;
Replace C<proxy.myorg.com>, C<username> and
C<password> with something suitable for your site.
=head1 ACCESS TO PROTECTED DOCUMENTS
Documents protected by basic authorization can easily be accessed
like this:
use LWP::UserAgent;
$ua = LWP::UserAgent->new;
$req = HTTP::Request->new(GET => 'http://www.linpro.no/secret/');
$req->authorization_basic('aas', 'mypassword');
print $ua->request($req)->as_string;
The other alternative is to provide a subclass of I<LWP::UserAgent> that
overrides the get_basic_credentials() method. Study the I<lwp-request>
program for an example of this.
=head1 COOKIES
Some sites like to play games with cookies. By default LWP ignores
cookies provided by the servers it visits. LWP will collect cookies
and respond to cookie requests if you set up a cookie jar. LWP doesn't
provide a cookie jar itself, but if you install L<HTTP::CookieJar::LWP>,
it can be used like this:
use LWP::UserAgent;
use HTTP::CookieJar::LWP;
$ua = LWP::UserAgent->new(
cookie_jar => HTTP::CookieJar::LWP->new,
);
# and then send requests just as you used to do
$res = $ua->request(HTTP::Request->new(GET => "http://no.yahoo.com/"));
print $res->status_line, "\n";
=head1 HTTPS
URLs with https scheme are accessed in exactly the same way as with
http scheme, provided that an SSL interface module for LWP has been
properly installed (see the F<README.SSL> file found in the
libwww-perl distribution for more details). If no SSL interface is
installed for LWP to use, then you will get "501 Protocol scheme
'https' is not supported" errors when accessing such URLs.
Here's an example of fetching and printing a WWW page using SSL:
use LWP::UserAgent;
my $ua = LWP::UserAgent->new;
my $req = HTTP::Request->new(GET => 'https://www.helsinki.fi/');
my $res = $ua->request($req);
if ($res->is_success) {
print $res->as_string;
}
else {
print "Failed: ", $res->status_line, "\n";
}
=head1 MIRRORING
If you want to mirror documents from a WWW server, then try to run
code similar to this at regular intervals:
use LWP::Simple;
%mirrors = (
'http://www.sn.no/' => 'sn.html',
'http://www.perl.com/' => 'perl.html',
'http://search.cpan.org/distlibwww-perl/' => 'lwp.html',
'gopher://gopher.sn.no/' => 'gopher.html',
);
while (($url, $localfile) = each(%mirrors)) {
mirror($url, $localfile);
}
Or, as a perl one-liner:
perl -MLWP::Simple -e 'mirror("http://www.perl.com/", "perl.html")';
The document will not be transferred unless it has been updated.
=head1 LARGE DOCUMENTS
If the document you want to fetch is too large to be kept in memory,
then you have two alternatives. You can instruct the library to write
the document content to a file (second $ua->request() argument is a file
name):
use LWP::UserAgent;
$ua = LWP::UserAgent->new;
my $req = HTTP::Request->new(GET =>
'http://www.cpan.org/CPAN/authors/id/O/OA/OALDERS/libwww-perl-6.26.tar.gz');
$res = $ua->request($req, "libwww-perl.tar.gz");
if ($res->is_success) {
print "ok\n";
}
else {
print $res->status_line, "\n";
}
Or you can process the document as it arrives (second $ua->request()
argument is a code reference):
use LWP::UserAgent;
$ua = LWP::UserAgent->new;
$URL = 'ftp://ftp.isc.org/pub/rfc/rfc-index.txt';
my $expected_length;
my $bytes_received = 0;
my $res =
$ua->request(HTTP::Request->new(GET => $URL),
sub {
my($chunk, $res) = @_;
$bytes_received += length($chunk);
unless (defined $expected_length) {
$expected_length = $res->content_length || 0;
}
if ($expected_length) {
printf STDERR "%d%% - ",
100 * $bytes_received / $expected_length;
}
print STDERR "$bytes_received bytes received\n";
# XXX Should really do something with the chunk itself
# print $chunk;
});
print $res->status_line, "\n";
=head1 COPYRIGHT
Copyright 1996-2001, Gisle Aas
This library is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
PK 1N%[�^�`R R perl5/Path/Class/Entity.pmnu ��6�$ use strict;
package Path::Class::Entity;
{
$Path::Class::Entity::VERSION = '0.37';
}
use File::Spec 3.26;
use File::stat ();
use Cwd;
use Carp();
use overload
(
q[""] => 'stringify',
'bool' => 'boolify',
fallback => 1,
);
sub new {
my $from = shift;
my ($class, $fs_class) = (ref($from)
? (ref $from, $from->{file_spec_class})
: ($from, $Path::Class::Foreign));
return bless {file_spec_class => $fs_class}, $class;
}
sub is_dir { 0 }
sub _spec_class {
my ($class, $type) = @_;
die "Invalid system type '$type'" unless ($type) = $type =~ /^(\w+)$/; # Untaint
my $spec = "File::Spec::$type";
## no critic
eval "require $spec; 1" or die $@;
return $spec;
}
sub new_foreign {
my ($class, $type) = (shift, shift);
local $Path::Class::Foreign = $class->_spec_class($type);
return $class->new(@_);
}
sub _spec { (ref($_[0]) && $_[0]->{file_spec_class}) || 'File::Spec' }
sub boolify { 1 }
sub is_absolute {
# 5.6.0 has a bug with regexes and stringification that's ticked by
# file_name_is_absolute(). Help it along with an explicit stringify().
$_[0]->_spec->file_name_is_absolute($_[0]->stringify)
}
sub is_relative { ! $_[0]->is_absolute }
sub cleanup {
my $self = shift;
my $cleaned = $self->new( $self->_spec->canonpath("$self") );
%$self = %$cleaned;
return $self;
}
sub resolve {
my $self = shift;
Carp::croak($! . " $self") unless -e $self; # No such file or directory
my $cleaned = $self->new( scalar Cwd::realpath($self->stringify) );
# realpath() always returns absolute path, kind of annoying
$cleaned = $cleaned->relative if $self->is_relative;
%$self = %$cleaned;
return $self;
}
sub absolute {
my $self = shift;
return $self if $self->is_absolute;
return $self->new($self->_spec->rel2abs($self->stringify, @_));
}
sub relative {
my $self = shift;
return $self->new($self->_spec->abs2rel($self->stringify, @_));
}
sub stat { File::stat::stat("$_[0]") }
sub lstat { File::stat::lstat("$_[0]") }
sub PRUNE { return \&PRUNE; }
1;
__END__
=head1 NAME
Path::Class::Entity - Base class for files and directories
=head1 VERSION
version 0.37
=head1 DESCRIPTION
This class is the base class for C<Path::Class::File> and
C<Path::Class::Dir>, it is not used directly by callers.
=head1 AUTHOR
Ken Williams, kwilliams@cpan.org
=head1 SEE ALSO
Path::Class
=cut
PK 1N%[K�+�k9 k9 perl5/Path/Class/File.pmnu ��6�$ use strict;
package Path::Class::File;
{
$Path::Class::File::VERSION = '0.37';
}
use Path::Class::Dir;
use parent qw(Path::Class::Entity);
use Carp;
use IO::File ();
sub new {
my $self = shift->SUPER::new;
my $file = pop();
my @dirs = @_;
my ($volume, $dirs, $base) = $self->_spec->splitpath($file);
if (length $dirs) {
push @dirs, $self->_spec->catpath($volume, $dirs, '');
}
$self->{dir} = @dirs ? $self->dir_class->new(@dirs) : undef;
$self->{file} = $base;
return $self;
}
sub dir_class { "Path::Class::Dir" }
sub as_foreign {
my ($self, $type) = @_;
local $Path::Class::Foreign = $self->_spec_class($type);
my $foreign = ref($self)->SUPER::new;
$foreign->{dir} = $self->{dir}->as_foreign($type) if defined $self->{dir};
$foreign->{file} = $self->{file};
return $foreign;
}
sub stringify {
my $self = shift;
return $self->{file} unless defined $self->{dir};
return $self->_spec->catfile($self->{dir}->stringify, $self->{file});
}
sub dir {
my $self = shift;
return $self->{dir} if defined $self->{dir};
return $self->dir_class->new($self->_spec->curdir);
}
BEGIN { *parent = \&dir; }
sub volume {
my $self = shift;
return '' unless defined $self->{dir};
return $self->{dir}->volume;
}
sub components {
my $self = shift;
croak "Arguments are not currently supported by File->components()" if @_;
return ($self->dir->components, $self->basename);
}
sub basename { shift->{file} }
sub open { IO::File->new(@_) }
sub openr { $_[0]->open('r') or croak "Can't read $_[0]: $!" }
sub openw { $_[0]->open('w') or croak "Can't write to $_[0]: $!" }
sub opena { $_[0]->open('a') or croak "Can't append to $_[0]: $!" }
sub touch {
my $self = shift;
if (-e $self) {
utime undef, undef, $self;
} else {
$self->openw;
}
}
sub slurp {
my ($self, %args) = @_;
my $iomode = $args{iomode} || 'r';
my $fh = $self->open($iomode) or croak "Can't read $self: $!";
if (wantarray) {
my @data = <$fh>;
chomp @data if $args{chomped} or $args{chomp};
if ( my $splitter = $args{split} ) {
@data = map { [ split $splitter, $_ ] } @data;
}
return @data;
}
croak "'split' argument can only be used in list context"
if $args{split};
if ($args{chomped} or $args{chomp}) {
chomp( my @data = <$fh> );
return join '', @data;
}
local $/;
return <$fh>;
}
sub spew {
my $self = shift;
my %args = splice( @_, 0, @_-1 );
my $iomode = $args{iomode} || 'w';
my $fh = $self->open( $iomode ) or croak "Can't write to $self: $!";
if (ref($_[0]) eq 'ARRAY') {
# Use old-school for loop to avoid copying.
for (my $i = 0; $i < @{ $_[0] }; $i++) {
print $fh $_[0]->[$i]
or croak "Can't write to $self: $!";
}
}
else {
print $fh $_[0]
or croak "Can't write to $self: $!";
}
close $fh
or croak "Can't write to $self: $!";
return;
}
sub spew_lines {
my $self = shift;
my %args = splice( @_, 0, @_-1 );
my $content = $_[0];
# If content is an array ref, appends $/ to each element of the array.
# Otherwise, if it is a simple scalar, just appends $/ to that scalar.
$content
= ref( $content ) eq 'ARRAY'
? [ map { $_, $/ } @$content ]
: "$content$/";
return $self->spew( %args, $content );
}
sub remove {
my $file = shift->stringify;
return unlink $file unless -e $file; # Sets $! correctly
1 while unlink $file;
return not -e $file;
}
sub copy_to {
my ($self, $dest) = @_;
if ( eval{ $dest->isa("Path::Class::File")} ) {
$dest = $dest->stringify;
croak "Can't copy to file $dest: it is a directory" if -d $dest;
} elsif ( eval{ $dest->isa("Path::Class::Dir") } ) {
$dest = $dest->stringify;
croak "Can't copy to directory $dest: it is a file" if -f $dest;
croak "Can't copy to directory $dest: no such directory" unless -d $dest;
} elsif ( ref $dest ) {
croak "Don't know how to copy files to objects of type '".ref($self)."'";
}
require Perl::OSType;
if ( !Perl::OSType::is_os_type('Unix') ) {
require File::Copy;
return unless File::Copy::cp($self->stringify, "${dest}");
} else {
return unless (system('cp', $self->stringify, "${dest}") == 0);
}
return $self->new($dest);
}
sub move_to {
my ($self, $dest) = @_;
require File::Copy;
if (File::Copy::move($self->stringify, "${dest}")) {
my $new = $self->new($dest);
$self->{$_} = $new->{$_} foreach (qw/ dir file /);
return $self;
} else {
return;
}
}
sub traverse {
my $self = shift;
my ($callback, @args) = @_;
return $self->$callback(sub { () }, @args);
}
sub traverse_if {
my $self = shift;
my ($callback, $condition, @args) = @_;
return $self->$callback(sub { () }, @args);
}
1;
__END__
=head1 NAME
Path::Class::File - Objects representing files
=head1 VERSION
version 0.37
=head1 SYNOPSIS
use Path::Class; # Exports file() by default
my $file = file('foo', 'bar.txt'); # Path::Class::File object
my $file = Path::Class::File->new('foo', 'bar.txt'); # Same thing
# Stringifies to 'foo/bar.txt' on Unix, 'foo\bar.txt' on Windows, etc.
print "file: $file\n";
if ($file->is_absolute) { ... }
if ($file->is_relative) { ... }
my $v = $file->volume; # Could be 'C:' on Windows, empty string
# on Unix, 'Macintosh HD:' on Mac OS
$file->cleanup; # Perform logical cleanup of pathname
$file->resolve; # Perform physical cleanup of pathname
my $dir = $file->dir; # A Path::Class::Dir object
my $abs = $file->absolute; # Transform to absolute path
my $rel = $file->relative; # Transform to relative path
=head1 DESCRIPTION
The C<Path::Class::File> class contains functionality for manipulating
file names in a cross-platform way.
=head1 METHODS
=over 4
=item $file = Path::Class::File->new( <dir1>, <dir2>, ..., <file> )
=item $file = file( <dir1>, <dir2>, ..., <file> )
Creates a new C<Path::Class::File> object and returns it. The
arguments specify the path to the file. Any volume may also be
specified as the first argument, or as part of the first argument.
You can use platform-neutral syntax:
my $file = file( 'foo', 'bar', 'baz.txt' );
or platform-native syntax:
my $file = file( 'foo/bar/baz.txt' );
or a mixture of the two:
my $file = file( 'foo/bar', 'baz.txt' );
All three of the above examples create relative paths. To create an
absolute path, either use the platform native syntax for doing so:
my $file = file( '/var/tmp/foo.txt' );
or use an empty string as the first argument:
my $file = file( '', 'var', 'tmp', 'foo.txt' );
If the second form seems awkward, that's somewhat intentional - paths
like C</var/tmp> or C<\Windows> aren't cross-platform concepts in the
first place, so they probably shouldn't appear in your code if you're
trying to be cross-platform. The first form is perfectly fine,
because paths like this may come from config files, user input, or
whatever.
=item $file->stringify
This method is called internally when a C<Path::Class::File> object is
used in a string context, so the following are equivalent:
$string = $file->stringify;
$string = "$file";
=item $file->volume
Returns the volume (e.g. C<C:> on Windows, C<Macintosh HD:> on Mac OS,
etc.) of the object, if any. Otherwise, returns the empty string.
=item $file->basename
Returns the name of the file as a string, without the directory
portion (if any).
=item $file->components
Returns a list of the directory components of this file, followed by
the basename.
Note: unlike C<< $dir->components >>, this method currently does not
accept any arguments to select which elements of the list will be
returned. It may do so in the future. Currently it throws an
exception if such arguments are present.
=item $file->is_dir
Returns a boolean value indicating whether this object represents a
directory. Not surprisingly, C<Path::Class::File> objects always
return false, and L<Path::Class::Dir> objects always return true.
=item $file->is_absolute
Returns true or false depending on whether the file refers to an
absolute path specifier (like C</usr/local/foo.txt> or C<\Windows\Foo.txt>).
=item $file->is_relative
Returns true or false depending on whether the file refers to a
relative path specifier (like C<lib/foo.txt> or C<.\Foo.txt>).
=item $file->cleanup
Performs a logical cleanup of the file path. For instance:
my $file = file('/foo//baz/./foo.txt')->cleanup;
# $file now represents '/foo/baz/foo.txt';
=item $dir->resolve
Performs a physical cleanup of the file path. For instance:
my $file = file('/foo/baz/../foo.txt')->resolve;
# $file now represents '/foo/foo.txt', assuming no symlinks
This actually consults the filesystem to verify the validity of the
path.
=item $dir = $file->dir
Returns a C<Path::Class::Dir> object representing the directory
containing this file.
=item $dir = $file->parent
A synonym for the C<dir()> method.
=item $abs = $file->absolute
Returns a C<Path::Class::File> object representing C<$file> as an
absolute path. An optional argument, given as either a string or a
L<Path::Class::Dir> object, specifies the directory to use as the base
of relativity - otherwise the current working directory will be used.
=item $rel = $file->relative
Returns a C<Path::Class::File> object representing C<$file> as a
relative path. An optional argument, given as either a string or a
C<Path::Class::Dir> object, specifies the directory to use as the base
of relativity - otherwise the current working directory will be used.
=item $foreign = $file->as_foreign($type)
Returns a C<Path::Class::File> object representing C<$file> as it would
be specified on a system of type C<$type>. Known types include
C<Unix>, C<Win32>, C<Mac>, C<VMS>, and C<OS2>, i.e. anything for which
there is a subclass of C<File::Spec>.
Any generated objects (subdirectories, files, parents, etc.) will also
retain this type.
=item $foreign = Path::Class::File->new_foreign($type, @args)
Returns a C<Path::Class::File> object representing a file as it would
be specified on a system of type C<$type>. Known types include
C<Unix>, C<Win32>, C<Mac>, C<VMS>, and C<OS2>, i.e. anything for which
there is a subclass of C<File::Spec>.
The arguments in C<@args> are the same as they would be specified in
C<new()>.
=item $fh = $file->open($mode, $permissions)
Passes the given arguments, including C<$file>, to C<< IO::File->new >>
(which in turn calls C<< IO::File->open >> and returns the result
as an L<IO::File> object. If the opening
fails, C<undef> is returned and C<$!> is set.
=item $fh = $file->openr()
A shortcut for
$fh = $file->open('r') or croak "Can't read $file: $!";
=item $fh = $file->openw()
A shortcut for
$fh = $file->open('w') or croak "Can't write to $file: $!";
=item $fh = $file->opena()
A shortcut for
$fh = $file->open('a') or croak "Can't append to $file: $!";
=item $file->touch
Sets the modification and access time of the given file to right now,
if the file exists. If it doesn't exist, C<touch()> will I<make> it
exist, and - YES! - set its modification and access time to now.
=item $file->slurp()
In a scalar context, returns the contents of C<$file> in a string. In
a list context, returns the lines of C<$file> (according to how C<$/>
is set) as a list. If the file can't be read, this method will throw
an exception.
If you want C<chomp()> run on each line of the file, pass a true value
for the C<chomp> or C<chomped> parameters:
my @lines = $file->slurp(chomp => 1);
You may also use the C<iomode> parameter to pass in an IO mode to use
when opening the file, usually IO layers (though anything accepted by
the MODE argument of C<open()> is accepted here). Just make sure it's
a I<reading> mode.
my @lines = $file->slurp(iomode => ':crlf');
my $lines = $file->slurp(iomode => '<:encoding(UTF-8)');
The default C<iomode> is C<r>.
Lines can also be automatically split, mimicking the perl command-line
option C<-a> by using the C<split> parameter. If this parameter is used,
each line will be returned as an array ref.
my @lines = $file->slurp( chomp => 1, split => qr/\s*,\s*/ );
The C<split> parameter can only be used in a list context.
=item $file->spew( $content );
The opposite of L</slurp>, this takes a list of strings and prints them
to the file in write mode. If the file can't be written to, this method
will throw an exception.
The content to be written can be either an array ref or a plain scalar.
If the content is an array ref then each entry in the array will be
written to the file.
You may use the C<iomode> parameter to pass in an IO mode to use when
opening the file, just like L</slurp> supports.
$file->spew(iomode => '>:raw', $content);
The default C<iomode> is C<w>.
=item $file->spew_lines( $content );
Just like C<spew>, but, if $content is a plain scalar, appends $/
to it, or, if $content is an array ref, appends $/ to each element
of the array.
Can also take an C<iomode> parameter like C<spew>. Again, the
default C<iomode> is C<w>.
=item $file->traverse(sub { ... }, @args)
Calls the given callback on $file. This doesn't do much on its own,
but see the associated documentation in L<Path::Class::Dir>.
=item $file->remove()
This method will remove the file in a way that works well on all
platforms, and returns a boolean value indicating whether or not the
file was successfully removed.
C<remove()> is better than simply calling Perl's C<unlink()> function,
because on some platforms (notably VMS) you actually may need to call
C<unlink()> several times before all versions of the file are gone -
the C<remove()> method handles this process for you.
=item $st = $file->stat()
Invokes C<< File::stat::stat() >> on this file and returns a
L<File::stat> object representing the result.
=item $st = $file->lstat()
Same as C<stat()>, but if C<$file> is a symbolic link, C<lstat()>
stats the link instead of the file the link points to.
=item $class = $file->dir_class()
Returns the class which should be used to create directory objects.
Generally overridden whenever this class is subclassed.
=item $copy = $file->copy_to( $dest );
Copies the C<$file> to C<$dest>. It returns a L<Path::Class::File>
object when successful, C<undef> otherwise.
=item $moved = $file->move_to( $dest );
Moves the C<$file> to C<$dest>, and updates C<$file> accordingly.
It returns C<$file> is successful, C<undef> otherwise.
=back
=head1 AUTHOR
Ken Williams, kwilliams@cpan.org
=head1 SEE ALSO
L<Path::Class>, L<Path::Class::Dir>, L<File::Spec>
=cut
PK 1N%[f����a �a perl5/Path/Class/Dir.pmnu ��6�$ use strict;
package Path::Class::Dir;
{
$Path::Class::Dir::VERSION = '0.37';
}
use Path::Class::File;
use Carp();
use parent qw(Path::Class::Entity);
use IO::Dir ();
use File::Path ();
use File::Temp ();
use Scalar::Util ();
# updir & curdir on the local machine, for screening them out in
# children(). Note that they don't respect 'foreign' semantics.
my $Updir = __PACKAGE__->_spec->updir;
my $Curdir = __PACKAGE__->_spec->curdir;
sub new {
my $self = shift->SUPER::new();
# If the only arg is undef, it's probably a mistake. Without this
# special case here, we'd return the root directory, which is a
# lousy thing to do to someone when they made a mistake. Return
# undef instead.
return if @_==1 && !defined($_[0]);
my $s = $self->_spec;
my $first = (@_ == 0 ? $s->curdir :
!ref($_[0]) && $_[0] eq '' ? (shift, $s->rootdir) :
shift()
);
$self->{dirs} = [];
if ( Scalar::Util::blessed($first) && $first->isa("Path::Class::Dir") ) {
$self->{volume} = $first->{volume};
push @{$self->{dirs}}, @{$first->{dirs}};
}
else {
($self->{volume}, my $dirs) = $s->splitpath( $s->canonpath("$first") , 1);
push @{$self->{dirs}}, $dirs eq $s->rootdir ? "" : $s->splitdir($dirs);
}
push @{$self->{dirs}}, map {
Scalar::Util::blessed($_) && $_->isa("Path::Class::Dir")
? @{$_->{dirs}}
: $s->splitdir( $s->canonpath($_) )
} @_;
return $self;
}
sub file_class { "Path::Class::File" }
sub is_dir { 1 }
sub as_foreign {
my ($self, $type) = @_;
my $foreign = do {
local $self->{file_spec_class} = $self->_spec_class($type);
$self->SUPER::new;
};
# Clone internal structure
$foreign->{volume} = $self->{volume};
my ($u, $fu) = ($self->_spec->updir, $foreign->_spec->updir);
$foreign->{dirs} = [ map {$_ eq $u ? $fu : $_} @{$self->{dirs}}];
return $foreign;
}
sub stringify {
my $self = shift;
my $s = $self->_spec;
return $s->catpath($self->{volume},
$s->catdir(@{$self->{dirs}}),
'');
}
sub volume { shift()->{volume} }
sub file {
local $Path::Class::Foreign = $_[0]->{file_spec_class} if $_[0]->{file_spec_class};
return $_[0]->file_class->new(@_);
}
sub basename { shift()->{dirs}[-1] }
sub dir_list {
my $self = shift;
my $d = $self->{dirs};
return @$d unless @_;
my $offset = shift;
if ($offset < 0) { $offset = $#$d + $offset + 1 }
return wantarray ? @$d[$offset .. $#$d] : $d->[$offset] unless @_;
my $length = shift;
if ($length < 0) { $length = $#$d + $length + 1 - $offset }
return @$d[$offset .. $length + $offset - 1];
}
sub components {
my $self = shift;
return $self->dir_list(@_);
}
sub subdir {
my $self = shift;
return $self->new($self, @_);
}
sub parent {
my $self = shift;
my $dirs = $self->{dirs};
my ($curdir, $updir) = ($self->_spec->curdir, $self->_spec->updir);
if ($self->is_absolute) {
my $parent = $self->new($self);
pop @{$parent->{dirs}} if @$dirs > 1;
return $parent;
} elsif ($self eq $curdir) {
return $self->new($updir);
} elsif (!grep {$_ ne $updir} @$dirs) { # All updirs
return $self->new($self, $updir); # Add one more
} elsif (@$dirs == 1) {
return $self->new($curdir);
} else {
my $parent = $self->new($self);
pop @{$parent->{dirs}};
return $parent;
}
}
sub relative {
# File::Spec->abs2rel before version 3.13 returned the empty string
# when the two paths were equal - work around it here.
my $self = shift;
my $rel = $self->_spec->abs2rel($self->stringify, @_);
return $self->new( length $rel ? $rel : $self->_spec->curdir );
}
sub open { IO::Dir->new(@_) }
sub mkpath { File::Path::mkpath(shift()->stringify, @_) }
sub rmtree { File::Path::rmtree(shift()->stringify, @_) }
sub remove {
rmdir( shift() );
}
sub traverse {
my $self = shift;
my ($callback, @args) = @_;
my @children = $self->children;
return $self->$callback(
sub {
my @inner_args = @_;
return map { $_->traverse($callback, @inner_args) } @children;
},
@args
);
}
sub traverse_if {
my $self = shift;
my ($callback, $condition, @args) = @_;
my @children = grep { $condition->($_) } $self->children;
return $self->$callback(
sub {
my @inner_args = @_;
return map { $_->traverse_if($callback, $condition, @inner_args) } @children;
},
@args
);
}
sub recurse {
my $self = shift;
my %opts = (preorder => 1, depthfirst => 0, @_);
my $callback = $opts{callback}
or Carp::croak( "Must provide a 'callback' parameter to recurse()" );
my @queue = ($self);
my $visit_entry;
my $visit_dir =
$opts{depthfirst} && $opts{preorder}
? sub {
my $dir = shift;
my $ret = $callback->($dir);
unless( ($ret||'') eq $self->PRUNE ) {
unshift @queue, $dir->children;
}
}
: $opts{preorder}
? sub {
my $dir = shift;
my $ret = $callback->($dir);
unless( ($ret||'') eq $self->PRUNE ) {
push @queue, $dir->children;
}
}
: sub {
my $dir = shift;
$visit_entry->($_) foreach $dir->children;
$callback->($dir);
};
$visit_entry = sub {
my $entry = shift;
if ($entry->is_dir) { $visit_dir->($entry) } # Will call $callback
else { $callback->($entry) }
};
while (@queue) {
$visit_entry->( shift @queue );
}
}
sub children {
my ($self, %opts) = @_;
my $dh = $self->open or Carp::croak( "Can't open directory $self: $!" );
my @out;
while (defined(my $entry = $dh->read)) {
next if !$opts{all} && $self->_is_local_dot_dir($entry);
next if ($opts{no_hidden} && $entry =~ /^\./);
push @out, $self->file($entry);
$out[-1] = $self->subdir($entry) if -d $out[-1];
}
return @out;
}
sub _is_local_dot_dir {
my $self = shift;
my $dir = shift;
return ($dir eq $Updir or $dir eq $Curdir);
}
sub next {
my $self = shift;
unless ($self->{dh}) {
$self->{dh} = $self->open or Carp::croak( "Can't open directory $self: $!" );
}
my $next = $self->{dh}->read;
unless (defined $next) {
delete $self->{dh};
## no critic
return undef;
}
# Figure out whether it's a file or directory
my $file = $self->file($next);
$file = $self->subdir($next) if -d $file;
return $file;
}
sub subsumes {
Carp::croak "Too many arguments given to subsumes()" if $#_ > 2;
my ($self, $other) = @_;
Carp::croak( "No second entity given to subsumes()" ) unless defined $other;
$other = $self->new($other) unless eval{$other->isa( "Path::Class::Entity")};
$other = $other->dir unless $other->is_dir;
if ($self->is_absolute) {
$other = $other->absolute;
} elsif ($other->is_absolute) {
$self = $self->absolute;
}
$self = $self->cleanup;
$other = $other->cleanup;
if ($self->volume || $other->volume) {
return 0 unless $other->volume eq $self->volume;
}
# The root dir subsumes everything (but ignore the volume because
# we've already checked that)
return 1 if "@{$self->{dirs}}" eq "@{$self->new('')->{dirs}}";
# The current dir subsumes every relative path (unless starting with updir)
if ($self eq $self->_spec->curdir) {
return $other->{dirs}[0] ne $self->_spec->updir;
}
my $i = 0;
while ($i <= $#{ $self->{dirs} }) {
return 0 if $i > $#{ $other->{dirs} };
return 0 if $self->{dirs}[$i] ne $other->{dirs}[$i];
$i++;
}
return 1;
}
sub contains {
Carp::croak "Too many arguments given to contains()" if $#_ > 2;
my ($self, $other) = @_;
Carp::croak "No second entity given to contains()" unless defined $other;
return unless -d $self and (-e $other or -l $other);
# We're going to resolve the path, and don't want side effects on the objects
# so clone them. This also handles strings passed as $other.
$self= $self->new($self)->resolve;
$other= $self->new($other)->resolve;
return $self->subsumes($other);
}
sub tempfile {
my $self = shift;
return File::Temp::tempfile(@_, DIR => $self->stringify);
}
1;
__END__
=head1 NAME
Path::Class::Dir - Objects representing directories
=head1 VERSION
version 0.37
=head1 SYNOPSIS
use Path::Class; # Exports dir() by default
my $dir = dir('foo', 'bar'); # Path::Class::Dir object
my $dir = Path::Class::Dir->new('foo', 'bar'); # Same thing
# Stringifies to 'foo/bar' on Unix, 'foo\bar' on Windows, etc.
print "dir: $dir\n";
if ($dir->is_absolute) { ... }
if ($dir->is_relative) { ... }
my $v = $dir->volume; # Could be 'C:' on Windows, empty string
# on Unix, 'Macintosh HD:' on Mac OS
$dir->cleanup; # Perform logical cleanup of pathname
$dir->resolve; # Perform physical cleanup of pathname
my $file = $dir->file('file.txt'); # A file in this directory
my $subdir = $dir->subdir('george'); # A subdirectory
my $parent = $dir->parent; # The parent directory, 'foo'
my $abs = $dir->absolute; # Transform to absolute path
my $rel = $abs->relative; # Transform to relative path
my $rel = $abs->relative('/foo'); # Relative to /foo
print $dir->as_foreign('Mac'); # :foo:bar:
print $dir->as_foreign('Win32'); # foo\bar
# Iterate with IO::Dir methods:
my $handle = $dir->open;
while (my $file = $handle->read) {
$file = $dir->file($file); # Turn into Path::Class::File object
...
}
# Iterate with Path::Class methods:
while (my $file = $dir->next) {
# $file is a Path::Class::File or Path::Class::Dir object
...
}
=head1 DESCRIPTION
The C<Path::Class::Dir> class contains functionality for manipulating
directory names in a cross-platform way.
=head1 METHODS
=over 4
=item $dir = Path::Class::Dir->new( <dir1>, <dir2>, ... )
=item $dir = dir( <dir1>, <dir2>, ... )
Creates a new C<Path::Class::Dir> object and returns it. The
arguments specify names of directories which will be joined to create
a single directory object. A volume may also be specified as the
first argument, or as part of the first argument. You can use
platform-neutral syntax:
my $dir = dir( 'foo', 'bar', 'baz' );
or platform-native syntax:
my $dir = dir( 'foo/bar/baz' );
or a mixture of the two:
my $dir = dir( 'foo/bar', 'baz' );
All three of the above examples create relative paths. To create an
absolute path, either use the platform native syntax for doing so:
my $dir = dir( '/var/tmp' );
or use an empty string as the first argument:
my $dir = dir( '', 'var', 'tmp' );
If the second form seems awkward, that's somewhat intentional - paths
like C</var/tmp> or C<\Windows> aren't cross-platform concepts in the
first place (many non-Unix platforms don't have a notion of a "root
directory"), so they probably shouldn't appear in your code if you're
trying to be cross-platform. The first form is perfectly natural,
because paths like this may come from config files, user input, or
whatever.
As a special case, since it doesn't otherwise mean anything useful and
it's convenient to define this way, C<< Path::Class::Dir->new() >> (or
C<dir()>) refers to the current directory (C<< File::Spec->curdir >>).
To get the current directory as an absolute path, do C<<
dir()->absolute >>.
Finally, as another special case C<dir(undef)> will return undef,
since that's usually an accident on the part of the caller, and
returning the root directory would be a nasty surprise just asking for
trouble a few lines later.
=item $dir->stringify
This method is called internally when a C<Path::Class::Dir> object is
used in a string context, so the following are equivalent:
$string = $dir->stringify;
$string = "$dir";
=item $dir->volume
Returns the volume (e.g. C<C:> on Windows, C<Macintosh HD:> on Mac OS,
etc.) of the directory object, if any. Otherwise, returns the empty
string.
=item $dir->basename
Returns the last directory name of the path as a string.
=item $dir->is_dir
Returns a boolean value indicating whether this object represents a
directory. Not surprisingly, L<Path::Class::File> objects always
return false, and C<Path::Class::Dir> objects always return true.
=item $dir->is_absolute
Returns true or false depending on whether the directory refers to an
absolute path specifier (like C</usr/local> or C<\Windows>).
=item $dir->is_relative
Returns true or false depending on whether the directory refers to a
relative path specifier (like C<lib/foo> or C<./dir>).
=item $dir->cleanup
Performs a logical cleanup of the file path. For instance:
my $dir = dir('/foo//baz/./foo')->cleanup;
# $dir now represents '/foo/baz/foo';
=item $dir->resolve
Performs a physical cleanup of the file path. For instance:
my $dir = dir('/foo//baz/../foo')->resolve;
# $dir now represents '/foo/foo', assuming no symlinks
This actually consults the filesystem to verify the validity of the
path.
=item $file = $dir->file( <dir1>, <dir2>, ..., <file> )
Returns a L<Path::Class::File> object representing an entry in C<$dir>
or one of its subdirectories. Internally, this just calls C<<
Path::Class::File->new( @_ ) >>.
=item $subdir = $dir->subdir( <dir1>, <dir2>, ... )
Returns a new C<Path::Class::Dir> object representing a subdirectory
of C<$dir>.
=item $parent = $dir->parent
Returns the parent directory of C<$dir>. Note that this is the
I<logical> parent, not necessarily the physical parent. It really
means we just chop off entries from the end of the directory list
until we cain't chop no more. If the directory is relative, we start
using the relative forms of parent directories.
The following code demonstrates the behavior on absolute and relative
directories:
$dir = dir('/foo/bar');
for (1..6) {
print "Absolute: $dir\n";
$dir = $dir->parent;
}
$dir = dir('foo/bar');
for (1..6) {
print "Relative: $dir\n";
$dir = $dir->parent;
}
########### Output on Unix ################
Absolute: /foo/bar
Absolute: /foo
Absolute: /
Absolute: /
Absolute: /
Absolute: /
Relative: foo/bar
Relative: foo
Relative: .
Relative: ..
Relative: ../..
Relative: ../../..
=item @list = $dir->children
Returns a list of L<Path::Class::File> and/or C<Path::Class::Dir>
objects listed in this directory, or in scalar context the number of
such objects. Obviously, it is necessary for C<$dir> to
exist and be readable in order to find its children.
Note that the children are returned as subdirectories of C<$dir>,
i.e. the children of F<foo> will be F<foo/bar> and F<foo/baz>, not
F<bar> and F<baz>.
Ordinarily C<children()> will not include the I<self> and I<parent>
entries C<.> and C<..> (or their equivalents on non-Unix systems),
because that's like I'm-my-own-grandpa business. If you do want all
directory entries including these special ones, pass a true value for
the C<all> parameter:
@c = $dir->children(); # Just the children
@c = $dir->children(all => 1); # All entries
In addition, there's a C<no_hidden> parameter that will exclude all
normally "hidden" entries - on Unix this means excluding all entries
that begin with a dot (C<.>):
@c = $dir->children(no_hidden => 1); # Just normally-visible entries
=item $abs = $dir->absolute
Returns a C<Path::Class::Dir> object representing C<$dir> as an
absolute path. An optional argument, given as either a string or a
C<Path::Class::Dir> object, specifies the directory to use as the base
of relativity - otherwise the current working directory will be used.
=item $rel = $dir->relative
Returns a C<Path::Class::Dir> object representing C<$dir> as a
relative path. An optional argument, given as either a string or a
C<Path::Class::Dir> object, specifies the directory to use as the base
of relativity - otherwise the current working directory will be used.
=item $boolean = $dir->subsumes($other)
Returns true if this directory spec subsumes the other spec, and false
otherwise. Think of "subsumes" as "contains", but we only look at the
I<specs>, not whether C<$dir> actually contains C<$other> on the
filesystem.
The C<$other> argument may be a C<Path::Class::Dir> object, a
L<Path::Class::File> object, or a string. In the latter case, we
assume it's a directory.
# Examples:
dir('foo/bar' )->subsumes(dir('foo/bar/baz')) # True
dir('/foo/bar')->subsumes(dir('/foo/bar/baz')) # True
dir('foo/..')->subsumes(dir('foo/../bar)) # True
dir('foo/bar' )->subsumes(dir('bar/baz')) # False
dir('/foo/bar')->subsumes(dir('foo/bar')) # False
dir('foo/..')->subsumes(dir('bar')) # False! Use C<contains> to resolve ".."
=item $boolean = $dir->contains($other)
Returns true if this directory actually contains C<$other> on the
filesystem. C<$other> doesn't have to be a direct child of C<$dir>,
it just has to be subsumed after both paths have been resolved.
=item $foreign = $dir->as_foreign($type)
Returns a C<Path::Class::Dir> object representing C<$dir> as it would
be specified on a system of type C<$type>. Known types include
C<Unix>, C<Win32>, C<Mac>, C<VMS>, and C<OS2>, i.e. anything for which
there is a subclass of C<File::Spec>.
Any generated objects (subdirectories, files, parents, etc.) will also
retain this type.
=item $foreign = Path::Class::Dir->new_foreign($type, @args)
Returns a C<Path::Class::Dir> object representing C<$dir> as it would
be specified on a system of type C<$type>. Known types include
C<Unix>, C<Win32>, C<Mac>, C<VMS>, and C<OS2>, i.e. anything for which
there is a subclass of C<File::Spec>.
The arguments in C<@args> are the same as they would be specified in
C<new()>.
=item @list = $dir->dir_list([OFFSET, [LENGTH]])
Returns the list of strings internally representing this directory
structure. Each successive member of the list is understood to be an
entry in its predecessor's directory list. By contract, C<<
Path::Class->new( $dir->dir_list ) >> should be equivalent to C<$dir>.
The semantics of this method are similar to Perl's C<splice> or
C<substr> functions; they return C<LENGTH> elements starting at
C<OFFSET>. If C<LENGTH> is omitted, returns all the elements starting
at C<OFFSET> up to the end of the list. If C<LENGTH> is negative,
returns the elements from C<OFFSET> onward except for C<-LENGTH>
elements at the end. If C<OFFSET> is negative, it counts backward
C<OFFSET> elements from the end of the list. If C<OFFSET> and
C<LENGTH> are both omitted, the entire list is returned.
In a scalar context, C<dir_list()> with no arguments returns the
number of entries in the directory list; C<dir_list(OFFSET)> returns
the single element at that offset; C<dir_list(OFFSET, LENGTH)> returns
the final element that would have been returned in a list context.
=item $dir->components
Identical to C<dir_list()>. It exists because there's an analogous
method C<dir_list()> in the C<Path::Class::File> class that also
returns the basename string, so this method lets someone call
C<components()> without caring whether the object is a file or a
directory.
=item $fh = $dir->open()
Passes C<$dir> to C<< IO::Dir->open >> and returns the result as an
L<IO::Dir> object. If the opening fails, C<undef> is returned and
C<$!> is set.
=item $dir->mkpath($verbose, $mode)
Passes all arguments, including C<$dir>, to C<< File::Path::mkpath()
>> and returns the result (a list of all directories created).
=item $dir->rmtree($verbose, $cautious)
Passes all arguments, including C<$dir>, to C<< File::Path::rmtree()
>> and returns the result (the number of files successfully deleted).
=item $dir->remove()
Removes the directory, which must be empty. Returns a boolean value
indicating whether or not the directory was successfully removed.
This method is mainly provided for consistency with
C<Path::Class::File>'s C<remove()> method.
=item $dir->tempfile(...)
An interface to L<File::Temp>'s C<tempfile()> function. Just like
that function, if you call this in a scalar context, the return value
is the filehandle and the file is C<unlink>ed as soon as possible
(which is immediately on Unix-like platforms). If called in a list
context, the return values are the filehandle and the filename.
The given directory is passed as the C<DIR> parameter.
Here's an example of pretty good usage which doesn't allow race
conditions, won't leave yucky tempfiles around on your filesystem,
etc.:
my $fh = $dir->tempfile;
print $fh "Here's some data...\n";
seek($fh, 0, 0);
while (<$fh>) { do something... }
Or in combination with a C<fork>:
my $fh = $dir->tempfile;
print $fh "Here's some more data...\n";
seek($fh, 0, 0);
if ($pid=fork()) {
wait;
} else {
something($_) while <$fh>;
}
=item $dir_or_file = $dir->next()
A convenient way to iterate through directory contents. The first
time C<next()> is called, it will C<open()> the directory and read the
first item from it, returning the result as a C<Path::Class::Dir> or
L<Path::Class::File> object (depending, of course, on its actual
type). Each subsequent call to C<next()> will simply iterate over the
directory's contents, until there are no more items in the directory,
and then the undefined value is returned. For example, to iterate
over all the regular files in a directory:
while (my $file = $dir->next) {
next unless -f $file;
my $fh = $file->open('r') or die "Can't read $file: $!";
...
}
If an error occurs when opening the directory (for instance, it
doesn't exist or isn't readable), C<next()> will throw an exception
with the value of C<$!>.
=item $dir->traverse( sub { ... }, @args )
Calls the given callback for the root, passing it a continuation
function which, when called, will call this recursively on each of its
children. The callback function should be of the form:
sub {
my ($child, $cont, @args) = @_;
# ...
}
For instance, to calculate the number of files in a directory, you
can do this:
my $nfiles = $dir->traverse(sub {
my ($child, $cont) = @_;
return sum($cont->(), ($child->is_dir ? 0 : 1));
});
or to calculate the maximum depth of a directory:
my $depth = $dir->traverse(sub {
my ($child, $cont, $depth) = @_;
return max($cont->($depth + 1), $depth);
}, 0);
You can also choose not to call the callback in certain situations:
$dir->traverse(sub {
my ($child, $cont) = @_;
return if -l $child; # don't follow symlinks
# do something with $child
return $cont->();
});
=item $dir->traverse_if( sub { ... }, sub { ... }, @args )
traverse with additional "should I visit this child" callback.
Particularly useful in case examined tree contains inaccessible
directories.
Canonical example:
$dir->traverse_if(
sub {
my ($child, $cont) = @_;
# do something with $child
return $cont->();
},
sub {
my ($child) = @_;
# Process only readable items
return -r $child;
});
Second callback gets single parameter: child. Only children for
which it returns true will be processed by the first callback.
Remaining parameters are interpreted as in traverse, in particular
C<traverse_if(callback, sub { 1 }, @args> is equivalent to
C<traverse(callback, @args)>.
=item $dir->recurse( callback => sub {...} )
Iterates through this directory and all of its children, and all of
its children's children, etc., calling the C<callback> subroutine for
each entry. This is a lot like what the L<File::Find> module does,
and of course C<File::Find> will work fine on L<Path::Class> objects,
but the advantage of the C<recurse()> method is that it will also feed
your callback routine C<Path::Class> objects rather than just pathname
strings.
The C<recurse()> method requires a C<callback> parameter specifying
the subroutine to invoke for each entry. It will be passed the
C<Path::Class> object as its first argument.
C<recurse()> also accepts two boolean parameters, C<depthfirst> and
C<preorder> that control the order of recursion. The default is a
preorder, breadth-first search, i.e. C<< depthfirst => 0, preorder => 1 >>.
At the time of this writing, all combinations of these two parameters
are supported I<except> C<< depthfirst => 0, preorder => 0 >>.
C<callback> is normally not required to return any value. If it
returns special constant C<Path::Class::Entity::PRUNE()> (more easily
available as C<< $item->PRUNE >>), no children of analyzed
item will be analyzed (mostly as if you set C<$File::Find::prune=1>). Of course
pruning is available only in C<preorder>, in postorder return value
has no effect.
=item $st = $file->stat()
Invokes C<< File::stat::stat() >> on this directory and returns a
C<File::stat> object representing the result.
=item $st = $file->lstat()
Same as C<stat()>, but if C<$file> is a symbolic link, C<lstat()>
stats the link instead of the directory the link points to.
=item $class = $file->file_class()
Returns the class which should be used to create file objects.
Generally overridden whenever this class is subclassed.
=back
=head1 AUTHOR
Ken Williams, kwilliams@cpan.org
=head1 SEE ALSO
L<Path::Class>, L<Path::Class::File>, L<File::Spec>
=cut
PK 1N%[6��� � perl5/Path/Tiny.pmnu ��6�$ use 5.008001;
use strict;
use warnings;
package Path::Tiny;
# ABSTRACT: File path utility
our $VERSION = '0.148';
# Dependencies
use Config;
use Exporter 5.57 (qw/import/);
use File::Spec 0.86 (); # shipped with 5.8.1
use Carp ();
our @EXPORT = qw/path/;
our @EXPORT_OK = qw/cwd rootdir tempfile tempdir/;
use constant {
PATH => 0,
CANON => 1,
VOL => 2,
DIR => 3,
FILE => 4,
TEMP => 5,
IS_WIN32 => ( $^O eq 'MSWin32' ),
};
use overload (
q{""} => 'stringify',
bool => sub () { 1 },
fallback => 1,
);
# FREEZE/THAW per Sereal/CBOR/Types::Serialiser protocol
sub THAW { return path( $_[2] ) }
{ no warnings 'once'; *TO_JSON = *FREEZE = \&stringify };
my $HAS_UU; # has Unicode::UTF8; lazily populated
sub _check_UU {
local $SIG{__DIE__}; # prevent outer handler from being called
!!eval {
require Unicode::UTF8;
Unicode::UTF8->VERSION(0.58);
1;
};
}
my $HAS_PU; # has PerlIO::utf8_strict; lazily populated
sub _check_PU {
local $SIG{__DIE__}; # prevent outer handler from being called
!!eval {
# MUST preload Encode or $SIG{__DIE__} localization fails
# on some Perl 5.8.8 (maybe other 5.8.*) compiled with -O2.
require Encode;
require PerlIO::utf8_strict;
PerlIO::utf8_strict->VERSION(0.003);
1;
};
}
my $HAS_FLOCK = $Config{d_flock} || $Config{d_fcntl_can_lock} || $Config{d_lockf};
# notions of "root" directories differ on Win32: \\server\dir\ or C:\ or \
my $SLASH = qr{[\\/]};
my $NOTSLASH = qr{[^\\/]};
my $DRV_VOL = qr{[a-z]:}i;
my $UNC_VOL = qr{$SLASH $SLASH $NOTSLASH+ $SLASH $NOTSLASH+}x;
my $WIN32_ROOT = qr{(?: $UNC_VOL $SLASH | $DRV_VOL $SLASH | $SLASH )}x;
sub _win32_vol {
my ( $path, $drv ) = @_;
require Cwd;
my $dcwd = eval { Cwd::getdcwd($drv) }; # C: -> C:\some\cwd
# getdcwd on non-existent drive returns empty string
# so just use the original drive Z: -> Z:
$dcwd = "$drv" unless defined $dcwd && length $dcwd;
# normalize dwcd to end with a slash: might be C:\some\cwd or D:\ or Z:
$dcwd =~ s{$SLASH?\z}{/};
# make the path absolute with dcwd
$path =~ s{^$DRV_VOL}{$dcwd};
return $path;
}
# This is a string test for before we have the object; see is_rootdir for well-formed
# object test
sub _is_root {
return IS_WIN32() ? ( $_[0] =~ /^$WIN32_ROOT\z/ ) : ( $_[0] eq '/' );
}
BEGIN {
*_same = IS_WIN32() ? sub { lc( $_[0] ) eq lc( $_[1] ) } : sub { $_[0] eq $_[1] };
}
# mode bits encoded for chmod in symbolic mode
my %MODEBITS = ( om => 0007, gm => 0070, um => 0700 ); ## no critic
{ my $m = 0; $MODEBITS{$_} = ( 1 << $m++ ) for qw/ox ow or gx gw gr ux uw ur/ };
sub _symbolic_chmod {
my ( $mode, $symbolic ) = @_;
for my $clause ( split /,\s*/, $symbolic ) {
if ( $clause =~ m{\A([augo]+)([=+-])([rwx]+)\z} ) {
my ( $who, $action, $perms ) = ( $1, $2, $3 );
$who =~ s/a/ugo/g;
for my $w ( split //, $who ) {
my $p = 0;
$p |= $MODEBITS{"$w$_"} for split //, $perms;
if ( $action eq '=' ) {
$mode = ( $mode & ~$MODEBITS{"${w}m"} ) | $p;
}
else {
$mode = $action eq "+" ? ( $mode | $p ) : ( $mode & ~$p );
}
}
}
else {
Carp::croak("Invalid mode clause '$clause' for chmod()");
}
}
return $mode;
}
# flock doesn't work on NFS on BSD or on some filesystems like lustre.
# Since program authors often can't control or detect that, we warn once
# instead of being fatal if we can detect it and people who need it strict
# can fatalize the 'flock' category
#<<< No perltidy
{ package flock; use warnings::register }
#>>>
my $WARNED_NO_FLOCK = 0;
sub _throw {
my ( $self, $function, $file, $msg ) = @_;
if ( $function =~ /^flock/
&& $! =~ /operation not supported|function not implemented/i
&& !warnings::fatal_enabled('flock') )
{
if ( !$WARNED_NO_FLOCK ) {
warnings::warn( flock => "Flock not available: '$!': continuing in unsafe mode" );
$WARNED_NO_FLOCK++;
}
}
else {
$msg = $! unless defined $msg;
Path::Tiny::Error->throw( $function, ( defined $file ? $file : $self->[PATH] ),
$msg );
}
return;
}
# cheapo option validation
sub _get_args {
my ( $raw, @valid ) = @_;
if ( defined($raw) && ref($raw) ne 'HASH' ) {
my ( undef, undef, undef, $called_as ) = caller(1);
$called_as =~ s{^.*::}{};
Carp::croak("Options for $called_as must be a hash reference");
}
my $cooked = {};
for my $k (@valid) {
$cooked->{$k} = delete $raw->{$k} if exists $raw->{$k};
}
if ( keys %$raw ) {
my ( undef, undef, undef, $called_as ) = caller(1);
$called_as =~ s{^.*::}{};
Carp::croak( "Invalid option(s) for $called_as: " . join( ", ", keys %$raw ) );
}
return $cooked;
}
#--------------------------------------------------------------------------#
# Constructors
#--------------------------------------------------------------------------#
#pod =construct path
#pod
#pod $path = path("foo/bar");
#pod $path = path("/tmp", "file.txt"); # list
#pod $path = path("."); # cwd
#pod
#pod Constructs a C<Path::Tiny> object. It doesn't matter if you give a file or
#pod directory path. It's still up to you to call directory-like methods only on
#pod directories and file-like methods only on files. This function is exported
#pod automatically by default.
#pod
#pod The first argument must be defined and have non-zero length or an exception
#pod will be thrown. This prevents subtle, dangerous errors with code like
#pod C<< path( maybe_undef() )->remove_tree >>.
#pod
#pod B<DEPRECATED>: If and only if the B<first> character of the B<first> argument
#pod to C<path> is a tilde ('~'), then tilde replacement will be applied to the
#pod first path segment. A single tilde will be replaced with C<glob('~')> and a
#pod tilde followed by a username will be replaced with output of
#pod C<glob('~username')>. B<No other method does tilde expansion on its arguments>.
#pod See L</Tilde expansion (deprecated)> for more.
#pod
#pod On Windows, if the path consists of a drive identifier without a path component
#pod (C<C:> or C<D:>), it will be expanded to the absolute path of the current
#pod directory on that volume using C<Cwd::getdcwd()>.
#pod
#pod If called with a single C<Path::Tiny> argument, the original is returned unless
#pod the original is holding a temporary file or directory reference in which case a
#pod stringified copy is made.
#pod
#pod $path = path("foo/bar");
#pod $temp = Path::Tiny->tempfile;
#pod
#pod $p2 = path($path); # like $p2 = $path
#pod $t2 = path($temp); # like $t2 = path( "$temp" )
#pod
#pod This optimizes copies without proliferating references unexpectedly if a copy is
#pod made by code outside your control.
#pod
#pod Current API available since 0.017.
#pod
#pod =cut
sub path {
my $path = shift;
Carp::croak("Path::Tiny paths require defined, positive-length parts")
unless 1 + @_ == grep { defined && length } $path, @_;
# non-temp Path::Tiny objects are effectively immutable and can be reused
if ( !@_ && ref($path) eq __PACKAGE__ && !$path->[TEMP] ) {
return $path;
}
# stringify objects
$path = "$path";
# do any tilde expansions
my ($tilde) = $path =~ m{^(~[^/]*)};
if ( defined $tilde ) {
# Escape File::Glob metacharacters
(my $escaped = $tilde) =~ s/([\[\{\*\?\\])/\\$1/g;
require File::Glob;
my ($homedir) = File::Glob::bsd_glob($escaped);
if (defined $homedir && ! $File::Glob::ERROR) {
$homedir =~ tr[\\][/] if IS_WIN32();
$path =~ s{^\Q$tilde\E}{$homedir};
}
}
unshift @_, $path;
goto &_pathify;
}
# _path is like path but without tilde expansion
sub _path {
my $path = shift;
Carp::croak("Path::Tiny paths require defined, positive-length parts")
unless 1 + @_ == grep { defined && length } $path, @_;
# non-temp Path::Tiny objects are effectively immutable and can be reused
if ( !@_ && ref($path) eq __PACKAGE__ && !$path->[TEMP] ) {
return $path;
}
# stringify objects
$path = "$path";
unshift @_, $path;
goto &_pathify;
}
# _pathify expects one or more string arguments, then joins and canonicalizes
# them into an object.
sub _pathify {
my $path = shift;
# expand relative volume paths on windows; put trailing slash on UNC root
if ( IS_WIN32() ) {
$path = _win32_vol( $path, $1 ) if $path =~ m{^($DRV_VOL)(?:$NOTSLASH|\z)};
$path .= "/" if $path =~ m{^$UNC_VOL\z};
}
# concatenations stringifies objects, too
if (@_) {
$path .= ( _is_root($path) ? "" : "/" ) . join( "/", @_ );
}
# canonicalize, but with unix slashes and put back trailing volume slash
my $cpath = $path = File::Spec->canonpath($path);
$path =~ tr[\\][/] if IS_WIN32();
$path = "/" if $path eq '/..'; # for old File::Spec
$path .= "/" if IS_WIN32() && $path =~ m{^$UNC_VOL\z};
# root paths must always have a trailing slash, but other paths must not
if ( _is_root($path) ) {
$path =~ s{/?\z}{/};
}
else {
$path =~ s{/\z}{};
}
bless [ $path, $cpath ], __PACKAGE__;
}
#pod =construct new
#pod
#pod $path = Path::Tiny->new("foo/bar");
#pod
#pod This is just like C<path>, but with method call overhead. (Why would you
#pod do that?)
#pod
#pod Current API available since 0.001.
#pod
#pod =cut
sub new { shift; path(@_) }
#pod =construct cwd
#pod
#pod $path = Path::Tiny->cwd; # path( Cwd::getcwd )
#pod $path = cwd; # optional export
#pod
#pod Gives you the absolute path to the current directory as a C<Path::Tiny> object.
#pod This is slightly faster than C<< path(".")->absolute >>.
#pod
#pod C<cwd> may be exported on request and used as a function instead of as a
#pod method.
#pod
#pod Current API available since 0.018.
#pod
#pod =cut
sub cwd {
require Cwd;
return _path( Cwd::getcwd() );
}
#pod =construct rootdir
#pod
#pod $path = Path::Tiny->rootdir; # /
#pod $path = rootdir; # optional export
#pod
#pod Gives you C<< File::Spec->rootdir >> as a C<Path::Tiny> object if you're too
#pod picky for C<path("/")>.
#pod
#pod C<rootdir> may be exported on request and used as a function instead of as a
#pod method.
#pod
#pod Current API available since 0.018.
#pod
#pod =cut
sub rootdir { _path( File::Spec->rootdir ) }
#pod =construct tempfile, tempdir
#pod
#pod $temp = Path::Tiny->tempfile( @options );
#pod $temp = Path::Tiny->tempdir( @options );
#pod $temp = $dirpath->tempfile( @options );
#pod $temp = $dirpath->tempdir( @options );
#pod $temp = tempfile( @options ); # optional export
#pod $temp = tempdir( @options ); # optional export
#pod
#pod C<tempfile> passes the options to C<< File::Temp->new >> and returns a
#pod C<Path::Tiny> object with the file name. The C<TMPDIR> option will be enabled
#pod by default, but you can override that by passing C<< TMPDIR => 0 >> along with
#pod the options. (If you use an absolute C<TEMPLATE> option, you will want to
#pod disable C<TMPDIR>.)
#pod
#pod The resulting C<File::Temp> object is cached. When the C<Path::Tiny> object is
#pod destroyed, the C<File::Temp> object will be as well.
#pod
#pod C<File::Temp> annoyingly requires you to specify a custom template in slightly
#pod different ways depending on which function or method you call, but
#pod C<Path::Tiny> lets you ignore that and can take either a leading template or a
#pod C<TEMPLATE> option and does the right thing.
#pod
#pod $temp = Path::Tiny->tempfile( "customXXXXXXXX" ); # ok
#pod $temp = Path::Tiny->tempfile( TEMPLATE => "customXXXXXXXX" ); # ok
#pod
#pod The tempfile path object will be normalized to have an absolute path, even if
#pod created in a relative directory using C<DIR>. If you want it to have
#pod the C<realpath> instead, pass a leading options hash like this:
#pod
#pod $real_temp = tempfile({realpath => 1}, @options);
#pod
#pod C<tempdir> is just like C<tempfile>, except it calls
#pod C<< File::Temp->newdir >> instead.
#pod
#pod Both C<tempfile> and C<tempdir> may be exported on request and used as
#pod functions instead of as methods.
#pod
#pod The methods can be called on an instances representing a
#pod directory. In this case, the directory is used as the base to create the
#pod temporary file/directory, setting the C<DIR> option in File::Temp.
#pod
#pod my $target_dir = path('/to/destination');
#pod my $tempfile = $target_dir->tempfile('foobarXXXXXX');
#pod $tempfile->spew('A lot of data...'); # not atomic
#pod $tempfile->move($target_dir->child('foobar')); # hopefully atomic
#pod
#pod In this case, any value set for option C<DIR> is ignored.
#pod
#pod B<Note>: for tempfiles, the filehandles from File::Temp are closed and not
#pod reused. This is not as secure as using File::Temp handles directly, but is
#pod less prone to deadlocks or access problems on some platforms. Think of what
#pod C<Path::Tiny> gives you to be just a temporary file B<name> that gets cleaned
#pod up.
#pod
#pod B<Note 2>: if you don't want these cleaned up automatically when the object
#pod is destroyed, File::Temp requires different options for directories and
#pod files. Use C<< CLEANUP => 0 >> for directories and C<< UNLINK => 0 >> for
#pod files.
#pod
#pod B<Note 3>: Don't lose the temporary object by chaining a method call instead
#pod of storing it:
#pod
#pod my $lost = tempdir()->child("foo"); # tempdir cleaned up right away
#pod
#pod B<Note 4>: The cached object may be accessed with the L</cached_temp> method.
#pod Keeping a reference to, or modifying the cached object may break the
#pod behavior documented above and is not supported. Use at your own risk.
#pod
#pod Current API available since 0.119.
#pod
#pod =cut
sub tempfile {
my ( $opts, $maybe_template, $args )
= _parse_file_temp_args(tempfile => @_);
# File::Temp->new demands TEMPLATE
$args->{TEMPLATE} = $maybe_template->[0] if @$maybe_template;
require File::Temp;
my $temp = File::Temp->new( TMPDIR => 1, %$args );
close $temp;
my $self = $opts->{realpath} ? _path($temp)->realpath : _path($temp)->absolute;
$self->[TEMP] = $temp; # keep object alive while we are
return $self;
}
sub tempdir {
my ( $opts, $maybe_template, $args )
= _parse_file_temp_args(tempdir => @_);
require File::Temp;
my $temp = File::Temp->newdir( @$maybe_template, TMPDIR => 1, %$args );
my $self = $opts->{realpath} ? _path($temp)->realpath : _path($temp)->absolute;
$self->[TEMP] = $temp; # keep object alive while we are
# Some ActiveState Perls for Windows break Cwd in ways that lead
# File::Temp to get confused about what path to remove; this
# monkey-patches the object with our own view of the absolute path
$temp->{REALNAME} = $self->[CANON] if IS_WIN32;
return $self;
}
# normalize the various ways File::Temp does templates
sub _parse_file_temp_args {
my $called_as = shift;
if ( @_ && $_[0] eq 'Path::Tiny' ) { shift } # class method
elsif ( @_ && eval{$_[0]->isa('Path::Tiny')} ) {
my $dir = shift;
if (! $dir->is_dir) {
$dir->_throw( $called_as, $dir, "is not a directory object" );
}
push @_, DIR => $dir->stringify; # no overriding
}
my $opts = ( @_ && ref $_[0] eq 'HASH' ) ? shift @_ : {};
$opts = _get_args( $opts, qw/realpath/ );
my $leading_template = ( scalar(@_) % 2 == 1 ? shift(@_) : '' );
my %args = @_;
%args = map { uc($_), $args{$_} } keys %args;
my @template = (
exists $args{TEMPLATE} ? delete $args{TEMPLATE}
: $leading_template ? $leading_template
: ()
);
return ( $opts, \@template, \%args );
}
#--------------------------------------------------------------------------#
# Private methods
#--------------------------------------------------------------------------#
sub _splitpath {
my ($self) = @_;
@{$self}[ VOL, DIR, FILE ] = File::Spec->splitpath( $self->[PATH] );
}
sub _resolve_symlinks {
my ($self) = @_;
my $new = $self;
my ( $count, %seen ) = 0;
while ( -l $new->[PATH] ) {
if ( $seen{ $new->[PATH] }++ ) {
$self->_throw( 'readlink', $self->[PATH], "symlink loop detected" );
}
if ( ++$count > 100 ) {
$self->_throw( 'readlink', $self->[PATH], "maximum symlink depth exceeded" );
}
my $resolved = readlink $new->[PATH];
$new->_throw( 'readlink', $new->[PATH] ) unless defined $resolved;
$resolved = _path($resolved);
$new = $resolved->is_absolute ? $resolved : $new->sibling($resolved);
}
return $new;
}
sub _replacement_path {
my ($self) = @_;
my $unique_suffix = $$ . int( rand( 2**31 ) );
my $temp = _path( $self . $unique_suffix );
# If filename with process+random suffix is too long, use a shorter
# version that doesn't preserve the basename.
if ( length $temp->basename > 255 ) {
$temp = $self->sibling( "temp" . $unique_suffix );
}
return $temp;
}
#--------------------------------------------------------------------------#
# Public methods
#--------------------------------------------------------------------------#
#pod =method absolute
#pod
#pod $abs = path("foo/bar")->absolute;
#pod $abs = path("foo/bar")->absolute("/tmp");
#pod
#pod Returns a new C<Path::Tiny> object with an absolute path (or itself if already
#pod absolute). If no argument is given, the current directory is used as the
#pod absolute base path. If an argument is given, it will be converted to an
#pod absolute path (if it is not already) and used as the absolute base path.
#pod
#pod This will not resolve upward directories ("foo/../bar") unless C<canonpath>
#pod in L<File::Spec> would normally do so on your platform. If you need them
#pod resolved, you must call the more expensive C<realpath> method instead.
#pod
#pod On Windows, an absolute path without a volume component will have it added
#pod based on the current drive.
#pod
#pod Current API available since 0.101.
#pod
#pod =cut
sub absolute {
my ( $self, $base ) = @_;
# absolute paths handled differently by OS
if (IS_WIN32) {
return $self if length $self->volume;
# add missing volume
if ( $self->is_absolute ) {
require Cwd;
# use Win32::GetCwd not Cwd::getdcwd because we're sure
# to have the former but not necessarily the latter
my ($drv) = Win32::GetCwd() =~ /^($DRV_VOL | $UNC_VOL)/x;
return _path( $drv . $self->[PATH] );
}
}
else {
return $self if $self->is_absolute;
}
# no base means use current directory as base
require Cwd;
return _path( Cwd::getcwd(), $_[0]->[PATH] ) unless defined $base;
# relative base should be made absolute; we check is_absolute rather
# than unconditionally make base absolute so that "/foo" doesn't become
# "C:/foo" on Windows.
$base = _path($base);
return _path( ( $base->is_absolute ? $base : $base->absolute ), $_[0]->[PATH] );
}
#pod =method append, append_raw, append_utf8
#pod
#pod path("foo.txt")->append(@data);
#pod path("foo.txt")->append(\@data);
#pod path("foo.txt")->append({binmode => ":raw"}, @data);
#pod path("foo.txt")->append_raw(@data);
#pod path("foo.txt")->append_utf8(@data);
#pod
#pod Appends data to a file. The file is locked with C<flock> prior to writing
#pod and closed afterwards. An optional hash reference may be used to pass
#pod options. Valid options are:
#pod
#pod =for :list
#pod * C<binmode>: passed to C<binmode()> on the handle used for writing.
#pod * C<truncate>: truncates the file after locking and before appending
#pod
#pod The C<truncate> option is a way to replace the contents of a file
#pod B<in place>, unlike L</spew> which writes to a temporary file and then
#pod replaces the original (if it exists).
#pod
#pod C<append_raw> is like C<append> with a C<binmode> of C<:unix> for a fast,
#pod unbuffered, raw write.
#pod
#pod C<append_utf8> is like C<append> with an unbuffered C<binmode>
#pod C<:unix:encoding(UTF-8)> (or C<:unix:utf8_strict> with
#pod L<PerlIO::utf8_strict>). If L<Unicode::UTF8> 0.58+ is installed, an
#pod unbuffered, raw append will be done instead on the data encoded with
#pod C<Unicode::UTF8>.
#pod
#pod Current API available since 0.060.
#pod
#pod =cut
sub append {
my ( $self, @data ) = @_;
my $args = ( @data && ref $data[0] eq 'HASH' ) ? shift @data : {};
$args = _get_args( $args, qw/binmode truncate/ );
my $binmode = $args->{binmode};
$binmode = ( ( caller(0) )[10] || {} )->{'open>'} unless defined $binmode;
my $mode = $args->{truncate} ? ">" : ">>";
my $fh = $self->filehandle( { locked => 1 }, $mode, $binmode );
print( {$fh} map { ref eq 'ARRAY' ? @$_ : $_ } @data ) or $self->_throw('print');
close $fh or $self->_throw('close');
}
sub append_raw {
my ( $self, @data ) = @_;
my $args = ( @data && ref $data[0] eq 'HASH' ) ? shift @data : {};
$args = _get_args( $args, qw/binmode truncate/ );
$args->{binmode} = ':unix';
append( $self, $args, @data );
}
sub append_utf8 {
my ( $self, @data ) = @_;
my $args = ( @data && ref $data[0] eq 'HASH' ) ? shift @data : {};
$args = _get_args( $args, qw/binmode truncate/ );
if ( defined($HAS_UU) ? $HAS_UU : ( $HAS_UU = _check_UU() ) ) {
$args->{binmode} = ":unix";
append( $self, $args, map { Unicode::UTF8::encode_utf8($_) } @data );
}
elsif ( defined($HAS_PU) ? $HAS_PU : ( $HAS_PU = _check_PU() ) ) {
$args->{binmode} = ":unix:utf8_strict";
append( $self, $args, @data );
}
else {
$args->{binmode} = ":unix:encoding(UTF-8)";
append( $self, $args, @data );
}
}
#pod =method assert
#pod
#pod $path = path("foo.txt")->assert( sub { $_->exists } );
#pod
#pod Returns the invocant after asserting that a code reference argument returns
#pod true. When the assertion code reference runs, it will have the invocant
#pod object in the C<$_> variable. If it returns false, an exception will be
#pod thrown. The assertion code reference may also throw its own exception.
#pod
#pod If no assertion is provided, the invocant is returned without error.
#pod
#pod Current API available since 0.062.
#pod
#pod =cut
sub assert {
my ( $self, $assertion ) = @_;
return $self unless $assertion;
if ( ref $assertion eq 'CODE' ) {
local $_ = $self;
$assertion->()
or Path::Tiny::Error->throw( "assert", $self->[PATH], "failed assertion" );
}
else {
Carp::croak("argument to assert must be a code reference argument");
}
return $self;
}
#pod =method basename
#pod
#pod $name = path("foo/bar.txt")->basename; # bar.txt
#pod $name = path("foo.txt")->basename('.txt'); # foo
#pod $name = path("foo.txt")->basename(qr/.txt/); # foo
#pod $name = path("foo.txt")->basename(@suffixes);
#pod
#pod Returns the file portion or last directory portion of a path.
#pod
#pod Given a list of suffixes as strings or regular expressions, any that match at
#pod the end of the file portion or last directory portion will be removed before
#pod the result is returned.
#pod
#pod Current API available since 0.054.
#pod
#pod =cut
sub basename {
my ( $self, @suffixes ) = @_;
$self->_splitpath unless defined $self->[FILE];
my $file = $self->[FILE];
for my $s (@suffixes) {
my $re = ref($s) eq 'Regexp' ? qr/$s\z/ : qr/\Q$s\E\z/;
last if $file =~ s/$re//;
}
return $file;
}
#pod =method canonpath
#pod
#pod $canonical = path("foo/bar")->canonpath; # foo\bar on Windows
#pod
#pod Returns a string with the canonical format of the path name for
#pod the platform. In particular, this means directory separators
#pod will be C<\> on Windows.
#pod
#pod Current API available since 0.001.
#pod
#pod =cut
sub canonpath { $_[0]->[CANON] }
#pod =method cached_temp
#pod
#pod Returns the cached C<File::Temp> or C<File::Temp::Dir> object if the
#pod C<Path::Tiny> object was created with C</tempfile> or C</tempdir>.
#pod If there is no such object, this method throws.
#pod
#pod B<WARNING>: Keeping a reference to, or modifying the cached object may
#pod break the behavior documented for temporary files and directories created
#pod with C<Path::Tiny> and is not supported. Use at your own risk.
#pod
#pod Current API available since 0.101.
#pod
#pod =cut
sub cached_temp {
my $self = shift;
$self->_throw( "cached_temp", $self, "has no cached File::Temp object" )
unless defined $self->[TEMP];
return $self->[TEMP];
}
#pod =method child
#pod
#pod $file = path("/tmp")->child("foo.txt"); # "/tmp/foo.txt"
#pod $file = path("/tmp")->child(@parts);
#pod
#pod Returns a new C<Path::Tiny> object relative to the original. Works
#pod like C<catfile> or C<catdir> from File::Spec, but without caring about
#pod file or directories.
#pod
#pod B<WARNING>: because the argument could contain C<..> or refer to symlinks,
#pod there is no guarantee that the new path refers to an actual descendent of
#pod the original. If this is important to you, transform parent and child with
#pod L</realpath> and check them with L</subsumes>.
#pod
#pod Current API available since 0.001.
#pod
#pod =cut
sub child {
my ( $self, @parts ) = @_;
return _path( $self->[PATH], @parts );
}
#pod =method children
#pod
#pod @paths = path("/tmp")->children;
#pod @paths = path("/tmp")->children( qr/\.txt\z/ );
#pod
#pod Returns a list of C<Path::Tiny> objects for all files and directories
#pod within a directory. Excludes "." and ".." automatically.
#pod
#pod If an optional C<qr//> argument is provided, it only returns objects for child
#pod names that match the given regular expression. Only the base name is used
#pod for matching:
#pod
#pod @paths = path("/tmp")->children( qr/^foo/ );
#pod # matches children like the glob foo*
#pod
#pod Current API available since 0.028.
#pod
#pod =cut
sub children {
my ( $self, $filter ) = @_;
my $dh;
opendir $dh, $self->[PATH] or $self->_throw('opendir');
my @children = readdir $dh;
closedir $dh or $self->_throw('closedir');
if ( not defined $filter ) {
@children = grep { $_ ne '.' && $_ ne '..' } @children;
}
elsif ( $filter && ref($filter) eq 'Regexp' ) {
@children = grep { $_ ne '.' && $_ ne '..' && $_ =~ $filter } @children;
}
else {
Carp::croak("Invalid argument '$filter' for children()");
}
return map { _path( $self->[PATH], $_ ) } @children;
}
#pod =method chmod
#pod
#pod path("foo.txt")->chmod(0777);
#pod path("foo.txt")->chmod("0755");
#pod path("foo.txt")->chmod("go-w");
#pod path("foo.txt")->chmod("a=r,u+wx");
#pod
#pod Sets file or directory permissions. The argument can be a numeric mode, a
#pod octal string beginning with a "0" or a limited subset of the symbolic mode use
#pod by F</bin/chmod>.
#pod
#pod The symbolic mode must be a comma-delimited list of mode clauses. Clauses must
#pod match C<< qr/\A([augo]+)([=+-])([rwx]+)\z/ >>, which defines "who", "op" and
#pod "perms" parameters for each clause. Unlike F</bin/chmod>, all three parameters
#pod are required for each clause, multiple ops are not allowed and permissions
#pod C<stugoX> are not supported. (See L<File::chmod> for more complex needs.)
#pod
#pod Current API available since 0.053.
#pod
#pod =cut
sub chmod {
my ( $self, $new_mode ) = @_;
my $mode;
if ( $new_mode =~ /\d/ ) {
$mode = ( $new_mode =~ /^0/ ? oct($new_mode) : $new_mode );
}
elsif ( $new_mode =~ /[=+-]/ ) {
$mode = _symbolic_chmod( $self->stat->mode & 07777, $new_mode ); ## no critic
}
else {
Carp::croak("Invalid mode argument '$new_mode' for chmod()");
}
CORE::chmod( $mode, $self->[PATH] ) or $self->_throw("chmod");
return 1;
}
#pod =method copy
#pod
#pod path("/tmp/foo.txt")->copy("/tmp/bar.txt");
#pod
#pod Copies the current path to the given destination using L<File::Copy>'s
#pod C<copy> function. Upon success, returns the C<Path::Tiny> object for the
#pod newly copied file.
#pod
#pod Current API available since 0.070.
#pod
#pod =cut
# XXX do recursively for directories?
sub copy {
my ( $self, $dest ) = @_;
require File::Copy;
File::Copy::copy( $self->[PATH], $dest )
or Carp::croak("copy failed for $self to $dest: $!");
return -d $dest ? _path( $dest, $self->basename ) : _path($dest);
}
#pod =method digest
#pod
#pod $obj = path("/tmp/foo.txt")->digest; # SHA-256
#pod $obj = path("/tmp/foo.txt")->digest("MD5"); # user-selected
#pod $obj = path("/tmp/foo.txt")->digest( { chunk_size => 1e6 }, "MD5" );
#pod
#pod Returns a hexadecimal digest for a file. An optional hash reference of options may
#pod be given. The only option is C<chunk_size>. If C<chunk_size> is given, that many
#pod bytes will be read at a time. If not provided, the entire file will be slurped
#pod into memory to compute the digest.
#pod
#pod Any subsequent arguments are passed to the constructor for L<Digest> to select
#pod an algorithm. If no arguments are given, the default is SHA-256.
#pod
#pod Current API available since 0.056.
#pod
#pod =cut
sub digest {
my ( $self, @opts ) = @_;
my $args = ( @opts && ref $opts[0] eq 'HASH' ) ? shift @opts : {};
$args = _get_args( $args, qw/chunk_size/ );
unshift @opts, 'SHA-256' unless @opts;
require Digest;
my $digest = Digest->new(@opts);
if ( $args->{chunk_size} ) {
my $fh = $self->filehandle( { locked => 1 }, "<", ":unix" );
my $buf;
while (!eof($fh)) {
my $rc = read $fh, $buf, $args->{chunk_size};
$self->_throw('read') unless defined $rc;
$digest->add($buf);
}
}
else {
$digest->add( $self->slurp_raw );
}
return $digest->hexdigest;
}
#pod =method dirname (deprecated)
#pod
#pod $name = path("/tmp/foo.txt")->dirname; # "/tmp/"
#pod
#pod Returns the directory portion you would get from calling
#pod C<< File::Spec->splitpath( $path->stringify ) >> or C<"."> for a path without a
#pod parent directory portion. Because L<File::Spec> is inconsistent, the result
#pod might or might not have a trailing slash. Because of this, this method is
#pod B<deprecated>.
#pod
#pod A better, more consistently approach is likely C<< $path->parent->stringify >>,
#pod which will not have a trailing slash except for a root directory.
#pod
#pod Deprecated in 0.056.
#pod
#pod =cut
sub dirname {
my ($self) = @_;
$self->_splitpath unless defined $self->[DIR];
return length $self->[DIR] ? $self->[DIR] : ".";
}
#pod =method edit, edit_raw, edit_utf8
#pod
#pod path("foo.txt")->edit( \&callback, $options );
#pod path("foo.txt")->edit_utf8( \&callback );
#pod path("foo.txt")->edit_raw( \&callback );
#pod
#pod These are convenience methods that allow "editing" a file using a single
#pod callback argument. They slurp the file using C<slurp>, place the contents
#pod inside a localized C<$_> variable, call the callback function (without
#pod arguments), and then write C<$_> (presumably mutated) back to the
#pod file with C<spew>.
#pod
#pod An optional hash reference may be used to pass options. The only option is
#pod C<binmode>, which is passed to C<slurp> and C<spew>.
#pod
#pod C<edit_utf8> and C<edit_raw> act like their respective C<slurp_*> and
#pod C<spew_*> methods.
#pod
#pod Current API available since 0.077.
#pod
#pod =cut
sub edit {
my $self = shift;
my $cb = shift;
my $args = _get_args( shift, qw/binmode/ );
Carp::croak("Callback for edit() must be a code reference")
unless defined($cb) && ref($cb) eq 'CODE';
local $_ =
$self->slurp( exists( $args->{binmode} ) ? { binmode => $args->{binmode} } : () );
$cb->();
$self->spew( $args, $_ );
return;
}
# this is done long-hand to benefit from slurp_utf8 optimizations
sub edit_utf8 {
my ( $self, $cb ) = @_;
Carp::croak("Callback for edit_utf8() must be a code reference")
unless defined($cb) && ref($cb) eq 'CODE';
local $_ = $self->slurp_utf8;
$cb->();
$self->spew_utf8($_);
return;
}
sub edit_raw { $_[2] = { binmode => ":unix" }; goto &edit }
#pod =method edit_lines, edit_lines_utf8, edit_lines_raw
#pod
#pod path("foo.txt")->edit_lines( \&callback, $options );
#pod path("foo.txt")->edit_lines_utf8( \&callback );
#pod path("foo.txt")->edit_lines_raw( \&callback );
#pod
#pod These are convenience methods that allow "editing" a file's lines using a
#pod single callback argument. They iterate over the file: for each line, the
#pod line is put into a localized C<$_> variable, the callback function is
#pod executed (without arguments) and then C<$_> is written to a temporary file.
#pod When iteration is finished, the temporary file is atomically renamed over
#pod the original.
#pod
#pod An optional hash reference may be used to pass options. The only option is
#pod C<binmode>, which is passed to the method that open handles for reading and
#pod writing.
#pod
#pod C<edit_lines_raw> is like C<edit_lines> with a buffered C<binmode> of
#pod C<:raw>.
#pod
#pod C<edit_lines_utf8> is like C<edit_lines> with a buffered C<binmode>
#pod C<:raw:encoding(UTF-8)> (or C<:raw:utf8_strict> with
#pod L<PerlIO::utf8_strict>).
#pod
#pod Current API available since 0.077.
#pod
#pod =cut
sub edit_lines {
my $self = shift;
my $cb = shift;
my $args = _get_args( shift, qw/binmode/ );
Carp::croak("Callback for edit_lines() must be a code reference")
unless defined($cb) && ref($cb) eq 'CODE';
my $binmode = $args->{binmode};
# get default binmode from caller's lexical scope (see "perldoc open")
$binmode = ( ( caller(0) )[10] || {} )->{'open>'} unless defined $binmode;
# writing needs to follow the link and create the tempfile in the same
# dir for later atomic rename
my $resolved_path = $self->_resolve_symlinks;
my $temp = $resolved_path->_replacement_path;
my $temp_fh = $temp->filehandle( { exclusive => 1, locked => 1 }, ">", $binmode );
my $in_fh = $self->filehandle( { locked => 1 }, '<', $binmode );
local $_;
while (! eof($in_fh) ) {
defined( $_ = readline($in_fh) ) or $self->_throw('readline');
$cb->();
$temp_fh->print($_) or $self->_throw('print', $temp);
}
close $temp_fh or $self->_throw( 'close', $temp );
close $in_fh or $self->_throw('close');
return $temp->move($resolved_path);
}
sub edit_lines_raw { $_[2] = { binmode => ":raw" }; goto &edit_lines }
sub edit_lines_utf8 {
if ( defined($HAS_PU) ? $HAS_PU : ( $HAS_PU = _check_PU() ) ) {
$_[2] = { binmode => ":raw:utf8_strict" };
}
else {
$_[2] = { binmode => ":raw:encoding(UTF-8)" };
}
goto &edit_lines;
}
#pod =method exists, is_file, is_dir
#pod
#pod if ( path("/tmp")->exists ) { ... } # -e
#pod if ( path("/tmp")->is_dir ) { ... } # -d
#pod if ( path("/tmp")->is_file ) { ... } # -e && ! -d
#pod
#pod Implements file test operations, this means the file or directory actually has
#pod to exist on the filesystem. Until then, it's just a path.
#pod
#pod B<Note>: C<is_file> is not C<-f> because C<-f> is not the opposite of C<-d>.
#pod C<-f> means "plain file", excluding symlinks, devices, etc. that often can be
#pod read just like files.
#pod
#pod Use C<-f> instead if you really mean to check for a plain file.
#pod
#pod Current API available since 0.053.
#pod
#pod =cut
sub exists { -e $_[0]->[PATH] }
sub is_file { -e $_[0]->[PATH] && !-d _ }
sub is_dir { -d $_[0]->[PATH] }
#pod =method filehandle
#pod
#pod $fh = path("/tmp/foo.txt")->filehandle($mode, $binmode);
#pod $fh = path("/tmp/foo.txt")->filehandle({ locked => 1 }, $mode, $binmode);
#pod $fh = path("/tmp/foo.txt")->filehandle({ exclusive => 1 }, $mode, $binmode);
#pod
#pod Returns an open file handle. The C<$mode> argument must be a Perl-style
#pod read/write mode string ("<" ,">", ">>", etc.). If a C<$binmode>
#pod is given, it is set during the C<open> call.
#pod
#pod An optional hash reference may be used to pass options.
#pod
#pod The C<locked> option governs file locking; if true, handles opened for writing,
#pod appending or read-write are locked with C<LOCK_EX>; otherwise, they are
#pod locked with C<LOCK_SH>. When using C<locked>, ">" or "+>" modes will delay
#pod truncation until after the lock is acquired.
#pod
#pod The C<exclusive> option causes the open() call to fail if the file already
#pod exists. This corresponds to the O_EXCL flag to sysopen / open(2).
#pod C<exclusive> implies C<locked> and will set it for you if you forget it.
#pod
#pod See C<openr>, C<openw>, C<openrw>, and C<opena> for sugar.
#pod
#pod Current API available since 0.066.
#pod
#pod =cut
# Note: must put binmode on open line, not subsequent binmode() call, so things
# like ":unix" actually stop perlio/crlf from being added
sub filehandle {
my ( $self, @args ) = @_;
my $args = ( @args && ref $args[0] eq 'HASH' ) ? shift @args : {};
$args = _get_args( $args, qw/locked exclusive/ );
$args->{locked} = 1 if $args->{exclusive};
my ( $opentype, $binmode ) = @args;
$opentype = "<" unless defined $opentype;
Carp::croak("Invalid file mode '$opentype'")
unless grep { $opentype eq $_ } qw/< +< > +> >> +>>/;
$binmode = ( ( caller(0) )[10] || {} )->{ 'open' . substr( $opentype, -1, 1 ) }
unless defined $binmode;
$binmode = "" unless defined $binmode;
my ( $fh, $lock, $trunc );
if ( $HAS_FLOCK && $args->{locked} && !$ENV{PERL_PATH_TINY_NO_FLOCK} ) {
require Fcntl;
# truncating file modes shouldn't truncate until lock acquired
if ( grep { $opentype eq $_ } qw( > +> ) ) {
# sysopen in write mode without truncation
my $flags = $opentype eq ">" ? Fcntl::O_WRONLY() : Fcntl::O_RDWR();
$flags |= Fcntl::O_CREAT();
$flags |= Fcntl::O_EXCL() if $args->{exclusive};
sysopen( $fh, $self->[PATH], $flags ) or $self->_throw("sysopen");
# fix up the binmode since sysopen() can't specify layers like
# open() and binmode() can't start with just :unix like open()
if ( $binmode =~ s/^:unix// ) {
# eliminate pseudo-layers
binmode( $fh, ":raw" ) or $self->_throw("binmode (:raw)");
# strip off real layers until only :unix is left
while ( 1 < ( my $layers =()= PerlIO::get_layers( $fh, output => 1 ) ) ) {
binmode( $fh, ":pop" ) or $self->_throw("binmode (:pop)");
}
}
# apply any remaining binmode layers
if ( length $binmode ) {
binmode( $fh, $binmode ) or $self->_throw("binmode ($binmode)");
}
# ask for lock and truncation
$lock = Fcntl::LOCK_EX();
$trunc = 1;
}
elsif ( $^O eq 'aix' && $opentype eq "<" ) {
# AIX can only lock write handles, so upgrade to RW and LOCK_EX if
# the file is writable; otherwise give up on locking. N.B.
# checking -w before open to determine the open mode is an
# unavoidable race condition
if ( -w $self->[PATH] ) {
$opentype = "+<";
$lock = Fcntl::LOCK_EX();
}
}
else {
$lock = $opentype eq "<" ? Fcntl::LOCK_SH() : Fcntl::LOCK_EX();
}
}
unless ($fh) {
my $mode = $opentype . $binmode;
open $fh, $mode, $self->[PATH] or $self->_throw("open ($mode)");
}
do { flock( $fh, $lock ) or $self->_throw("flock ($lock)") } if $lock;
do { truncate( $fh, 0 ) or $self->_throw("truncate") } if $trunc;
return $fh;
}
#pod =method has_same_bytes
#pod
#pod if ( path("foo.txt")->has_same_bytes("bar.txt") ) {
#pod # ...
#pod }
#pod
#pod This method returns true if both the invocant and the argument can be opened as
#pod file handles and the handles contain the same bytes. It returns false if their
#pod contents differ. If either can't be opened as a file (e.g. a directory or
#pod non-existent file), the method throws an exception. If both can be opened and
#pod both have the same C<realpath>, the method returns true without scanning any
#pod data.
#pod
#pod Current API available since 0.125.
#pod
#pod =cut
sub has_same_bytes {
my ($self, $other_path) = @_;
my $other = _path($other_path);
my $fh1 = $self->openr_raw({ locked => 1 });
my $fh2 = $other->openr_raw({ locked => 1 });
# check for directories
if (-d $fh1) {
$self->_throw('has_same_bytes', $self->[PATH], "directory not allowed");
}
if (-d $fh2) {
$self->_throw('has_same_bytes', $other->[PATH], "directory not allowed");
}
# Now that handles are open, we know the inputs are readable files that
# exist, so it's safe to compare via realpath
if ($self->realpath eq $other->realpath) {
return 1
}
# result is 0 for equal, 1 for unequal, -1 for error
require File::Compare;
my $res = File::Compare::compare($fh1, $fh2, 65536);
if ($res < 0) {
$self->_throw('has_same_bytes')
}
return $res == 0;
}
#pod =method is_absolute, is_relative
#pod
#pod if ( path("/tmp")->is_absolute ) { ... }
#pod if ( path("/tmp")->is_relative ) { ... }
#pod
#pod Booleans for whether the path appears absolute or relative.
#pod
#pod Current API available since 0.001.
#pod
#pod =cut
sub is_absolute { substr( $_[0]->dirname, 0, 1 ) eq '/' }
sub is_relative { substr( $_[0]->dirname, 0, 1 ) ne '/' }
#pod =method is_rootdir
#pod
#pod while ( ! $path->is_rootdir ) {
#pod $path = $path->parent;
#pod ...
#pod }
#pod
#pod Boolean for whether the path is the root directory of the volume. I.e. the
#pod C<dirname> is C<q[/]> and the C<basename> is C<q[]>.
#pod
#pod This works even on C<MSWin32> with drives and UNC volumes:
#pod
#pod path("C:/")->is_rootdir; # true
#pod path("//server/share/")->is_rootdir; #true
#pod
#pod Current API available since 0.038.
#pod
#pod =cut
sub is_rootdir {
my ($self) = @_;
$self->_splitpath unless defined $self->[DIR];
return $self->[DIR] eq '/' && $self->[FILE] eq '';
}
#pod =method iterator
#pod
#pod $iter = path("/tmp")->iterator( \%options );
#pod
#pod Returns a code reference that walks a directory lazily. Each invocation
#pod returns a C<Path::Tiny> object or undef when the iterator is exhausted.
#pod
#pod $iter = path("/tmp")->iterator;
#pod while ( $path = $iter->() ) {
#pod ...
#pod }
#pod
#pod The current and parent directory entries ("." and "..") will not
#pod be included.
#pod
#pod If the C<recurse> option is true, the iterator will walk the directory
#pod recursively, breadth-first. If the C<follow_symlinks> option is also true,
#pod directory links will be followed recursively. There is no protection against
#pod loops when following links. If a directory is not readable, it will not be
#pod followed.
#pod
#pod The default is the same as:
#pod
#pod $iter = path("/tmp")->iterator( {
#pod recurse => 0,
#pod follow_symlinks => 0,
#pod } );
#pod
#pod For a more powerful, recursive iterator with built-in loop avoidance, see
#pod L<Path::Iterator::Rule>.
#pod
#pod See also L</visit>.
#pod
#pod Current API available since 0.016.
#pod
#pod =cut
sub iterator {
my $self = shift;
my $args = _get_args( shift, qw/recurse follow_symlinks/ );
my @dirs = $self;
my $current;
return sub {
my $next;
while (@dirs) {
if ( ref $dirs[0] eq 'Path::Tiny' ) {
if ( !-r $dirs[0] ) {
# Directory is missing or not readable, so skip it. There
# is still a race condition possible between the check and
# the opendir, but we can't easily differentiate between
# error cases that are OK to skip and those that we want
# to be exceptions, so we live with the race and let opendir
# be fatal.
shift @dirs and next;
}
$current = $dirs[0];
my $dh;
opendir( $dh, $current->[PATH] )
or $self->_throw( 'opendir', $current->[PATH] );
$dirs[0] = $dh;
if ( -l $current->[PATH] && !$args->{follow_symlinks} ) {
# Symlink attack! It was a real dir, but is now a symlink!
# N.B. we check *after* opendir so the attacker has to win
# two races: replace dir with symlink before opendir and
# replace symlink with dir before -l check above
shift @dirs and next;
}
}
while ( defined( $next = readdir $dirs[0] ) ) {
next if $next eq '.' || $next eq '..';
my $path = $current->child($next);
push @dirs, $path
if $args->{recurse} && -d $path && !( !$args->{follow_symlinks} && -l $path );
return $path;
}
shift @dirs;
}
return;
};
}
#pod =method lines, lines_raw, lines_utf8
#pod
#pod @contents = path("/tmp/foo.txt")->lines;
#pod @contents = path("/tmp/foo.txt")->lines(\%options);
#pod @contents = path("/tmp/foo.txt")->lines_raw;
#pod @contents = path("/tmp/foo.txt")->lines_utf8;
#pod
#pod @contents = path("/tmp/foo.txt")->lines( { chomp => 1, count => 4 } );
#pod
#pod Returns a list of lines from a file. Optionally takes a hash-reference of
#pod options. Valid options are C<binmode>, C<count> and C<chomp>.
#pod
#pod If C<binmode> is provided, it will be set on the handle prior to reading.
#pod
#pod If a positive C<count> is provided, that many lines will be returned from the
#pod start of the file. If a negative C<count> is provided, the entire file will be
#pod read, but only C<abs(count)> will be kept and returned. If C<abs(count)>
#pod exceeds the number of lines in the file, all lines will be returned.
#pod
#pod If C<chomp> is set, any end-of-line character sequences (C<CR>, C<CRLF>, or
#pod C<LF>) will be removed from the lines returned.
#pod
#pod Because the return is a list, C<lines> in scalar context will return the number
#pod of lines (and throw away the data).
#pod
#pod $number_of_lines = path("/tmp/foo.txt")->lines;
#pod
#pod C<lines_raw> is like C<lines> with a C<binmode> of C<:raw>. We use C<:raw>
#pod instead of C<:unix> so PerlIO buffering can manage reading by line.
#pod
#pod C<lines_utf8> is like C<lines> with a C<binmode> of C<:raw:encoding(UTF-8)>
#pod (or C<:raw:utf8_strict> with L<PerlIO::utf8_strict>). If L<Unicode::UTF8>
#pod 0.58+ is installed, a raw, unbuffered UTF-8 slurp will be done and then the
#pod lines will be split. This is actually faster than relying on
#pod IO layers, though a bit memory intensive. If memory use is a
#pod concern, consider C<openr_utf8> and iterating directly on the handle.
#pod
#pod See also L</slurp> if you want to load a file as a whole chunk.
#pod
#pod Current API available since 0.065.
#pod
#pod =cut
sub lines {
my $self = shift;
my $args = _get_args( shift, qw/binmode chomp count/ );
my $binmode = $args->{binmode};
$binmode = ( ( caller(0) )[10] || {} )->{'open<'} unless defined $binmode;
my $fh = $self->filehandle( { locked => 1 }, "<", $binmode );
my $chomp = $args->{chomp};
# XXX more efficient to read @lines then chomp(@lines) vs map?
if ( $args->{count} ) {
my ( $counter, $mod, @result ) = ( 0, abs( $args->{count} ) );
my $line;
while ( !eof($fh) ) {
defined( $line = readline($fh) ) or $self->_throw('readline');
$line =~ s/(?:\x{0d}?\x{0a}|\x{0d})\z// if $chomp;
$result[ $counter++ ] = $line;
# for positive count, terminate after right number of lines
last if $counter == $args->{count};
# for negative count, eventually wrap around in the result array
$counter %= $mod;
}
# reorder results if full and wrapped somewhere in the middle
splice( @result, 0, 0, splice( @result, $counter ) )
if @result == $mod && $counter % $mod;
return @result;
}
elsif ($chomp) {
local $!;
my @lines = map { s/(?:\x{0d}?\x{0a}|\x{0d})\z//; $_ } <$fh>; ## no critic
$self->_throw('readline') if $!;
return @lines;
}
else {
if ( wantarray ) {
local $!;
my @lines = <$fh>;
$self->_throw('readline') if $!;
return @lines;
} else {
local $!;
my $count =()= <$fh>;
$self->_throw('readline') if $!;
return $count;
}
}
}
sub lines_raw {
my $self = shift;
my $args = _get_args( shift, qw/binmode chomp count/ );
if ( $args->{chomp} && !$args->{count} ) {
return split /\n/, slurp_raw($self); ## no critic
}
else {
$args->{binmode} = ":raw";
return lines( $self, $args );
}
}
my $CRLF = qr/(?:\x{0d}?\x{0a}|\x{0d})/;
sub lines_utf8 {
my $self = shift;
my $args = _get_args( shift, qw/binmode chomp count/ );
if ( ( defined($HAS_UU) ? $HAS_UU : ( $HAS_UU = _check_UU() ) )
&& $args->{chomp}
&& !$args->{count} )
{
my $slurp = slurp_utf8($self);
$slurp =~ s/$CRLF\z//; # like chomp, but full CR?LF|CR
return split $CRLF, $slurp, -1; ## no critic
}
elsif ( defined($HAS_PU) ? $HAS_PU : ( $HAS_PU = _check_PU() ) ) {
$args->{binmode} = ":raw:utf8_strict";
return lines( $self, $args );
}
else {
$args->{binmode} = ":raw:encoding(UTF-8)";
return lines( $self, $args );
}
}
#pod =method mkdir
#pod
#pod path("foo/bar/baz")->mkdir;
#pod path("foo/bar/baz")->mkdir( \%options );
#pod
#pod Like calling C<make_path> from L<File::Path>. An optional hash reference
#pod is passed through to C<make_path>. Errors will be trapped and an exception
#pod thrown. Returns the the path object to facilitate chaining.
#pod
#pod B<NOTE>: unlike Perl's builtin C<mkdir>, this will create intermediate paths
#pod similar to the Unix C<mkdir -p> command. It will not error if applied to an
#pod existing directory.
#pod
#pod Passing a defined argument I<other> than a hash reference is an error, and an
#pod exception will be thrown.
#pod
#pod Current API available since 0.125.
#pod
#pod =cut
sub mkdir {
my ( $self, $args, @rest ) = @_;
$args = {} unless defined $args;
if (@rest || (defined $args && ref $args ne 'HASH')) {
$self->_throw('mkdir', undef, "method argument was given, but was not a hash reference");
}
my $err;
$args->{error} = \$err unless defined $args->{error};
require File::Path;
my @dirs;
my $ok = eval {
File::Path::make_path( $self->[PATH], $args );
1;
};
if (!$ok) {
$self->_throw('mkdir', $self->[PATH], "error creating path: $@");
}
if ( $err && @$err ) {
my ( $file, $message ) = %{ $err->[0] };
$self->_throw('mkdir', $file, $message);
}
return $self;
}
#pod =method mkpath (deprecated)
#pod
#pod Like calling C<mkdir>, but returns the list of directories created or an empty list if
#pod the directories already exist, just like C<make_path>.
#pod
#pod Passing a defined argument I<other> than a hash reference is an error, and an
#pod exception will be thrown.
#pod
#pod Deprecated in 0.125.
#pod
#pod =cut
sub mkpath {
my ( $self, $args, @rest ) = @_;
$args = {} unless defined $args;
if (@rest || (defined $args && ref $args ne 'HASH')) {
$self->_throw('mkdir', undef, "method argument was given, but was not a hash reference");
}
my $err;
$args->{error} = \$err unless defined $args->{error};
require File::Path;
my @dirs = File::Path::make_path( $self->[PATH], $args );
if ( $err && @$err ) {
my ( $file, $message ) = %{ $err->[0] };
Carp::croak("mkpath failed for $file: $message");
}
return @dirs;
}
#pod =method move
#pod
#pod path("foo.txt")->move("bar.txt");
#pod
#pod Moves the current path to the given destination using L<File::Copy>'s
#pod C<move> function. Upon success, returns the C<Path::Tiny> object for the
#pod newly moved file.
#pod
#pod If the destination already exists and is a directory, and the source is not a
#pod directory, then the source file will be renamed into the directory
#pod specified by the destination.
#pod
#pod If possible, move() will simply rename the file. Otherwise, it
#pod copies the file to the new location and deletes the original. If an
#pod error occurs during this copy-and-delete process, you may be left
#pod with a (possibly partial) copy of the file under the destination
#pod name.
#pod
#pod Current API available since 0.124. Prior versions used Perl's
#pod -built-in (and less robust) L<rename|perlfunc/rename> function
#pod and did not return an object.
#pod
#pod =cut
sub move {
my ( $self, $dest ) = @_;
require File::Copy;
File::Copy::move( $self->[PATH], $dest )
or $self->_throw( 'move', $self->[PATH] . "' -> '$dest" );
return -d $dest ? _path( $dest, $self->basename ) : _path($dest);
}
#pod =method openr, openw, openrw, opena
#pod
#pod $fh = path("foo.txt")->openr($binmode); # read
#pod $fh = path("foo.txt")->openr_raw;
#pod $fh = path("foo.txt")->openr_utf8;
#pod
#pod $fh = path("foo.txt")->openw($binmode); # write
#pod $fh = path("foo.txt")->openw_raw;
#pod $fh = path("foo.txt")->openw_utf8;
#pod
#pod $fh = path("foo.txt")->opena($binmode); # append
#pod $fh = path("foo.txt")->opena_raw;
#pod $fh = path("foo.txt")->opena_utf8;
#pod
#pod $fh = path("foo.txt")->openrw($binmode); # read/write
#pod $fh = path("foo.txt")->openrw_raw;
#pod $fh = path("foo.txt")->openrw_utf8;
#pod
#pod Returns a file handle opened in the specified mode. The C<openr> style methods
#pod take a single C<binmode> argument. All of the C<open*> methods have
#pod C<open*_raw> and C<open*_utf8> equivalents that use buffered I/O layers C<:raw>
#pod and C<:raw:encoding(UTF-8)> (or C<:raw:utf8_strict> with
#pod L<PerlIO::utf8_strict>).
#pod
#pod An optional hash reference may be used to pass options. The only option is
#pod C<locked>. If true, handles opened for writing, appending or read-write are
#pod locked with C<LOCK_EX>; otherwise, they are locked for C<LOCK_SH>.
#pod
#pod $fh = path("foo.txt")->openrw_utf8( { locked => 1 } );
#pod
#pod See L</filehandle> for more on locking.
#pod
#pod Current API available since 0.011.
#pod
#pod =cut
# map method names to corresponding open mode
my %opens = (
opena => ">>",
openr => "<",
openw => ">",
openrw => "+<"
);
while ( my ( $k, $v ) = each %opens ) {
no strict 'refs';
# must check for lexical IO mode hint
*{$k} = sub {
my ( $self, @args ) = @_;
my $args = ( @args && ref $args[0] eq 'HASH' ) ? shift @args : {};
$args = _get_args( $args, qw/locked/ );
my ($binmode) = @args;
$binmode = ( ( caller(0) )[10] || {} )->{ 'open' . substr( $v, -1, 1 ) }
unless defined $binmode;
$self->filehandle( $args, $v, $binmode );
};
*{ $k . "_raw" } = sub {
my ( $self, @args ) = @_;
my $args = ( @args && ref $args[0] eq 'HASH' ) ? shift @args : {};
$args = _get_args( $args, qw/locked/ );
$self->filehandle( $args, $v, ":raw" );
};
*{ $k . "_utf8" } = sub {
my ( $self, @args ) = @_;
my $args = ( @args && ref $args[0] eq 'HASH' ) ? shift @args : {};
$args = _get_args( $args, qw/locked/ );
my $layer;
if ( defined($HAS_PU) ? $HAS_PU : ( $HAS_PU = _check_PU() ) ) {
$layer = ":raw:utf8_strict";
}
else {
$layer = ":raw:encoding(UTF-8)";
}
$self->filehandle( $args, $v, $layer );
};
}
#pod =method parent
#pod
#pod $parent = path("foo/bar/baz")->parent; # foo/bar
#pod $parent = path("foo/wibble.txt")->parent; # foo
#pod
#pod $parent = path("foo/bar/baz")->parent(2); # foo
#pod
#pod Returns a C<Path::Tiny> object corresponding to the parent directory of the
#pod original directory or file. An optional positive integer argument is the number
#pod of parent directories upwards to return. C<parent> by itself is equivalent to
#pod C<parent(1)>.
#pod
#pod Current API available since 0.014.
#pod
#pod =cut
# XXX this is ugly and coverage is incomplete. I think it's there for windows
# so need to check coverage there and compare
sub parent {
my ( $self, $level ) = @_;
$level = 1 unless defined $level && $level > 0;
$self->_splitpath unless defined $self->[FILE];
my $parent;
if ( length $self->[FILE] ) {
if ( $self->[FILE] eq '.' || $self->[FILE] eq ".." ) {
$parent = _path( $self->[PATH] . "/.." );
}
else {
$parent = _path( _non_empty( $self->[VOL] . $self->[DIR] ) );
}
}
elsif ( length $self->[DIR] ) {
# because of symlinks, any internal updir requires us to
# just add more updirs at the end
if ( $self->[DIR] =~ m{(?:^\.\./|/\.\./|/\.\.\z)} ) {
$parent = _path( $self->[VOL] . $self->[DIR] . "/.." );
}
else {
( my $dir = $self->[DIR] ) =~ s{/[^\/]+/\z}{/};
$parent = _path( $self->[VOL] . $dir );
}
}
else {
$parent = _path( _non_empty( $self->[VOL] ) );
}
return $level == 1 ? $parent : $parent->parent( $level - 1 );
}
sub _non_empty {
my ($string) = shift;
return ( ( defined($string) && length($string) ) ? $string : "." );
}
#pod =method realpath
#pod
#pod $real = path("/baz/foo/../bar")->realpath;
#pod $real = path("foo/../bar")->realpath;
#pod
#pod Returns a new C<Path::Tiny> object with all symbolic links and upward directory
#pod parts resolved using L<Cwd>'s C<realpath>. Compared to C<absolute>, this is
#pod more expensive as it must actually consult the filesystem.
#pod
#pod If the parent path can't be resolved (e.g. if it includes directories that
#pod don't exist), an exception will be thrown:
#pod
#pod $real = path("doesnt_exist/foo")->realpath; # dies
#pod
#pod However, if the parent path exists and only the last component (e.g. filename)
#pod doesn't exist, the realpath will be the realpath of the parent plus the
#pod non-existent last component:
#pod
#pod $real = path("./aasdlfasdlf")->realpath; # works
#pod
#pod The underlying L<Cwd> module usually worked this way on Unix, but died on
#pod Windows (and some Unixes) if the full path didn't exist. As of version 0.064,
#pod it's safe to use anywhere.
#pod
#pod Current API available since 0.001.
#pod
#pod =cut
# Win32 and some Unixes need parent path resolved separately so realpath
# doesn't throw an error resolving non-existent basename
sub realpath {
my $self = shift;
$self = $self->_resolve_symlinks;
require Cwd;
$self->_splitpath if !defined $self->[FILE];
my $check_parent =
length $self->[FILE] && $self->[FILE] ne '.' && $self->[FILE] ne '..';
my $realpath = eval {
# pure-perl Cwd can carp
local $SIG{__WARN__} = sub { };
Cwd::realpath( $check_parent ? $self->parent->[PATH] : $self->[PATH] );
};
# parent realpath must exist; not all Cwd::realpath will error if it doesn't
$self->_throw("resolving realpath")
unless defined $realpath && length $realpath && -e $realpath;
return ( $check_parent ? _path( $realpath, $self->[FILE] ) : _path($realpath) );
}
#pod =method relative
#pod
#pod $rel = path("/tmp/foo/bar")->relative("/tmp"); # foo/bar
#pod
#pod Returns a C<Path::Tiny> object with a path relative to a new base path
#pod given as an argument. If no argument is given, the current directory will
#pod be used as the new base path.
#pod
#pod If either path is already relative, it will be made absolute based on the
#pod current directly before determining the new relative path.
#pod
#pod The algorithm is roughly as follows:
#pod
#pod =for :list
#pod * If the original and new base path are on different volumes, an exception
#pod will be thrown.
#pod * If the original and new base are identical, the relative path is C<".">.
#pod * If the new base subsumes the original, the relative path is the original
#pod path with the new base chopped off the front
#pod * If the new base does not subsume the original, a common prefix path is
#pod determined (possibly the root directory) and the relative path will
#pod consist of updirs (C<"..">) to reach the common prefix, followed by the
#pod original path less the common prefix.
#pod
#pod Unlike C<File::Spec::abs2rel>, in the last case above, the calculation based
#pod on a common prefix takes into account symlinks that could affect the updir
#pod process. Given an original path "/A/B" and a new base "/A/C",
#pod (where "A", "B" and "C" could each have multiple path components):
#pod
#pod =for :list
#pod * Symlinks in "A" don't change the result unless the last component of A is
#pod a symlink and the first component of "C" is an updir.
#pod * Symlinks in "B" don't change the result and will exist in the result as
#pod given.
#pod * Symlinks and updirs in "C" must be resolved to actual paths, taking into
#pod account the possibility that not all path components might exist on the
#pod filesystem.
#pod
#pod Current API available since 0.001. New algorithm (that accounts for
#pod symlinks) available since 0.079.
#pod
#pod =cut
sub relative {
my ( $self, $base ) = @_;
$base = _path( defined $base && length $base ? $base : '.' );
# relative paths must be converted to absolute first
$self = $self->absolute if $self->is_relative;
$base = $base->absolute if $base->is_relative;
# normalize volumes if they exist
$self = $self->absolute if !length $self->volume && length $base->volume;
$base = $base->absolute if length $self->volume && !length $base->volume;
# can't make paths relative across volumes
if ( !_same( $self->volume, $base->volume ) ) {
Carp::croak("relative() can't cross volumes: '$self' vs '$base'");
}
# if same absolute path, relative is current directory
return _path(".") if _same( $self->[PATH], $base->[PATH] );
# if base is a prefix of self, chop prefix off self
if ( $base->subsumes($self) ) {
$base = "" if $base->is_rootdir;
my $relative = "$self";
$relative =~ s{\A\Q$base/}{};
return _path(".", $relative);
}
# base is not a prefix, so must find a common prefix (even if root)
my ( @common, @self_parts, @base_parts );
@base_parts = split /\//, $base->_just_filepath;
# if self is rootdir, then common directory is root (shown as empty
# string for later joins); otherwise, must be computed from path parts.
if ( $self->is_rootdir ) {
@common = ("");
shift @base_parts;
}
else {
@self_parts = split /\//, $self->_just_filepath;
while ( @self_parts && @base_parts && _same( $self_parts[0], $base_parts[0] ) ) {
push @common, shift @base_parts;
shift @self_parts;
}
}
# if there are any symlinks from common to base, we have a problem, as
# you can't guarantee that updir from base reaches the common prefix;
# we must resolve symlinks and try again; likewise, any updirs are
# a problem as it throws off calculation of updirs needed to get from
# self's path to the common prefix.
if ( my $new_base = $self->_resolve_between( \@common, \@base_parts ) ) {
return $self->relative($new_base);
}
# otherwise, symlinks in common or from common to A don't matter as
# those don't involve updirs
my @new_path = ( ("..") x ( 0+ @base_parts ), @self_parts );
return _path(@new_path);
}
sub _just_filepath {
my $self = shift;
my $self_vol = $self->volume;
return "$self" if !length $self_vol;
( my $self_path = "$self" ) =~ s{\A\Q$self_vol}{};
return $self_path;
}
sub _resolve_between {
my ( $self, $common, $base ) = @_;
my $path = $self->volume . join( "/", @$common );
my $changed = 0;
for my $p (@$base) {
$path .= "/$p";
if ( $p eq '..' ) {
$changed = 1;
if ( -e $path ) {
$path = _path($path)->realpath->[PATH];
}
else {
$path =~ s{/[^/]+/..\z}{/};
}
}
if ( -l $path ) {
$changed = 1;
$path = _path($path)->realpath->[PATH];
}
}
return $changed ? _path($path) : undef;
}
#pod =method remove
#pod
#pod path("foo.txt")->remove;
#pod
#pod This is just like C<unlink>, except for its error handling: if the path does
#pod not exist, it returns false; if deleting the file fails, it throws an
#pod exception.
#pod
#pod Current API available since 0.012.
#pod
#pod =cut
sub remove {
my $self = shift;
return 0 if !-e $self->[PATH] && !-l $self->[PATH];
return unlink( $self->[PATH] ) || $self->_throw('unlink');
}
#pod =method remove_tree
#pod
#pod # directory
#pod path("foo/bar/baz")->remove_tree;
#pod path("foo/bar/baz")->remove_tree( \%options );
#pod path("foo/bar/baz")->remove_tree( { safe => 0 } ); # force remove
#pod
#pod Like calling C<remove_tree> from L<File::Path>, but defaults to C<safe> mode.
#pod An optional hash reference is passed through to C<remove_tree>. Errors will be
#pod trapped and an exception thrown. Returns the number of directories deleted,
#pod just like C<remove_tree>.
#pod
#pod If you want to remove a directory only if it is empty, use the built-in
#pod C<rmdir> function instead.
#pod
#pod rmdir path("foo/bar/baz/");
#pod
#pod Current API available since 0.013.
#pod
#pod Passing a defined argument I<other> than a hash reference is an error, and an
#pod exception will be thrown.
#pod
#pod =cut
sub remove_tree {
my ( $self, $args, @rest ) = @_;
$args = {} unless defined $args;
if (@rest || (defined $args && ref $args ne 'HASH')) {
$self->_throw('mkdir', undef, "method argument was given, but was not a hash reference");
}
return 0 if !-e $self->[PATH] && !-l $self->[PATH];
my $err;
$args->{error} = \$err unless defined $args->{error};
$args->{safe} = 1 unless defined $args->{safe};
require File::Path;
my $count = File::Path::remove_tree( $self->[PATH], $args );
if ( $err && @$err ) {
my ( $file, $message ) = %{ $err->[0] };
Carp::croak("remove_tree failed for $file: $message");
}
return $count;
}
#pod =method sibling
#pod
#pod $foo = path("/tmp/foo.txt");
#pod $sib = $foo->sibling("bar.txt"); # /tmp/bar.txt
#pod $sib = $foo->sibling("baz", "bam.txt"); # /tmp/baz/bam.txt
#pod
#pod Returns a new C<Path::Tiny> object relative to the parent of the original.
#pod This is slightly more efficient than C<< $path->parent->child(...) >>.
#pod
#pod Current API available since 0.058.
#pod
#pod =cut
sub sibling {
my $self = shift;
return _path( $self->parent->[PATH], @_ );
}
#pod =method size, size_human
#pod
#pod my $p = path("foo"); # with size 1025 bytes
#pod
#pod $p->size; # "1025"
#pod $p->size_human; # "1.1 K"
#pod $p->size_human( {format => "iec"} ); # "1.1 KiB"
#pod
#pod Returns the size of a file. The C<size> method is just a wrapper around C<-s>.
#pod
#pod The C<size_human> method provides a human-readable string similar to
#pod C<ls -lh>. Like C<ls>, it rounds upwards and provides one decimal place for
#pod single-digit sizes and no decimal places for larger sizes. The only available
#pod option is C<format>, which has three valid values:
#pod
#pod =for :list
#pod * 'ls' (the default): base-2 sizes, with C<ls> style single-letter suffixes (K, M, etc.)
#pod * 'iec': base-2 sizes, with IEC binary suffixes (KiB, MiB, etc.)
#pod * 'si': base-10 sizes, with SI decimal suffixes (kB, MB, etc.)
#pod
#pod If C<-s> would return C<undef>, C<size_human> returns the empty string.
#pod
#pod Current API available since 0.122.
#pod
#pod =cut
sub size { -s $_[0]->[PATH] }
my %formats = (
'ls' => [ 1024, log(1024), [ "", map { " $_" } qw/K M G T/ ] ],
'iec' => [ 1024, log(1024), [ "", map { " $_" } qw/KiB MiB GiB TiB/ ] ],
'si' => [ 1000, log(1000), [ "", map { " $_" } qw/kB MB GB TB/ ] ],
);
sub _formats { return $formats{$_[0]} }
sub size_human {
my $self = shift;
my $args = _get_args( shift, qw/format/ );
my $format = defined $args->{format} ? $args->{format} : "ls";
my $fmt_opts = $formats{$format}
or Carp::croak("Invalid format '$format' for size_human()");
my $size = -s $self->[PATH];
return defined $size ? _human_size( $size, @$fmt_opts ) : "";
}
sub _ceil {
return $_[0] == int($_[0]) ? $_[0] : int($_[0]+1);
}
sub _human_size {
my ( $size, $base, $log_base, $suffixes ) = @_;
return "0" if $size == 0;
my $mag = int( log($size) / $log_base );
$size /= $base**$mag;
$size =
$mag == 0 ? $size
: length( int($size) ) == 1 ? _ceil( $size * 10 ) / 10
: _ceil($size);
if ( $size >= $base ) {
$size /= $base;
$mag++;
}
my $fmt = ( $mag == 0 || length( int($size) ) > 1 ) ? "%.0f%s" : "%.1f%s";
return sprintf( $fmt, $size, $suffixes->[$mag] );
}
#pod =method slurp, slurp_raw, slurp_utf8
#pod
#pod $data = path("foo.txt")->slurp;
#pod $data = path("foo.txt")->slurp( {binmode => ":raw"} );
#pod $data = path("foo.txt")->slurp_raw;
#pod $data = path("foo.txt")->slurp_utf8;
#pod
#pod Reads file contents into a scalar. Takes an optional hash reference which may
#pod be used to pass options. The only available option is C<binmode>, which is
#pod passed to C<binmode()> on the handle used for reading.
#pod
#pod C<slurp_raw> is like C<slurp> with a C<binmode> of C<:unix> for
#pod a fast, unbuffered, raw read.
#pod
#pod C<slurp_utf8> is like C<slurp> with a C<binmode> of
#pod C<:unix:encoding(UTF-8)> (or C<:unix:utf8_strict> with
#pod L<PerlIO::utf8_strict>). If L<Unicode::UTF8> 0.58+ is installed, a
#pod unbuffered, raw slurp will be done instead and the result decoded with
#pod C<Unicode::UTF8>. This is just as strict and is roughly an order of
#pod magnitude faster than using C<:encoding(UTF-8)>.
#pod
#pod B<Note>: C<slurp> and friends lock the filehandle before slurping. If
#pod you plan to slurp from a file created with L<File::Temp>, be sure to
#pod close other handles or open without locking to avoid a deadlock:
#pod
#pod my $tempfile = File::Temp->new(EXLOCK => 0);
#pod my $guts = path($tempfile)->slurp;
#pod
#pod See also L</lines> if you want to slurp a file into a line array.
#pod
#pod Current API available since 0.004.
#pod
#pod =cut
sub slurp {
my $self = shift;
my $args = _get_args( shift, qw/binmode/ );
my $binmode = $args->{binmode};
$binmode = ( ( caller(0) )[10] || {} )->{'open<'} unless defined $binmode;
my $fh = $self->filehandle( { locked => 1 }, "<", $binmode );
if ( ( defined($binmode) ? $binmode : "" ) eq ":unix"
and my $size = -s $fh )
{
my $buf;
my $rc = read $fh, $buf, $size; # File::Slurp in a nutshell
$self->_throw('read') unless defined $rc;
return $buf;
}
else {
local $/;
my $buf = scalar <$fh>;
$self->_throw('read') unless defined $buf;
return $buf;
}
}
sub slurp_raw { $_[1] = { binmode => ":unix" }; goto &slurp }
sub slurp_utf8 {
if ( defined($HAS_UU) ? $HAS_UU : ( $HAS_UU = _check_UU() ) ) {
return Unicode::UTF8::decode_utf8( slurp( $_[0], { binmode => ":unix" } ) );
}
elsif ( defined($HAS_PU) ? $HAS_PU : ( $HAS_PU = _check_PU() ) ) {
$_[1] = { binmode => ":unix:utf8_strict" };
goto &slurp;
}
else {
$_[1] = { binmode => ":unix:encoding(UTF-8)" };
goto &slurp;
}
}
#pod =method spew, spew_raw, spew_utf8
#pod
#pod path("foo.txt")->spew(@data);
#pod path("foo.txt")->spew(\@data);
#pod path("foo.txt")->spew({binmode => ":raw"}, @data);
#pod path("foo.txt")->spew_raw(@data);
#pod path("foo.txt")->spew_utf8(@data);
#pod
#pod Writes data to a file atomically. The file is written to a temporary file in
#pod the same directory, then renamed over the original. An optional hash reference
#pod may be used to pass options. The only option is C<binmode>, which is passed to
#pod C<binmode()> on the handle used for writing.
#pod
#pod C<spew_raw> is like C<spew> with a C<binmode> of C<:unix> for a fast,
#pod unbuffered, raw write.
#pod
#pod C<spew_utf8> is like C<spew> with a C<binmode> of C<:unix:encoding(UTF-8)>
#pod (or C<:unix:utf8_strict> with L<PerlIO::utf8_strict>). If L<Unicode::UTF8>
#pod 0.58+ is installed, a raw, unbuffered spew will be done instead on the data
#pod encoded with C<Unicode::UTF8>.
#pod
#pod B<NOTE>: because the file is written to a temporary file and then renamed, the
#pod new file will wind up with permissions based on your current umask. This is a
#pod feature to protect you from a race condition that would otherwise give
#pod different permissions than you might expect. If you really want to keep the
#pod original mode flags, use L</append> with the C<truncate> option.
#pod
#pod Current API available since 0.011.
#pod
#pod =cut
sub spew {
my ( $self, @data ) = @_;
my $args = ( @data && ref $data[0] eq 'HASH' ) ? shift @data : {};
$args = _get_args( $args, qw/binmode/ );
my $binmode = $args->{binmode};
# get default binmode from caller's lexical scope (see "perldoc open")
$binmode = ( ( caller(0) )[10] || {} )->{'open>'} unless defined $binmode;
# writing needs to follow the link and create the tempfile in the same
# dir for later atomic rename
my $resolved_path = $self->_resolve_symlinks;
my $temp = $resolved_path->_replacement_path;
my $fh;
my $ok = eval { $fh = $temp->filehandle( { exclusive => 1, locked => 1 }, ">", $binmode ); 1 };
if (!$ok) {
my $msg = ref($@) eq 'Path::Tiny::Error'
? "error opening temp file '$@->{file}' for atomic write: $@->{err}"
: "error opening temp file for atomic write: $@";
$self->_throw('spew', $self->[PATH], $msg);
}
print( {$fh} map { ref eq 'ARRAY' ? @$_ : $_ } @data) or $self->_throw('print', $temp->[PATH]);
close $fh or $self->_throw( 'close', $temp->[PATH] );
return $temp->move($resolved_path);
}
sub spew_raw { splice @_, 1, 0, { binmode => ":unix" }; goto &spew }
sub spew_utf8 {
if ( defined($HAS_UU) ? $HAS_UU : ( $HAS_UU = _check_UU() ) ) {
my $self = shift;
spew(
$self,
{ binmode => ":unix" },
map { Unicode::UTF8::encode_utf8($_) } map { ref eq 'ARRAY' ? @$_ : $_ } @_
);
}
elsif ( defined($HAS_PU) ? $HAS_PU : ( $HAS_PU = _check_PU() ) ) {
splice @_, 1, 0, { binmode => ":unix:utf8_strict" };
goto &spew;
}
else {
splice @_, 1, 0, { binmode => ":unix:encoding(UTF-8)" };
goto &spew;
}
}
#pod =method stat, lstat
#pod
#pod $stat = path("foo.txt")->stat;
#pod $stat = path("/some/symlink")->lstat;
#pod
#pod Like calling C<stat> or C<lstat> from L<File::stat>.
#pod
#pod Current API available since 0.001.
#pod
#pod =cut
# XXX break out individual stat() components as subs?
sub stat {
my $self = shift;
require File::stat;
return File::stat::stat( $self->[PATH] ) || $self->_throw('stat');
}
sub lstat {
my $self = shift;
require File::stat;
return File::stat::lstat( $self->[PATH] ) || $self->_throw('lstat');
}
#pod =method stringify
#pod
#pod $path = path("foo.txt");
#pod say $path->stringify; # same as "$path"
#pod
#pod Returns a string representation of the path. Unlike C<canonpath>, this method
#pod returns the path standardized with Unix-style C</> directory separators.
#pod
#pod Current API available since 0.001.
#pod
#pod =cut
sub stringify { $_[0]->[PATH] =~ /^~/ ? './' . $_[0]->[PATH] : $_[0]->[PATH] }
#pod =method subsumes
#pod
#pod path("foo/bar")->subsumes("foo/bar/baz"); # true
#pod path("/foo/bar")->subsumes("/foo/baz"); # false
#pod
#pod Returns true if the first path is a prefix of the second path at a directory
#pod boundary.
#pod
#pod This B<does not> resolve parent directory entries (C<..>) or symlinks:
#pod
#pod path("foo/bar")->subsumes("foo/bar/../baz"); # true
#pod
#pod If such things are important to you, ensure that both paths are resolved to
#pod the filesystem with C<realpath>:
#pod
#pod my $p1 = path("foo/bar")->realpath;
#pod my $p2 = path("foo/bar/../baz")->realpath;
#pod if ( $p1->subsumes($p2) ) { ... }
#pod
#pod Current API available since 0.048.
#pod
#pod =cut
sub subsumes {
my $self = shift;
Carp::croak("subsumes() requires a defined, positive-length argument")
unless defined $_[0];
my $other = _path(shift);
# normalize absolute vs relative
if ( $self->is_absolute && !$other->is_absolute ) {
$other = $other->absolute;
}
elsif ( $other->is_absolute && !$self->is_absolute ) {
$self = $self->absolute;
}
# normalize volume vs non-volume; do this after absolute path
# adjustments above since that might add volumes already
if ( length $self->volume && !length $other->volume ) {
$other = $other->absolute;
}
elsif ( length $other->volume && !length $self->volume ) {
$self = $self->absolute;
}
if ( $self->[PATH] eq '.' ) {
return !!1; # cwd subsumes everything relative
}
elsif ( $self->is_rootdir ) {
# a root directory ("/", "c:/") already ends with a separator
return $other->[PATH] =~ m{^\Q$self->[PATH]\E};
}
else {
# exact match or prefix breaking at a separator
return $other->[PATH] =~ m{^\Q$self->[PATH]\E(?:/|\z)};
}
}
#pod =method touch
#pod
#pod path("foo.txt")->touch;
#pod path("foo.txt")->touch($epoch_secs);
#pod
#pod Like the Unix C<touch> utility. Creates the file if it doesn't exist, or else
#pod changes the modification and access times to the current time. If the first
#pod argument is the epoch seconds then it will be used.
#pod
#pod Returns the path object so it can be easily chained with other methods:
#pod
#pod # won't die if foo.txt doesn't exist
#pod $content = path("foo.txt")->touch->slurp;
#pod
#pod Current API available since 0.015.
#pod
#pod =cut
sub touch {
my ( $self, $epoch ) = @_;
if ( !-e $self->[PATH] ) {
my $fh = $self->openw;
close $fh or $self->_throw('close');
}
if ( defined $epoch ) {
utime $epoch, $epoch, $self->[PATH]
or $self->_throw("utime ($epoch)");
}
else {
# literal undef prevents warnings :-(
utime undef, undef, $self->[PATH]
or $self->_throw("utime ()");
}
return $self;
}
#pod =method touchpath
#pod
#pod path("bar/baz/foo.txt")->touchpath;
#pod
#pod Combines C<mkdir> and C<touch>. Creates the parent directory if it doesn't exist,
#pod before touching the file. Returns the path object like C<touch> does.
#pod
#pod If you need to pass options, use C<mkdir> and C<touch> separately:
#pod
#pod path("bar/baz")->mkdir( \%options )->child("foo.txt")->touch($epoch_secs);
#pod
#pod Current API available since 0.022.
#pod
#pod =cut
sub touchpath {
my ($self) = @_;
my $parent = $self->parent;
$parent->mkdir unless $parent->exists;
$self->touch;
}
#pod =method visit
#pod
#pod path("/tmp")->visit( \&callback, \%options );
#pod
#pod Executes a callback for each child of a directory. It returns a hash
#pod reference with any state accumulated during iteration.
#pod
#pod The options are the same as for L</iterator> (which it uses internally):
#pod C<recurse> and C<follow_symlinks>. Both default to false.
#pod
#pod The callback function will receive a C<Path::Tiny> object as the first argument
#pod and a hash reference to accumulate state as the second argument. For example:
#pod
#pod # collect files sizes
#pod my $sizes = path("/tmp")->visit(
#pod sub {
#pod my ($path, $state) = @_;
#pod return if $path->is_dir;
#pod $state->{$path} = -s $path;
#pod },
#pod { recurse => 1 }
#pod );
#pod
#pod For convenience, the C<Path::Tiny> object will also be locally aliased as the
#pod C<$_> global variable:
#pod
#pod # print paths matching /foo/
#pod path("/tmp")->visit( sub { say if /foo/ }, { recurse => 1} );
#pod
#pod If the callback returns a B<reference> to a false scalar value, iteration will
#pod terminate. This is not the same as "pruning" a directory search; this just
#pod stops all iteration and returns the state hash reference.
#pod
#pod # find up to 10 files larger than 100K
#pod my $files = path("/tmp")->visit(
#pod sub {
#pod my ($path, $state) = @_;
#pod $state->{$path}++ if -s $path > 102400
#pod return \0 if keys %$state == 10;
#pod },
#pod { recurse => 1 }
#pod );
#pod
#pod If you want more flexible iteration, use a module like L<Path::Iterator::Rule>.
#pod
#pod Current API available since 0.062.
#pod
#pod =cut
sub visit {
my $self = shift;
my $cb = shift;
my $args = _get_args( shift, qw/recurse follow_symlinks/ );
Carp::croak("Callback for visit() must be a code reference")
unless defined($cb) && ref($cb) eq 'CODE';
my $next = $self->iterator($args);
my $state = {};
while ( my $file = $next->() ) {
local $_ = $file;
my $r = $cb->( $file, $state );
last if ref($r) eq 'SCALAR' && !$$r;
}
return $state;
}
#pod =method volume
#pod
#pod $vol = path("/tmp/foo.txt")->volume; # ""
#pod $vol = path("C:/tmp/foo.txt")->volume; # "C:"
#pod
#pod Returns the volume portion of the path. This is equivalent
#pod to what L<File::Spec> would give from C<splitpath> and thus
#pod usually is the empty string on Unix-like operating systems or the
#pod drive letter for an absolute path on C<MSWin32>.
#pod
#pod Current API available since 0.001.
#pod
#pod =cut
sub volume {
my ($self) = @_;
$self->_splitpath unless defined $self->[VOL];
return $self->[VOL];
}
package Path::Tiny::Error;
our @CARP_NOT = qw/Path::Tiny/;
use overload ( q{""} => sub { (shift)->{msg} }, fallback => 1 );
sub throw {
my ( $class, $op, $file, $err ) = @_;
chomp( my $trace = Carp::shortmess );
my $msg = "Error $op on '$file': $err$trace\n";
die bless { op => $op, file => $file, err => $err, msg => $msg }, $class;
}
1;
# vim: ts=4 sts=4 sw=4 et:
__END__
=pod
=encoding UTF-8
=head1 NAME
Path::Tiny - File path utility
=head1 VERSION
version 0.148
=head1 SYNOPSIS
use Path::Tiny;
# Creating Path::Tiny objects
my $dir = path("/tmp");
my $foo = path("foo.txt");
my $subdir = $dir->child("foo");
my $bar = $subdir->child("bar.txt");
# Stringifies as cleaned up path
my $file = path("./foo.txt");
print $file; # "foo.txt"
# Reading files
my $guts = $file->slurp;
$guts = $file->slurp_utf8;
my @lines = $file->lines;
@lines = $file->lines_utf8;
my ($head) = $file->lines( {count => 1} );
my ($tail) = $file->lines( {count => -1} );
# Writing files
$bar->spew( @data );
$bar->spew_utf8( @data );
# Reading directories
for ( $dir->children ) { ... }
my $iter = $dir->iterator;
while ( my $next = $iter->() ) { ... }
=head1 DESCRIPTION
This module provides a small, fast utility for working with file paths. It is
friendlier to use than L<File::Spec> and provides easy access to functions from
several other core file handling modules. It aims to be smaller and faster
than many alternatives on CPAN, while helping people do many common things in
consistent and less error-prone ways.
Path::Tiny does not try to work for anything except Unix-like and Win32
platforms. Even then, it might break if you try something particularly obscure
or tortuous. (Quick! What does this mean:
C<< ///../../..//./././a//b/.././c/././ >>? And how does it differ on Win32?)
All paths are forced to have Unix-style forward slashes. Stringifying
the object gives you back the path (after some clean up).
File input/output methods C<flock> handles before reading or writing,
as appropriate (if supported by the platform and/or filesystem).
The C<*_utf8> methods (C<slurp_utf8>, C<lines_utf8>, etc.) operate in raw
mode. On Windows, that means they will not have CRLF translation from the
C<:crlf> IO layer. Installing L<Unicode::UTF8> 0.58 or later will speed up
C<*_utf8> situations in many cases and is highly recommended.
Alternatively, installing L<PerlIO::utf8_strict> 0.003 or later will be
used in place of the default C<:encoding(UTF-8)>.
This module depends heavily on PerlIO layers for correct operation and thus
requires Perl 5.008001 or later.
=head1 CONSTRUCTORS
=head2 path
$path = path("foo/bar");
$path = path("/tmp", "file.txt"); # list
$path = path("."); # cwd
Constructs a C<Path::Tiny> object. It doesn't matter if you give a file or
directory path. It's still up to you to call directory-like methods only on
directories and file-like methods only on files. This function is exported
automatically by default.
The first argument must be defined and have non-zero length or an exception
will be thrown. This prevents subtle, dangerous errors with code like
C<< path( maybe_undef() )->remove_tree >>.
B<DEPRECATED>: If and only if the B<first> character of the B<first> argument
to C<path> is a tilde ('~'), then tilde replacement will be applied to the
first path segment. A single tilde will be replaced with C<glob('~')> and a
tilde followed by a username will be replaced with output of
C<glob('~username')>. B<No other method does tilde expansion on its arguments>.
See L</Tilde expansion (deprecated)> for more.
On Windows, if the path consists of a drive identifier without a path component
(C<C:> or C<D:>), it will be expanded to the absolute path of the current
directory on that volume using C<Cwd::getdcwd()>.
If called with a single C<Path::Tiny> argument, the original is returned unless
the original is holding a temporary file or directory reference in which case a
stringified copy is made.
$path = path("foo/bar");
$temp = Path::Tiny->tempfile;
$p2 = path($path); # like $p2 = $path
$t2 = path($temp); # like $t2 = path( "$temp" )
This optimizes copies without proliferating references unexpectedly if a copy is
made by code outside your control.
Current API available since 0.017.
=head2 new
$path = Path::Tiny->new("foo/bar");
This is just like C<path>, but with method call overhead. (Why would you
do that?)
Current API available since 0.001.
=head2 cwd
$path = Path::Tiny->cwd; # path( Cwd::getcwd )
$path = cwd; # optional export
Gives you the absolute path to the current directory as a C<Path::Tiny> object.
This is slightly faster than C<< path(".")->absolute >>.
C<cwd> may be exported on request and used as a function instead of as a
method.
Current API available since 0.018.
=head2 rootdir
$path = Path::Tiny->rootdir; # /
$path = rootdir; # optional export
Gives you C<< File::Spec->rootdir >> as a C<Path::Tiny> object if you're too
picky for C<path("/")>.
C<rootdir> may be exported on request and used as a function instead of as a
method.
Current API available since 0.018.
=head2 tempfile, tempdir
$temp = Path::Tiny->tempfile( @options );
$temp = Path::Tiny->tempdir( @options );
$temp = $dirpath->tempfile( @options );
$temp = $dirpath->tempdir( @options );
$temp = tempfile( @options ); # optional export
$temp = tempdir( @options ); # optional export
C<tempfile> passes the options to C<< File::Temp->new >> and returns a
C<Path::Tiny> object with the file name. The C<TMPDIR> option will be enabled
by default, but you can override that by passing C<< TMPDIR => 0 >> along with
the options. (If you use an absolute C<TEMPLATE> option, you will want to
disable C<TMPDIR>.)
The resulting C<File::Temp> object is cached. When the C<Path::Tiny> object is
destroyed, the C<File::Temp> object will be as well.
C<File::Temp> annoyingly requires you to specify a custom template in slightly
different ways depending on which function or method you call, but
C<Path::Tiny> lets you ignore that and can take either a leading template or a
C<TEMPLATE> option and does the right thing.
$temp = Path::Tiny->tempfile( "customXXXXXXXX" ); # ok
$temp = Path::Tiny->tempfile( TEMPLATE => "customXXXXXXXX" ); # ok
The tempfile path object will be normalized to have an absolute path, even if
created in a relative directory using C<DIR>. If you want it to have
the C<realpath> instead, pass a leading options hash like this:
$real_temp = tempfile({realpath => 1}, @options);
C<tempdir> is just like C<tempfile>, except it calls
C<< File::Temp->newdir >> instead.
Both C<tempfile> and C<tempdir> may be exported on request and used as
functions instead of as methods.
The methods can be called on an instances representing a
directory. In this case, the directory is used as the base to create the
temporary file/directory, setting the C<DIR> option in File::Temp.
my $target_dir = path('/to/destination');
my $tempfile = $target_dir->tempfile('foobarXXXXXX');
$tempfile->spew('A lot of data...'); # not atomic
$tempfile->move($target_dir->child('foobar')); # hopefully atomic
In this case, any value set for option C<DIR> is ignored.
B<Note>: for tempfiles, the filehandles from File::Temp are closed and not
reused. This is not as secure as using File::Temp handles directly, but is
less prone to deadlocks or access problems on some platforms. Think of what
C<Path::Tiny> gives you to be just a temporary file B<name> that gets cleaned
up.
B<Note 2>: if you don't want these cleaned up automatically when the object
is destroyed, File::Temp requires different options for directories and
files. Use C<< CLEANUP => 0 >> for directories and C<< UNLINK => 0 >> for
files.
B<Note 3>: Don't lose the temporary object by chaining a method call instead
of storing it:
my $lost = tempdir()->child("foo"); # tempdir cleaned up right away
B<Note 4>: The cached object may be accessed with the L</cached_temp> method.
Keeping a reference to, or modifying the cached object may break the
behavior documented above and is not supported. Use at your own risk.
Current API available since 0.119.
=head1 METHODS
=head2 absolute
$abs = path("foo/bar")->absolute;
$abs = path("foo/bar")->absolute("/tmp");
Returns a new C<Path::Tiny> object with an absolute path (or itself if already
absolute). If no argument is given, the current directory is used as the
absolute base path. If an argument is given, it will be converted to an
absolute path (if it is not already) and used as the absolute base path.
This will not resolve upward directories ("foo/../bar") unless C<canonpath>
in L<File::Spec> would normally do so on your platform. If you need them
resolved, you must call the more expensive C<realpath> method instead.
On Windows, an absolute path without a volume component will have it added
based on the current drive.
Current API available since 0.101.
=head2 append, append_raw, append_utf8
path("foo.txt")->append(@data);
path("foo.txt")->append(\@data);
path("foo.txt")->append({binmode => ":raw"}, @data);
path("foo.txt")->append_raw(@data);
path("foo.txt")->append_utf8(@data);
Appends data to a file. The file is locked with C<flock> prior to writing
and closed afterwards. An optional hash reference may be used to pass
options. Valid options are:
=over 4
=item *
C<binmode>: passed to C<binmode()> on the handle used for writing.
=item *
C<truncate>: truncates the file after locking and before appending
=back
The C<truncate> option is a way to replace the contents of a file
B<in place>, unlike L</spew> which writes to a temporary file and then
replaces the original (if it exists).
C<append_raw> is like C<append> with a C<binmode> of C<:unix> for a fast,
unbuffered, raw write.
C<append_utf8> is like C<append> with an unbuffered C<binmode>
C<:unix:encoding(UTF-8)> (or C<:unix:utf8_strict> with
L<PerlIO::utf8_strict>). If L<Unicode::UTF8> 0.58+ is installed, an
unbuffered, raw append will be done instead on the data encoded with
C<Unicode::UTF8>.
Current API available since 0.060.
=head2 assert
$path = path("foo.txt")->assert( sub { $_->exists } );
Returns the invocant after asserting that a code reference argument returns
true. When the assertion code reference runs, it will have the invocant
object in the C<$_> variable. If it returns false, an exception will be
thrown. The assertion code reference may also throw its own exception.
If no assertion is provided, the invocant is returned without error.
Current API available since 0.062.
=head2 basename
$name = path("foo/bar.txt")->basename; # bar.txt
$name = path("foo.txt")->basename('.txt'); # foo
$name = path("foo.txt")->basename(qr/.txt/); # foo
$name = path("foo.txt")->basename(@suffixes);
Returns the file portion or last directory portion of a path.
Given a list of suffixes as strings or regular expressions, any that match at
the end of the file portion or last directory portion will be removed before
the result is returned.
Current API available since 0.054.
=head2 canonpath
$canonical = path("foo/bar")->canonpath; # foo\bar on Windows
Returns a string with the canonical format of the path name for
the platform. In particular, this means directory separators
will be C<\> on Windows.
Current API available since 0.001.
=head2 cached_temp
Returns the cached C<File::Temp> or C<File::Temp::Dir> object if the
C<Path::Tiny> object was created with C</tempfile> or C</tempdir>.
If there is no such object, this method throws.
B<WARNING>: Keeping a reference to, or modifying the cached object may
break the behavior documented for temporary files and directories created
with C<Path::Tiny> and is not supported. Use at your own risk.
Current API available since 0.101.
=head2 child
$file = path("/tmp")->child("foo.txt"); # "/tmp/foo.txt"
$file = path("/tmp")->child(@parts);
Returns a new C<Path::Tiny> object relative to the original. Works
like C<catfile> or C<catdir> from File::Spec, but without caring about
file or directories.
B<WARNING>: because the argument could contain C<..> or refer to symlinks,
there is no guarantee that the new path refers to an actual descendent of
the original. If this is important to you, transform parent and child with
L</realpath> and check them with L</subsumes>.
Current API available since 0.001.
=head2 children
@paths = path("/tmp")->children;
@paths = path("/tmp")->children( qr/\.txt\z/ );
Returns a list of C<Path::Tiny> objects for all files and directories
within a directory. Excludes "." and ".." automatically.
If an optional C<qr//> argument is provided, it only returns objects for child
names that match the given regular expression. Only the base name is used
for matching:
@paths = path("/tmp")->children( qr/^foo/ );
# matches children like the glob foo*
Current API available since 0.028.
=head2 chmod
path("foo.txt")->chmod(0777);
path("foo.txt")->chmod("0755");
path("foo.txt")->chmod("go-w");
path("foo.txt")->chmod("a=r,u+wx");
Sets file or directory permissions. The argument can be a numeric mode, a
octal string beginning with a "0" or a limited subset of the symbolic mode use
by F</bin/chmod>.
The symbolic mode must be a comma-delimited list of mode clauses. Clauses must
match C<< qr/\A([augo]+)([=+-])([rwx]+)\z/ >>, which defines "who", "op" and
"perms" parameters for each clause. Unlike F</bin/chmod>, all three parameters
are required for each clause, multiple ops are not allowed and permissions
C<stugoX> are not supported. (See L<File::chmod> for more complex needs.)
Current API available since 0.053.
=head2 copy
path("/tmp/foo.txt")->copy("/tmp/bar.txt");
Copies the current path to the given destination using L<File::Copy>'s
C<copy> function. Upon success, returns the C<Path::Tiny> object for the
newly copied file.
Current API available since 0.070.
=head2 digest
$obj = path("/tmp/foo.txt")->digest; # SHA-256
$obj = path("/tmp/foo.txt")->digest("MD5"); # user-selected
$obj = path("/tmp/foo.txt")->digest( { chunk_size => 1e6 }, "MD5" );
Returns a hexadecimal digest for a file. An optional hash reference of options may
be given. The only option is C<chunk_size>. If C<chunk_size> is given, that many
bytes will be read at a time. If not provided, the entire file will be slurped
into memory to compute the digest.
Any subsequent arguments are passed to the constructor for L<Digest> to select
an algorithm. If no arguments are given, the default is SHA-256.
Current API available since 0.056.
=head2 dirname (deprecated)
$name = path("/tmp/foo.txt")->dirname; # "/tmp/"
Returns the directory portion you would get from calling
C<< File::Spec->splitpath( $path->stringify ) >> or C<"."> for a path without a
parent directory portion. Because L<File::Spec> is inconsistent, the result
might or might not have a trailing slash. Because of this, this method is
B<deprecated>.
A better, more consistently approach is likely C<< $path->parent->stringify >>,
which will not have a trailing slash except for a root directory.
Deprecated in 0.056.
=head2 edit, edit_raw, edit_utf8
path("foo.txt")->edit( \&callback, $options );
path("foo.txt")->edit_utf8( \&callback );
path("foo.txt")->edit_raw( \&callback );
These are convenience methods that allow "editing" a file using a single
callback argument. They slurp the file using C<slurp>, place the contents
inside a localized C<$_> variable, call the callback function (without
arguments), and then write C<$_> (presumably mutated) back to the
file with C<spew>.
An optional hash reference may be used to pass options. The only option is
C<binmode>, which is passed to C<slurp> and C<spew>.
C<edit_utf8> and C<edit_raw> act like their respective C<slurp_*> and
C<spew_*> methods.
Current API available since 0.077.
=head2 edit_lines, edit_lines_utf8, edit_lines_raw
path("foo.txt")->edit_lines( \&callback, $options );
path("foo.txt")->edit_lines_utf8( \&callback );
path("foo.txt")->edit_lines_raw( \&callback );
These are convenience methods that allow "editing" a file's lines using a
single callback argument. They iterate over the file: for each line, the
line is put into a localized C<$_> variable, the callback function is
executed (without arguments) and then C<$_> is written to a temporary file.
When iteration is finished, the temporary file is atomically renamed over
the original.
An optional hash reference may be used to pass options. The only option is
C<binmode>, which is passed to the method that open handles for reading and
writing.
C<edit_lines_raw> is like C<edit_lines> with a buffered C<binmode> of
C<:raw>.
C<edit_lines_utf8> is like C<edit_lines> with a buffered C<binmode>
C<:raw:encoding(UTF-8)> (or C<:raw:utf8_strict> with
L<PerlIO::utf8_strict>).
Current API available since 0.077.
=head2 exists, is_file, is_dir
if ( path("/tmp")->exists ) { ... } # -e
if ( path("/tmp")->is_dir ) { ... } # -d
if ( path("/tmp")->is_file ) { ... } # -e && ! -d
Implements file test operations, this means the file or directory actually has
to exist on the filesystem. Until then, it's just a path.
B<Note>: C<is_file> is not C<-f> because C<-f> is not the opposite of C<-d>.
C<-f> means "plain file", excluding symlinks, devices, etc. that often can be
read just like files.
Use C<-f> instead if you really mean to check for a plain file.
Current API available since 0.053.
=head2 filehandle
$fh = path("/tmp/foo.txt")->filehandle($mode, $binmode);
$fh = path("/tmp/foo.txt")->filehandle({ locked => 1 }, $mode, $binmode);
$fh = path("/tmp/foo.txt")->filehandle({ exclusive => 1 }, $mode, $binmode);
Returns an open file handle. The C<$mode> argument must be a Perl-style
read/write mode string ("<" ,">", ">>", etc.). If a C<$binmode>
is given, it is set during the C<open> call.
An optional hash reference may be used to pass options.
The C<locked> option governs file locking; if true, handles opened for writing,
appending or read-write are locked with C<LOCK_EX>; otherwise, they are
locked with C<LOCK_SH>. When using C<locked>, ">" or "+>" modes will delay
truncation until after the lock is acquired.
The C<exclusive> option causes the open() call to fail if the file already
exists. This corresponds to the O_EXCL flag to sysopen / open(2).
C<exclusive> implies C<locked> and will set it for you if you forget it.
See C<openr>, C<openw>, C<openrw>, and C<opena> for sugar.
Current API available since 0.066.
=head2 has_same_bytes
if ( path("foo.txt")->has_same_bytes("bar.txt") ) {
# ...
}
This method returns true if both the invocant and the argument can be opened as
file handles and the handles contain the same bytes. It returns false if their
contents differ. If either can't be opened as a file (e.g. a directory or
non-existent file), the method throws an exception. If both can be opened and
both have the same C<realpath>, the method returns true without scanning any
data.
Current API available since 0.125.
=head2 is_absolute, is_relative
if ( path("/tmp")->is_absolute ) { ... }
if ( path("/tmp")->is_relative ) { ... }
Booleans for whether the path appears absolute or relative.
Current API available since 0.001.
=head2 is_rootdir
while ( ! $path->is_rootdir ) {
$path = $path->parent;
...
}
Boolean for whether the path is the root directory of the volume. I.e. the
C<dirname> is C<q[/]> and the C<basename> is C<q[]>.
This works even on C<MSWin32> with drives and UNC volumes:
path("C:/")->is_rootdir; # true
path("//server/share/")->is_rootdir; #true
Current API available since 0.038.
=head2 iterator
$iter = path("/tmp")->iterator( \%options );
Returns a code reference that walks a directory lazily. Each invocation
returns a C<Path::Tiny> object or undef when the iterator is exhausted.
$iter = path("/tmp")->iterator;
while ( $path = $iter->() ) {
...
}
The current and parent directory entries ("." and "..") will not
be included.
If the C<recurse> option is true, the iterator will walk the directory
recursively, breadth-first. If the C<follow_symlinks> option is also true,
directory links will be followed recursively. There is no protection against
loops when following links. If a directory is not readable, it will not be
followed.
The default is the same as:
$iter = path("/tmp")->iterator( {
recurse => 0,
follow_symlinks => 0,
} );
For a more powerful, recursive iterator with built-in loop avoidance, see
L<Path::Iterator::Rule>.
See also L</visit>.
Current API available since 0.016.
=head2 lines, lines_raw, lines_utf8
@contents = path("/tmp/foo.txt")->lines;
@contents = path("/tmp/foo.txt")->lines(\%options);
@contents = path("/tmp/foo.txt")->lines_raw;
@contents = path("/tmp/foo.txt")->lines_utf8;
@contents = path("/tmp/foo.txt")->lines( { chomp => 1, count => 4 } );
Returns a list of lines from a file. Optionally takes a hash-reference of
options. Valid options are C<binmode>, C<count> and C<chomp>.
If C<binmode> is provided, it will be set on the handle prior to reading.
If a positive C<count> is provided, that many lines will be returned from the
start of the file. If a negative C<count> is provided, the entire file will be
read, but only C<abs(count)> will be kept and returned. If C<abs(count)>
exceeds the number of lines in the file, all lines will be returned.
If C<chomp> is set, any end-of-line character sequences (C<CR>, C<CRLF>, or
C<LF>) will be removed from the lines returned.
Because the return is a list, C<lines> in scalar context will return the number
of lines (and throw away the data).
$number_of_lines = path("/tmp/foo.txt")->lines;
C<lines_raw> is like C<lines> with a C<binmode> of C<:raw>. We use C<:raw>
instead of C<:unix> so PerlIO buffering can manage reading by line.
C<lines_utf8> is like C<lines> with a C<binmode> of C<:raw:encoding(UTF-8)>
(or C<:raw:utf8_strict> with L<PerlIO::utf8_strict>). If L<Unicode::UTF8>
0.58+ is installed, a raw, unbuffered UTF-8 slurp will be done and then the
lines will be split. This is actually faster than relying on
IO layers, though a bit memory intensive. If memory use is a
concern, consider C<openr_utf8> and iterating directly on the handle.
See also L</slurp> if you want to load a file as a whole chunk.
Current API available since 0.065.
=head2 mkdir
path("foo/bar/baz")->mkdir;
path("foo/bar/baz")->mkdir( \%options );
Like calling C<make_path> from L<File::Path>. An optional hash reference
is passed through to C<make_path>. Errors will be trapped and an exception
thrown. Returns the the path object to facilitate chaining.
B<NOTE>: unlike Perl's builtin C<mkdir>, this will create intermediate paths
similar to the Unix C<mkdir -p> command. It will not error if applied to an
existing directory.
Passing a defined argument I<other> than a hash reference is an error, and an
exception will be thrown.
Current API available since 0.125.
=head2 mkpath (deprecated)
Like calling C<mkdir>, but returns the list of directories created or an empty list if
the directories already exist, just like C<make_path>.
Passing a defined argument I<other> than a hash reference is an error, and an
exception will be thrown.
Deprecated in 0.125.
=head2 move
path("foo.txt")->move("bar.txt");
Moves the current path to the given destination using L<File::Copy>'s
C<move> function. Upon success, returns the C<Path::Tiny> object for the
newly moved file.
If the destination already exists and is a directory, and the source is not a
directory, then the source file will be renamed into the directory
specified by the destination.
If possible, move() will simply rename the file. Otherwise, it
copies the file to the new location and deletes the original. If an
error occurs during this copy-and-delete process, you may be left
with a (possibly partial) copy of the file under the destination
name.
Current API available since 0.124. Prior versions used Perl's
-built-in (and less robust) L<rename|perlfunc/rename> function
and did not return an object.
=head2 openr, openw, openrw, opena
$fh = path("foo.txt")->openr($binmode); # read
$fh = path("foo.txt")->openr_raw;
$fh = path("foo.txt")->openr_utf8;
$fh = path("foo.txt")->openw($binmode); # write
$fh = path("foo.txt")->openw_raw;
$fh = path("foo.txt")->openw_utf8;
$fh = path("foo.txt")->opena($binmode); # append
$fh = path("foo.txt")->opena_raw;
$fh = path("foo.txt")->opena_utf8;
$fh = path("foo.txt")->openrw($binmode); # read/write
$fh = path("foo.txt")->openrw_raw;
$fh = path("foo.txt")->openrw_utf8;
Returns a file handle opened in the specified mode. The C<openr> style methods
take a single C<binmode> argument. All of the C<open*> methods have
C<open*_raw> and C<open*_utf8> equivalents that use buffered I/O layers C<:raw>
and C<:raw:encoding(UTF-8)> (or C<:raw:utf8_strict> with
L<PerlIO::utf8_strict>).
An optional hash reference may be used to pass options. The only option is
C<locked>. If true, handles opened for writing, appending or read-write are
locked with C<LOCK_EX>; otherwise, they are locked for C<LOCK_SH>.
$fh = path("foo.txt")->openrw_utf8( { locked => 1 } );
See L</filehandle> for more on locking.
Current API available since 0.011.
=head2 parent
$parent = path("foo/bar/baz")->parent; # foo/bar
$parent = path("foo/wibble.txt")->parent; # foo
$parent = path("foo/bar/baz")->parent(2); # foo
Returns a C<Path::Tiny> object corresponding to the parent directory of the
original directory or file. An optional positive integer argument is the number
of parent directories upwards to return. C<parent> by itself is equivalent to
C<parent(1)>.
Current API available since 0.014.
=head2 realpath
$real = path("/baz/foo/../bar")->realpath;
$real = path("foo/../bar")->realpath;
Returns a new C<Path::Tiny> object with all symbolic links and upward directory
parts resolved using L<Cwd>'s C<realpath>. Compared to C<absolute>, this is
more expensive as it must actually consult the filesystem.
If the parent path can't be resolved (e.g. if it includes directories that
don't exist), an exception will be thrown:
$real = path("doesnt_exist/foo")->realpath; # dies
However, if the parent path exists and only the last component (e.g. filename)
doesn't exist, the realpath will be the realpath of the parent plus the
non-existent last component:
$real = path("./aasdlfasdlf")->realpath; # works
The underlying L<Cwd> module usually worked this way on Unix, but died on
Windows (and some Unixes) if the full path didn't exist. As of version 0.064,
it's safe to use anywhere.
Current API available since 0.001.
=head2 relative
$rel = path("/tmp/foo/bar")->relative("/tmp"); # foo/bar
Returns a C<Path::Tiny> object with a path relative to a new base path
given as an argument. If no argument is given, the current directory will
be used as the new base path.
If either path is already relative, it will be made absolute based on the
current directly before determining the new relative path.
The algorithm is roughly as follows:
=over 4
=item *
If the original and new base path are on different volumes, an exception will be thrown.
=item *
If the original and new base are identical, the relative path is C<".">.
=item *
If the new base subsumes the original, the relative path is the original path with the new base chopped off the front
=item *
If the new base does not subsume the original, a common prefix path is determined (possibly the root directory) and the relative path will consist of updirs (C<"..">) to reach the common prefix, followed by the original path less the common prefix.
=back
Unlike C<File::Spec::abs2rel>, in the last case above, the calculation based
on a common prefix takes into account symlinks that could affect the updir
process. Given an original path "/A/B" and a new base "/A/C",
(where "A", "B" and "C" could each have multiple path components):
=over 4
=item *
Symlinks in "A" don't change the result unless the last component of A is a symlink and the first component of "C" is an updir.
=item *
Symlinks in "B" don't change the result and will exist in the result as given.
=item *
Symlinks and updirs in "C" must be resolved to actual paths, taking into account the possibility that not all path components might exist on the filesystem.
=back
Current API available since 0.001. New algorithm (that accounts for
symlinks) available since 0.079.
=head2 remove
path("foo.txt")->remove;
This is just like C<unlink>, except for its error handling: if the path does
not exist, it returns false; if deleting the file fails, it throws an
exception.
Current API available since 0.012.
=head2 remove_tree
# directory
path("foo/bar/baz")->remove_tree;
path("foo/bar/baz")->remove_tree( \%options );
path("foo/bar/baz")->remove_tree( { safe => 0 } ); # force remove
Like calling C<remove_tree> from L<File::Path>, but defaults to C<safe> mode.
An optional hash reference is passed through to C<remove_tree>. Errors will be
trapped and an exception thrown. Returns the number of directories deleted,
just like C<remove_tree>.
If you want to remove a directory only if it is empty, use the built-in
C<rmdir> function instead.
rmdir path("foo/bar/baz/");
Current API available since 0.013.
Passing a defined argument I<other> than a hash reference is an error, and an
exception will be thrown.
=head2 sibling
$foo = path("/tmp/foo.txt");
$sib = $foo->sibling("bar.txt"); # /tmp/bar.txt
$sib = $foo->sibling("baz", "bam.txt"); # /tmp/baz/bam.txt
Returns a new C<Path::Tiny> object relative to the parent of the original.
This is slightly more efficient than C<< $path->parent->child(...) >>.
Current API available since 0.058.
=head2 size, size_human
my $p = path("foo"); # with size 1025 bytes
$p->size; # "1025"
$p->size_human; # "1.1 K"
$p->size_human( {format => "iec"} ); # "1.1 KiB"
Returns the size of a file. The C<size> method is just a wrapper around C<-s>.
The C<size_human> method provides a human-readable string similar to
C<ls -lh>. Like C<ls>, it rounds upwards and provides one decimal place for
single-digit sizes and no decimal places for larger sizes. The only available
option is C<format>, which has three valid values:
=over 4
=item *
'ls' (the default): base-2 sizes, with C<ls> style single-letter suffixes (K, M, etc.)
=item *
'iec': base-2 sizes, with IEC binary suffixes (KiB, MiB, etc.)
=item *
'si': base-10 sizes, with SI decimal suffixes (kB, MB, etc.)
=back
If C<-s> would return C<undef>, C<size_human> returns the empty string.
Current API available since 0.122.
=head2 slurp, slurp_raw, slurp_utf8
$data = path("foo.txt")->slurp;
$data = path("foo.txt")->slurp( {binmode => ":raw"} );
$data = path("foo.txt")->slurp_raw;
$data = path("foo.txt")->slurp_utf8;
Reads file contents into a scalar. Takes an optional hash reference which may
be used to pass options. The only available option is C<binmode>, which is
passed to C<binmode()> on the handle used for reading.
C<slurp_raw> is like C<slurp> with a C<binmode> of C<:unix> for
a fast, unbuffered, raw read.
C<slurp_utf8> is like C<slurp> with a C<binmode> of
C<:unix:encoding(UTF-8)> (or C<:unix:utf8_strict> with
L<PerlIO::utf8_strict>). If L<Unicode::UTF8> 0.58+ is installed, a
unbuffered, raw slurp will be done instead and the result decoded with
C<Unicode::UTF8>. This is just as strict and is roughly an order of
magnitude faster than using C<:encoding(UTF-8)>.
B<Note>: C<slurp> and friends lock the filehandle before slurping. If
you plan to slurp from a file created with L<File::Temp>, be sure to
close other handles or open without locking to avoid a deadlock:
my $tempfile = File::Temp->new(EXLOCK => 0);
my $guts = path($tempfile)->slurp;
See also L</lines> if you want to slurp a file into a line array.
Current API available since 0.004.
=head2 spew, spew_raw, spew_utf8
path("foo.txt")->spew(@data);
path("foo.txt")->spew(\@data);
path("foo.txt")->spew({binmode => ":raw"}, @data);
path("foo.txt")->spew_raw(@data);
path("foo.txt")->spew_utf8(@data);
Writes data to a file atomically. The file is written to a temporary file in
the same directory, then renamed over the original. An optional hash reference
may be used to pass options. The only option is C<binmode>, which is passed to
C<binmode()> on the handle used for writing.
C<spew_raw> is like C<spew> with a C<binmode> of C<:unix> for a fast,
unbuffered, raw write.
C<spew_utf8> is like C<spew> with a C<binmode> of C<:unix:encoding(UTF-8)>
(or C<:unix:utf8_strict> with L<PerlIO::utf8_strict>). If L<Unicode::UTF8>
0.58+ is installed, a raw, unbuffered spew will be done instead on the data
encoded with C<Unicode::UTF8>.
B<NOTE>: because the file is written to a temporary file and then renamed, the
new file will wind up with permissions based on your current umask. This is a
feature to protect you from a race condition that would otherwise give
different permissions than you might expect. If you really want to keep the
original mode flags, use L</append> with the C<truncate> option.
Current API available since 0.011.
=head2 stat, lstat
$stat = path("foo.txt")->stat;
$stat = path("/some/symlink")->lstat;
Like calling C<stat> or C<lstat> from L<File::stat>.
Current API available since 0.001.
=head2 stringify
$path = path("foo.txt");
say $path->stringify; # same as "$path"
Returns a string representation of the path. Unlike C<canonpath>, this method
returns the path standardized with Unix-style C</> directory separators.
Current API available since 0.001.
=head2 subsumes
path("foo/bar")->subsumes("foo/bar/baz"); # true
path("/foo/bar")->subsumes("/foo/baz"); # false
Returns true if the first path is a prefix of the second path at a directory
boundary.
This B<does not> resolve parent directory entries (C<..>) or symlinks:
path("foo/bar")->subsumes("foo/bar/../baz"); # true
If such things are important to you, ensure that both paths are resolved to
the filesystem with C<realpath>:
my $p1 = path("foo/bar")->realpath;
my $p2 = path("foo/bar/../baz")->realpath;
if ( $p1->subsumes($p2) ) { ... }
Current API available since 0.048.
=head2 touch
path("foo.txt")->touch;
path("foo.txt")->touch($epoch_secs);
Like the Unix C<touch> utility. Creates the file if it doesn't exist, or else
changes the modification and access times to the current time. If the first
argument is the epoch seconds then it will be used.
Returns the path object so it can be easily chained with other methods:
# won't die if foo.txt doesn't exist
$content = path("foo.txt")->touch->slurp;
Current API available since 0.015.
=head2 touchpath
path("bar/baz/foo.txt")->touchpath;
Combines C<mkdir> and C<touch>. Creates the parent directory if it doesn't exist,
before touching the file. Returns the path object like C<touch> does.
If you need to pass options, use C<mkdir> and C<touch> separately:
path("bar/baz")->mkdir( \%options )->child("foo.txt")->touch($epoch_secs);
Current API available since 0.022.
=head2 visit
path("/tmp")->visit( \&callback, \%options );
Executes a callback for each child of a directory. It returns a hash
reference with any state accumulated during iteration.
The options are the same as for L</iterator> (which it uses internally):
C<recurse> and C<follow_symlinks>. Both default to false.
The callback function will receive a C<Path::Tiny> object as the first argument
and a hash reference to accumulate state as the second argument. For example:
# collect files sizes
my $sizes = path("/tmp")->visit(
sub {
my ($path, $state) = @_;
return if $path->is_dir;
$state->{$path} = -s $path;
},
{ recurse => 1 }
);
For convenience, the C<Path::Tiny> object will also be locally aliased as the
C<$_> global variable:
# print paths matching /foo/
path("/tmp")->visit( sub { say if /foo/ }, { recurse => 1} );
If the callback returns a B<reference> to a false scalar value, iteration will
terminate. This is not the same as "pruning" a directory search; this just
stops all iteration and returns the state hash reference.
# find up to 10 files larger than 100K
my $files = path("/tmp")->visit(
sub {
my ($path, $state) = @_;
$state->{$path}++ if -s $path > 102400
return \0 if keys %$state == 10;
},
{ recurse => 1 }
);
If you want more flexible iteration, use a module like L<Path::Iterator::Rule>.
Current API available since 0.062.
=head2 volume
$vol = path("/tmp/foo.txt")->volume; # ""
$vol = path("C:/tmp/foo.txt")->volume; # "C:"
Returns the volume portion of the path. This is equivalent
to what L<File::Spec> would give from C<splitpath> and thus
usually is the empty string on Unix-like operating systems or the
drive letter for an absolute path on C<MSWin32>.
Current API available since 0.001.
=for Pod::Coverage openr_utf8 opena_utf8 openw_utf8 openrw_utf8
openr_raw opena_raw openw_raw openrw_raw
IS_WIN32 FREEZE THAW TO_JSON abs2rel
=head1 EXCEPTION HANDLING
Simple usage errors will generally croak. Failures of underlying Perl
functions will be thrown as exceptions in the class
C<Path::Tiny::Error>.
A C<Path::Tiny::Error> object will be a hash reference with the following fields:
=over 4
=item *
C<op> — a description of the operation, usually function call and any extra info
=item *
C<file> — the file or directory relating to the error
=item *
C<err> — hold C<$!> at the time the error was thrown
=item *
C<msg> — a string combining the above data and a Carp-like short stack trace
=back
Exception objects will stringify as the C<msg> field.
=head1 ENVIRONMENT
=head2 PERL_PATH_TINY_NO_FLOCK
If the environment variable C<PERL_PATH_TINY_NO_FLOCK> is set to a true
value then flock will NOT be used when accessing files (this is not
recommended).
=head1 CAVEATS
=head2 Subclassing not supported
For speed, this class is implemented as an array based object and uses many
direct function calls internally. You must not subclass it and expect
things to work properly.
=head2 Tilde expansion (deprecated)
Tilde expansion was a nice idea, but it can't easily be applied consistently
across the entire API. This was a source of bugs and confusion for users.
Therefore, it is B<deprecated> and its use is discouraged. Limitations to the
existing, legacy behavior follow.
Tilde expansion will only occur if the B<first> argument to C<path> begins with
a tilde. B<No other method does tilde expansion on its arguments>. If you want
tilde expansion on arguments, you must explicitly wrap them in a call to
C<path>.
path( "~/foo.txt" )->copy( path( "~/bar.txt" ) );
If you need a literal leading tilde, use C<path("./~whatever")> so that the
argument to C<path> doesn't start with a tilde, but the path still resolves to
the current directory.
Behaviour of tilde expansion with a username for non-existent users depends on
the output of C<glob> on the system.
=head2 File locking
If flock is not supported on a platform, it will not be used, even if
locking is requested.
In situations where a platform normally would support locking, but the
flock fails due to a filesystem limitation, Path::Tiny has some heuristics
to detect this and will warn once and continue in an unsafe mode. If you
want this failure to be fatal, you can fatalize the 'flock' warnings
category:
use warnings FATAL => 'flock';
See additional caveats below.
=head3 NFS and BSD
On BSD, Perl's flock implementation may not work to lock files on an
NFS filesystem. If detected, this situation will warn once, as described
above.
=head3 Lustre
The Lustre filesystem does not support flock. If detected, this situation
will warn once, as described above.
=head3 AIX and locking
AIX requires a write handle for locking. Therefore, calls that normally
open a read handle and take a shared lock instead will open a read-write
handle and take an exclusive lock. If the user does not have write
permission, no lock will be used.
=head2 utf8 vs UTF-8
All the C<*_utf8> methods by default use C<:encoding(UTF-8)> -- either as
C<:unix:encoding(UTF-8)> (unbuffered, for whole file operations) or
C<:raw:encoding(UTF-8)> (buffered, for line-by-line operations). These are
strict against the Unicode spec and disallows illegal Unicode codepoints or
UTF-8 sequences.
Unfortunately, C<:encoding(UTF-8)> is very, very slow. If you install
L<Unicode::UTF8> 0.58 or later, that module will be used by some C<*_utf8>
methods to encode or decode data after a raw, binary input/output operation,
which is much faster. Alternatively, if you install L<PerlIO::utf8_strict>,
that will be used instead of C<:encoding(UTF-8)> and is also very fast.
If you need the performance and can accept the security risk,
C<< slurp({binmode => ":unix:utf8"}) >> will be faster than C<:unix:encoding(UTF-8)>
(but not as fast as C<Unicode::UTF8>).
Note that the C<*_utf8> methods read in B<raw> mode. There is no CRLF
translation on Windows. If you must have CRLF translation, use the regular
input/output methods with an appropriate binmode:
$path->spew_utf8($data); # raw
$path->spew({binmode => ":encoding(UTF-8)"}, $data; # LF -> CRLF
=head2 Default IO layers and the open pragma
If you have Perl 5.10 or later, file input/output methods (C<slurp>, C<spew>,
etc.) and high-level handle opening methods ( C<filehandle>, C<openr>,
C<openw>, etc. ) respect default encodings set by the C<-C> switch or lexical
L<open> settings of the caller. For UTF-8, this is almost certainly slower
than using the dedicated C<_utf8> methods if you have L<Unicode::UTF8> or
L<PerlIP::utf8_strict>.
=head1 TYPE CONSTRAINTS AND COERCION
A standard L<MooseX::Types> library is available at
L<MooseX::Types::Path::Tiny>. A L<Type::Tiny> equivalent is available as
L<Types::Path::Tiny>.
=head1 SEE ALSO
These are other file/path utilities, which may offer a different feature
set than C<Path::Tiny>.
=over 4
=item *
L<File::chmod>
=item *
L<File::Fu>
=item *
L<IO::All>
=item *
L<Path::Class>
=back
These iterators may be slightly faster than the recursive iterator in
C<Path::Tiny>:
=over 4
=item *
L<Path::Iterator::Rule>
=item *
L<File::Next>
=back
There are probably comparable, non-Tiny tools. Let me know if you want me to
add a module to the list.
This module was featured in the L<2013 Perl Advent Calendar|http://www.perladvent.org/2013/2013-12-18.html>.
=for :stopwords cpan testmatrix url bugtracker rt cpants kwalitee diff irc mailto metadata placeholders metacpan
=head1 SUPPORT
=head2 Bugs / Feature Requests
Please report any bugs or feature requests through the issue tracker
at L<https://github.com/dagolden/Path-Tiny/issues>.
You will be notified automatically of any progress on your issue.
=head2 Source Code
This is open source software. The code repository is available for
public review and contribution under the terms of the license.
L<https://github.com/dagolden/Path-Tiny>
git clone https://github.com/dagolden/Path-Tiny.git
=head1 AUTHOR
David Golden <dagolden@cpan.org>
=head1 CONTRIBUTORS
=for stopwords Alex Efros Aristotle Pagaltzis Chris Williams Dan Book Dave Rolsky David Steinbrunner Doug Bell Elvin Aslanov Flavio Poletti Gabor Szabo Gabriel Andrade George Hartzell Geraud Continsouzas Goro Fuji Graham Knop Ollis Ian Sillitoe James Hunt John Karr Karen Etheridge Mark Ellis Martin H. Sluka Kjeldsen Mary Ehlers Michael G. Schwern NATARAJ (Nikolay Shaplov) Nicolas R Rochelemagne Nigel Gregoire Philippe Bruhat (BooK) regina-verbae Ricardo Signes Roy Ivy III Shlomi Fish Smylers Tatsuhiko Miyagawa Toby Inkster Yanick Champoux yoshikazusawa 김도형 - Keedi Kim
=over 4
=item *
Alex Efros <powerman@powerman.name>
=item *
Aristotle Pagaltzis <pagaltzis@gmx.de>
=item *
Chris Williams <bingos@cpan.org>
=item *
Dan Book <grinnz@grinnz.com>
=item *
Dave Rolsky <autarch@urth.org>
=item *
David Steinbrunner <dsteinbrunner@pobox.com>
=item *
Doug Bell <madcityzen@gmail.com>
=item *
Elvin Aslanov <rwp.primary@gmail.com>
=item *
Flavio Poletti <flavio@polettix.it>
=item *
Gabor Szabo <szabgab@cpan.org>
=item *
Gabriel Andrade <gabiruh@gmail.com>
=item *
George Hartzell <hartzell@cpan.org>
=item *
Geraud Continsouzas <geraud@scsi.nc>
=item *
Goro Fuji <gfuji@cpan.org>
=item *
Graham Knop <haarg@haarg.org>
=item *
Graham Ollis <plicease@cpan.org>
=item *
Ian Sillitoe <ian@sillit.com>
=item *
James Hunt <james@niftylogic.com>
=item *
John Karr <brainbuz@brainbuz.org>
=item *
Karen Etheridge <ether@cpan.org>
=item *
Mark Ellis <mark.ellis@cartridgesave.co.uk>
=item *
Martin H. Sluka <fany@cpan.org>
=item *
Martin Kjeldsen <mk@bluepipe.dk>
=item *
Martin Sluka <martin@sluka.de>
=item *
Mary Ehlers <regina.verb.ae@gmail.com>
=item *
Michael G. Schwern <mschwern@cpan.org>
=item *
NATARAJ (Nikolay Shaplov) <dhyan@nataraj.su>
=item *
Nicolas R <nicolas@atoomic.org>
=item *
Nicolas Rochelemagne <rochelemagne@cpanel.net>
=item *
Nigel Gregoire <nigelgregoire@gmail.com>
=item *
Philippe Bruhat (BooK) <book@cpan.org>
=item *
regina-verbae <regina-verbae@users.noreply.github.com>
=item *
Ricardo Signes <rjbs@semiotic.systems>
=item *
Roy Ivy III <rivy@cpan.org>
=item *
Shlomi Fish <shlomif@shlomifish.org>
=item *
Smylers <Smylers@stripey.com>
=item *
Tatsuhiko Miyagawa <miyagawa@bulknews.net>
=item *
Toby Inkster <tobyink@cpan.org>
=item *
Yanick Champoux <yanick@babyl.dyndns.org>
=item *
yoshikazusawa <883514+yoshikazusawa@users.noreply.github.com>
=item *
김도형 - Keedi Kim <keedi@cpan.org>
=back
=head1 COPYRIGHT AND LICENSE
This software is Copyright (c) 2014 by David Golden.
This is free software, licensed under:
The Apache License, Version 2.0, January 2004
=cut
PK 1N%[!�<� � perl5/Path/Class.pmnu ��6�$ use strict;
package Path::Class;
{
$Path::Class::VERSION = '0.37';
}
{
## no critic
no strict 'vars';
@ISA = qw(Exporter);
@EXPORT = qw(file dir);
@EXPORT_OK = qw(file dir foreign_file foreign_dir tempdir);
}
use Exporter;
use Path::Class::File;
use Path::Class::Dir;
use File::Temp ();
sub file { Path::Class::File->new(@_) }
sub dir { Path::Class::Dir ->new(@_) }
sub foreign_file { Path::Class::File->new_foreign(@_) }
sub foreign_dir { Path::Class::Dir ->new_foreign(@_) }
sub tempdir { Path::Class::Dir->new(File::Temp::tempdir(@_)) }
1;
__END__
=head1 NAME
Path::Class - Cross-platform path specification manipulation
=head1 VERSION
version 0.37
=head1 SYNOPSIS
use Path::Class;
my $dir = dir('foo', 'bar'); # Path::Class::Dir object
my $file = file('bob', 'file.txt'); # Path::Class::File object
# Stringifies to 'foo/bar' on Unix, 'foo\bar' on Windows, etc.
print "dir: $dir\n";
# Stringifies to 'bob/file.txt' on Unix, 'bob\file.txt' on Windows
print "file: $file\n";
my $subdir = $dir->subdir('baz'); # foo/bar/baz
my $parent = $subdir->parent; # foo/bar
my $parent2 = $parent->parent; # foo
my $dir2 = $file->dir; # bob
# Work with foreign paths
use Path::Class qw(foreign_file foreign_dir);
my $file = foreign_file('Mac', ':foo:file.txt');
print $file->dir; # :foo:
print $file->as_foreign('Win32'); # foo\file.txt
# Interact with the underlying filesystem:
# $dir_handle is an IO::Dir object
my $dir_handle = $dir->open or die "Can't read $dir: $!";
# $file_handle is an IO::File object
my $file_handle = $file->open($mode) or die "Can't read $file: $!";
=head1 DESCRIPTION
C<Path::Class> is a module for manipulation of file and directory
specifications (strings describing their locations, like
C<'/home/ken/foo.txt'> or C<'C:\Windows\Foo.txt'>) in a cross-platform
manner. It supports pretty much every platform Perl runs on,
including Unix, Windows, Mac, VMS, Epoc, Cygwin, OS/2, and NetWare.
The well-known module L<File::Spec> also provides this service, but
it's sort of awkward to use well, so people sometimes avoid it, or use
it in a way that won't actually work properly on platforms
significantly different than the ones they've tested their code on.
In fact, C<Path::Class> uses C<File::Spec> internally, wrapping all
the unsightly details so you can concentrate on your application code.
Whereas C<File::Spec> provides functions for some common path
manipulations, C<Path::Class> provides an object-oriented model of the
world of path specifications and their underlying semantics.
C<File::Spec> doesn't create any objects, and its classes represent
the different ways in which paths must be manipulated on various
platforms (not a very intuitive concept). C<Path::Class> creates
objects representing files and directories, and provides methods that
relate them to each other. For instance, the following C<File::Spec>
code:
my $absolute = File::Spec->file_name_is_absolute(
File::Spec->catfile( @dirs, $file )
);
can be written using C<Path::Class> as
my $absolute = Path::Class::File->new( @dirs, $file )->is_absolute;
or even as
my $absolute = file( @dirs, $file )->is_absolute;
Similar readability improvements should happen all over the place when
using C<Path::Class>.
Using C<Path::Class> can help solve real problems in your code too -
for instance, how many people actually take the "volume" (like C<C:>
on Windows) into account when writing C<File::Spec>-using code? I
thought not. But if you use C<Path::Class>, your file and directory objects
will know what volumes they refer to and do the right thing.
The guts of the C<Path::Class> code live in the L<Path::Class::File>
and L<Path::Class::Dir> modules, so please see those
modules' documentation for more details about how to use them.
=head2 EXPORT
The following functions are exported by default.
=over 4
=item file
A synonym for C<< Path::Class::File->new >>.
=item dir
A synonym for C<< Path::Class::Dir->new >>.
=back
If you would like to prevent their export, you may explicitly pass an
empty list to perl's C<use>, i.e. C<use Path::Class ()>.
The following are exported only on demand.
=over 4
=item foreign_file
A synonym for C<< Path::Class::File->new_foreign >>.
=item foreign_dir
A synonym for C<< Path::Class::Dir->new_foreign >>.
=item tempdir
Create a new Path::Class::Dir instance pointed to temporary directory.
my $temp = Path::Class::tempdir(CLEANUP => 1);
A synonym for C<< Path::Class::Dir->new(File::Temp::tempdir(@_)) >>.
=back
=head1 Notes on Cross-Platform Compatibility
Although it is much easier to write cross-platform-friendly code with
this module than with C<File::Spec>, there are still some issues to be
aware of.
=over 4
=item *
On some platforms, notably VMS and some older versions of DOS (I think),
all filenames must have an extension. Thus if you create a file
called F<foo/bar> and then ask for a list of files in the directory
F<foo>, you may find a file called F<bar.> instead of the F<bar> you
were expecting. Thus it might be a good idea to use an extension in
the first place.
=back
=head1 AUTHOR
Ken Williams, KWILLIAMS@cpan.org
=head1 COPYRIGHT
Copyright (c) Ken Williams. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
=head1 SEE ALSO
L<Path::Class::Dir>, L<Path::Class::File>, L<File::Spec>
=cut
PK 1N%[(�*�A �A perl5/alienfile.pmnu ��6�$ package alienfile;
use strict;
use warnings;
use 5.008004;
use Alien::Build;
use Exporter ();
use Path::Tiny ();
use Carp ();
sub _path { Path::Tiny::path(@_) }
# ABSTRACT: Specification for defining an external dependency for CPAN
our $VERSION = '2.84'; # VERSION
our @EXPORT = qw( requires on plugin probe configure share sys download fetch decode prefer extract patch patch_ffi build build_ffi gather gather_ffi meta_prop ffi log test start_url before after digest );
sub requires
{
my($module, $version) = @_;
$version ||= 0;
my $caller = caller;
my $meta = $caller->meta;
$meta->add_requires($meta->{phase}, $module, $version);
();
}
sub plugin
{
my($name, @args) = @_;
my $caller = caller;
$caller->meta->apply_plugin($name, @args);
return;
}
sub probe
{
my($instr) = @_;
my $caller = caller;
if(my $phase = $caller->meta->{phase})
{
Carp::croak "probe must not be in a $phase block" if $phase ne 'any';
}
$caller->meta->register_hook(probe => $instr);
return;
}
sub _phase
{
my($code, $phase) = @_;
my $caller = caller(1);
my $meta = $caller->meta;
local $meta->{phase} = $phase;
$code->();
return;
}
sub configure (&)
{
_phase($_[0], 'configure');
}
sub sys (&)
{
_phase($_[0], 'system');
}
sub share (&)
{
_phase($_[0], 'share');
}
sub _in_phase
{
my($phase) = @_;
my $caller = caller(1);
my(undef, undef, undef, $sub) = caller(1);
my $meta = $caller->meta;
$sub =~ s/^.*:://;
Carp::croak "$sub must be in a $phase block"
unless $meta->{phase} eq $phase;
}
sub start_url
{
my($url) = @_;
_in_phase 'share';
my $caller = caller;
my $meta = $caller->meta;
$meta->prop->{start_url} = $url;
$meta->add_requires('configure' => 'Alien::Build' => '1.19');
return;
}
sub digest
{
my($algo, $digest) = @_;
my $caller = caller;
$caller->meta->apply_plugin('Digest', [$algo, $digest]);
return;
}
sub download
{
my($instr) = @_;
_in_phase 'share';
my $caller = caller;
$caller->meta->register_hook(download => $instr);
return;
}
sub fetch
{
my($instr) = @_;
_in_phase 'share';
my $caller = caller;
$caller->meta->register_hook(fetch => $instr);
return;
}
sub decode
{
my($instr) = @_;
_in_phase 'share';
my $caller = caller;
$caller->meta->register_hook(decode => $instr);
return;
}
sub prefer
{
my($instr) = @_;
_in_phase 'share';
my $caller = caller;
$caller->meta->register_hook(prefer => $instr);
return;
}
sub extract
{
my($instr) = @_;
_in_phase 'share';
my $caller = caller;
$caller->meta->register_hook(extract => $instr);
return;
}
sub patch
{
my($instr) = @_;
_in_phase 'share';
my $caller = caller;
my $suffix = $caller->meta->{build_suffix};
$caller->meta->register_hook("patch$suffix" => $instr);
return;
}
sub patch_ffi
{
my($instr) = @_;
Carp::carp("patch_ffi is deprecated, use ffi { patch ... } } instead");
_in_phase 'share';
my $caller = caller;
$caller->meta->register_hook(patch_ffi => $instr);
return;
}
sub build
{
my($instr) = @_;
_in_phase 'share';
my $caller = caller;
my $suffix = $caller->meta->{build_suffix};
$caller->meta->register_hook("build$suffix" => $instr);
return;
}
sub build_ffi
{
my($instr) = @_;
Carp::carp("build_ffi is deprecated, use ffi { build ... } } instead");
_in_phase 'share';
my $caller = caller;
$caller->meta->register_hook(build_ffi => $instr);
return;
}
sub gather
{
my($instr) = @_;
my $caller = caller;
my $meta = $caller->meta;
my $phase = $meta->{phase};
Carp::croak "gather is not allowed in configure block"
if $phase eq 'configure';
my $suffix = $caller->meta->{build_suffix};
if($suffix eq '_ffi')
{
$meta->register_hook(gather_ffi => $instr)
}
else
{
$meta->register_hook(gather_system => $instr) if $phase =~ /^(any|system)$/;
$meta->register_hook(gather_share => $instr) if $phase =~ /^(any|share)$/;
}
return;
}
sub gather_ffi
{
my($instr) = @_;
Carp::carp("gather_ffi is deprecated, use ffi { gather ... } } instead");
_in_phase 'share';
my $caller = caller;
$caller->meta->register_hook(gather_ffi => $instr);
return;
}
sub ffi (&)
{
my($code) = @_;
_in_phase 'share';
my $caller = caller;
local $caller->meta->{build_suffix} = '_ffi';
$code->();
return;
}
sub meta_prop
{
my $caller = caller;
my $meta = $caller->meta;
$meta->prop;
}
sub log
{
unshift @_, 'Alien::Build';
goto &Alien::Build::log;
}
sub test
{
my($instr) = @_;
my $caller = caller;
my $meta = $caller->meta;
my $phase = $meta->{phase};
Carp::croak "test is not allowed in $phase block"
if $phase eq 'any' || $phase eq 'configure';
$meta->add_requires('configure' => 'Alien::Build' => '1.14');
if($phase eq 'share')
{
my $suffix = $caller->meta->{build_suffix} || '_share';
$meta->register_hook(
"test$suffix" => $instr,
);
}
elsif($phase eq 'system')
{
$meta->register_hook(
"test_system" => $instr,
);
}
else
{
die "unknown phase: $phase";
}
}
my %modifiers = (
probe => { any => 'probe' },
download => { share => 'download' },
fetch => { share => 'fetch' },
decode => { share => 'fetch' },
prefer => { share => 'prefer' },
extract => { share => 'extract' },
patch => { share => 'patch$' },
build => { share => 'build$' },
test => { share => 'test$' },
# Note: below special case gather_ffi for the ffi block :P
gather => { share => 'gather_share', system => 'gather_system', any => 'gather_share,gather_system' },
);
sub _add_modifier
{
my($type, $stage, $sub) = @_;
my $method = "${type}_hook";
Carp::croak "No such stage $stage" unless defined $modifiers{$stage};
Carp::croak "$type $stage argument must be a code reference" unless defined $sub && ref($sub) eq 'CODE';
my $caller = caller;
my $meta = $caller->meta;
Carp::croak "$type $stage is not allowed in sys block" unless defined $modifiers{$stage}->{$meta->{phase}};
$meta->add_requires('configure' => 'Alien::Build' => '1.40');
my $suffix = $meta->{build_suffix};
if($suffix eq '_ffi' && $stage eq 'gather')
{
$meta->$method('gather_ffi' => $sub);
}
foreach my $hook (
map { split /,/, $_ } # split on , for when multiple hooks must be attached (gather in any)
map { my $x = $_ ; $x =~ s/\$/$suffix/; $x } # substitute $ at the end for a suffix (_ffi) if any
$modifiers{$stage}->{$meta->{phase}}) # get the list of modifiers
{
$meta->$method($hook => $sub);
}
return;
}
sub before
{
my($stage, $sub) = @_;
@_ = ('before', @_);
goto &alienfile::_add_modifier;
}
sub after
{
my($stage, $sub) = @_;
@_ = ('after', @_);
goto &alienfile::_add_modifier;
}
sub import
{
strict->import;
warnings->import;
goto &Exporter::import;
}
1;
__END__
=pod
=encoding UTF-8
=head1 NAME
alienfile - Specification for defining an external dependency for CPAN
=head1 VERSION
version 2.84
=head1 SYNOPSIS
Do-it-yourself approach:
use alienfile;
probe [ 'pkg-config --exists libarchive' ];
share {
start_url 'http://libarchive.org/downloads/libarchive-3.2.2.tar.gz';
# the first one which succeeds will be used
download [ 'wget %{.meta.start_url}' ];
download [ 'curl -o %{.meta.start_url}' ];
extract [ 'tar xf %{.install.download}' ];
build [
# Note: will not work on Windows, better to use Build::Autoconf plugin
# if you need windows support
'./configure --prefix=%{.install.prefix} --disable-shared',
'%{make}',
'%{make} install',
];
}
gather [
[ 'pkg-config', '--modversion', 'libarchive', \'%{.runtime.version}' ],
[ 'pkg-config', '--cflags', 'libarchive', \'%{.runtime.cflags}' ],
[ 'pkg-config', '--libs', 'libarchive', \'%{.runtime.libs}' ],
];
With plugins (better):
use alienfile;
plugin 'PkgConfig' => 'libarchive';
share {
start_url 'http://libarchive.org/downloads/';
plugin Download => (
filter => qr/^libarchive-.*\.tar\.gz$/,
version => qr/([0-9\.]+)/,
);
plugin Extract => 'tar.gz';
plugin 'Build::Autoconf';
plugin 'Gather::IsolateDynamic';
build [
'%{configure}',
'%{make}',
'%{make} install',
];
};
=head1 DESCRIPTION
An alienfile is a recipe used by L<Alien::Build> to, probe for system libraries or download from the internet, and build source
for those libraries. This document acts as reference for the alienfile system, but if you are starting out writing your own Alien
you should read L<Alien::Build::Manual::AlienAuthor>, which will teach you how to write your own complete Alien using alienfile +
L<Alien::Build> + L<ExtUtils::MakeMaker>. Special attention should be taken to the section "a note about dynamic vs. static
libraries".
=head1 DIRECTIVES
=head2 requires
"any" requirement (either share or system):
requires $module;
requires $module => $version;
configure time requirement:
configure {
requires $module;
requires $module => $version;
};
system requirement:
sys {
requires $module;
requires $module => $version;
};
share requirement:
share {
requires $module;
requires $module => $version;
};
specifies a requirement. L<Alien::Build> takes advantage of dynamic requirements, so only
modules that are needed for the specific type of install need to be loaded. Here are the
different types of requirements:
=over
=item configure
Configure requirements should already be installed before the alienfile is loaded.
=item any
"Any" requirements are those that are needed either for the probe stage, or in either the
system or share installs.
=item share
Share requirements are those modules needed when downloading and building from source.
=item system
System requirements are those modules needed when the system provides the library or tool.
=back
=head2 plugin
plugin $name => (%args);
plugin $name => $arg;
Load the given plugin. If you prefix the plugin name with an C<=> sign,
then it will be assumed to be a fully qualified path name. Otherwise the
plugin will be assumed to live in the C<Alien::Build::Plugin> namespace.
If there is an appropriate negotiate plugin, that one will be loaded.
Examples:
# Loads Alien::Build::Plugin::Fetch::Negotiate
# which will pick the best Alien::Build::Plugin::Fetch
# plugin based on the URL, and system configuration
plugin 'Fetch' => 'http://ftp.gnu.org/gnu/gcc';
# loads the plugin with the badly named class!
plugin '=Badly::Named::Plugin::Not::In::Alien::Build::Namespace';
# explicitly loads Alien::Build::Plugin::Prefer::SortVersions
plugin 'Prefer::SortVersions' => (
filter => qr/^gcc-.*\.tar\.gz$/,
version => qr/([0-9\.]+)/,
);
=head2 probe
probe \&code;
probe \@commandlist;
Instructions for the probe stage. May be either a code reference, or a command list.
Multiple probes and probe plugins can be given. These will be used in sequence,
stopping at the first that detects a system installation. L<Alien::Build> will use
a share install if no system installation is detected by the probes.
=head2 configure
configure {
...
};
Configure block. The only directive allowed in a configure block is
requires.
=head2 sys
sys {
...
};
System block. Allowed directives are: requires and gather.
=head2 share
share {
...
};
System block. Allowed directives are: download, fetch, decode, prefer, extract, build, gather.
=head2 start_url
share {
start_url $url;
};
Set the start URL for download. This should be the URL to an index page, or the actual tarball of the source.
=head2 digest
[experimental]
share {
digest $algorithm, $digest;
};
Check fetched and downloaded files against the given algorithm and
digest. Typically you will want to use SHA256 as the algorithm.
=head2 download
share {
download \&code;
download \@commandlist;
};
Instructions for the download stage. May be either a
code reference, or a command list.
=head2 fetch
share {
fetch \&code;
fetch \@commandlist;
};
Instructions for the fetch stage. May be either a
code reference, or a command list.
=head2 decode
share {
decode \&code;
decode \@commandlist;
};
Instructions for the decode stage. May be either a
code reference, or a command list.
=head2 prefer
share {
prefer \&code;
prefer \@commandlist;
};
Instructions for the prefer stage. May be either a
code reference, or a command list.
=head2 extract
share {
extract \&code;
extract \@commandlist;
};
Instructions for the extract stage. May be either a
code reference, or a command list.
=head2 patch
share {
patch \&code;
patch \@commandlist;
};
Instructions for the patch stage. May be either a
code reference, or a command list.
=head2 patch_ffi
share {
patch_ffi \&code;
patch_ffi \@commandlist;
};
[DEPRECATED]
Instructions for the patch_ffi stage. May be either a
code reference, or a command list.
=head2 build
share {
build \&code;
build \@commandlist;
};
Instructions for the build stage. May be either a
code reference, or a command list.
=head2 build_ffi
share {
build \&code;
build \@commandlist;
};
[DEPRECATED]
Instructions for the build FFI stage. Builds shared libraries instead of static.
This is optional, and is only necessary if a fresh and separate build needs to be
done for FFI.
=head2 gather
gather \&code;
gather \@commandlist;
share {
gather \&code;
gather \@commandlist;
};
sys {
gather \&code;
gather \@commandlist;
};
Instructions for the gather stage. May be either a code reference, or a command list.
In the root block of the alienfile it will trigger in both share and system build.
In the share or sys block it will only trigger in the corresponding build.
=head2 gather_ffi
share {
gather_ffi \&code;
gather_ffi \@commandlist;
}
[DEPRECATED]
Gather specific to C<build_ffi>. Not usually necessary.
=head2 ffi
share {
ffi {
patch \&code;
patch \@commandlist;
build \&code;
build \@commandlist;
gather \&code;
gather \@commandlist;
}
}
Specify patch, build or gather stages related to FFI.
=head2 meta_prop
my $hash = meta_prop;
Get the meta_prop hash reference.
=head2 meta
my $meta = meta;
Returns the meta object for your L<alienfile>. For methods that can be used on the
meta object, see L<Alien::Build/"META METHODS">.
=head2 log
log($message);
Prints the given log to stdout.
=head2 test
share {
test \&code;
test \@commandlist;
};
sys {
test \&code;
test \@commandlist;
};
Run the tests
=head2 before
before $stage => \&code;
Execute the given code before the given stage. Stage should be one of
C<probe>, C<download>, C<fetch>, C<decode>, C<prefer>, C<extract>,
C<patch>, C<build>, C<test>, and C<gather>.
The before directive is only legal in the same blocks as the stage would
normally be legal in. For example, you can't do this:
use alienfile;
sys {
before 'build' => sub {
...
};
};
Because a C<build> wouldn't be legal inside a C<sys> block.
=head2 after
after $stage => \&code;
Execute the given code after the given stage. Stage should be one of
C<probe>, C<download>, C<fetch>, C<decode>, C<prefer>, C<extract>,
C<patch>, C<build>, C<test>, and C<gather>.
The after directive is only legal in the same blocks as the stage would
normally be legal in. For example, you can't do this:
use alienfile;
sys {
after 'build' => sub {
...
};
};
Because a C<build> wouldn't be legal inside a C<sys> block.
=head1 SEE ALSO
=over 4
=item L<Alien>
=item L<Alien::Build>
=item L<Alien::Build::MM>
=item L<Alien::Base>
=back
=head1 AUTHOR
Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>
Contributors:
Diab Jerius (DJERIUS)
Roy Storey (KIWIROY)
Ilya Pavlov
David Mertens (run4flat)
Mark Nunberg (mordy, mnunberg)
Christian Walde (Mithaldu)
Brian Wightman (MidLifeXis)
Zaki Mughal (zmughal)
mohawk (mohawk2, ETJ)
Vikas N Kumar (vikasnkumar)
Flavio Poletti (polettix)
Salvador Fandiño (salva)
Gianni Ceccarelli (dakkar)
Pavel Shaydo (zwon, trinitum)
Kang-min Liu (劉康民, gugod)
Nicholas Shipp (nshp)
Juan Julián Merelo Guervós (JJ)
Joel Berger (JBERGER)
Petr Písař (ppisar)
Lance Wicks (LANCEW)
Ahmad Fatoum (a3f, ATHREEF)
José Joaquín Atria (JJATRIA)
Duke Leto (LETO)
Shoichi Kaji (SKAJI)
Shawn Laffan (SLAFFAN)
Paul Evans (leonerd, PEVANS)
Håkon Hægland (hakonhagland, HAKONH)
nick nauwelaerts (INPHOBIA)
Florian Weimer
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2011-2022 by Graham Ollis.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut
PK 1N%[���va va perl5/lwptut.podnu ��6�$ =head1 NAME
lwptut -- An LWP Tutorial
=head1 DESCRIPTION
LWP (short for "Library for WWW in Perl") is a very popular group of
Perl modules for accessing data on the Web. Like most Perl
module-distributions, each of LWP's component modules comes with
documentation that is a complete reference to its interface. However,
there are so many modules in LWP that it's hard to know where to start
looking for information on how to do even the simplest most common
things.
Really introducing you to using LWP would require a whole book -- a book
that just happens to exist, called I<Perl & LWP>. But this article
should give you a taste of how you can go about some common tasks with
LWP.
=head2 Getting documents with LWP::Simple
If you just want to get what's at a particular URL, the simplest way
to do it is LWP::Simple's functions.
In a Perl program, you can call its C<get($url)> function. It will try
getting that URL's content. If it works, then it'll return the
content; but if there's some error, it'll return undef.
my $url = 'http://www.npr.org/programs/fa/?todayDate=current';
# Just an example: the URL for the most recent /Fresh Air/ show
use LWP::Simple;
my $content = get $url;
die "Couldn't get $url" unless defined $content;
# Then go do things with $content, like this:
if($content =~ m/jazz/i) {
print "They're talking about jazz today on Fresh Air!\n";
}
else {
print "Fresh Air is apparently jazzless today.\n";
}
The handiest variant on C<get> is C<getprint>, which is useful in Perl
one-liners. If it can get the page whose URL you provide, it sends it
to STDOUT; otherwise it complains to STDERR.
% perl -MLWP::Simple -e "getprint 'http://www.cpan.org/RECENT'"
That is the URL of a plain text file that lists new files in CPAN in
the past two weeks. You can easily make it part of a tidy little
shell command, like this one that mails you the list of new
C<Acme::> modules:
% perl -MLWP::Simple -e "getprint 'http://www.cpan.org/RECENT'" \
| grep "/by-module/Acme" | mail -s "New Acme modules! Joy!" $USER
There are other useful functions in LWP::Simple, including one function
for running a HEAD request on a URL (useful for checking links, or
getting the last-revised time of a URL), and two functions for
saving/mirroring a URL to a local file. See L<the LWP::Simple
documentation|LWP::Simple> for the full details, or chapter 2 of I<Perl
& LWP> for more examples.
=for comment
##########################################################################
=head2 The Basics of the LWP Class Model
LWP::Simple's functions are handy for simple cases, but its functions
don't support cookies or authorization, don't support setting header
lines in the HTTP request, generally don't support reading header lines
in the HTTP response (notably the full HTTP error message, in case of an
error). To get at all those features, you'll have to use the full LWP
class model.
While LWP consists of dozens of classes, the main two that you have to
understand are L<LWP::UserAgent> and L<HTTP::Response>. LWP::UserAgent
is a class for "virtual browsers" which you use for performing requests,
and L<HTTP::Response> is a class for the responses (or error messages)
that you get back from those requests.
The basic idiom is C<< $response = $browser->get($url) >>, or more fully
illustrated:
# Early in your program:
use LWP 5.64; # Loads all important LWP classes, and makes
# sure your version is reasonably recent.
my $browser = LWP::UserAgent->new;
...
# Then later, whenever you need to make a get request:
my $url = 'http://www.npr.org/programs/fa/?todayDate=current';
my $response = $browser->get( $url );
die "Can't get $url -- ", $response->status_line
unless $response->is_success;
die "Hey, I was expecting HTML, not ", $response->content_type
unless $response->content_type eq 'text/html';
# or whatever content-type you're equipped to deal with
# Otherwise, process the content somehow:
if($response->decoded_content =~ m/jazz/i) {
print "They're talking about jazz today on Fresh Air!\n";
}
else {
print "Fresh Air is apparently jazzless today.\n";
}
There are two objects involved: C<$browser>, which holds an object of
class LWP::UserAgent, and then the C<$response> object, which is of
class HTTP::Response. You really need only one browser object per
program; but every time you make a request, you get back a new
HTTP::Response object, which will have some interesting attributes:
=over
=item *
A status code indicating
success or failure
(which you can test with C<< $response->is_success >>).
=item *
An HTTP status
line that is hopefully informative if there's failure (which you can
see with C<< $response->status_line >>,
returning something like "404 Not Found").
=item *
A MIME content-type like "text/html", "image/gif",
"application/xml", etc., which you can see with
C<< $response->content_type >>
=item *
The actual content of the response, in C<< $response->decoded_content >>.
If the response is HTML, that's where the HTML source will be; if
it's a GIF, then C<< $response->decoded_content >> will be the binary
GIF data.
=item *
And dozens of other convenient and more specific methods that are
documented in the docs for L<HTTP::Response>, and its superclasses
L<HTTP::Message> and L<HTTP::Headers>.
=back
=for comment
##########################################################################
=head2 Adding Other HTTP Request Headers
The most commonly used syntax for requests is C<< $response =
$browser->get($url) >>, but in truth, you can add extra HTTP header
lines to the request by adding a list of key-value pairs after the URL,
like so:
$response = $browser->get( $url, $key1, $value1, $key2, $value2, ... );
For example, here's how to send some commonly used headers, in case
you're dealing with a site that would otherwise reject your request:
my @ns_headers = (
'User-Agent' => 'Mozilla/4.76 [en] (Win98; U)',
'Accept' => 'image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*',
'Accept-Charset' => 'iso-8859-1,*,utf-8',
'Accept-Language' => 'en-US',
);
...
$response = $browser->get($url, @ns_headers);
If you weren't reusing that array, you could just go ahead and do this:
$response = $browser->get($url,
'User-Agent' => 'Mozilla/4.76 [en] (Win98; U)',
'Accept' => 'image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*',
'Accept-Charset' => 'iso-8859-1,*,utf-8',
'Accept-Language' => 'en-US',
);
If you were only ever changing the 'User-Agent' line, you could just change
the C<$browser> object's default line from "libwww-perl/5.65" (or the like)
to whatever you like, using the LWP::UserAgent C<agent> method:
$browser->agent('Mozilla/4.76 [en] (Win98; U)');
=for comment
##########################################################################
=head2 Enabling Cookies
A default LWP::UserAgent object acts like a browser with its cookies
support turned off. There are various ways of turning it on, by setting
its C<cookie_jar> attribute. A "cookie jar" is an object representing
a little database of all
the HTTP cookies that a browser knows about. It can correspond to a
file on disk or
an in-memory object that starts out empty, and whose collection of
cookies will disappear once the program is finished running.
To give a browser an in-memory empty cookie jar, you set its C<cookie_jar>
attribute like so:
use HTTP::CookieJar::LWP;
$browser->cookie_jar( HTTP::CookieJar::LWP->new );
To save a cookie jar to disk, see L<< HTTP::CookieJar/dump_cookies >>.
To load cookies from disk into a jar, see L<<
HTTP::CookieJar/load_cookies >>.
=for comment
##########################################################################
=head2 Posting Form Data
Many HTML forms send data to their server using an HTTP POST request, which
you can send with this syntax:
$response = $browser->post( $url,
[
formkey1 => value1,
formkey2 => value2,
...
],
);
Or if you need to send HTTP headers:
$response = $browser->post( $url,
[
formkey1 => value1,
formkey2 => value2,
...
],
headerkey1 => value1,
headerkey2 => value2,
);
For example, the following program makes a search request to AltaVista
(by sending some form data via an HTTP POST request), and extracts from
the HTML the report of the number of matches:
use strict;
use warnings;
use LWP 5.64;
my $browser = LWP::UserAgent->new;
my $word = 'tarragon';
my $url = 'http://search.yahoo.com/yhs/search';
my $response = $browser->post( $url,
[ 'q' => $word, # the Altavista query string
'fr' => 'altavista', 'pg' => 'q', 'avkw' => 'tgz', 'kl' => 'XX',
]
);
die "$url error: ", $response->status_line
unless $response->is_success;
die "Weird content type at $url -- ", $response->content_type
unless $response->content_is_html;
if( $response->decoded_content =~ m{([0-9,]+)(?:<.*?>)? results for} ) {
# The substring will be like "996,000</strong> results for"
print "$word: $1\n";
}
else {
print "Couldn't find the match-string in the response\n";
}
=for comment
##########################################################################
=head2 Sending GET Form Data
Some HTML forms convey their form data not by sending the data
in an HTTP POST request, but by making a normal GET request with
the data stuck on the end of the URL. For example, if you went to
C<www.imdb.com> and ran a search on "Blade Runner", the URL you'd see
in your browser window would be:
http://www.imdb.com/find?s=all&q=Blade+Runner
To run the same search with LWP, you'd use this idiom, which involves
the URI class:
use URI;
my $url = URI->new( 'http://www.imdb.com/find' );
# makes an object representing the URL
$url->query_form( # And here the form data pairs:
'q' => 'Blade Runner',
's' => 'all',
);
my $response = $browser->get($url);
See chapter 5 of I<Perl & LWP> for a longer discussion of HTML forms
and of form data, and chapters 6 through 9 for a longer discussion of
extracting data from HTML.
=head2 Absolutizing URLs
The URI class that we just mentioned above provides all sorts of methods
for accessing and modifying parts of URLs (such as asking sort of URL it
is with C<< $url->scheme >>, and asking what host it refers to with C<<
$url->host >>, and so on, as described in L<the docs for the URI
class|URI>. However, the methods of most immediate interest
are the C<query_form> method seen above, and now the C<new_abs> method
for taking a probably-relative URL string (like "../foo.html") and getting
back an absolute URL (like "http://www.perl.com/stuff/foo.html"), as
shown here:
use URI;
$abs = URI->new_abs($maybe_relative, $base);
For example, consider this program that matches URLs in the HTML
list of new modules in CPAN:
use strict;
use warnings;
use LWP;
my $browser = LWP::UserAgent->new;
my $url = 'http://www.cpan.org/RECENT.html';
my $response = $browser->get($url);
die "Can't get $url -- ", $response->status_line
unless $response->is_success;
my $html = $response->decoded_content;
while( $html =~ m/<A HREF=\"(.*?)\"/g ) {
print "$1\n";
}
When run, it emits output that starts out something like this:
MIRRORING.FROM
RECENT
RECENT.html
authors/00whois.html
authors/01mailrc.txt.gz
authors/id/A/AA/AASSAD/CHECKSUMS
...
However, if you actually want to have those be absolute URLs, you
can use the URI module's C<new_abs> method, by changing the C<while>
loop to this:
while( $html =~ m/<A HREF=\"(.*?)\"/g ) {
print URI->new_abs( $1, $response->base ) ,"\n";
}
(The C<< $response->base >> method from L<HTTP::Message|HTTP::Message>
is for returning what URL
should be used for resolving relative URLs -- it's usually just
the same as the URL that you requested.)
That program then emits nicely absolute URLs:
http://www.cpan.org/MIRRORING.FROM
http://www.cpan.org/RECENT
http://www.cpan.org/RECENT.html
http://www.cpan.org/authors/00whois.html
http://www.cpan.org/authors/01mailrc.txt.gz
http://www.cpan.org/authors/id/A/AA/AASSAD/CHECKSUMS
...
See chapter 4 of I<Perl & LWP> for a longer discussion of URI objects.
Of course, using a regexp to match hrefs is a bit simplistic, and for
more robust programs, you'll probably want to use an HTML-parsing module
like L<HTML::LinkExtor> or L<HTML::TokeParser> or even maybe
L<HTML::TreeBuilder>.
=for comment
##########################################################################
=head2 Other Browser Attributes
LWP::UserAgent objects have many attributes for controlling how they
work. Here are a few notable ones:
=over
=item *
C<< $browser->timeout(15); >>
This sets this browser object to give up on requests that don't answer
within 15 seconds.
=item *
C<< $browser->protocols_allowed( [ 'http', 'gopher'] ); >>
This sets this browser object to not speak any protocols other than HTTP
and gopher. If it tries accessing any other kind of URL (like an "ftp:"
or "mailto:" or "news:" URL), then it won't actually try connecting, but
instead will immediately return an error code 500, with a message like
"Access to 'ftp' URIs has been disabled".
=item *
C<< use LWP::ConnCache; $browser->conn_cache(LWP::ConnCache->new()); >>
This tells the browser object to try using the HTTP/1.1 "Keep-Alive"
feature, which speeds up requests by reusing the same socket connection
for multiple requests to the same server.
=item *
C<< $browser->agent( 'SomeName/1.23 (more info here maybe)' ) >>
This changes how the browser object will identify itself in
the default "User-Agent" line is its HTTP requests. By default,
it'll send "libwww-perl/I<versionnumber>", like
"libwww-perl/5.65". You can change that to something more descriptive
like this:
$browser->agent( 'SomeName/3.14 (contact@robotplexus.int)' );
Or if need be, you can go in disguise, like this:
$browser->agent( 'Mozilla/4.0 (compatible; MSIE 5.12; Mac_PowerPC)' );
=item *
C<< push @{ $ua->requests_redirectable }, 'POST'; >>
This tells this browser to obey redirection responses to POST requests
(like most modern interactive browsers), even though the HTTP RFC says
that should not normally be done.
=back
For more options and information, see L<the full documentation for
LWP::UserAgent|LWP::UserAgent>.
=for comment
##########################################################################
=head2 Writing Polite Robots
If you want to make sure that your LWP-based program respects F<robots.txt>
files and doesn't make too many requests too fast, you can use the LWP::RobotUA
class instead of the LWP::UserAgent class.
LWP::RobotUA class is just like LWP::UserAgent, and you can use it like so:
use LWP::RobotUA;
my $browser = LWP::RobotUA->new('YourSuperBot/1.34', 'you@yoursite.com');
# Your bot's name and your email address
my $response = $browser->get($url);
But HTTP::RobotUA adds these features:
=over
=item *
If the F<robots.txt> on C<$url>'s server forbids you from accessing
C<$url>, then the C<$browser> object (assuming it's of class LWP::RobotUA)
won't actually request it, but instead will give you back (in C<$response>) a 403 error
with a message "Forbidden by robots.txt". That is, if you have this line:
die "$url -- ", $response->status_line, "\nAborted"
unless $response->is_success;
then the program would die with an error message like this:
http://whatever.site.int/pith/x.html -- 403 Forbidden by robots.txt
Aborted at whateverprogram.pl line 1234
=item *
If this C<$browser> object sees that the last time it talked to
C<$url>'s server was too recently, then it will pause (via C<sleep>) to
avoid making too many requests too often. How long it will pause for, is
by default one minute -- but you can control it with the C<<
$browser->delay( I<minutes> ) >> attribute.
For example, this code:
$browser->delay( 7/60 );
...means that this browser will pause when it needs to avoid talking to
any given server more than once every 7 seconds.
=back
For more options and information, see L<the full documentation for
LWP::RobotUA|LWP::RobotUA>.
=for comment
##########################################################################
=head2 Using Proxies
In some cases, you will want to (or will have to) use proxies for
accessing certain sites and/or using certain protocols. This is most
commonly the case when your LWP program is running (or could be running)
on a machine that is behind a firewall.
To make a browser object use proxies that are defined in the usual
environment variables (C<HTTP_PROXY>, etc.), just call the C<env_proxy>
on a user-agent object before you go making any requests on it.
Specifically:
use LWP::UserAgent;
my $browser = LWP::UserAgent->new;
# And before you go making any requests:
$browser->env_proxy;
For more information on proxy parameters, see L<the LWP::UserAgent
documentation|LWP::UserAgent>, specifically the C<proxy>, C<env_proxy>,
and C<no_proxy> methods.
=for comment
##########################################################################
=head2 HTTP Authentication
Many web sites restrict access to documents by using "HTTP
Authentication". This isn't just any form of "enter your password"
restriction, but is a specific mechanism where the HTTP server sends the
browser an HTTP code that says "That document is part of a protected
'realm', and you can access it only if you re-request it and add some
special authorization headers to your request".
For example, the Unicode.org admins stop email-harvesting bots from
harvesting the contents of their mailing list archives, by protecting
them with HTTP Authentication, and then publicly stating the username
and password (at C<http://www.unicode.org/mail-arch/>) -- namely
username "unicode-ml" and password "unicode".
For example, consider this URL, which is part of the protected
area of the web site:
http://www.unicode.org/mail-arch/unicode-ml/y2002-m08/0067.html
If you access that with a browser, you'll get a prompt
like
"Enter username and password for 'Unicode-MailList-Archives' at server
'www.unicode.org'".
In LWP, if you just request that URL, like this:
use LWP;
my $browser = LWP::UserAgent->new;
my $url =
'http://www.unicode.org/mail-arch/unicode-ml/y2002-m08/0067.html';
my $response = $browser->get($url);
die "Error: ", $response->header('WWW-Authenticate') || 'Error accessing',
# ('WWW-Authenticate' is the realm-name)
"\n ", $response->status_line, "\n at $url\n Aborting"
unless $response->is_success;
Then you'll get this error:
Error: Basic realm="Unicode-MailList-Archives"
401 Authorization Required
at http://www.unicode.org/mail-arch/unicode-ml/y2002-m08/0067.html
Aborting at auth1.pl line 9. [or wherever]
...because the C<$browser> doesn't know any the username and password
for that realm ("Unicode-MailList-Archives") at that host
("www.unicode.org"). The simplest way to let the browser know about this
is to use the C<credentials> method to let it know about a username and
password that it can try using for that realm at that host. The syntax is:
$browser->credentials(
'servername:portnumber',
'realm-name',
'username' => 'password'
);
In most cases, the port number is 80, the default TCP/IP port for HTTP; and
you usually call the C<credentials> method before you make any requests.
For example:
$browser->credentials(
'reports.mybazouki.com:80',
'web_server_usage_reports',
'plinky' => 'banjo123'
);
So if we add the following to the program above, right after the C<<
$browser = LWP::UserAgent->new; >> line...
$browser->credentials( # add this to our $browser 's "key ring"
'www.unicode.org:80',
'Unicode-MailList-Archives',
'unicode-ml' => 'unicode'
);
...then when we run it, the request succeeds, instead of causing the
C<die> to be called.
=for comment
##########################################################################
=head2 Accessing HTTPS URLs
When you access an HTTPS URL, it'll work for you just like an HTTP URL
would -- if your LWP installation has HTTPS support (via an appropriate
Secure Sockets Layer library). For example:
use LWP;
my $url = 'https://www.paypal.com/'; # Yes, HTTPS!
my $browser = LWP::UserAgent->new;
my $response = $browser->get($url);
die "Error at $url\n ", $response->status_line, "\n Aborting"
unless $response->is_success;
print "Whee, it worked! I got that ",
$response->content_type, " document!\n";
If your LWP installation doesn't have HTTPS support set up, then the
response will be unsuccessful, and you'll get this error message:
Error at https://www.paypal.com/
501 Protocol scheme 'https' is not supported
Aborting at paypal.pl line 7. [or whatever program and line]
If your LWP installation I<does> have HTTPS support installed, then the
response should be successful, and you should be able to consult
C<$response> just like with any normal HTTP response.
For information about installing HTTPS support for your LWP
installation, see the helpful F<README.SSL> file that comes in the
libwww-perl distribution.
=for comment
##########################################################################
=head2 Getting Large Documents
When you're requesting a large (or at least potentially large) document,
a problem with the normal way of using the request methods (like C<<
$response = $browser->get($url) >>) is that the response object in
memory will have to hold the whole document -- I<in memory>. If the
response is a thirty megabyte file, this is likely to be quite an
imposition on this process's memory usage.
A notable alternative is to have LWP save the content to a file on disk,
instead of saving it up in memory. This is the syntax to use:
$response = $ua->get($url,
':content_file' => $filespec,
);
For example,
$response = $ua->get('http://search.cpan.org/',
':content_file' => '/tmp/sco.html'
);
When you use this C<:content_file> option, the C<$response> will have
all the normal header lines, but C<< $response->content >> will be
empty. Errors writing to the content file (for example due to
permission denied or the filesystem being full) will be reported via
the C<Client-Aborted> or C<X-Died> response headers, and not the
C<is_success> method:
if ($response->header('Client-Aborted') eq 'die') {
# handle error ...
Note that this ":content_file" option isn't supported under older
versions of LWP, so you should consider adding C<use LWP 5.66;> to check
the LWP version, if you think your program might run on systems with
older versions.
If you need to be compatible with older LWP versions, then use
this syntax, which does the same thing:
use HTTP::Request::Common;
$response = $ua->request( GET($url), $filespec );
=for comment
##########################################################################
=head1 SEE ALSO
Remember, this article is just the most rudimentary introduction to
LWP -- to learn more about LWP and LWP-related tasks, you really
must read from the following:
=over
=item *
L<LWP::Simple> -- simple functions for getting/heading/mirroring URLs
=item *
L<LWP> -- overview of the libwww-perl modules
=item *
L<LWP::UserAgent> -- the class for objects that represent "virtual browsers"
=item *
L<HTTP::Response> -- the class for objects that represent the response to
a LWP response, as in C<< $response = $browser->get(...) >>
=item *
L<HTTP::Message> and L<HTTP::Headers> -- classes that provide more methods
to HTTP::Response.
=item *
L<URI> -- class for objects that represent absolute or relative URLs
=item *
L<URI::Escape> -- functions for URL-escaping and URL-unescaping strings
(like turning "this & that" to and from "this%20%26%20that").
=item *
L<HTML::Entities> -- functions for HTML-escaping and HTML-unescaping strings
(like turning "C. & E. BrontE<euml>" to and from "C. & E. Brontë")
=item *
L<HTML::TokeParser> and L<HTML::TreeBuilder> -- classes for parsing HTML
=item *
L<HTML::LinkExtor> -- class for finding links in HTML documents
=item *
The book I<Perl & LWP> by Sean M. Burke. O'Reilly & Associates,
2002. ISBN: 0-596-00178-9, L<http://oreilly.com/catalog/perllwp/>. The
whole book is also available free online:
L<http://lwp.interglacial.com>.
=back
=head1 COPYRIGHT
Copyright 2002, Sean M. Burke. You can redistribute this document and/or
modify it, but only under the same terms as Perl itself.
=head1 AUTHOR
Sean M. Burke C<sburke@cpan.org>
=for comment
##########################################################################
=cut
# End of Pod
PK 1N%[-�* * perl5/Canary/Stability.pmnu ��6�$ =head1 NAME
Canary::Stability - canary to check perl compatibility for schmorp's modules
=head1 SYNOPSIS
# in Makefile.PL
use Canary::Stability DISTNAME => 2001, MINIMUM_PERL_VERSION;
=head1 DESCRIPTION
This module is used by Schmorp's modules during configuration stage to
test the installed perl for compatibility with his modules.
It's not, at this stage, meant as a tool for other module authors,
although in principle nothing prevents them from subscribing to the same
ideas.
See the F<Makefile.PL> in L<Coro> or L<AnyEvent> for usage examples.
=cut
package Canary::Stability;
BEGIN {
$VERSION = 2013;
}
sub sgr {
# we just assume ANSI almost everywhere
# red 31, yellow 33, green 32
local $| = 1;
$ENV{PERL_CANARY_STABILITY_COLOUR} ne 0
and ((-t STDOUT and length $ENV{TERM}) or $ENV{PERL_CANARY_STABILITY_COLOUR})
and print "\e[$_[0]m";
}
sub import {
my (undef, $distname, $minvers, $minperl) = @_;
$ENV{PERL_CANARY_STABILITY_DISABLE}
and return;
$minperl ||= 5.008002;
print <<EOF;
***
*** Canary::Stability COMPATIBILITY AND SUPPORT CHECK
*** =================================================
***
*** Hi!
***
*** I do my best to provide predictable and reliable software.
***
*** However, in recent releases, P5P (who maintain perl) have been
*** introducing regressions that are sometimes subtle and at other times
*** catastrophic, often for personal preferences with little or no concern
*** for existing code, most notably CPAN.
***
*** For this reason, it has become very hard for me to maintain the level
*** of reliability and support I have committed myself to in the past, at
*** least with some perl versions: I simply can't keep up working around new
*** bugs or gratituous incompatibilities, and in turn you might suffer from
*** unanticipated problems.
***
*** Therefore I have introduced a support and compatibility check, the results
*** of which follow below, together with a FAQ and some recommendations.
***
*** This check is just to let you know that there might be a risk, so you can
*** make judgement calls on how to proceed - it will not keep the module from
*** installing or working.
***
EOF
if ($minvers > $VERSION) {
sgr 33;
print <<EOF;
*** The stability canary says: (nothing, it died of old age).
***
*** Your Canary::Stability module (used by $distname) is too old.
*** This is not a fatal problem - while you might want to upgrade to version
*** $minvers (currently installed version: $VERSION) to get better support
*** status testing, you might also not want to care at all, and all will
*** be well as long $distname works well enough for you, as the stability
*** canary is only used when installing the distribution.
***
EOF
} elsif ($] < $minperl) {
sgr 33;
print <<EOF;
*** The stability canary says: chirp (it seems concerned about something).
***
*** Your perl version ($]) is older than the $distname distribution
*** likes ($minperl). This is not a fatal problem - the module might work
*** well with your version of perl, but it does mean the author likely
*** won't do anything to make it work if it breaks.
***
EOF
if ($ENV{AUTOMATED_TESTING}) {
print <<EOF;
*** Since this is an AUTOMATED_TESTING environment, the stability canary
*** decided to fail cleanly here, rather than to generate a false test
*** result.
***
EOF
exit 0;
}
} elsif (defined $Internals::StabilityBranchVersion) {
# note to people studying this modules sources:
# the above test is not considered a clean or stable way to
# test for the stability branch.
sgr 32;
print <<EOF;
*** The stability canary says: chirp! chirp! (it seems to be quite excited)
***
*** It seems you are running schmorp's stability branch of perl.
*** All should be well, and if it isn't, you should report this as a bug
*** to the $distname author.
***
EOF
} elsif ($] < 5.021) {
#sgr 32;
print <<EOF;
*** The stability canary says: chirp! chirp! (it seems to be quite happy)
***
*** Your version of perl ($]) is quite supported by $distname, nothing
*** else to be said, hope it comes in handy.
***
EOF
} else {
sgr 31;
print <<EOF;
*** The stability canary says: (nothing, it was driven away by harsh weather)
***
*** It seems you are running perl version $], likely the "official" or
*** "standard" version. While there is nothing wrong with doing that,
*** standard perl versions 5.022 and up are not supported by $distname.
*** While this might be fatal, it might also be all right - if you run into
*** problems, you might want to downgrade your perl or switch to the
*** stability branch.
***
*** If everything works fine, you can ignore this message.
***
EOF
sgr 0;
print <<EOF;
***
*** Stability canary mini-FAQ:
***
*** Do I need to do anything?
*** With luck, no. While some distributions are known to fail
*** already, most should probably work. This message is here
*** to alert you that your perl is not supported by $distname,
*** and if things go wrong, you either need to downgrade, or
*** sidegrade to the stability variant of your perl version,
*** or simply live with the consequences.
***
*** What is this canary thing?
*** It's purpose is to check support status of $distname with
*** respect to your perl version.
***
*** What is this "stability branch"?
*** It's a branch or fork of the official perl, by schmorp, to
*** improve stability and compatibility with existing modules.
***
*** How can I skip this prompt on automated installs?
*** Set PERL_CANARY_STABILITY_NOPROMPT=1 in your environment.
*** More info is in the Canary::Stability manpage.
***
*** Long version of this FAQ: http://stableperl.schmorp.de/faq.html
*** Stability Branch homepage: http://stableperl.schmorp.de/
***
EOF
unless ($ENV{PERL_CANARY_STABILITY_NOPROMPT}) {
require ExtUtils::MakeMaker;
ExtUtils::MakeMaker::prompt ("Continue anyways? ", "y") =~ /^y/i
or die "FATAL: User aborted configuration of $distname.\n";
}
}
sgr 0;
}
=head1 ENVIRONMENT VARIABLES
=over 4
=item C<PERL_CANARY_STABILITY_NOPROMPT=1>
Do not prompt the user on alert messages.
=item C<PERL_CANARY_STABILITY_COLOUR=0>
Disable use of colour.
=item C<PERL_CANARY_STABILITY_COLOUR=1>
Force use of colour.
=item C<PERL_CANARY_STABILITY_DISABLE=1>
Disable this modules functionality completely.
=item C<AUTOMATED_TESTING=1>
When this variable is set to a true value and the perl minimum version
requirement is not met, the module will exit, which should skip testing
under automated testing environments.
This is done to avoid false failure or success reports when the chances of
success are already quite low and the failures are not supported by the
author.
=back
=head1 AUTHOR
Marc Lehmann <schmorp@schmorp.de>
http://software.schmorp.de/pkg/Canary-Stability.html
=cut
1
PK 1N%[���O� O� perl5/local/lib.pmnu ��6�$ package local::lib;
use 5.006;
BEGIN {
if ($ENV{RELEASE_TESTING}) {
require strict;
strict->import;
require warnings;
warnings->import;
}
}
use Config ();
our $VERSION = '2.000029';
$VERSION =~ tr/_//d;
BEGIN {
*_WIN32 = ($^O eq 'MSWin32' || $^O eq 'NetWare' || $^O eq 'symbian')
? sub(){1} : sub(){0};
# punt on these systems
*_USE_FSPEC = ($^O eq 'MacOS' || $^O eq 'VMS' || $INC{'File/Spec.pm'})
? sub(){1} : sub(){0};
}
my $_archname = $Config::Config{archname};
my $_version = $Config::Config{version};
my @_inc_version_list = reverse split / /, $Config::Config{inc_version_list};
my $_path_sep = $Config::Config{path_sep};
our $_DIR_JOIN = _WIN32 ? '\\' : '/';
our $_DIR_SPLIT = (_WIN32 || $^O eq 'cygwin') ? qr{[\\/]}
: qr{/};
our $_ROOT = _WIN32 ? do {
my $UNC = qr{[\\/]{2}[^\\/]+[\\/][^\\/]+};
qr{^(?:$UNC|[A-Za-z]:|)$_DIR_SPLIT};
} : qr{^/};
our $_PERL;
sub _perl {
if (!$_PERL) {
# untaint and validate
($_PERL, my $exe) = $^X =~ /((?:.*$_DIR_SPLIT)?(.+))/;
$_PERL = 'perl'
if $exe !~ /perl/;
if (_is_abs($_PERL)) {
}
elsif (-x $Config::Config{perlpath}) {
$_PERL = $Config::Config{perlpath};
}
elsif ($_PERL =~ $_DIR_SPLIT && -x $_PERL) {
$_PERL = _rel2abs($_PERL);
}
else {
($_PERL) =
map { /(.*)/ }
grep { -x $_ }
map { ($_, _WIN32 ? ("$_.exe") : ()) }
map { join($_DIR_JOIN, $_, $_PERL) }
split /\Q$_path_sep\E/, $ENV{PATH};
}
}
$_PERL;
}
sub _cwd {
if (my $cwd
= defined &Cwd::sys_cwd ? \&Cwd::sys_cwd
: defined &Cwd::cwd ? \&Cwd::cwd
: undef
) {
no warnings 'redefine';
*_cwd = $cwd;
goto &$cwd;
}
my $drive = shift;
return Win32::GetCwd()
if _WIN32 && defined &Win32::GetCwd && !$drive;
local @ENV{qw(PATH IFS CDPATH ENV BASH_ENV)};
delete @ENV{qw(PATH IFS CDPATH ENV BASH_ENV)};
my $cmd = $drive ? "eval { Cwd::getdcwd(q($drive)) }"
: 'getcwd';
my $perl = _perl;
my $cwd = `"$perl" -MCwd -le "print $cmd"`;
chomp $cwd;
if (!length $cwd && $drive) {
$cwd = $drive;
}
$cwd =~ s/$_DIR_SPLIT?$/$_DIR_JOIN/;
$cwd;
}
sub _catdir {
if (_USE_FSPEC) {
require File::Spec;
File::Spec->catdir(@_);
}
else {
my $dir = join($_DIR_JOIN, @_);
$dir =~ s{($_DIR_SPLIT)(?:\.?$_DIR_SPLIT)+}{$1}g;
$dir;
}
}
sub _is_abs {
if (_USE_FSPEC) {
require File::Spec;
File::Spec->file_name_is_absolute($_[0]);
}
else {
$_[0] =~ $_ROOT;
}
}
sub _rel2abs {
my ($dir, $base) = @_;
return $dir
if _is_abs($dir);
$base = _WIN32 && $dir =~ s/^([A-Za-z]:)// ? _cwd("$1")
: $base ? _rel2abs($base)
: _cwd;
return _catdir($base, $dir);
}
our $_DEVNULL;
sub _devnull {
return $_DEVNULL ||=
_USE_FSPEC ? (require File::Spec, File::Spec->devnull)
: _WIN32 ? 'nul'
: $^O eq 'os2' ? '/dev/nul'
: '/dev/null';
}
sub import {
my ($class, @args) = @_;
if ($0 eq '-') {
push @args, @ARGV;
require Cwd;
}
my @steps;
my %opts;
my %attr;
my $shelltype;
while (@args) {
my $arg = shift @args;
# check for lethal dash first to stop processing before causing problems
# the fancy dash is U+2212 or \xE2\x88\x92
if ($arg =~ /\xE2\x88\x92/) {
die <<'DEATH';
WHOA THERE! It looks like you've got some fancy dashes in your commandline!
These are *not* the traditional -- dashes that software recognizes. You
probably got these by copy-pasting from the perldoc for this module as
rendered by a UTF8-capable formatter. This most typically happens on an OS X
terminal, but can happen elsewhere too. Please try again after replacing the
dashes with normal minus signs.
DEATH
}
elsif ($arg eq '--self-contained') {
die <<'DEATH';
FATAL: The local::lib --self-contained flag has never worked reliably and the
original author, Mark Stosberg, was unable or unwilling to maintain it. As
such, this flag has been removed from the local::lib codebase in order to
prevent misunderstandings and potentially broken builds. The local::lib authors
recommend that you look at the lib::core::only module shipped with this
distribution in order to create a more robust environment that is equivalent to
what --self-contained provided (although quite possibly not what you originally
thought it provided due to the poor quality of the documentation, for which we
apologise).
DEATH
}
elsif( $arg =~ /^--deactivate(?:=(.*))?$/ ) {
my $path = defined $1 ? $1 : shift @args;
push @steps, ['deactivate', $path];
}
elsif ( $arg eq '--deactivate-all' ) {
push @steps, ['deactivate_all'];
}
elsif ( $arg =~ /^--shelltype(?:=(.*))?$/ ) {
$shelltype = defined $1 ? $1 : shift @args;
}
elsif ( $arg eq '--no-create' ) {
$opts{no_create} = 1;
}
elsif ( $arg eq '--quiet' ) {
$attr{quiet} = 1;
}
elsif ( $arg eq '--always' ) {
$attr{always} = 1;
}
elsif ( $arg =~ /^--/ ) {
die "Unknown import argument: $arg";
}
else {
push @steps, ['activate', $arg, \%opts];
}
}
if (!@steps) {
push @steps, ['activate', undef, \%opts];
}
my $self = $class->new(%attr);
for (@steps) {
my ($method, @args) = @$_;
$self = $self->$method(@args);
}
if ($0 eq '-') {
print $self->environment_vars_string($shelltype);
exit 0;
}
else {
$self->setup_local_lib;
}
}
sub new {
my $class = shift;
bless {@_}, $class;
}
sub clone {
my $self = shift;
bless {%$self, @_}, ref $self;
}
sub inc { $_[0]->{inc} ||= \@INC }
sub libs { $_[0]->{libs} ||= [ \'PERL5LIB' ] }
sub bins { $_[0]->{bins} ||= [ \'PATH' ] }
sub roots { $_[0]->{roots} ||= [ \'PERL_LOCAL_LIB_ROOT' ] }
sub extra { $_[0]->{extra} ||= {} }
sub quiet { $_[0]->{quiet} }
sub _as_list {
my $list = shift;
grep length, map {
!(ref $_ && ref $_ eq 'SCALAR') ? $_ : (
defined $ENV{$$_} ? split(/\Q$_path_sep/, $ENV{$$_})
: ()
)
} ref $list ? @$list : $list;
}
sub _remove_from {
my ($list, @remove) = @_;
return @$list
if !@remove;
my %remove = map { $_ => 1 } @remove;
grep !$remove{$_}, _as_list($list);
}
my @_lib_subdirs = (
[$_version, $_archname],
[$_version],
[$_archname],
(map [$_], @_inc_version_list),
[],
);
sub install_base_bin_path {
my ($class, $path) = @_;
return _catdir($path, 'bin');
}
sub install_base_perl_path {
my ($class, $path) = @_;
return _catdir($path, 'lib', 'perl5');
}
sub install_base_arch_path {
my ($class, $path) = @_;
_catdir($class->install_base_perl_path($path), $_archname);
}
sub lib_paths_for {
my ($class, $path) = @_;
my $base = $class->install_base_perl_path($path);
return map { _catdir($base, @$_) } @_lib_subdirs;
}
sub _mm_escape_path {
my $path = shift;
$path =~ s/\\/\\\\/g;
if ($path =~ s/ /\\ /g) {
$path = qq{"$path"};
}
return $path;
}
sub _mb_escape_path {
my $path = shift;
$path =~ s/\\/\\\\/g;
return qq{"$path"};
}
sub installer_options_for {
my ($class, $path) = @_;
return (
PERL_MM_OPT =>
defined $path ? "INSTALL_BASE="._mm_escape_path($path) : undef,
PERL_MB_OPT =>
defined $path ? "--install_base "._mb_escape_path($path) : undef,
);
}
sub active_paths {
my ($self) = @_;
$self = ref $self ? $self : $self->new;
return grep {
# screen out entries that aren't actually reflected in @INC
my $active_ll = $self->install_base_perl_path($_);
grep { $_ eq $active_ll } @{$self->inc};
} _as_list($self->roots);
}
sub deactivate {
my ($self, $path) = @_;
$self = $self->new unless ref $self;
$path = $self->resolve_path($path);
$path = $self->normalize_path($path);
my @active_lls = $self->active_paths;
if (!grep { $_ eq $path } @active_lls) {
warn "Tried to deactivate inactive local::lib '$path'\n";
return $self;
}
my %args = (
bins => [ _remove_from($self->bins,
$self->install_base_bin_path($path)) ],
libs => [ _remove_from($self->libs,
$self->install_base_perl_path($path)) ],
inc => [ _remove_from($self->inc,
$self->lib_paths_for($path)) ],
roots => [ _remove_from($self->roots, $path) ],
);
$args{extra} = { $self->installer_options_for($args{roots}[0]) };
$self->clone(%args);
}
sub deactivate_all {
my ($self) = @_;
$self = $self->new unless ref $self;
my @active_lls = $self->active_paths;
my %args;
if (@active_lls) {
%args = (
bins => [ _remove_from($self->bins,
map $self->install_base_bin_path($_), @active_lls) ],
libs => [ _remove_from($self->libs,
map $self->install_base_perl_path($_), @active_lls) ],
inc => [ _remove_from($self->inc,
map $self->lib_paths_for($_), @active_lls) ],
roots => [ _remove_from($self->roots, @active_lls) ],
);
}
$args{extra} = { $self->installer_options_for(undef) };
$self->clone(%args);
}
sub activate {
my ($self, $path, $opts) = @_;
$opts ||= {};
$self = $self->new unless ref $self;
$path = $self->resolve_path($path);
$self->ensure_dir_structure_for($path, { quiet => $self->quiet })
unless $opts->{no_create};
$path = $self->normalize_path($path);
my @active_lls = $self->active_paths;
if (grep { $_ eq $path } @active_lls[1 .. $#active_lls]) {
$self = $self->deactivate($path);
}
my %args;
if ($opts->{always} || !@active_lls || $active_lls[0] ne $path) {
%args = (
bins => [ $self->install_base_bin_path($path), @{$self->bins} ],
libs => [ $self->install_base_perl_path($path), @{$self->libs} ],
inc => [ $self->lib_paths_for($path), @{$self->inc} ],
roots => [ $path, @{$self->roots} ],
);
}
$args{extra} = { $self->installer_options_for($path) };
$self->clone(%args);
}
sub normalize_path {
my ($self, $path) = @_;
$path = ( Win32::GetShortPathName($path) || $path )
if $^O eq 'MSWin32';
return $path;
}
sub build_environment_vars_for {
my $self = $_[0]->new->activate($_[1], { always => 1 });
$self->build_environment_vars;
}
sub build_activate_environment_vars_for {
my $self = $_[0]->new->activate($_[1], { always => 1 });
$self->build_environment_vars;
}
sub build_deactivate_environment_vars_for {
my $self = $_[0]->new->deactivate($_[1]);
$self->build_environment_vars;
}
sub build_deact_all_environment_vars_for {
my $self = $_[0]->new->deactivate_all;
$self->build_environment_vars;
}
sub build_environment_vars {
my $self = shift;
(
PATH => join($_path_sep, _as_list($self->bins)),
PERL5LIB => join($_path_sep, _as_list($self->libs)),
PERL_LOCAL_LIB_ROOT => join($_path_sep, _as_list($self->roots)),
%{$self->extra},
);
}
sub setup_local_lib_for {
my $self = $_[0]->new->activate($_[1]);
$self->setup_local_lib;
}
sub setup_local_lib {
my $self = shift;
# if Carp is already loaded, ensure Carp::Heavy is also loaded, to avoid
# $VERSION mismatch errors (Carp::Heavy loads Carp, so we do not need to
# check in the other direction)
require Carp::Heavy if $INC{'Carp.pm'};
$self->setup_env_hash;
@INC = @{$self->inc};
}
sub setup_env_hash_for {
my $self = $_[0]->new->activate($_[1]);
$self->setup_env_hash;
}
sub setup_env_hash {
my $self = shift;
my %env = $self->build_environment_vars;
for my $key (keys %env) {
if (defined $env{$key}) {
$ENV{$key} = $env{$key};
}
else {
delete $ENV{$key};
}
}
}
sub print_environment_vars_for {
print $_[0]->environment_vars_string_for(@_[1..$#_]);
}
sub environment_vars_string_for {
my $self = $_[0]->new->activate($_[1], { always => 1});
$self->environment_vars_string;
}
sub environment_vars_string {
my ($self, $shelltype) = @_;
$shelltype ||= $self->guess_shelltype;
my $extra = $self->extra;
my @envs = (
PATH => $self->bins,
PERL5LIB => $self->libs,
PERL_LOCAL_LIB_ROOT => $self->roots,
map { $_ => $extra->{$_} } sort keys %$extra,
);
$self->_build_env_string($shelltype, \@envs);
}
sub _build_env_string {
my ($self, $shelltype, $envs) = @_;
my @envs = @$envs;
my $build_method = "build_${shelltype}_env_declaration";
my $out = '';
while (@envs) {
my ($name, $value) = (shift(@envs), shift(@envs));
if (
ref $value
&& @$value == 1
&& ref $value->[0]
&& ref $value->[0] eq 'SCALAR'
&& ${$value->[0]} eq $name) {
next;
}
$out .= $self->$build_method($name, $value);
}
my $wrap_method = "wrap_${shelltype}_output";
if ($self->can($wrap_method)) {
return $self->$wrap_method($out);
}
return $out;
}
sub build_bourne_env_declaration {
my ($class, $name, $args) = @_;
my $value = $class->_interpolate($args, '${%s:-}', qr/["\\\$!`]/, '\\%s');
if (!defined $value) {
return qq{unset $name;\n};
}
$value =~ s/(^|\G|$_path_sep)\$\{$name:-\}$_path_sep/$1\${$name}\${$name:+$_path_sep}/g;
$value =~ s/$_path_sep\$\{$name:-\}$/\${$name:+$_path_sep\${$name}}/;
qq{${name}="$value"; export ${name};\n}
}
sub build_csh_env_declaration {
my ($class, $name, $args) = @_;
my ($value, @vars) = $class->_interpolate($args, '${%s}', qr/["\$]/, '"\\%s"');
if (!defined $value) {
return qq{unsetenv $name;\n};
}
my $out = '';
for my $var (@vars) {
$out .= qq{if ! \$?$name setenv $name '';\n};
}
my $value_without = $value;
if ($value_without =~ s/(?:^|$_path_sep)\$\{$name\}(?:$_path_sep|$)//g) {
$out .= qq{if "\${$name}" != '' setenv $name "$value";\n};
$out .= qq{if "\${$name}" == '' };
}
$out .= qq{setenv $name "$value_without";\n};
return $out;
}
sub build_cmd_env_declaration {
my ($class, $name, $args) = @_;
my $value = $class->_interpolate($args, '%%%s%%', qr(%), '%s');
if (!$value) {
return qq{\@set $name=\n};
}
my $out = '';
my $value_without = $value;
if ($value_without =~ s/(?:^|$_path_sep)%$name%(?:$_path_sep|$)//g) {
$out .= qq{\@if not "%$name%"=="" set "$name=$value"\n};
$out .= qq{\@if "%$name%"=="" };
}
$out .= qq{\@set "$name=$value_without"\n};
return $out;
}
sub build_powershell_env_declaration {
my ($class, $name, $args) = @_;
my $value = $class->_interpolate($args, '$env:%s', qr/["\$]/, '`%s');
if (!$value) {
return qq{Remove-Item -ErrorAction 0 Env:\\$name;\n};
}
my $maybe_path_sep = qq{\$(if("\$env:$name"-eq""){""}else{"$_path_sep"})};
$value =~ s/(^|\G|$_path_sep)\$env:$name$_path_sep/$1\$env:$name"+$maybe_path_sep+"/g;
$value =~ s/$_path_sep\$env:$name$/"+$maybe_path_sep+\$env:$name+"/;
qq{\$env:$name = \$("$value");\n};
}
sub wrap_powershell_output {
my ($class, $out) = @_;
return $out || " \n";
}
sub build_fish_env_declaration {
my ($class, $name, $args) = @_;
my $value = $class->_interpolate($args, '$%s', qr/[\\"'$ ]/, '\\%s');
if (!defined $value) {
return qq{set -e $name;\n};
}
# fish has special handling for PATH, CDPATH, and MANPATH. They are always
# treated as arrays, and joined with ; when storing the environment. Other
# env vars can be arrays, but will be joined without a separator. We only
# really care about PATH, but might as well make this routine more general.
if ($name =~ /^(?:CD|MAN)?PATH$/) {
$value =~ s/$_path_sep/ /g;
my $silent = $name =~ /^(?:CD)?PATH$/ ? " 2>"._devnull : '';
return qq{set -x $name $value$silent;\n};
}
my $out = '';
my $value_without = $value;
if ($value_without =~ s/(?:^|$_path_sep)\$$name(?:$_path_sep|$)//g) {
$out .= qq{set -q $name; and set -x $name $value;\n};
$out .= qq{set -q $name; or };
}
$out .= qq{set -x $name $value_without;\n};
$out;
}
sub _interpolate {
my ($class, $args, $var_pat, $escape, $escape_pat) = @_;
return
unless defined $args;
my @args = ref $args ? @$args : $args;
return
unless @args;
my @vars = map { $$_ } grep { ref $_ eq 'SCALAR' } @args;
my $string = join $_path_sep, map {
ref $_ eq 'SCALAR' ? sprintf($var_pat, $$_) : do {
s/($escape)/sprintf($escape_pat, $1)/ge; $_;
};
} @args;
return wantarray ? ($string, \@vars) : $string;
}
sub pipeline;
sub pipeline {
my @methods = @_;
my $last = pop(@methods);
if (@methods) {
\sub {
my ($obj, @args) = @_;
$obj->${pipeline @methods}(
$obj->$last(@args)
);
};
} else {
\sub {
shift->$last(@_);
};
}
}
sub resolve_path {
my ($class, $path) = @_;
$path = $class->${pipeline qw(
resolve_relative_path
resolve_home_path
resolve_empty_path
)}($path);
$path;
}
sub resolve_empty_path {
my ($class, $path) = @_;
if (defined $path) {
$path;
} else {
'~/perl5';
}
}
sub resolve_home_path {
my ($class, $path) = @_;
$path =~ /^~([^\/]*)/ or return $path;
my $user = $1;
my $homedir = do {
if (! length($user) && defined $ENV{HOME}) {
$ENV{HOME};
}
else {
require File::Glob;
File::Glob::bsd_glob("~$user", File::Glob::GLOB_TILDE());
}
};
unless (defined $homedir) {
require Carp; require Carp::Heavy;
Carp::croak(
"Couldn't resolve homedir for "
.(defined $user ? $user : 'current user')
);
}
$path =~ s/^~[^\/]*/$homedir/;
$path;
}
sub resolve_relative_path {
my ($class, $path) = @_;
_rel2abs($path);
}
sub ensure_dir_structure_for {
my ($class, $path, $opts) = @_;
$opts ||= {};
my @dirs;
foreach my $dir (
$class->lib_paths_for($path),
$class->install_base_bin_path($path),
) {
my $d = $dir;
while (!-d $d) {
push @dirs, $d;
require File::Basename;
$d = File::Basename::dirname($d);
}
}
warn "Attempting to create directory ${path}\n"
if !$opts->{quiet} && @dirs;
my %seen;
foreach my $dir (reverse @dirs) {
next
if $seen{$dir}++;
mkdir $dir
or -d $dir
or die "Unable to create $dir: $!"
}
return;
}
sub guess_shelltype {
my $shellbin
= defined $ENV{SHELL} && length $ENV{SHELL}
? ($ENV{SHELL} =~ /([\w.]+)$/)[-1]
: ( $^O eq 'MSWin32' && exists $ENV{'!EXITCODE'} )
? 'bash'
: ( $^O eq 'MSWin32' && $ENV{PROMPT} && $ENV{COMSPEC} )
? ($ENV{COMSPEC} =~ /([\w.]+)$/)[-1]
: ( $^O eq 'MSWin32' && !$ENV{PROMPT} )
? 'powershell.exe'
: 'sh';
for ($shellbin) {
return
/csh$/ ? 'csh'
: /fish$/ ? 'fish'
: /command(?:\.com)?$/i ? 'cmd'
: /cmd(?:\.exe)?$/i ? 'cmd'
: /4nt(?:\.exe)?$/i ? 'cmd'
: /powershell(?:\.exe)?$/i ? 'powershell'
: 'bourne';
}
}
1;
__END__
=encoding utf8
=head1 NAME
local::lib - create and use a local lib/ for perl modules with PERL5LIB
=head1 SYNOPSIS
In code -
use local::lib; # sets up a local lib at ~/perl5
use local::lib '~/foo'; # same, but ~/foo
# Or...
use FindBin;
use local::lib "$FindBin::Bin/../support"; # app-local support library
From the shell -
# Install LWP and its missing dependencies to the '~/perl5' directory
perl -MCPAN -Mlocal::lib -e 'CPAN::install(LWP)'
# Just print out useful shell commands
$ perl -Mlocal::lib
PERL_MB_OPT='--install_base /home/username/perl5'; export PERL_MB_OPT;
PERL_MM_OPT='INSTALL_BASE=/home/username/perl5'; export PERL_MM_OPT;
PERL5LIB="/home/username/perl5/lib/perl5"; export PERL5LIB;
PATH="/home/username/perl5/bin:$PATH"; export PATH;
PERL_LOCAL_LIB_ROOT="/home/usename/perl5:$PERL_LOCAL_LIB_ROOT"; export PERL_LOCAL_LIB_ROOT;
From a F<.bash_profile> or F<.bashrc> file -
eval "$(perl -I$HOME/perl5/lib/perl5 -Mlocal::lib)"
=head2 The bootstrapping technique
A typical way to install local::lib is using what is known as the
"bootstrapping" technique. You would do this if your system administrator
hasn't already installed local::lib. In this case, you'll need to install
local::lib in your home directory.
Even if you do have administrative privileges, you will still want to set up your
environment variables, as discussed in step 4. Without this, you would still
install the modules into the system CPAN installation and also your Perl scripts
will not use the lib/ path you bootstrapped with local::lib.
By default local::lib installs itself and the CPAN modules into ~/perl5.
Windows users must also see L</Differences when using this module under Win32>.
=over 4
=item 1.
Download and unpack the local::lib tarball from CPAN (search for "Download"
on the CPAN page about local::lib). Do this as an ordinary user, not as root
or administrator. Unpack the file in your home directory or in any other
convenient location.
=item 2.
Run this:
perl Makefile.PL --bootstrap
If the system asks you whether it should automatically configure as much
as possible, you would typically answer yes.
=item 3.
Run this: (local::lib assumes you have make installed on your system)
make test && make install
=item 4.
Now we need to setup the appropriate environment variables, so that Perl
starts using our newly generated lib/ directory. If you are using bash or
any other Bourne shells, you can add this to your shell startup script this
way:
echo 'eval "$(perl -I$HOME/perl5/lib/perl5 -Mlocal::lib)"' >>~/.bashrc
If you are using C shell, you can do this as follows:
% echo $SHELL
/bin/csh
$ echo 'eval `perl -I$HOME/perl5/lib/perl5 -Mlocal::lib`' >> ~/.cshrc
After writing your shell configuration file, be sure to re-read it to get the
changed settings into your current shell's environment. Bourne shells use
C<. ~/.bashrc> for this, whereas C shells use C<source ~/.cshrc>.
=back
=head3 Bootstrapping into an alternate directory
In order to install local::lib into a directory other than the default, you need
to specify the name of the directory when you call bootstrap. Then, when
setting up the environment variables, both perl and local::lib must be told the
location of the bootstrap directory. The setup process would look as follows:
perl Makefile.PL --bootstrap=~/foo
make test && make install
echo 'eval "$(perl -I$HOME/foo/lib/perl5 -Mlocal::lib=$HOME/foo)"' >>~/.bashrc
. ~/.bashrc
=head3 Other bootstrapping options
If you're on a slower machine, or are operating under draconian disk space
limitations, you can disable the automatic generation of manpages from POD when
installing modules by using the C<--no-manpages> argument when bootstrapping:
perl Makefile.PL --bootstrap --no-manpages
To avoid doing several bootstrap for several Perl module environments on the
same account, for example if you use it for several different deployed
applications independently, you can use one bootstrapped local::lib
installation to install modules in different directories directly this way:
cd ~/mydir1
perl -Mlocal::lib=./
eval $(perl -Mlocal::lib=./) ### To set the environment for this shell alone
printenv ### You will see that ~/mydir1 is in the PERL5LIB
perl -MCPAN -e install ... ### whatever modules you want
cd ../mydir2
... REPEAT ...
If you use F<.bashrc> to activate a local::lib automatically, the local::lib
will be re-enabled in any sub-shells used, overriding adjustments you may have
made in the parent shell. To avoid this, you can initialize the local::lib in
F<.bash_profile> rather than F<.bashrc>, or protect the local::lib invocation
with a C<$SHLVL> check:
[ $SHLVL -eq 1 ] && eval "$(perl -I$HOME/perl5/lib/perl5 -Mlocal::lib)"
If you are working with several C<local::lib> environments, you may want to
remove some of them from the current environment without disturbing the others.
You can deactivate one environment like this (using bourne sh):
eval $(perl -Mlocal::lib=--deactivate,~/path)
which will generate and run the commands needed to remove C<~/path> from your
various search paths. Whichever environment was B<activated most recently> will
remain the target for module installations. That is, if you activate
C<~/path_A> and then you activate C<~/path_B>, new modules you install will go
in C<~/path_B>. If you deactivate C<~/path_B> then modules will be installed
into C<~/pathA> -- but if you deactivate C<~/path_A> then they will still be
installed in C<~/pathB> because pathB was activated later.
You can also ask C<local::lib> to clean itself completely out of the current
shell's environment with the C<--deactivate-all> option.
For multiple environments for multiple apps you may need to include a modified
version of the C<< use FindBin >> instructions in the "In code" sample above.
If you did something like the above, you have a set of Perl modules at C<<
~/mydir1/lib >>. If you have a script at C<< ~/mydir1/scripts/myscript.pl >>,
you need to tell it where to find the modules you installed for it at C<<
~/mydir1/lib >>.
In C<< ~/mydir1/scripts/myscript.pl >>:
use strict;
use warnings;
use local::lib "$FindBin::Bin/.."; ### points to ~/mydir1 and local::lib finds lib
use lib "$FindBin::Bin/../lib"; ### points to ~/mydir1/lib
Put this before any BEGIN { ... } blocks that require the modules you installed.
=head2 Differences when using this module under Win32
To set up the proper environment variables for your current session of
C<CMD.exe>, you can use this:
C:\>perl -Mlocal::lib
set PERL_MB_OPT=--install_base C:\DOCUME~1\ADMINI~1\perl5
set PERL_MM_OPT=INSTALL_BASE=C:\DOCUME~1\ADMINI~1\perl5
set PERL5LIB=C:\DOCUME~1\ADMINI~1\perl5\lib\perl5
set PATH=C:\DOCUME~1\ADMINI~1\perl5\bin;%PATH%
### To set the environment for this shell alone
C:\>perl -Mlocal::lib > %TEMP%\tmp.bat && %TEMP%\tmp.bat && del %TEMP%\tmp.bat
### instead of $(perl -Mlocal::lib=./)
If you want the environment entries to persist, you'll need to add them to the
Control Panel's System applet yourself or use L<App::local::lib::Win32Helper>.
The "~" is translated to the user's profile directory (the directory named for
the user under "Documents and Settings" (Windows XP or earlier) or "Users"
(Windows Vista or later)) unless $ENV{HOME} exists. After that, the home
directory is translated to a short name (which means the directory must exist)
and the subdirectories are created.
=head3 PowerShell
local::lib also supports PowerShell, and can be used with the
C<Invoke-Expression> cmdlet.
Invoke-Expression "$(perl -Mlocal::lib)"
=head1 RATIONALE
The version of a Perl package on your machine is not always the version you
need. Obviously, the best thing to do would be to update to the version you
need. However, you might be in a situation where you're prevented from doing
this. Perhaps you don't have system administrator privileges; or perhaps you
are using a package management system such as Debian, and nobody has yet gotten
around to packaging up the version you need.
local::lib solves this problem by allowing you to create your own directory of
Perl packages downloaded from CPAN (in a multi-user system, this would typically
be within your own home directory). The existing system Perl installation is
not affected; you simply invoke Perl with special options so that Perl uses the
packages in your own local package directory rather than the system packages.
local::lib arranges things so that your locally installed version of the Perl
packages takes precedence over the system installation.
If you are using a package management system (such as Debian), you don't need to
worry about Debian and CPAN stepping on each other's toes. Your local version
of the packages will be written to an entirely separate directory from those
installed by Debian.
=head1 DESCRIPTION
This module provides a quick, convenient way of bootstrapping a user-local Perl
module library located within the user's home directory. It also constructs and
prints out for the user the list of environment variables using the syntax
appropriate for the user's current shell (as specified by the C<SHELL>
environment variable), suitable for directly adding to one's shell
configuration file.
More generally, local::lib allows for the bootstrapping and usage of a
directory containing Perl modules outside of Perl's C<@INC>. This makes it
easier to ship an application with an app-specific copy of a Perl module, or
collection of modules. Useful in cases like when an upstream maintainer hasn't
applied a patch to a module of theirs that you need for your application.
On import, local::lib sets the following environment variables to appropriate
values:
=over 4
=item PERL_MB_OPT
=item PERL_MM_OPT
=item PERL5LIB
=item PATH
=item PERL_LOCAL_LIB_ROOT
=back
When possible, these will be appended to instead of overwritten entirely.
These values are then available for reference by any code after import.
=head1 CREATING A SELF-CONTAINED SET OF MODULES
See L<lib::core::only> for one way to do this - but note that
there are a number of caveats, and the best approach is always to perform a
build against a clean perl (i.e. site and vendor as close to empty as possible).
=head1 IMPORT OPTIONS
Options are values that can be passed to the C<local::lib> import besides the
directory to use. They are specified as C<use local::lib '--option'[, path];>
or C<perl -Mlocal::lib=--option[,path]>.
=head2 --deactivate
Remove the chosen path (or the default path) from the module search paths if it
was added by C<local::lib>, instead of adding it.
=head2 --deactivate-all
Remove all directories that were added to search paths by C<local::lib> from the
search paths.
=head2 --quiet
Don't output any messages about directories being created.
=head2 --always
Always add directories to environment variables, ignoring if they are already
included.
=head2 --shelltype
Specify the shell type to use for output. By default, the shell will be
detected based on the environment. Should be one of: C<bourne>, C<csh>,
C<cmd>, or C<powershell>.
=head2 --no-create
Prevents C<local::lib> from creating directories when activating dirs. This is
likely to cause issues on Win32 systems.
=head1 CLASS METHODS
=head2 ensure_dir_structure_for
=over 4
=item Arguments: $path
=item Return value: None
=back
Attempts to create a local::lib directory, including subdirectories and all
required parent directories. Throws an exception on failure.
=head2 print_environment_vars_for
=over 4
=item Arguments: $path
=item Return value: None
=back
Prints to standard output the variables listed above, properly set to use the
given path as the base directory.
=head2 build_environment_vars_for
=over 4
=item Arguments: $path
=item Return value: %environment_vars
=back
Returns a hash with the variables listed above, properly set to use the
given path as the base directory.
=head2 setup_env_hash_for
=over 4
=item Arguments: $path
=item Return value: None
=back
Constructs the C<%ENV> keys for the given path, by calling
L</build_environment_vars_for>.
=head2 active_paths
=over 4
=item Arguments: None
=item Return value: @paths
=back
Returns a list of active C<local::lib> paths, according to the
C<PERL_LOCAL_LIB_ROOT> environment variable and verified against
what is really in C<@INC>.
=head2 install_base_perl_path
=over 4
=item Arguments: $path
=item Return value: $install_base_perl_path
=back
Returns a path describing where to install the Perl modules for this local
library installation. Appends the directories C<lib> and C<perl5> to the given
path.
=head2 lib_paths_for
=over 4
=item Arguments: $path
=item Return value: @lib_paths
=back
Returns the list of paths perl will search for libraries, given a base path.
This includes the base path itself, the architecture specific subdirectory, and
perl version specific subdirectories. These paths may not all exist.
=head2 install_base_bin_path
=over 4
=item Arguments: $path
=item Return value: $install_base_bin_path
=back
Returns a path describing where to install the executable programs for this
local library installation. Appends the directory C<bin> to the given path.
=head2 installer_options_for
=over 4
=item Arguments: $path
=item Return value: %installer_env_vars
=back
Returns a hash of environment variables that should be set to cause
installation into the given path.
=head2 resolve_empty_path
=over 4
=item Arguments: $path
=item Return value: $base_path
=back
Builds and returns the base path into which to set up the local module
installation. Defaults to C<~/perl5>.
=head2 resolve_home_path
=over 4
=item Arguments: $path
=item Return value: $home_path
=back
Attempts to find the user's home directory.
If no definite answer is available, throws an exception.
=head2 resolve_relative_path
=over 4
=item Arguments: $path
=item Return value: $absolute_path
=back
Translates the given path into an absolute path.
=head2 resolve_path
=over 4
=item Arguments: $path
=item Return value: $absolute_path
=back
Calls the following in a pipeline, passing the result from the previous to the
next, in an attempt to find where to configure the environment for a local
library installation: L</resolve_empty_path>, L</resolve_home_path>,
L</resolve_relative_path>. Passes the given path argument to
L</resolve_empty_path> which then returns a result that is passed to
L</resolve_home_path>, which then has its result passed to
L</resolve_relative_path>. The result of this final call is returned from
L</resolve_path>.
=head1 OBJECT INTERFACE
=head2 new
=over 4
=item Arguments: %attributes
=item Return value: $local_lib
=back
Constructs a new C<local::lib> object, representing the current state of
C<@INC> and the relevant environment variables.
=head1 ATTRIBUTES
=head2 roots
An arrayref representing active C<local::lib> directories.
=head2 inc
An arrayref representing C<@INC>.
=head2 libs
An arrayref representing the PERL5LIB environment variable.
=head2 bins
An arrayref representing the PATH environment variable.
=head2 extra
A hashref of extra environment variables (e.g. C<PERL_MM_OPT> and
C<PERL_MB_OPT>)
=head2 no_create
If set, C<local::lib> will not try to create directories when activating them.
=head1 OBJECT METHODS
=head2 clone
=over 4
=item Arguments: %attributes
=item Return value: $local_lib
=back
Constructs a new C<local::lib> object based on the existing one, overriding the
specified attributes.
=head2 activate
=over 4
=item Arguments: $path
=item Return value: $new_local_lib
=back
Constructs a new instance with the specified path active.
=head2 deactivate
=over 4
=item Arguments: $path
=item Return value: $new_local_lib
=back
Constructs a new instance with the specified path deactivated.
=head2 deactivate_all
=over 4
=item Arguments: None
=item Return value: $new_local_lib
=back
Constructs a new instance with all C<local::lib> directories deactivated.
=head2 environment_vars_string
=over 4
=item Arguments: [ $shelltype ]
=item Return value: $shell_env_string
=back
Returns a string to set up the C<local::lib>, meant to be run by a shell.
=head2 build_environment_vars
=over 4
=item Arguments: None
=item Return value: %environment_vars
=back
Returns a hash with the variables listed above, properly set to use the
given path as the base directory.
=head2 setup_env_hash
=over 4
=item Arguments: None
=item Return value: None
=back
Constructs the C<%ENV> keys for the given path, by calling
L</build_environment_vars>.
=head2 setup_local_lib
Constructs the C<%ENV> hash using L</setup_env_hash>, and set up C<@INC>.
=head1 A WARNING ABOUT UNINST=1
Be careful about using local::lib in combination with "make install UNINST=1".
The idea of this feature is that will uninstall an old version of a module
before installing a new one. However it lacks a safety check that the old
version and the new version will go in the same directory. Used in combination
with local::lib, you can potentially delete a globally accessible version of a
module while installing the new version in a local place. Only combine "make
install UNINST=1" and local::lib if you understand these possible consequences.
=head1 LIMITATIONS
=over 4
=item * Directory names with spaces in them are not well supported by the perl
toolchain and the programs it uses. Pure-perl distributions should support
spaces, but problems are more likely with dists that require compilation. A
workaround you can do is moving your local::lib to a directory with spaces
B<after> you installed all modules inside your local::lib bootstrap. But be
aware that you can't update or install CPAN modules after the move.
=item * Rather basic shell detection. Right now anything with csh in its name is
assumed to be a C shell or something compatible, and everything else is assumed
to be Bourne, except on Win32 systems. If the C<SHELL> environment variable is
not set, a Bourne-compatible shell is assumed.
=item * Kills any existing PERL_MM_OPT or PERL_MB_OPT.
=item * Should probably auto-fixup CPAN config if not already done.
=item * On VMS and MacOS Classic (pre-OS X), local::lib loads L<File::Spec>.
This means any L<File::Spec> version installed in the local::lib will be
ignored by scripts using local::lib. A workaround for this is using
C<use lib "$local_lib/lib/perl5";> instead of using C<local::lib> directly.
=item * Conflicts with L<ExtUtils::MakeMaker>'s C<PREFIX> option.
C<local::lib> uses the C<INSTALL_BASE> option, as it has more predictable and
sane behavior. If something attempts to use the C<PREFIX> option when running
a F<Makefile.PL>, L<ExtUtils::MakeMaker> will refuse to run, as the two
options conflict. This can be worked around by temporarily unsetting the
C<PERL_MM_OPT> environment variable.
=item * Conflicts with L<Module::Build>'s C<--prefix> option. Similar to the
previous limitation, but any C<--prefix> option specified will be ignored.
This can be worked around by temporarily unsetting the C<PERL_MB_OPT>
environment variable.
=back
Patches very much welcome for any of the above.
=over 4
=item * On Win32 systems, does not have a way to write the created environment
variables to the registry, so that they can persist through a reboot.
=back
=head1 TROUBLESHOOTING
If you've configured local::lib to install CPAN modules somewhere in to your
home directory, and at some point later you try to install a module with C<cpan
-i Foo::Bar>, but it fails with an error like: C<Warning: You do not have
permissions to install into /usr/lib64/perl5/site_perl/5.8.8/x86_64-linux at
/usr/lib64/perl5/5.8.8/Foo/Bar.pm> and buried within the install log is an
error saying C<'INSTALL_BASE' is not a known MakeMaker parameter name>, then
you've somehow lost your updated ExtUtils::MakeMaker module.
To remedy this situation, rerun the bootstrapping procedure documented above.
Then, run C<rm -r ~/.cpan/build/Foo-Bar*>
Finally, re-run C<cpan -i Foo::Bar> and it should install without problems.
=head1 ENVIRONMENT
=over 4
=item SHELL
=item COMSPEC
local::lib looks at the user's C<SHELL> environment variable when printing out
commands to add to the shell configuration file.
On Win32 systems, C<COMSPEC> is also examined.
=back
=head1 SEE ALSO
=over 4
=item * L<Perl Advent article, 2011|http://perladvent.org/2011/2011-12-01.html>
=back
=head1 SUPPORT
IRC:
Join #toolchain on irc.perl.org.
=head1 AUTHOR
Matt S Trout <mst@shadowcat.co.uk> http://www.shadowcat.co.uk/
auto_install fixes kindly sponsored by http://www.takkle.com/
=head1 CONTRIBUTORS
Patches to correctly output commands for csh style shells, as well as some
documentation additions, contributed by Christopher Nehren <apeiron@cpan.org>.
Doc patches for a custom local::lib directory, more cleanups in the english
documentation and a L<german documentation|POD2::DE::local::lib> contributed by
Torsten Raudssus <torsten@raudssus.de>.
Hans Dieter Pearcey <hdp@cpan.org> sent in some additional tests for ensuring
things will install properly, submitted a fix for the bug causing problems with
writing Makefiles during bootstrapping, contributed an example program, and
submitted yet another fix to ensure that local::lib can install and bootstrap
properly. Many, many thanks!
pattern of Freenode IRC contributed the beginnings of the Troubleshooting
section. Many thanks!
Patch to add Win32 support contributed by Curtis Jewell <csjewell@cpan.org>.
Warnings for missing PATH/PERL5LIB (as when not running interactively) silenced
by a patch from Marco Emilio Poleggi.
Mark Stosberg <mark@summersault.com> provided the code for the now deleted
'--self-contained' option.
Documentation patches to make win32 usage clearer by
David Mertens <dcmertens.perl@gmail.com> (run4flat).
Brazilian L<portuguese translation|POD2::PT_BR::local::lib> and minor doc
patches contributed by Breno G. de Oliveira <garu@cpan.org>.
Improvements to stacking multiple local::lib dirs and removing them from the
environment later on contributed by Andrew Rodland <arodland@cpan.org>.
Patch for Carp version mismatch contributed by Hakim Cassimally
<osfameron@cpan.org>.
Rewrite of internals and numerous bug fixes and added features contributed by
Graham Knop <haarg@haarg.org>.
=head1 COPYRIGHT
Copyright (c) 2007 - 2013 the local::lib L</AUTHOR> and L</CONTRIBUTORS> as
listed above.
=head1 LICENSE
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut
PK 1N%[UD�� N perl5/x86_64-linux-thread-multi/.meta/LWP-UserAgent-DNS-Hosts-0.14/MYMETA.jsonnu ��6�$ {
"abstract" : "Override LWP HTTP/HTTPS request's host like /etc/hosts",
"author" : [
"NAKAGAWA Masaki <masaki@cpan.org>"
],
"dynamic_config" : 0,
"generated_by" : "Minilla/v3.1.10, CPAN::Meta::Converter version 2.150010",
"license" : [
"perl_5"
],
"meta-spec" : {
"url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
"version" : 2
},
"name" : "LWP-UserAgent-DNS-Hosts",
"no_index" : {
"directory" : [
"t",
"xt",
"inc",
"share",
"eg",
"examples",
"author",
"builder"
]
},
"optional_features" : {
"https" : {
"description" : "SSL support",
"prereqs" : {
"runtime" : {
"recommends" : {
"LWP::Protocol::https" : "0"
}
},
"test" : {
"requires" : {
"HTTP::Daemon::SSL" : "0"
}
}
}
}
},
"prereqs" : {
"configure" : {
"requires" : {
"Module::Build::Tiny" : "0.035"
}
},
"develop" : {
"requires" : {
"Test::CPAN::Meta" : "0",
"Test::MinimumVersion::Fast" : "0.04",
"Test::PAUSE::Permissions" : "0.07",
"Test::Pod" : "1.41",
"Test::Spellunker" : "v0.2.7"
}
},
"runtime" : {
"requires" : {
"LWP::Protocol" : "0",
"LWP::Protocol::http" : "0",
"Scope::Guard" : "0",
"parent" : "0",
"perl" : "5.008001"
}
},
"test" : {
"requires" : {
"File::Temp" : "0",
"LWP::UserAgent" : "0",
"Test::Fake::HTTPD" : "0.08",
"Test::More" : "0.98",
"Test::UseAllModules" : "0"
}
}
},
"provides" : {
"LWP::Protocol::http::hosts" : {
"file" : "lib/LWP/Protocol/http/hosts.pm"
},
"LWP::Protocol::https::hosts" : {
"file" : "lib/LWP/Protocol/https/hosts.pm"
},
"LWP::UserAgent::DNS::Hosts" : {
"file" : "lib/LWP/UserAgent/DNS/Hosts.pm",
"version" : "0.14"
}
},
"release_status" : "stable",
"resources" : {
"bugtracker" : {
"web" : "https://github.com/masaki/p5-LWP-UserAgent-DNS-Hosts/issues"
},
"homepage" : "https://github.com/masaki/p5-LWP-UserAgent-DNS-Hosts",
"repository" : {
"type" : "git",
"url" : "git://github.com/masaki/p5-LWP-UserAgent-DNS-Hosts.git",
"web" : "https://github.com/masaki/p5-LWP-UserAgent-DNS-Hosts"
}
},
"version" : "0.14",
"x_authority" : "cpan:MASAKI",
"x_contributors" : [
"Anirvan Chatterjee <anirvan@users.noreply.github.com>",
"Masaki Nakagawa <masaki.nakagawa@gmail.com>",
"Petr Písař <ppisar@redhat.com>",
"Tatsuhiko Miyagawa <miyagawa@bulknews.net>"
],
"x_serialization_backend" : "JSON::PP version 2.97001",
"x_static_install" : 1
}
PK 1N%[�
�ٴ � O perl5/x86_64-linux-thread-multi/.meta/LWP-UserAgent-DNS-Hosts-0.14/install.jsonnu ��6�$ {"pathname":"M/MA/MASAKI/LWP-UserAgent-DNS-Hosts-0.14.tar.gz","dist":"LWP-UserAgent-DNS-Hosts-0.14","name":"LWP::UserAgent::DNS::Hosts","version":"0.14","target":"LWP::UserAgent::DNS::Hosts","provides":{"LWP::UserAgent::DNS::Hosts":{"file":"lib/LWP/UserAgent/DNS/Hosts.pm","version":"0.14"},"LWP::Protocol::http::hosts":{"file":"lib/LWP/Protocol/http/hosts.pm"},"LWP::Protocol::https::hosts":{"file":"lib/LWP/Protocol/https/hosts.pm"}}}PK 1N%[P��U? ? C perl5/x86_64-linux-thread-multi/.meta/common-sense-3.75/MYMETA.jsonnu ��6�$ {
"abstract" : "unknown",
"author" : [
"unknown"
],
"dynamic_config" : 0,
"generated_by" : "ExtUtils::MakeMaker version 7.34, CPAN::Meta::Converter version 2.150001, CPAN::Meta::Converter version 2.150010",
"license" : [
"unknown"
],
"meta-spec" : {
"url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
"version" : 2
},
"name" : "common-sense",
"no_index" : {
"directory" : [
"t",
"inc"
]
},
"prereqs" : {
"build" : {
"requires" : {
"ExtUtils::MakeMaker" : "0"
}
},
"configure" : {
"requires" : {
"ExtUtils::MakeMaker" : "0"
}
}
},
"release_status" : "stable",
"version" : 3.75,
"x_serialization_backend" : "JSON::PP version 2.97001"
}
PK 1N%[�*� � D perl5/x86_64-linux-thread-multi/.meta/common-sense-3.75/install.jsonnu ��6�$ {"name":"common::sense","dist":"common-sense-3.75","version":3.75,"target":"common::sense","provides":{"common::sense":{"file":"sense.pm.PL","version":3.75}},"pathname":"M/ML/MLEHMANN/common-sense-3.75.tar.gz"}PK 1N%[Q^��� � @ perl5/x86_64-linux-thread-multi/.meta/YAML-Syck-1.34/MYMETA.jsonnu ��6�$ {
"abstract" : "Fast, lightweight YAML loader and dumper",
"author" : [
"Todd Rinaldo <toddr@cpan.org>"
],
"dynamic_config" : 0,
"generated_by" : "ExtUtils::MakeMaker version 7.44, CPAN::Meta::Converter version 2.150010",
"license" : [
"mit"
],
"meta-spec" : {
"url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
"version" : 2
},
"name" : "YAML-Syck",
"no_index" : {
"directory" : [
"t",
"inc"
]
},
"prereqs" : {
"build" : {
"requires" : {
"Test::More" : "0"
}
},
"configure" : {
"requires" : {
"ExtUtils::MakeMaker" : "0"
}
},
"runtime" : {
"requires" : {
"perl" : "5.006"
}
}
},
"release_status" : "stable",
"resources" : {
"bugtracker" : {
"web" : "https://github.com/toddr/YAML-Syck/issues"
},
"homepage" : "http://github.com/toddr/YAML-Syck",
"license" : [
"http://dev.perl.org/licenses/"
],
"repository" : {
"url" : "http://github.com/toddr/YAML-Syck"
}
},
"version" : "1.34",
"x_serialization_backend" : "JSON::PP version 2.97001"
}
PK 1N%[ˊo�m m A perl5/x86_64-linux-thread-multi/.meta/YAML-Syck-1.34/install.jsonnu ��6�$ {"name":"YAML::Syck","dist":"YAML-Syck-1.34","version":1.34,"target":"YAML::Syck","provides":{"YAML::Syck":{"version":1.34,"file":"lib/YAML/Syck.pm"},"YAML::Loader::Syck":{"file":"lib/YAML/Loader/Syck.pm"},"JSON::Syck":{"file":"lib/JSON/Syck.pm","version":1.34},"YAML::Dumper::Syck":{"file":"lib/YAML/Dumper/Syck.pm"}},"pathname":"T/TO/TODDR/YAML-Syck-1.34.tar.gz"}PK 1N%[I~�Uo Uo C perl5/x86_64-linux-thread-multi/.meta/HTTP-Cookies-6.11/MYMETA.jsonnu ��6�$ {
"abstract" : "HTTP cookie jars",
"author" : [
"Gisle Aas <gisle@activestate.com>"
],
"dynamic_config" : 0,
"generated_by" : "Dist::Zilla version 6.031, CPAN::Meta::Converter version 2.150010",
"license" : [
"perl_5"
],
"meta-spec" : {
"url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
"version" : 2
},
"name" : "HTTP-Cookies",
"no_index" : {
"directory" : [
"examples",
"t",
"xt"
]
},
"prereqs" : {
"build" : {
"requires" : {
"ExtUtils::MakeMaker" : "0"
}
},
"configure" : {
"requires" : {
"ExtUtils::MakeMaker" : "0"
}
},
"develop" : {
"requires" : {
"Pod::Coverage::TrustPod" : "0",
"Test::CPAN::Changes" : "0.19",
"Test::EOL" : "0",
"Test::Mojibake" : "0",
"Test::More" : "0.96",
"Test::Pod" : "1.41",
"Test::Pod::Coverage" : "1.08",
"Test::Portability::Files" : "0",
"Test::Version" : "1",
"warnings" : "0"
}
},
"runtime" : {
"requires" : {
"Carp" : "0",
"HTTP::Date" : "6",
"HTTP::Headers::Util" : "6",
"HTTP::Request" : "0",
"locale" : "0",
"perl" : "5.008001",
"strict" : "0"
}
},
"test" : {
"recommends" : {
"CPAN::Meta" : "2.120900"
},
"requires" : {
"ExtUtils::MakeMaker" : "0",
"File::Spec" : "0",
"HTTP::Response" : "0",
"Test::More" : "0",
"URI" : "0",
"warnings" : "0"
}
}
},
"release_status" : "stable",
"resources" : {
"bugtracker" : {
"web" : "https://github.com/libwww-perl/HTTP-Cookies/issues"
},
"homepage" : "https://github.com/libwww-perl/HTTP-Cookies",
"repository" : {
"type" : "git",
"url" : "https://github.com/libwww-perl/HTTP-Cookies.git",
"web" : "https://github.com/libwww-perl/HTTP-Cookies"
}
},
"version" : "6.11",
"x_Dist_Zilla" : {
"perl" : {
"version" : "5.034000"
},
"plugins" : [
{
"class" : "Dist::Zilla::Plugin::Encoding",
"name" : "Encoding",
"version" : "6.031"
},
{
"class" : "Dist::Zilla::Plugin::OSPrereqs",
"config" : {
"Dist::Zilla::Plugin::OSPrereqs" : {
"os" : "MSWin32"
}
},
"name" : "MSWin32",
"version" : "0.011"
},
{
"class" : "Dist::Zilla::Plugin::AutoPrereqs",
"name" : "AutoPrereqs",
"version" : "6.031"
},
{
"class" : "Dist::Zilla::Plugin::Prereqs",
"config" : {
"Dist::Zilla::Plugin::Prereqs" : {
"phase" : "runtime",
"type" : "requires"
}
},
"name" : "Prereqs",
"version" : "6.031"
},
{
"class" : "Dist::Zilla::Plugin::PromptIfStale",
"config" : {
"Dist::Zilla::Plugin::PromptIfStale" : {
"check_all_plugins" : 0,
"check_all_prereqs" : 0,
"modules" : [
"Dist::Zilla::PluginBundle::Author::OALDERS"
],
"phase" : "build",
"run_under_travis" : 0,
"skip" : []
}
},
"name" : "@Author::OALDERS/stale modules, build",
"version" : "0.058"
},
{
"class" : "Dist::Zilla::Plugin::PromptIfStale",
"config" : {
"Dist::Zilla::Plugin::PromptIfStale" : {
"check_all_plugins" : 1,
"check_all_prereqs" : 1,
"modules" : [],
"phase" : "release",
"run_under_travis" : 0,
"skip" : []
}
},
"name" : "@Author::OALDERS/stale modules, release",
"version" : "0.058"
},
{
"class" : "Dist::Zilla::Plugin::CheckChangesHasContent",
"name" : "@Author::OALDERS/CheckChangesHasContent",
"version" : "0.011"
},
{
"class" : "Dist::Zilla::Plugin::MakeMaker",
"config" : {
"Dist::Zilla::Role::TestRunner" : {
"default_jobs" : "8"
}
},
"name" : "@Author::OALDERS/MakeMaker",
"version" : "6.031"
},
{
"class" : "Dist::Zilla::Plugin::CPANFile",
"name" : "@Author::OALDERS/CPANFile",
"version" : "6.031"
},
{
"class" : "Dist::Zilla::Plugin::ContributorsFile",
"name" : "@Author::OALDERS/ContributorsFile",
"version" : "0.3.0"
},
{
"class" : "Dist::Zilla::Plugin::MetaJSON",
"name" : "@Author::OALDERS/MetaJSON",
"version" : "6.031"
},
{
"class" : "Dist::Zilla::Plugin::MetaYAML",
"name" : "@Author::OALDERS/MetaYAML",
"version" : "6.031"
},
{
"class" : "Dist::Zilla::Plugin::Manifest",
"name" : "@Author::OALDERS/Manifest",
"version" : "6.031"
},
{
"class" : "Dist::Zilla::Plugin::MetaNoIndex",
"name" : "@Author::OALDERS/MetaNoIndex",
"version" : "6.031"
},
{
"class" : "Dist::Zilla::Plugin::MetaConfig",
"name" : "@Author::OALDERS/MetaConfig",
"version" : "6.031"
},
{
"class" : "Dist::Zilla::Plugin::MetaResources",
"name" : "@Author::OALDERS/MetaResources",
"version" : "6.031"
},
{
"class" : "Dist::Zilla::Plugin::License",
"name" : "@Author::OALDERS/License",
"version" : "6.031"
},
{
"class" : "Dist::Zilla::Plugin::InstallGuide",
"config" : {
"Dist::Zilla::Role::ModuleMetadata" : {
"Module::Metadata" : "1.000037",
"version" : "0.006"
}
},
"name" : "@Author::OALDERS/InstallGuide",
"version" : "1.200014"
},
{
"class" : "Dist::Zilla::Plugin::ExecDir",
"name" : "@Author::OALDERS/ExecDir",
"version" : "6.031"
},
{
"class" : "Dist::Zilla::Plugin::MojibakeTests",
"name" : "@Author::OALDERS/MojibakeTests",
"version" : "0.8"
},
{
"class" : "Dist::Zilla::Plugin::PodSyntaxTests",
"name" : "@Author::OALDERS/PodSyntaxTests",
"version" : "6.031"
},
{
"class" : "Dist::Zilla::Plugin::Test::CPAN::Changes",
"config" : {
"Dist::Zilla::Plugin::Test::CPAN::Changes" : {
"changelog" : "Changes"
}
},
"name" : "@Author::OALDERS/Test::CPAN::Changes",
"version" : "0.012"
},
{
"class" : "Dist::Zilla::Plugin::Test::EOL",
"config" : {
"Dist::Zilla::Plugin::Test::EOL" : {
"filename" : "xt/author/eol.t",
"finder" : [
":ExecFiles",
":InstallModules",
":TestFiles"
],
"trailing_whitespace" : 1
}
},
"name" : "@Author::OALDERS/Test::EOL",
"version" : "0.19"
},
{
"class" : "Dist::Zilla::Plugin::Test::Pod::Coverage::Configurable",
"name" : "@Author::OALDERS/Test::Pod::Coverage::Configurable",
"version" : "0.07"
},
{
"class" : "Dist::Zilla::Plugin::Test::Portability",
"config" : {
"Dist::Zilla::Plugin::Test::Portability" : {
"options" : ""
}
},
"name" : "@Author::OALDERS/Test::Portability",
"version" : "2.001001"
},
{
"class" : "Dist::Zilla::Plugin::TestRelease",
"name" : "@Author::OALDERS/TestRelease",
"version" : "6.031"
},
{
"class" : "Dist::Zilla::Plugin::Test::ReportPrereqs",
"name" : "@Author::OALDERS/Test::ReportPrereqs",
"version" : "0.029"
},
{
"class" : "Dist::Zilla::Plugin::Test::Version",
"name" : "@Author::OALDERS/Test::Version",
"version" : "1.09"
},
{
"class" : "Dist::Zilla::Plugin::RunExtraTests",
"config" : {
"Dist::Zilla::Role::TestRunner" : {
"default_jobs" : "8"
}
},
"name" : "@Author::OALDERS/RunExtraTests",
"version" : "0.029"
},
{
"class" : "Dist::Zilla::Plugin::PodWeaver",
"config" : {
"Dist::Zilla::Plugin::PodWeaver" : {
"finder" : [
":InstallModules",
":PerlExecFiles"
],
"plugins" : [
{
"class" : "Pod::Weaver::Plugin::EnsurePod5",
"name" : "@CorePrep/EnsurePod5",
"version" : "4.019"
},
{
"class" : "Pod::Weaver::Plugin::H1Nester",
"name" : "@CorePrep/H1Nester",
"version" : "4.019"
},
{
"class" : "Pod::Weaver::Plugin::SingleEncoding",
"name" : "@Default/SingleEncoding",
"version" : "4.019"
},
{
"class" : "Pod::Weaver::Section::Name",
"name" : "@Default/Name",
"version" : "4.019"
},
{
"class" : "Pod::Weaver::Section::Version",
"name" : "@Default/Version",
"version" : "4.019"
},
{
"class" : "Pod::Weaver::Section::Region",
"name" : "@Default/prelude",
"version" : "4.019"
},
{
"class" : "Pod::Weaver::Section::Generic",
"name" : "SYNOPSIS",
"version" : "4.019"
},
{
"class" : "Pod::Weaver::Section::Generic",
"name" : "DESCRIPTION",
"version" : "4.019"
},
{
"class" : "Pod::Weaver::Section::Generic",
"name" : "OVERVIEW",
"version" : "4.019"
},
{
"class" : "Pod::Weaver::Section::Collect",
"name" : "ATTRIBUTES",
"version" : "4.019"
},
{
"class" : "Pod::Weaver::Section::Collect",
"name" : "METHODS",
"version" : "4.019"
},
{
"class" : "Pod::Weaver::Section::Collect",
"name" : "FUNCTIONS",
"version" : "4.019"
},
{
"class" : "Pod::Weaver::Section::Leftovers",
"name" : "@Default/Leftovers",
"version" : "4.019"
},
{
"class" : "Pod::Weaver::Section::Region",
"name" : "@Default/postlude",
"version" : "4.019"
},
{
"class" : "Pod::Weaver::Section::Authors",
"name" : "@Default/Authors",
"version" : "4.019"
},
{
"class" : "Pod::Weaver::Section::Legal",
"name" : "@Default/Legal",
"version" : "4.019"
}
]
}
},
"name" : "@Author::OALDERS/PodWeaver",
"version" : "4.010"
},
{
"class" : "Dist::Zilla::Plugin::PruneCruft",
"name" : "@Author::OALDERS/PruneCruft",
"version" : "6.031"
},
{
"class" : "Dist::Zilla::Plugin::CopyFilesFromBuild",
"name" : "@Author::OALDERS/CopyFilesFromBuild",
"version" : "0.170880"
},
{
"class" : "Dist::Zilla::Plugin::GithubMeta",
"name" : "@Author::OALDERS/GithubMeta",
"version" : "0.58"
},
{
"class" : "Dist::Zilla::Plugin::Git::GatherDir",
"config" : {
"Dist::Zilla::Plugin::GatherDir" : {
"exclude_filename" : [
"Install",
"LICENSE",
"META.json",
"Makefile.PL",
"README.md",
"cpanfile"
],
"exclude_match" : [],
"follow_symlinks" : 0,
"include_dotfiles" : 0,
"prefix" : "",
"prune_directory" : [],
"root" : "."
},
"Dist::Zilla::Plugin::Git::GatherDir" : {
"include_untracked" : 0
}
},
"name" : "@Author::OALDERS/Git::GatherDir",
"version" : "2.048"
},
{
"class" : "Dist::Zilla::Plugin::CopyFilesFromRelease",
"config" : {
"Dist::Zilla::Plugin::CopyFilesFromRelease" : {
"filename" : [
"Install"
],
"match" : []
}
},
"name" : "@Author::OALDERS/CopyFilesFromRelease",
"version" : "0.007"
},
{
"class" : "Dist::Zilla::Plugin::Git::Check",
"config" : {
"Dist::Zilla::Plugin::Git::Check" : {
"untracked_files" : "die"
},
"Dist::Zilla::Role::Git::DirtyFiles" : {
"allow_dirty" : [
"Changes",
"Install",
"LICENSE",
"META.json",
"Makefile.PL",
"README.md",
"cpanfile",
"dist.ini"
],
"allow_dirty_match" : [],
"changelog" : "Changes"
},
"Dist::Zilla::Role::Git::Repo" : {
"git_version" : "2.34.1",
"repo_root" : "."
}
},
"name" : "@Author::OALDERS/Git::Check",
"version" : "2.048"
},
{
"class" : "Dist::Zilla::Plugin::Git::Contributors",
"config" : {
"Dist::Zilla::Plugin::Git::Contributors" : {
"git_version" : "2.34.1",
"include_authors" : 0,
"include_releaser" : 1,
"order_by" : "name",
"paths" : []
}
},
"name" : "@Author::OALDERS/Git::Contributors",
"version" : "0.036"
},
{
"class" : "Dist::Zilla::Plugin::ReadmeAnyFromPod",
"config" : {
"Dist::Zilla::Role::FileWatcher" : {
"version" : "0.006"
}
},
"name" : "@Author::OALDERS/ReadmeMdInBuild",
"version" : "0.163250"
},
{
"class" : "Dist::Zilla::Plugin::StaticInstall",
"config" : {
"Dist::Zilla::Plugin::StaticInstall" : {
"dry_run" : 0,
"mode" : "off"
}
},
"name" : "@Author::OALDERS/StaticInstall",
"version" : "0.012"
},
{
"class" : "Dist::Zilla::Plugin::ShareDir",
"name" : "@Author::OALDERS/ShareDir",
"version" : "6.031"
},
{
"class" : "Dist::Zilla::Plugin::CheckIssues",
"name" : "@Author::OALDERS/CheckIssues",
"version" : "0.011"
},
{
"class" : "Dist::Zilla::Plugin::ConfirmRelease",
"name" : "@Author::OALDERS/ConfirmRelease",
"version" : "6.031"
},
{
"class" : "Dist::Zilla::Plugin::UploadToCPAN",
"name" : "@Author::OALDERS/UploadToCPAN",
"version" : "6.031"
},
{
"class" : "Dist::Zilla::Plugin::RewriteVersion::Transitional",
"config" : {
"Dist::Zilla::Plugin::RewriteVersion" : {
"add_tarball_name" : 0,
"finders" : [
":ExecFiles",
":InstallModules"
],
"global" : 0,
"skip_version_provider" : 0
},
"Dist::Zilla::Plugin::RewriteVersion::Transitional" : {}
},
"name" : "@Author::OALDERS/@Git::VersionManager/RewriteVersion::Transitional",
"version" : "0.009"
},
{
"class" : "Dist::Zilla::Plugin::MetaProvides::Update",
"name" : "@Author::OALDERS/@Git::VersionManager/MetaProvides::Update",
"version" : "0.007"
},
{
"class" : "Dist::Zilla::Plugin::CopyFilesFromRelease",
"config" : {
"Dist::Zilla::Plugin::CopyFilesFromRelease" : {
"filename" : [
"Changes"
],
"match" : []
}
},
"name" : "@Author::OALDERS/@Git::VersionManager/CopyFilesFromRelease",
"version" : "0.007"
},
{
"class" : "Dist::Zilla::Plugin::Git::Commit",
"config" : {
"Dist::Zilla::Plugin::Git::Commit" : {
"add_files_in" : [],
"commit_msg" : "v%V%n%n%c",
"signoff" : 0
},
"Dist::Zilla::Role::Git::DirtyFiles" : {
"allow_dirty" : [
"Changes",
"Install",
"LICENSE",
"META.json",
"Makefile.PL",
"README.md",
"cpanfile",
"dist.ini"
],
"allow_dirty_match" : [],
"changelog" : "Changes"
},
"Dist::Zilla::Role::Git::Repo" : {
"git_version" : "2.34.1",
"repo_root" : "."
},
"Dist::Zilla::Role::Git::StringFormatter" : {
"time_zone" : "local"
}
},
"name" : "@Author::OALDERS/@Git::VersionManager/release snapshot",
"version" : "2.048"
},
{
"class" : "Dist::Zilla::Plugin::Git::Tag",
"config" : {
"Dist::Zilla::Plugin::Git::Tag" : {
"branch" : null,
"changelog" : "Changes",
"signed" : 0,
"tag" : "v6.11",
"tag_format" : "v%V",
"tag_message" : "v%V"
},
"Dist::Zilla::Role::Git::Repo" : {
"git_version" : "2.34.1",
"repo_root" : "."
},
"Dist::Zilla::Role::Git::StringFormatter" : {
"time_zone" : "local"
}
},
"name" : "@Author::OALDERS/@Git::VersionManager/Git::Tag",
"version" : "2.048"
},
{
"class" : "Dist::Zilla::Plugin::BumpVersionAfterRelease::Transitional",
"config" : {
"Dist::Zilla::Plugin::BumpVersionAfterRelease" : {
"finders" : [
":ExecFiles",
":InstallModules"
],
"global" : 0,
"munge_makefile_pl" : 1
},
"Dist::Zilla::Plugin::BumpVersionAfterRelease::Transitional" : {}
},
"name" : "@Author::OALDERS/@Git::VersionManager/BumpVersionAfterRelease::Transitional",
"version" : "0.009"
},
{
"class" : "Dist::Zilla::Plugin::NextRelease",
"name" : "@Author::OALDERS/@Git::VersionManager/NextRelease",
"version" : "6.031"
},
{
"class" : "Dist::Zilla::Plugin::Git::Commit",
"config" : {
"Dist::Zilla::Plugin::Git::Commit" : {
"add_files_in" : [],
"commit_msg" : "increment $VERSION after %v release",
"signoff" : 0
},
"Dist::Zilla::Role::Git::DirtyFiles" : {
"allow_dirty" : [
"Build.PL",
"Changes",
"Makefile.PL"
],
"allow_dirty_match" : [
"(?^:^lib/.*\\.pm$)"
],
"changelog" : "Changes"
},
"Dist::Zilla::Role::Git::Repo" : {
"git_version" : "2.34.1",
"repo_root" : "."
},
"Dist::Zilla::Role::Git::StringFormatter" : {
"time_zone" : "local"
}
},
"name" : "@Author::OALDERS/@Git::VersionManager/post-release commit",
"version" : "2.048"
},
{
"class" : "Dist::Zilla::Plugin::Git::Push",
"config" : {
"Dist::Zilla::Plugin::Git::Push" : {
"push_to" : [
"origin"
],
"remotes_must_exist" : 1
},
"Dist::Zilla::Role::Git::Repo" : {
"git_version" : "2.34.1",
"repo_root" : "."
}
},
"name" : "@Author::OALDERS/Git::Push",
"version" : "2.048"
},
{
"class" : "Dist::Zilla::Plugin::BumpVersionAfterRelease",
"config" : {
"Dist::Zilla::Plugin::BumpVersionAfterRelease" : {
"finders" : [
":ExecFiles",
":InstallModules"
],
"global" : 0,
"munge_makefile_pl" : 1
}
},
"name" : "BumpVersionAfterRelease",
"version" : "0.018"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":InstallModules",
"version" : "6.031"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":IncModules",
"version" : "6.031"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":TestFiles",
"version" : "6.031"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":ExtraTestFiles",
"version" : "6.031"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":ExecFiles",
"version" : "6.031"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":PerlExecFiles",
"version" : "6.031"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":ShareFiles",
"version" : "6.031"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":MainModule",
"version" : "6.031"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":AllFiles",
"version" : "6.031"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":NoFiles",
"version" : "6.031"
}
],
"zilla" : {
"class" : "Dist::Zilla::Dist::Builder",
"config" : {
"is_trial" : 0
},
"version" : "6.031"
}
},
"x_contributors" : [
"Adam Kennedy <adamk@cpan.org>",
"Adam Sjogren <asjo@koldfront.dk>",
"Alexey Tourbin <at@altlinux.ru>",
"Alex Kapranoff <ka@nadoby.ru>",
"Alex Peters <alex@peters.net>",
"Alex Peters <lxp@cpan.org>",
"amire80 <amir.aharoni@gmail.com>",
"Andreas J. Koenig <andreas.koenig@anima.de>",
"Bernhard M. Wiedemann <bwiedemann@suse.de>",
"Bill Mann <wfmann@alum.mit.edu>",
"Bron Gondwana <brong@fastmail.fm>",
"Charlie Hothersall-Thomas <me@charlie.ht>",
"Chase Whitener <capoeirab@cpan.org>",
"Colin Newell <c.newell@cv-library.co.uk>",
"Colin Newell <colin.newell@gmail.com>",
"Daniel Hedlund <Daniel.Hedlund@eprize.com>",
"Dave Menninger <dave.menninger@online-rewards.com>",
"David E. Wheeler <david@justatheory.com>",
"DAVIDRW <davidrw@cpan.org>",
"Father Chrysostomos <sprout@cpan.org>",
"FWILES <FWILES@cpan.org>",
"Gavin Peters <gpeters@deepsky.com>",
"George Grozdev <g.grozdev@cv-library.co.uk>",
"Graeme Thompson <Graeme.Thompson@mobilecohesion.com>",
"Hans-H. Froehlich <hfroehlich@co-de-co.de>",
"Ian Kilgore <iank@cpan.org>",
"Jacob J <waif@chaos2.org>",
"James McCoy <vega.james@gmail.com>",
"James Raspass <jraspass@gmail.com>",
"jefflee <shaohua@gmail.com>",
"john9art <john9art@yahoo.com>",
"Mark Raymond <m.raymond@cv-library.co.uk>",
"Mark Stosberg <MARKSTOS@cpan.org>",
"Mike Schilli <m@perlmeiser.com>",
"Mohammad S Anwar <mohammad.anwar@yahoo.com>",
"murphy <murphy@genome.chop.edu>",
"Olaf Alders <olaf@wundersolutions.com>",
"Ondrej Hanak <ondrej.hanak@ubs.com>",
"Perlover <perlover@perlover.com>",
"Peter Rabbitson <ribasushi@cpan.org>",
"Philip J. Ludlam <p.ludlam@cv-library.co.uk>",
"phrstbrn <phrstbrn@gmail.com>",
"Robert Stone <talby@trap.mtview.ca.us>",
"robnagler <github@q33.us>",
"Rolf Grossmann <rg@progtech.net>",
"ruff <ruff@ukrpost.net>",
"sasao <sasao@yugen.org>",
"Sean M. Burke <sburke@cpan.org>",
"simbabque <simbabque@cpan.org>",
"Slaven Rezic <slaven@rezic.de>",
"Spiros Denaxas <s.denaxas@gmail.com>",
"Steve Hay <SteveHay@planit.com>",
"Todd Lipcon <todd@amiestreet.com>",
"Tom Hukins <tom@eborcom.com>",
"Tony Finch <dot@dotat.at>",
"Toru Yamaguchi <zigorou@cpan.org>",
"Ville Skyttä <ville.skytta@iki.fi>",
"Yuri Karaban <tech@askold.net>",
"Zefram <zefram@fysh.org>"
],
"x_generated_by_perl" : "v5.34.0",
"x_serialization_backend" : "JSON::PP version 2.97001",
"x_spdx_expression" : "Artistic-1.0-Perl OR GPL-1.0-or-later",
"x_static_install" : 0
}
PK 1N%[�B҇} } D perl5/x86_64-linux-thread-multi/.meta/HTTP-Cookies-6.11/install.jsonnu ��6�$ {"name":"HTTP::Cookies","target":"HTTP::Cookies","version":6.11,"provides":{"HTTP::Cookies::Microsoft":{"version":6.11,"file":"lib/HTTP/Cookies/Microsoft.pm"},"HTTP::Cookies":{"version":6.11,"file":"lib/HTTP/Cookies.pm"},"HTTP::Cookies::Netscape":{"version":6.11,"file":"lib/HTTP/Cookies/Netscape.pm"}},"pathname":"O/OA/OALDERS/HTTP-Cookies-6.11.tar.gz","dist":"HTTP-Cookies-6.11"}PK 2N%[����= = C perl5/x86_64-linux-thread-multi/.meta/Capture-Tiny-0.50/MYMETA.jsonnu ��6�$ {
"abstract" : "Capture STDOUT and STDERR from Perl, XS or external programs",
"author" : [
"David Golden <dagolden@cpan.org>"
],
"dynamic_config" : 0,
"generated_by" : "Dist::Zilla version 6.032, CPAN::Meta::Converter version 2.150010",
"license" : [
"apache_2_0"
],
"meta-spec" : {
"url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
"version" : 2
},
"name" : "Capture-Tiny",
"no_index" : {
"directory" : [
"corpus",
"examples",
"t",
"xt"
],
"package" : [
"DB"
]
},
"prereqs" : {
"build" : {
"requires" : {
"ExtUtils::MakeMaker" : "0"
}
},
"configure" : {
"requires" : {
"ExtUtils::MakeMaker" : "6.17"
}
},
"develop" : {
"requires" : {
"Dist::Zilla" : "5",
"Dist::Zilla::Plugin::OSPrereqs" : "0",
"Dist::Zilla::Plugin::Prereqs" : "0",
"Dist::Zilla::Plugin::ReleaseStatus::FromVersion" : "0",
"Dist::Zilla::Plugin::RemovePrereqs" : "0",
"Dist::Zilla::PluginBundle::DAGOLDEN" : "0.072",
"File::Spec" : "0",
"File::Temp" : "0",
"IO::Handle" : "0",
"IPC::Open3" : "0",
"Pod::Coverage::TrustPod" : "0",
"Pod::Wordlist" : "0",
"Software::License::Apache_2_0" : "0",
"Test::CPAN::Meta" : "0",
"Test::MinimumVersion" : "0",
"Test::More" : "0",
"Test::Perl::Critic" : "0",
"Test::Pod" : "1.41",
"Test::Pod::Coverage" : "1.08",
"Test::Portability::Files" : "0",
"Test::Spelling" : "0.17",
"Test::Version" : "1"
}
},
"runtime" : {
"requires" : {
"Carp" : "0",
"Exporter" : "0",
"File::Spec" : "0",
"File::Temp" : "0",
"IO::Handle" : "0",
"Scalar::Util" : "0",
"perl" : "5.006",
"strict" : "0",
"warnings" : "0"
}
},
"test" : {
"recommends" : {
"CPAN::Meta" : "2.120900"
},
"requires" : {
"ExtUtils::MakeMaker" : "0",
"File::Spec" : "0",
"IO::File" : "0",
"Test::More" : "0.62",
"lib" : "0"
}
}
},
"provides" : {
"Capture::Tiny" : {
"file" : "lib/Capture/Tiny.pm",
"version" : "0.50"
}
},
"release_status" : "stable",
"resources" : {
"bugtracker" : {
"web" : "https://github.com/dagolden/Capture-Tiny/issues"
},
"homepage" : "https://github.com/dagolden/Capture-Tiny",
"repository" : {
"type" : "git",
"url" : "https://github.com/dagolden/Capture-Tiny.git",
"web" : "https://github.com/dagolden/Capture-Tiny"
}
},
"version" : "0.50",
"x_authority" : "cpan:DAGOLDEN",
"x_contributors" : [
"Dagfinn Ilmari Mannsåker <ilmari@ilmari.org>",
"David E. Wheeler <david@justatheory.com>",
"Ed Sabol <esabol@users.noreply.github.com>",
"fecundf <not.com+github@gmail.com>",
"Graham Knop <haarg@haarg.org>",
"Karen Etheridge <ether@cpan.org>",
"Mohammad S Anwar <mohammad.anwar@yahoo.com>",
"Peter Rabbitson <ribasushi@cpan.org>",
"Sven Kirmess <sven.kirmess@kzone.ch>"
],
"x_generated_by_perl" : "v5.36.0",
"x_serialization_backend" : "JSON::PP version 2.97001",
"x_spdx_expression" : "Apache-2.0"
}
PK 2N%[�;/�� � D perl5/x86_64-linux-thread-multi/.meta/Capture-Tiny-0.50/install.jsonnu ��6�$ {"provides":{"Capture::Tiny":{"file":"lib/Capture/Tiny.pm","version":"0.50"}},"name":"Capture::Tiny","dist":"Capture-Tiny-0.50","target":"Capture::Tiny","pathname":"D/DA/DAGOLDEN/Capture-Tiny-0.50.tar.gz","version":"0.50"}PK 2N%[��" K perl5/x86_64-linux-thread-multi/.meta/XML-NamespaceSupport-1.12/MYMETA.jsonnu ��6�$ {
"abstract" : "A simple generic namespace processor",
"author" : [
"Robin Berjon <robin@knowscape.com>",
"Chris Prather <chris@prather.org>"
],
"dynamic_config" : 0,
"generated_by" : "Dist::Zilla version 6.009, CPAN::Meta::Converter version 2.150005, CPAN::Meta::Converter version 2.150010",
"license" : [
"perl_5"
],
"meta-spec" : {
"url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
"version" : 2
},
"name" : "XML-NamespaceSupport",
"no_index" : {
"directory" : [
"corpus",
"examples",
"t",
"xt"
],
"package" : [
"DB"
]
},
"prereqs" : {
"build" : {
"requires" : {
"ExtUtils::MakeMaker" : "0"
}
},
"configure" : {
"requires" : {
"ExtUtils::MakeMaker" : "6.17"
}
},
"develop" : {
"requires" : {
"Dist::Zilla" : "5",
"Dist::Zilla::Plugin::Authority" : "0",
"Dist::Zilla::Plugin::AutoPrereqs" : "0",
"Dist::Zilla::Plugin::CPANFile" : "0",
"Dist::Zilla::Plugin::CheckChangesHasContent" : "0",
"Dist::Zilla::Plugin::CheckMetaResources" : "0",
"Dist::Zilla::Plugin::CheckPrereqsIndexed" : "0",
"Dist::Zilla::Plugin::ConfirmRelease" : "0",
"Dist::Zilla::Plugin::CopyFilesFromBuild" : "0",
"Dist::Zilla::Plugin::ExecDir" : "0",
"Dist::Zilla::Plugin::Git::Check" : "0",
"Dist::Zilla::Plugin::Git::CheckFor::CorrectBranch" : "0",
"Dist::Zilla::Plugin::Git::Commit" : "0",
"Dist::Zilla::Plugin::Git::Contributors" : "0",
"Dist::Zilla::Plugin::Git::GatherDir" : "0",
"Dist::Zilla::Plugin::Git::NextVersion" : "0",
"Dist::Zilla::Plugin::Git::Push" : "0",
"Dist::Zilla::Plugin::Git::Tag" : "0",
"Dist::Zilla::Plugin::GithubMeta" : "0",
"Dist::Zilla::Plugin::InsertCopyright" : "0",
"Dist::Zilla::Plugin::License" : "0",
"Dist::Zilla::Plugin::MakeMaker" : "0",
"Dist::Zilla::Plugin::Manifest" : "0",
"Dist::Zilla::Plugin::ManifestSkip" : "0",
"Dist::Zilla::Plugin::MetaJSON" : "0",
"Dist::Zilla::Plugin::MetaNoIndex" : "0",
"Dist::Zilla::Plugin::MetaProvides::Package" : "0",
"Dist::Zilla::Plugin::MetaYAML" : "0",
"Dist::Zilla::Plugin::MinimumPerl" : "0",
"Dist::Zilla::Plugin::NextRelease" : "0",
"Dist::Zilla::Plugin::OurPkgVersion" : "0",
"Dist::Zilla::Plugin::PodWeaver" : "0",
"Dist::Zilla::Plugin::Prereqs::AuthorDeps" : "0",
"Dist::Zilla::Plugin::PromptIfStale" : "0",
"Dist::Zilla::Plugin::PruneCruft" : "0",
"Dist::Zilla::Plugin::RunExtraTests" : "0",
"Dist::Zilla::Plugin::ShareDir" : "0",
"Dist::Zilla::Plugin::TestRelease" : "0",
"Dist::Zilla::Plugin::UploadToCPAN" : "0",
"Software::License::Perl_5" : "0"
}
},
"runtime" : {
"requires" : {
"constant" : "0",
"perl" : "5.006",
"strict" : "0",
"vars" : "0",
"warnings" : "0"
}
},
"test" : {
"requires" : {
"Test::More" : "0"
}
}
},
"provides" : {
"XML::NamespaceSupport" : {
"file" : "lib/XML/NamespaceSupport.pm",
"version" : "1.12"
}
},
"release_status" : "stable",
"resources" : {
"bugtracker" : {
"web" : "https://github.com/perigrin/xml-namespacesupport/issues"
},
"homepage" : "https://github.com/perigrin/xml-namespacesupport",
"repository" : {
"type" : "git",
"url" : "https://github.com/perigrin/xml-namespacesupport.git",
"web" : "https://github.com/perigrin/xml-namespacesupport"
}
},
"version" : "1.12",
"x_authority" : "cpan:PERIGRIN",
"x_contributors" : [
"Chris Prather <cprather@hdpublishing.com>",
"David Steinbrunner <dsteinbrunner@pobox.com>",
"Paul Cochrane <paul@liekut.de>",
"Paulo Custodio <pauloscustodio@gmail.com>"
],
"x_serialization_backend" : "JSON::PP version 2.97001"
}
PK 2N%[��� L perl5/x86_64-linux-thread-multi/.meta/XML-NamespaceSupport-1.12/install.jsonnu ��6�$ {"version":"1.12","provides":{"XML::NamespaceSupport":{"file":"lib/XML/NamespaceSupport.pm","version":"1.12"}},"pathname":"P/PE/PERIGRIN/XML-NamespaceSupport-1.12.tar.gz","dist":"XML-NamespaceSupport-1.12","name":"XML::NamespaceSupport","target":"XML::NamespaceSupport"}PK 2N%[aE�|p p E perl5/x86_64-linux-thread-multi/.meta/HTTP-Negotiate-6.01/MYMETA.jsonnu ��6�$ {
"abstract" : "choose a variant to serve",
"author" : [
"Gisle Aas <gisle@activestate.com>"
],
"dynamic_config" : 0,
"generated_by" : "ExtUtils::MakeMaker version 6.57_05, CPAN::Meta::Converter version 2.150010",
"license" : [
"perl_5"
],
"meta-spec" : {
"url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
"version" : 2
},
"name" : "HTTP-Negotiate",
"no_index" : {
"directory" : [
"t",
"inc"
]
},
"prereqs" : {
"build" : {
"requires" : {
"ExtUtils::MakeMaker" : "0"
}
},
"configure" : {
"requires" : {
"ExtUtils::MakeMaker" : "0"
}
},
"runtime" : {
"requires" : {
"HTTP::Headers" : "6",
"perl" : "5.008001"
}
}
},
"release_status" : "stable",
"resources" : {
"repository" : {
"url" : "http://github.com/gisle/http-negotiate"
},
"x_MailingList" : "mailto:libwww@perl.org"
},
"version" : "6.01",
"x_serialization_backend" : "JSON::PP version 2.97001"
}
PK 2N%[��ϧ� � F perl5/x86_64-linux-thread-multi/.meta/HTTP-Negotiate-6.01/install.jsonnu ��6�$ {"target":"HTTP::Negotiate","name":"HTTP::Negotiate","pathname":"G/GA/GAAS/HTTP-Negotiate-6.01.tar.gz","provides":{"HTTP::Negotiate":{"version":6.01,"file":"lib/HTTP/Negotiate.pm"}},"version":6.01,"dist":"HTTP-Negotiate-6.01"}PK 2N%[Y�lm� � B perl5/x86_64-linux-thread-multi/.meta/libwww-perl-6.78/MYMETA.jsonnu ��6�$ {
"abstract" : "The World-Wide Web library for Perl",
"author" : [
"Gisle Aas <gisle@activestate.com>"
],
"dynamic_config" : 0,
"generated_by" : "Dist::Zilla version 6.032, CPAN::Meta::Converter version 2.150010",
"license" : [
"perl_5"
],
"meta-spec" : {
"url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
"version" : 2
},
"name" : "libwww-perl",
"no_index" : {
"directory" : [
"t",
"xt"
]
},
"prereqs" : {
"build" : {
"requires" : {
"ExtUtils::MakeMaker" : "0"
}
},
"configure" : {
"requires" : {
"ExtUtils::MakeMaker" : "0",
"File::Copy" : "0",
"Getopt::Long" : "0"
},
"suggests" : {
"JSON::PP" : "2.27300"
}
},
"develop" : {
"recommends" : {
"Dist::Zilla::PluginBundle::Git::VersionManager" : "0.007"
},
"requires" : {
"Authen::NTLM" : "1.02",
"File::Spec" : "0",
"IO::Handle" : "0",
"IPC::Open3" : "0",
"Pod::Coverage::TrustPod" : "0",
"Pod::Spell" : "1.25",
"Test::EOL" : "2.00",
"Test::LeakTrace" : "0.16",
"Test::MinimumVersion" : "0",
"Test::Mojibake" : "0",
"Test::More" : "0.94",
"Test::Pod" : "1.41",
"Test::Pod::Coverage" : "1.08",
"Test::Portability::Files" : "0",
"Test::Spelling" : "0.17",
"Test::Version" : "1"
}
},
"runtime" : {
"requires" : {
"Digest::MD5" : "0",
"Encode" : "2.12",
"Encode::Locale" : "0",
"File::Copy" : "0",
"File::Listing" : "6",
"File::Temp" : "0",
"Getopt::Long" : "0",
"HTML::Entities" : "0",
"HTML::HeadParser" : "3.71",
"HTTP::Cookies" : "6",
"HTTP::Date" : "6",
"HTTP::Negotiate" : "6",
"HTTP::Request" : "6.18",
"HTTP::Request::Common" : "6.18",
"HTTP::Response" : "6.18",
"HTTP::Status" : "6.18",
"IO::Select" : "0",
"IO::Socket" : "0",
"LWP::MediaTypes" : "6",
"MIME::Base64" : "2.1",
"Module::Load" : "0",
"Net::FTP" : "2.58",
"Net::HTTP" : "6.18",
"Scalar::Util" : "0",
"Try::Tiny" : "0",
"URI" : "1.10",
"URI::Escape" : "0",
"WWW::RobotRules" : "6",
"parent" : "0.217",
"perl" : "5.008001",
"strict" : "0",
"warnings" : "0"
},
"suggests" : {
"Authen::NTLM" : "1.02",
"Data::Dump" : "1.13",
"IO::Socket::INET" : "0",
"LWP::Protocol::https" : "6.02"
}
},
"test" : {
"recommends" : {
"CPAN::Meta" : "2.120900",
"Test::LeakTrace" : "0"
},
"requires" : {
"ExtUtils::MakeMaker" : "0",
"File::Spec" : "0",
"FindBin" : "0",
"HTTP::CookieJar::LWP" : "0",
"HTTP::Daemon" : "6.12",
"Test::Fatal" : "0",
"Test::More" : "0.96",
"Test::Needs" : "0",
"Test::RequiresInternet" : "0"
}
}
},
"provides" : {
"LWP" : {
"file" : "lib/LWP.pm",
"version" : "6.78"
},
"LWP::Authen::Basic" : {
"file" : "lib/LWP/Authen/Basic.pm",
"version" : "6.78"
},
"LWP::Authen::Digest" : {
"file" : "lib/LWP/Authen/Digest.pm",
"version" : "6.78"
},
"LWP::Authen::Ntlm" : {
"file" : "lib/LWP/Authen/Ntlm.pm",
"version" : "6.78"
},
"LWP::ConnCache" : {
"file" : "lib/LWP/ConnCache.pm",
"version" : "6.78"
},
"LWP::Debug" : {
"file" : "lib/LWP/Debug.pm",
"version" : "6.78",
"x_deprecated" : 1
},
"LWP::Debug::TraceHTTP" : {
"file" : "lib/LWP/Debug/TraceHTTP.pm",
"version" : "6.78"
},
"LWP::DebugFile" : {
"file" : "lib/LWP/DebugFile.pm",
"version" : "6.78"
},
"LWP::MemberMixin" : {
"file" : "lib/LWP/MemberMixin.pm",
"version" : "6.78"
},
"LWP::Protocol" : {
"file" : "lib/LWP/Protocol.pm",
"version" : "6.78"
},
"LWP::Protocol::cpan" : {
"file" : "lib/LWP/Protocol/cpan.pm",
"version" : "6.78"
},
"LWP::Protocol::data" : {
"file" : "lib/LWP/Protocol/data.pm",
"version" : "6.78"
},
"LWP::Protocol::file" : {
"file" : "lib/LWP/Protocol/file.pm",
"version" : "6.78"
},
"LWP::Protocol::ftp" : {
"file" : "lib/LWP/Protocol/ftp.pm",
"version" : "6.78"
},
"LWP::Protocol::gopher" : {
"file" : "lib/LWP/Protocol/gopher.pm",
"version" : "6.78"
},
"LWP::Protocol::http" : {
"file" : "lib/LWP/Protocol/http.pm",
"version" : "6.78"
},
"LWP::Protocol::loopback" : {
"file" : "lib/LWP/Protocol/loopback.pm",
"version" : "6.78"
},
"LWP::Protocol::mailto" : {
"file" : "lib/LWP/Protocol/mailto.pm",
"version" : "6.78"
},
"LWP::Protocol::nntp" : {
"file" : "lib/LWP/Protocol/nntp.pm",
"version" : "6.78"
},
"LWP::Protocol::nogo" : {
"file" : "lib/LWP/Protocol/nogo.pm",
"version" : "6.78"
},
"LWP::RobotUA" : {
"file" : "lib/LWP/RobotUA.pm",
"version" : "6.78"
},
"LWP::Simple" : {
"file" : "lib/LWP/Simple.pm",
"version" : "6.78"
},
"LWP::UserAgent" : {
"file" : "lib/LWP/UserAgent.pm",
"version" : "6.78"
}
},
"release_status" : "stable",
"resources" : {
"bugtracker" : {
"web" : "https://github.com/libwww-perl/libwww-perl/issues"
},
"homepage" : "https://github.com/libwww-perl/libwww-perl",
"repository" : {
"type" : "git",
"url" : "https://github.com/libwww-perl/libwww-perl.git",
"web" : "https://github.com/libwww-perl/libwww-perl"
},
"x_IRC" : "irc://irc.perl.org/#lwp",
"x_MailingList" : "mailto:libwww@perl.org"
},
"version" : "6.78",
"x_Dist_Zilla" : {
"perl" : {
"version" : "5.038002"
},
"plugins" : [
{
"class" : "Dist::Zilla::Plugin::Git::GatherDir",
"config" : {
"Dist::Zilla::Plugin::GatherDir" : {
"exclude_filename" : [
"LICENSE",
"META.json",
"README.md"
],
"exclude_match" : [],
"include_dotfiles" : 0,
"prefix" : "",
"prune_directory" : [],
"root" : "."
},
"Dist::Zilla::Plugin::Git::GatherDir" : {
"include_untracked" : 0
}
},
"name" : "Git::GatherDir",
"version" : "2.051"
},
{
"class" : "Dist::Zilla::Plugin::MetaConfig",
"name" : "MetaConfig",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::MetaProvides::Package",
"config" : {
"Dist::Zilla::Plugin::MetaProvides::Package" : {
"finder_objects" : [
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : "MetaProvides::Package/AUTOVIV/:InstallModulesPM",
"version" : "6.032"
}
],
"include_underscores" : 0
},
"Dist::Zilla::Role::MetaProvider::Provider" : {
"$Dist::Zilla::Role::MetaProvider::Provider::VERSION" : "2.002004",
"inherit_missing" : 1,
"inherit_version" : 1,
"meta_noindex" : 1
},
"Dist::Zilla::Role::ModuleMetadata" : {
"Module::Metadata" : "1.000037",
"version" : "0.006"
}
},
"name" : "MetaProvides::Package",
"version" : "2.004003"
},
{
"class" : "Dist::Zilla::Plugin::MetaNoIndex",
"name" : "MetaNoIndex",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::MetaYAML",
"name" : "MetaYAML",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::MetaJSON",
"name" : "MetaJSON",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::MetaResources",
"name" : "MetaResources",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::Deprecated",
"config" : {
"Dist::Zilla::Plugin::Deprecated" : {
"all" : 0,
"modules" : [
"LWP::Debug"
]
}
},
"name" : "Deprecated",
"version" : "0.007"
},
{
"class" : "Dist::Zilla::Plugin::Git::Contributors",
"config" : {
"Dist::Zilla::Plugin::Git::Contributors" : {
"git_version" : "2.43.0",
"include_authors" : 0,
"include_releaser" : 1,
"order_by" : "name",
"paths" : []
}
},
"name" : "Git::Contributors",
"version" : "0.037"
},
{
"class" : "Dist::Zilla::Plugin::GithubMeta",
"name" : "GithubMeta",
"version" : "0.58"
},
{
"class" : "Dist::Zilla::Plugin::Manifest",
"name" : "Manifest",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::License",
"name" : "License",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::InstallGuide",
"config" : {
"Dist::Zilla::Role::ModuleMetadata" : {
"Module::Metadata" : "1.000037",
"version" : "0.006"
}
},
"name" : "InstallGuide",
"version" : "1.200014"
},
{
"class" : "Dist::Zilla::Plugin::ExecDir",
"name" : "ExecDir",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::Prereqs::FromCPANfile",
"name" : "Prereqs::FromCPANfile",
"version" : "0.08"
},
{
"class" : "Dist::Zilla::Plugin::MakeMaker::Awesome",
"config" : {
"Dist::Zilla::Plugin::MakeMaker" : {
"make_path" : "make",
"version" : "6.032"
},
"Dist::Zilla::Role::TestRunner" : {
"default_jobs" : "8",
"version" : "6.032"
}
},
"name" : "MakeMaker::Awesome",
"version" : "0.49"
},
{
"class" : "Dist::Zilla::Plugin::MojibakeTests",
"name" : "MojibakeTests",
"version" : "0.8"
},
{
"class" : "Dist::Zilla::Plugin::Test::Version",
"name" : "Test::Version",
"version" : "1.09"
},
{
"class" : "Dist::Zilla::Plugin::Test::ReportPrereqs",
"name" : "Test::ReportPrereqs",
"version" : "0.029"
},
{
"class" : "Dist::Zilla::Plugin::Test::Compile",
"config" : {
"Dist::Zilla::Plugin::Test::Compile" : {
"bail_out_on_fail" : "1",
"fail_on_warning" : "author",
"fake_home" : 0,
"filename" : "xt/author/00-compile.t",
"module_finder" : [
":InstallModules"
],
"needs_display" : 0,
"phase" : "develop",
"script_finder" : [
":PerlExecFiles"
],
"skips" : [],
"switch" : []
}
},
"name" : "Test::Compile",
"version" : "2.058"
},
{
"class" : "Dist::Zilla::Plugin::Substitute",
"name" : "00-compile.t",
"version" : "0.008"
},
{
"class" : "Dist::Zilla::Plugin::Test::Portability",
"config" : {
"Dist::Zilla::Plugin::Test::Portability" : {
"options" : ""
}
},
"name" : "Test::Portability",
"version" : "2.001003"
},
{
"class" : "Dist::Zilla::Plugin::Test::EOL",
"config" : {
"Dist::Zilla::Plugin::Test::EOL" : {
"filename" : "xt/author/eol.t",
"finder" : [
":ExecFiles",
":InstallModules",
":TestFiles"
],
"trailing_whitespace" : 1
}
},
"name" : "Test::EOL",
"version" : "0.19"
},
{
"class" : "Dist::Zilla::Plugin::Test::MinimumVersion",
"config" : {
"Dist::Zilla::Plugin::Test::MinimumVersion" : {
"max_target_perl" : null
}
},
"name" : "Test::MinimumVersion",
"version" : "2.000011"
},
{
"class" : "Dist::Zilla::Plugin::PodSyntaxTests",
"name" : "PodSyntaxTests",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::Test::Pod::Coverage::Configurable",
"name" : "Test::Pod::Coverage::Configurable",
"version" : "0.07"
},
{
"class" : "Dist::Zilla::Plugin::Test::PodSpelling",
"config" : {
"Dist::Zilla::Plugin::Test::PodSpelling" : {
"directories" : [
"bin",
"lib"
],
"spell_cmd" : "aspell --master=en_US list",
"stopwords" : [
"Accomazzi",
"Alexandre",
"Andreas",
"Asplund",
"Betts",
"Bochner",
"BooK",
"Buenzli",
"CGI",
"CPAN",
"Chamas",
"Coppit",
"Dalgleish",
"Dubois",
"Dunkin",
"Duret",
"Dvornik",
"Eldridge",
"Gertjan",
"Graaff",
"Greab",
"Guenther",
"Gurusamy",
"Gustafsson",
"Hakanson",
"Harald",
"Hedlund",
"Hoblitt",
"Hwa",
"INOUE",
"Joao",
"Joerg",
"KONISHI",
"Kaminsky",
"Kartik",
"Katsuhiro",
"Kebsch",
"Keiichiro",
"Kilzer",
"Klar",
"Koster",
"Kronengold",
"Krüger",
"Kubb",
"König",
"Laker",
"Langfeldt",
"Langheinrich",
"Liam",
"Lindley",
"Lotterer",
"Lutz",
"MacEachern",
"Macdonald",
"Mailto",
"Marko",
"Markus",
"Martijn",
"McCauley",
"Melchner",
"Moshe",
"Murrell",
"NNTP",
"NTLM",
"Nagano",
"Newby",
"Nicolai",
"Nierstrasz",
"Olly",
"Oosten",
"Panchenko",
"Pimlott",
"Pon",
"Quaranta",
"Radoslaw",
"Radu",
"Rai",
"Rezic",
"RobotUA",
"Sarathy",
"Schilli",
"Schinder",
"Shirazi",
"Skyttä",
"Slaven",
"Spafford",
"Stosberg",
"Subbarao",
"TCP",
"Takanori",
"Thoennes",
"Thurn",
"Tilly",
"UA",
"Ugai",
"Unger",
"UserAgent",
"VanHeyningen",
"Vandewege",
"Ville",
"WireShark",
"Yee",
"Yitzchak",
"Yoshinari",
"Zajac",
"Zakharevich",
"Zielinski",
"Zoest",
"afPuUsSedvhx",
"de",
"erik",
"getprint",
"getstore",
"instantiation",
"peterm",
"shildreth"
],
"wordlist" : "Pod::Wordlist"
}
},
"name" : "Test::PodSpelling",
"version" : "2.007006"
},
{
"class" : "Dist::Zilla::Plugin::Git::Check",
"config" : {
"Dist::Zilla::Plugin::Git::Check" : {
"untracked_files" : "die"
},
"Dist::Zilla::Role::Git::DirtyFiles" : {
"allow_dirty" : [],
"allow_dirty_match" : [],
"changelog" : "Changes"
},
"Dist::Zilla::Role::Git::Repo" : {
"git_version" : "2.43.0",
"repo_root" : "."
}
},
"name" : "Git::Check",
"version" : "2.051"
},
{
"class" : "Dist::Zilla::Plugin::CheckStrictVersion",
"name" : "CheckStrictVersion",
"version" : "0.001"
},
{
"class" : "Dist::Zilla::Plugin::RunExtraTests",
"config" : {
"Dist::Zilla::Role::TestRunner" : {
"default_jobs" : "8"
}
},
"name" : "RunExtraTests",
"version" : "0.029"
},
{
"class" : "Dist::Zilla::Plugin::CheckChangeLog",
"name" : "CheckChangeLog",
"version" : "0.05"
},
{
"class" : "Dist::Zilla::Plugin::CheckChangesHasContent",
"name" : "CheckChangesHasContent",
"version" : "0.011"
},
{
"class" : "Dist::Zilla::Plugin::TestRelease",
"name" : "TestRelease",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::UploadToCPAN",
"name" : "UploadToCPAN",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::ReadmeAnyFromPod",
"config" : {
"Dist::Zilla::Role::FileWatcher" : {
"version" : "0.006"
}
},
"name" : "Markdown_Readme",
"version" : "0.163250"
},
{
"class" : "Dist::Zilla::Plugin::CopyFilesFromRelease",
"config" : {
"Dist::Zilla::Plugin::CopyFilesFromRelease" : {
"filename" : [
"LICENSE",
"META.json"
],
"match" : []
}
},
"name" : "CopyFilesFromRelease",
"version" : "0.007"
},
{
"class" : "Dist::Zilla::Plugin::Prereqs",
"config" : {
"Dist::Zilla::Plugin::Prereqs" : {
"phase" : "develop",
"type" : "recommends"
}
},
"name" : "@Git::VersionManager/pluginbundle version",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::RewriteVersion::Transitional",
"config" : {
"Dist::Zilla::Plugin::RewriteVersion" : {
"add_tarball_name" : 0,
"finders" : [
":ExecFiles",
":InstallModules"
],
"global" : 0,
"skip_version_provider" : 0
},
"Dist::Zilla::Plugin::RewriteVersion::Transitional" : {}
},
"name" : "@Git::VersionManager/RewriteVersion::Transitional",
"version" : "0.009"
},
{
"class" : "Dist::Zilla::Plugin::MetaProvides::Update",
"name" : "@Git::VersionManager/MetaProvides::Update",
"version" : "0.007"
},
{
"class" : "Dist::Zilla::Plugin::CopyFilesFromRelease",
"config" : {
"Dist::Zilla::Plugin::CopyFilesFromRelease" : {
"filename" : [
"Changes"
],
"match" : []
}
},
"name" : "@Git::VersionManager/CopyFilesFromRelease",
"version" : "0.007"
},
{
"class" : "Dist::Zilla::Plugin::Git::Commit",
"config" : {
"Dist::Zilla::Plugin::Git::Commit" : {
"add_files_in" : [],
"commit_msg" : "v%V%n%n%c",
"signoff" : 0
},
"Dist::Zilla::Role::Git::DirtyFiles" : {
"allow_dirty" : [
"Changes",
"LICENSE",
"META.json",
"README.md"
],
"allow_dirty_match" : [],
"changelog" : "Changes"
},
"Dist::Zilla::Role::Git::Repo" : {
"git_version" : "2.43.0",
"repo_root" : "."
},
"Dist::Zilla::Role::Git::StringFormatter" : {
"time_zone" : "local"
}
},
"name" : "@Git::VersionManager/release snapshot",
"version" : "2.051"
},
{
"class" : "Dist::Zilla::Plugin::Git::Tag",
"config" : {
"Dist::Zilla::Plugin::Git::Tag" : {
"branch" : null,
"changelog" : "Changes",
"signed" : 0,
"tag" : "v6.78",
"tag_format" : "v%V",
"tag_message" : "v%V"
},
"Dist::Zilla::Role::Git::Repo" : {
"git_version" : "2.43.0",
"repo_root" : "."
},
"Dist::Zilla::Role::Git::StringFormatter" : {
"time_zone" : "local"
}
},
"name" : "@Git::VersionManager/Git::Tag",
"version" : "2.051"
},
{
"class" : "Dist::Zilla::Plugin::BumpVersionAfterRelease::Transitional",
"config" : {
"Dist::Zilla::Plugin::BumpVersionAfterRelease" : {
"finders" : [
":ExecFiles",
":InstallModules"
],
"global" : 0,
"munge_makefile_pl" : 1
},
"Dist::Zilla::Plugin::BumpVersionAfterRelease::Transitional" : {}
},
"name" : "@Git::VersionManager/BumpVersionAfterRelease::Transitional",
"version" : "0.009"
},
{
"class" : "Dist::Zilla::Plugin::NextRelease",
"name" : "@Git::VersionManager/NextRelease",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::Git::Commit",
"config" : {
"Dist::Zilla::Plugin::Git::Commit" : {
"add_files_in" : [],
"commit_msg" : "increment $VERSION after %v release",
"signoff" : 0
},
"Dist::Zilla::Role::Git::DirtyFiles" : {
"allow_dirty" : [
"Build.PL",
"Changes",
"Makefile.PL"
],
"allow_dirty_match" : [
"(?^:^lib/.*\\.pm$)"
],
"changelog" : "Changes"
},
"Dist::Zilla::Role::Git::Repo" : {
"git_version" : "2.43.0",
"repo_root" : "."
},
"Dist::Zilla::Role::Git::StringFormatter" : {
"time_zone" : "local"
}
},
"name" : "@Git::VersionManager/post-release commit",
"version" : "2.051"
},
{
"class" : "Dist::Zilla::Plugin::Git::Push",
"config" : {
"Dist::Zilla::Plugin::Git::Push" : {
"push_to" : [
"origin"
],
"remotes_must_exist" : 1
},
"Dist::Zilla::Role::Git::Repo" : {
"git_version" : "2.43.0",
"repo_root" : "."
}
},
"name" : "Git::Push",
"version" : "2.051"
},
{
"class" : "Dist::Zilla::Plugin::ConfirmRelease",
"name" : "ConfirmRelease",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":InstallModules",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":IncModules",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":TestFiles",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":ExtraTestFiles",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":ExecFiles",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":PerlExecFiles",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":ShareFiles",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":MainModule",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":AllFiles",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":NoFiles",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : "MetaProvides::Package/AUTOVIV/:InstallModulesPM",
"version" : "6.032"
}
],
"zilla" : {
"class" : "Dist::Zilla::Dist::Builder",
"config" : {
"is_trial" : 0
},
"version" : "6.032"
}
},
"x_contributors" : [
"Adam Kennedy <adamk@cpan.org>",
"Adam Sjogren <asjo@koldfront.dk>",
"Alexey Tourbin <at@altlinux.ru>",
"Alex Kapranoff <ka@nadoby.ru>",
"amire80 <amir.aharoni@gmail.com>",
"Andreas J. Koenig <andreas.koenig@anima.de>",
"Andrew Grangaard <granny-github@ofb.net>",
"Andrew Hewus Fresh <andrew@afresh1.com>",
"Anirvan Chatterjee <anirvan@users.noreply.github.com>",
"Arne Johannessen <git@arne.johannessen.de>",
"Austin Hill <austin.hill@grantstreet.com>",
"Axel Burri <axel@tty0.ch>",
"BGMNT <freeerider@mailinator.com>",
"Bill Mann <wfmann@alum.mit.edu>",
"Bron Gondwana <brong@fastmail.fm>",
"Bryan Cardillo <bryan.cardillo@gmail.com>",
"Burak Gursoy <burak@cpan.org>",
"Chase Whitener <capoeirab@cpan.org>",
"Christopher J. Madsen <cjm@cpan.org>",
"Colin Newell <colin.newell@gmail.com>",
"Daina Pettit <dpettit@bluehost.com>",
"Daniel Hedlund <Daniel.Hedlund@eprize.com>",
"David E. Wheeler <david@justatheory.com>",
"DAVIDRW <davidrw@cpan.org>",
"David Standish <dnstandish@gmail.com>",
"David Steinbrunner <dsteinbrunner@MountainBook-Pro.local>",
"dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
"Desmond Daignault <nawglan@cpan.org>",
"Dmitriy Shamatrin <dshamatrin@cloudbees.com>",
"Doug Bell <doug@preaction.me>",
"Eric Johnson <eric.git@iijo.org>",
"Fabian Zeindler <faz@open.ch>",
"Father Chrysostomos <sprout@cpan.org>",
"Frank Maas <maas.frank@gmail.com>",
"FWILES <FWILES@cpan.org>",
"Galen Huntington <galen@alumni.reed.edu>",
"Gavin Peters <gpeters@deepsky.com>",
"Gerhard Poul <gerhard.poul@gmail.com>",
"Gianni Ceccarelli <gianni.ceccarelli@broadbean.com>",
"Gisle Aas <gisle@aas.no>",
"Graeme Thompson <Graeme.Thompson@mobilecohesion.com>",
"Graham Knop <haarg@haarg.org>",
"Gregory Oschwald <oschwald@gmail.com>",
"grr <grr@users.noreply.github.com>",
"Hans-H. Froehlich <hfroehlich@co-de-co.de>",
"Ian Kilgore <iank@cpan.org>",
"Jacob J <waif@chaos2.org>",
"Jakub Wilk <jwilk@jwilk.net>",
"James Raspass <jraspass@gmail.com>",
"Jason A Fesler <jfesler@gigo.com>",
"Javier Puche <javier.puche@educa.madrid.org>",
"jefflee <shaohua@gmail.com>",
"Jeremy Mates <jmates@cpan.org>",
"Joe Atzberger <ohiocore@gmail.com>",
"john9art <john9art@yahoo.com>",
"John Wittkoski <jwittkoski@gmail.com>",
"Jonathan Dahan <jonathan@augwa.com>",
"Julien Fiegehenn <simbabque@cpan.org>",
"Kacper Gutowski <mwgamera@gmail.com>",
"Karen Etheridge <ether@cpan.org>",
"Katarina Durechova <katarina.durechova@nic.cz>",
"leedo <leedo@users.noreply.github.com>",
"Mark Fowler <mark@twoshortplanks.com>",
"Mark Stosberg <mark@stosberg.com>",
"Martin H. Sluka <martin@sluka.de>",
"Matthew Horsfall <wolfsage@gmail.com>",
"Max Maischein <corion@corion.net>",
"michael gong <michealgong@126.com>",
"Michael G. Schwern <schwern@pobox.com>",
"Michal Josef Špaček <mspacek@redhat.com>",
"Michiel Beijen <michiel.beijen@otrs.com>",
"Mike Schilli <github@perlmeister.com>",
"Moritz Onken <onken@netcubed.de>",
"murphy <murphy@genome.chop.edu>",
"Naveed Massjouni <naveedm9@gmail.com>",
"Nigel Gregoire <nigelgregoire@gmail.com>",
"Nik LaBelle <nalabelle@gmail.com>",
"Niko Tyni <ntyni@debian.org>",
"Olaf Alders <olaf@wundersolutions.com>",
"Ondrej Hanak <ondrej.hanak@ubs.com>",
"Patrik Lundin <patrik.lundin@su.se>",
"Peter Rabbitson <ribasushi@cpan.org>",
"phrstbrn <phrstbrn@gmail.com>",
"Piotr Roszatycki <piotr.roszatycki@gmail.com>",
"Robert Stone <talby@trap.mtview.ca.us>",
"Rolf Grossmann <rg@progtech.net>",
"Roman Galeev <roman.galeev@gooddata.com>",
"ruff <ruff@ukrpost.net>",
"Russell Shingleton <reshingleton@gmail.com>",
"sasao <sasao@yugen.org>",
"Sean M. Burke <sburke@cpan.org>",
"Sebastian Paaske Tørholm <Eckankar@gmail.com>",
"Sergey Romanov <sromanov-dev@yandex.ru>",
"Shoichi Kaji <skaji@cpan.org>",
"Slaven Rezic <slaven@rezic.de>",
"Slaven Rezic <slaven.rezic@idealo.de>",
"Spiros Denaxas <s.denaxas@gmail.com>",
"Steffen Ullrich <Steffen_Ullrich@genua.de>",
"Steve Hay <SteveHay@planit.com>",
"Takumi Akiyama <t.akiym@gmail.com>",
"Theodore Robert Campbell Jr <trcjr@stupidfoot.com>",
"Theo van Hoesel <Th.J.v.Hoesel+GitHub@gmail.com>",
"Tim Couzins <tim.couzins@sophos.com>",
"Todd Lipcon <todd@amiestreet.com>",
"Tomasz Konojacki <me@xenu.pl>",
"Tom Hukins <tom@eborcom.com>",
"Tony Finch <dot@dotat.at>",
"Toru Yamaguchi <zigorou@cpan.org>",
"turugina <turugina@floralcompany.jp>",
"uid39246 <uid39246>",
"Ville Skyttä <ville.skytta@iki.fi>",
"Vyacheslav Matyukhin <mmcleric@yandex-team.ru>",
"Yuri Karaban <tech@askold.net>",
"Yury Zavarin <yury.zavarin@gmail.com>",
"Yves Orton <yves.orton@booking.com>",
"Zefram <zefram@fysh.org>"
],
"x_generated_by_perl" : "v5.38.2",
"x_serialization_backend" : "JSON::PP version 2.97001",
"x_spdx_expression" : "Artistic-1.0-Perl OR GPL-1.0-or-later"
}
PK 2N%[hhā� � C perl5/x86_64-linux-thread-multi/.meta/libwww-perl-6.78/install.jsonnu ��6�$ {"target":"LWP::UserAgent","name":"LWP","dist":"libwww-perl-6.78","pathname":"O/OA/OALDERS/libwww-perl-6.78.tar.gz","provides":{"LWP::Authen::Digest":{"file":"lib/LWP/Authen/Digest.pm","version":"6.78"},"LWP::Protocol::nogo":{"file":"lib/LWP/Protocol/nogo.pm","version":"6.78"},"LWP::RobotUA":{"version":"6.78","file":"lib/LWP/RobotUA.pm"},"LWP::Protocol::cpan":{"file":"lib/LWP/Protocol/cpan.pm","version":"6.78"},"LWP::Authen::Ntlm":{"file":"lib/LWP/Authen/Ntlm.pm","version":"6.78"},"LWP":{"version":"6.78","file":"lib/LWP.pm"},"LWP::ConnCache":{"file":"lib/LWP/ConnCache.pm","version":"6.78"},"LWP::Protocol::file":{"file":"lib/LWP/Protocol/file.pm","version":"6.78"},"LWP::Debug":{"file":"lib/LWP/Debug.pm","x_deprecated":1,"version":"6.78"},"LWP::DebugFile":{"version":"6.78","file":"lib/LWP/DebugFile.pm"},"LWP::Protocol::ftp":{"version":"6.78","file":"lib/LWP/Protocol/ftp.pm"},"LWP::Simple":{"version":"6.78","file":"lib/LWP/Simple.pm"},"LWP::Protocol::data":{"version":"6.78","file":"lib/LWP/Protocol/data.pm"},"LWP::Protocol::http":{"version":"6.78","file":"lib/LWP/Protocol/http.pm"},"LWP::Protocol::mailto":{"file":"lib/LWP/Protocol/mailto.pm","version":"6.78"},"LWP::Protocol::nntp":{"version":"6.78","file":"lib/LWP/Protocol/nntp.pm"},"LWP::Authen::Basic":{"version":"6.78","file":"lib/LWP/Authen/Basic.pm"},"LWP::Protocol":{"version":"6.78","file":"lib/LWP/Protocol.pm"},"LWP::MemberMixin":{"version":"6.78","file":"lib/LWP/MemberMixin.pm"},"LWP::Protocol::gopher":{"file":"lib/LWP/Protocol/gopher.pm","version":"6.78"},"LWP::UserAgent":{"file":"lib/LWP/UserAgent.pm","version":"6.78"},"LWP::Debug::TraceHTTP":{"version":"6.78","file":"lib/LWP/Debug/TraceHTTP.pm"},"LWP::Protocol::loopback":{"version":"6.78","file":"lib/LWP/Protocol/loopback.pm"}},"version":"6.78"}PK 2N%[R�<� � @ perl5/x86_64-linux-thread-multi/.meta/version-0.9933/MYMETA.jsonnu ��6�$ {
"abstract" : "Structured version objects",
"author" : [
"John Peacock <jpeacock@cpan.org>"
],
"dynamic_config" : 0,
"generated_by" : "ExtUtils::MakeMaker version 7.70, CPAN::Meta::Converter version 2.150010",
"license" : [
"perl_5"
],
"meta-spec" : {
"url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
"version" : 2
},
"name" : "version",
"no_index" : {
"directory" : [
"t",
"inc"
],
"package" : [
"charstar"
]
},
"prereqs" : {
"build" : {
"requires" : {
"ExtUtils::MakeMaker" : "0"
}
},
"configure" : {
"requires" : {
"ExtUtils::MakeMaker" : "0"
}
},
"runtime" : {
"requires" : {
"perl" : "5.006002"
}
},
"test" : {
"requires" : {
"File::Temp" : "0.13",
"Test::More" : "0.45",
"base" : "0"
}
}
},
"release_status" : "stable",
"resources" : {
"bugtracker" : {
"mailto" : "bug-version@rt.cpan.org",
"web" : "https://rt.cpan.org/Public/Dist/Display.html?Name=version"
},
"repository" : {
"type" : "git",
"url" : "git://github.com/Perl/version.pm.git",
"web" : "https://github.com/Perl/version.pm"
}
},
"version" : "0.9933",
"x_serialization_backend" : "JSON::PP version 2.97001"
}
PK 2N%[5:��| | A perl5/x86_64-linux-thread-multi/.meta/version-0.9933/install.jsonnu ��6�$ {"dist":"version-0.9933","version":0.9933,"name":"version","pathname":"L/LE/LEONT/version-0.9933.tar.gz","target":"version","provides":{"version":{"file":"lib/version.pm","version":0.9933},"version::vxs":{"file":"vutil/lib/version/vxs.pm","version":0.9933},"version::regex":{"version":0.9933,"file":"lib/version/regex.pm"},"version::vpp":{"version":0.9933,"file":"vperl/vpp.pm"}}}PK 2N%[{�9�� �� ? perl5/x86_64-linux-thread-multi/.meta/Try-Tiny-0.32/MYMETA.jsonnu ��6�$ {
"abstract" : "Minimal try/catch with proper preservation of $@",
"author" : [
"יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org>",
"Jesse Luehrs <doy@tozt.net>"
],
"dynamic_config" : 0,
"generated_by" : "Dist::Zilla version 6.032, CPAN::Meta::Converter version 2.150010",
"license" : [
"mit"
],
"meta-spec" : {
"url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
"version" : 2
},
"name" : "Try-Tiny",
"no_index" : {
"directory" : [
"t",
"xt"
]
},
"prereqs" : {
"build" : {
"requires" : {
"ExtUtils::MakeMaker" : "0"
}
},
"configure" : {
"requires" : {
"ExtUtils::MakeMaker" : "0"
},
"suggests" : {
"JSON::PP" : "2.27300"
}
},
"develop" : {
"recommends" : {
"Dist::Zilla::PluginBundle::Author::ETHER" : "0.163",
"Dist::Zilla::PluginBundle::Git::VersionManager" : "0.007"
},
"requires" : {
"Capture::Tiny" : "0.12",
"Encode" : "0",
"File::Spec" : "0",
"IO::Handle" : "0",
"IPC::Open3" : "0",
"Pod::Coverage::TrustPod" : "0",
"Pod::Wordlist" : "0",
"Sub::Name" : "0.08",
"Sub::Util" : "0",
"Test::CPAN::Changes" : "0.19",
"Test::CPAN::Meta" : "0",
"Test::EOL" : "0",
"Test::Kwalitee" : "1.21",
"Test::MinimumVersion" : "0",
"Test::Mojibake" : "0",
"Test::More" : "0.96",
"Test::NoTabs" : "0",
"Test::Pod" : "1.41",
"Test::Pod::Coverage" : "1.08",
"Test::Pod::No404s" : "0",
"Test::Portability::Files" : "0",
"Test::Spelling" : "0.12"
}
},
"runtime" : {
"requires" : {
"Carp" : "0",
"Exporter" : "5.57",
"constant" : "0",
"perl" : "5.006",
"strict" : "0",
"warnings" : "0"
},
"suggests" : {
"Sub::Name" : "0.08",
"Sub::Util" : "0"
}
},
"test" : {
"recommends" : {
"CPAN::Meta" : "2.120900"
},
"requires" : {
"ExtUtils::MakeMaker" : "0",
"File::Spec" : "0",
"Test::More" : "0",
"if" : "0"
},
"suggests" : {
"CPAN::Meta::Check" : "0.011",
"CPAN::Meta::Requirements" : "0",
"Capture::Tiny" : "0.12"
}
},
"x_Dist_Zilla" : {
"requires" : {
"Dist::Zilla" : "5",
"Dist::Zilla::Plugin::Authority" : "1.009",
"Dist::Zilla::Plugin::AutoMetaResources" : "0",
"Dist::Zilla::Plugin::AutoPrereqs" : "5.038",
"Dist::Zilla::Plugin::Breaks" : "0",
"Dist::Zilla::Plugin::BumpVersionAfterRelease::Transitional" : "0.004",
"Dist::Zilla::Plugin::CheckIssues" : "0",
"Dist::Zilla::Plugin::CheckMetaResources" : "0",
"Dist::Zilla::Plugin::CheckPrereqsIndexed" : "0.019",
"Dist::Zilla::Plugin::CheckSelfDependency" : "0",
"Dist::Zilla::Plugin::CheckStrictVersion" : "0",
"Dist::Zilla::Plugin::ConfirmRelease" : "0",
"Dist::Zilla::Plugin::CopyFilesFromRelease" : "0",
"Dist::Zilla::Plugin::EnsureLatestPerl" : "0",
"Dist::Zilla::Plugin::FileFinder::ByName" : "0",
"Dist::Zilla::Plugin::FileFinder::Filter" : "0",
"Dist::Zilla::Plugin::GenerateFile::FromShareDir" : "0",
"Dist::Zilla::Plugin::Git::Check" : "0",
"Dist::Zilla::Plugin::Git::CheckFor::CorrectBranch" : "0.004",
"Dist::Zilla::Plugin::Git::CheckFor::MergeConflicts" : "0",
"Dist::Zilla::Plugin::Git::Commit" : "2.020",
"Dist::Zilla::Plugin::Git::Contributors" : "0.029",
"Dist::Zilla::Plugin::Git::Describe" : "0.004",
"Dist::Zilla::Plugin::Git::GatherDir" : "2.016",
"Dist::Zilla::Plugin::Git::Push" : "0",
"Dist::Zilla::Plugin::Git::Remote::Check" : "0",
"Dist::Zilla::Plugin::Git::Tag" : "0",
"Dist::Zilla::Plugin::GitHub::Update" : "0.40",
"Dist::Zilla::Plugin::GithubMeta" : "0.54",
"Dist::Zilla::Plugin::InstallGuide" : "1.200005",
"Dist::Zilla::Plugin::Keywords" : "0.004",
"Dist::Zilla::Plugin::License" : "5.038",
"Dist::Zilla::Plugin::MakeMaker" : "0",
"Dist::Zilla::Plugin::Manifest" : "0",
"Dist::Zilla::Plugin::MetaConfig" : "0",
"Dist::Zilla::Plugin::MetaJSON" : "0",
"Dist::Zilla::Plugin::MetaNoIndex" : "0",
"Dist::Zilla::Plugin::MetaProvides::Package" : "1.15000002",
"Dist::Zilla::Plugin::MetaTests" : "0",
"Dist::Zilla::Plugin::MetaYAML" : "0",
"Dist::Zilla::Plugin::MinimumPerl" : "1.006",
"Dist::Zilla::Plugin::MojibakeTests" : "0.8",
"Dist::Zilla::Plugin::NextRelease" : "5.033",
"Dist::Zilla::Plugin::OnlyCorePrereqs" : "0",
"Dist::Zilla::Plugin::PodCoverageTests" : "5.040",
"Dist::Zilla::Plugin::PodSyntaxTests" : "5.040",
"Dist::Zilla::Plugin::PodWeaver" : "4.008",
"Dist::Zilla::Plugin::Prereqs" : "0",
"Dist::Zilla::Plugin::Prereqs::AuthorDeps" : "0.006",
"Dist::Zilla::Plugin::Prereqs::Soften" : "0",
"Dist::Zilla::Plugin::PromptIfStale" : "0",
"Dist::Zilla::Plugin::Readme" : "0",
"Dist::Zilla::Plugin::ReadmeAnyFromPod" : "0.142180",
"Dist::Zilla::Plugin::RewriteVersion::Transitional" : "0.006",
"Dist::Zilla::Plugin::Run::AfterBuild" : "0.041",
"Dist::Zilla::Plugin::Run::AfterRelease" : "0.038",
"Dist::Zilla::Plugin::RunExtraTests" : "0.024",
"Dist::Zilla::Plugin::StaticInstall" : "0.005",
"Dist::Zilla::Plugin::Substitute" : "0",
"Dist::Zilla::Plugin::Test::CPAN::Changes" : "0.012",
"Dist::Zilla::Plugin::Test::ChangesHasContent" : "0",
"Dist::Zilla::Plugin::Test::CheckBreaks" : "0.018",
"Dist::Zilla::Plugin::Test::Compile" : "2.039",
"Dist::Zilla::Plugin::Test::EOL" : "0.17",
"Dist::Zilla::Plugin::Test::Kwalitee" : "2.10",
"Dist::Zilla::Plugin::Test::MinimumVersion" : "2.000010",
"Dist::Zilla::Plugin::Test::NoTabs" : "0.08",
"Dist::Zilla::Plugin::Test::Pod::No404s" : "1.003",
"Dist::Zilla::Plugin::Test::PodSpelling" : "2.006003",
"Dist::Zilla::Plugin::Test::Portability" : "2.000007",
"Dist::Zilla::Plugin::Test::ReportPrereqs" : "0.022",
"Dist::Zilla::Plugin::TestRelease" : "0",
"Dist::Zilla::Plugin::UploadToCPAN" : "0",
"Dist::Zilla::Plugin::UseUnsafeInc" : "0",
"Dist::Zilla::PluginBundle::Author::ETHER" : "0.136",
"Dist::Zilla::PluginBundle::Git::VersionManager" : "0.007",
"Software::License::MIT" : "0"
}
}
},
"provides" : {
"Try::Tiny" : {
"file" : "lib/Try/Tiny.pm",
"version" : "0.32"
}
},
"release_status" : "stable",
"resources" : {
"bugtracker" : {
"mailto" : "bug-Try-Tiny@rt.cpan.org",
"web" : "https://rt.cpan.org/Public/Dist/Display.html?Name=Try-Tiny"
},
"homepage" : "https://github.com/p5sagit/Try-Tiny",
"repository" : {
"type" : "git",
"url" : "https://github.com/p5sagit/Try-Tiny.git",
"web" : "https://github.com/p5sagit/Try-Tiny"
}
},
"version" : "0.32",
"x_Dist_Zilla" : {
"perl" : {
"version" : "5.041002"
},
"plugins" : [
{
"class" : "Dist::Zilla::Plugin::FileFinder::Filter",
"name" : "all_files_but_using_5.10_features",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::Prereqs",
"config" : {
"Dist::Zilla::Plugin::Prereqs" : {
"phase" : "develop",
"type" : "recommends"
}
},
"name" : "@Author::ETHER/pluginbundle version",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::PromptIfStale",
"config" : {
"Dist::Zilla::Plugin::PromptIfStale" : {
"check_all_plugins" : 0,
"check_all_prereqs" : 0,
"modules" : [
"Dist::Zilla::PluginBundle::Author::ETHER"
],
"phase" : "build",
"run_under_travis" : 0,
"skip" : []
}
},
"name" : "@Author::ETHER/stale modules, build",
"version" : "0.060"
},
{
"class" : "Dist::Zilla::Plugin::FileFinder::ByName",
"name" : "@Author::ETHER/Examples",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::Git::GatherDir",
"config" : {
"Dist::Zilla::Plugin::GatherDir" : {
"exclude_filename" : [
"CONTRIBUTING",
"INSTALL",
"LICENCE",
"README.pod"
],
"exclude_match" : [],
"include_dotfiles" : 0,
"prefix" : "",
"prune_directory" : [],
"root" : "."
},
"Dist::Zilla::Plugin::Git::GatherDir" : {
"include_untracked" : 0
}
},
"name" : "@Author::ETHER/Git::GatherDir",
"version" : "2.051"
},
{
"class" : "Dist::Zilla::Plugin::MetaYAML",
"name" : "@Author::ETHER/MetaYAML",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::MetaJSON",
"name" : "@Author::ETHER/MetaJSON",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::Readme",
"name" : "@Author::ETHER/Readme",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::Manifest",
"name" : "@Author::ETHER/Manifest",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::License",
"name" : "@Author::ETHER/License",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::GenerateFile::FromShareDir",
"config" : {
"Dist::Zilla::Plugin::GenerateFile::FromShareDir" : {
"destination_filename" : "CONTRIBUTING",
"dist" : "Dist-Zilla-PluginBundle-Author-ETHER",
"encoding" : "UTF-8",
"has_xs" : 0,
"location" : "build",
"source_filename" : "CONTRIBUTING"
},
"Dist::Zilla::Role::RepoFileInjector" : {
"allow_overwrite" : 1,
"repo_root" : ".",
"version" : "0.009"
}
},
"name" : "@Author::ETHER/generate CONTRIBUTING",
"version" : "0.015"
},
{
"class" : "Dist::Zilla::Plugin::InstallGuide",
"config" : {
"Dist::Zilla::Role::ModuleMetadata" : {
"Module::Metadata" : "1.000038",
"version" : "0.006"
}
},
"name" : "@Author::ETHER/InstallGuide",
"version" : "1.200014"
},
{
"class" : "Dist::Zilla::Plugin::Test::Compile",
"config" : {
"Dist::Zilla::Plugin::Test::Compile" : {
"bail_out_on_fail" : 1,
"fail_on_warning" : "author",
"fake_home" : 0,
"filename" : "xt/author/00-compile.t",
"module_finder" : [
":InstallModules"
],
"needs_display" : 0,
"phase" : "develop",
"script_finder" : [
":PerlExecFiles",
"@Author::ETHER/Examples"
],
"skips" : [],
"switch" : []
}
},
"name" : "@Author::ETHER/Test::Compile",
"version" : "2.058"
},
{
"class" : "Dist::Zilla::Plugin::Test::NoTabs",
"config" : {
"Dist::Zilla::Plugin::Test::NoTabs" : {
"filename" : "xt/author/no-tabs.t",
"finder" : [
":InstallModules",
":ExecFiles",
"@Author::ETHER/Examples",
":TestFiles",
":ExtraTestFiles"
]
}
},
"name" : "@Author::ETHER/Test::NoTabs",
"version" : "0.15"
},
{
"class" : "Dist::Zilla::Plugin::Test::EOL",
"config" : {
"Dist::Zilla::Plugin::Test::EOL" : {
"filename" : "xt/author/eol.t",
"finder" : [
":ExecFiles",
":ExtraTestFiles",
":InstallModules",
":TestFiles",
"@Author::ETHER/Examples"
],
"trailing_whitespace" : 1
}
},
"name" : "@Author::ETHER/Test::EOL",
"version" : "0.19"
},
{
"class" : "Dist::Zilla::Plugin::MetaTests",
"name" : "@Author::ETHER/MetaTests",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::Test::CPAN::Changes",
"config" : {
"Dist::Zilla::Plugin::Test::CPAN::Changes" : {
"changelog" : "Changes"
}
},
"name" : "@Author::ETHER/Test::CPAN::Changes",
"version" : "0.012"
},
{
"class" : "Dist::Zilla::Plugin::Test::ChangesHasContent",
"name" : "@Author::ETHER/Test::ChangesHasContent",
"version" : "0.011"
},
{
"class" : "Dist::Zilla::Plugin::Test::MinimumVersion",
"config" : {
"Dist::Zilla::Plugin::Test::MinimumVersion" : {
"max_target_perl" : "5.006"
}
},
"name" : "@Author::ETHER/Test::MinimumVersion",
"version" : "2.000010"
},
{
"class" : "Dist::Zilla::Plugin::PodSyntaxTests",
"name" : "@Author::ETHER/PodSyntaxTests",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::PodCoverageTests",
"name" : "@Author::ETHER/PodCoverageTests",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::Test::PodSpelling",
"config" : {
"Dist::Zilla::Plugin::Test::PodSpelling" : {
"directories" : [
"examples",
"lib",
"script",
"t",
"xt"
],
"spell_cmd" : "",
"stopwords" : [
"irc"
],
"wordlist" : "Pod::Wordlist"
}
},
"name" : "@Author::ETHER/Test::PodSpelling",
"version" : "2.007005"
},
{
"class" : "Dist::Zilla::Plugin::Test::Pod::No404s",
"name" : "@Author::ETHER/Test::Pod::No404s",
"version" : "1.004"
},
{
"class" : "Dist::Zilla::Plugin::Test::Kwalitee",
"config" : {
"Dist::Zilla::Plugin::Test::Kwalitee" : {
"filename" : "xt/author/kwalitee.t",
"skiptest" : []
}
},
"name" : "@Author::ETHER/Test::Kwalitee",
"version" : "2.12"
},
{
"class" : "Dist::Zilla::Plugin::MojibakeTests",
"name" : "@Author::ETHER/MojibakeTests",
"version" : "0.8"
},
{
"class" : "Dist::Zilla::Plugin::Test::ReportPrereqs",
"name" : "@Author::ETHER/Test::ReportPrereqs",
"version" : "0.029"
},
{
"class" : "Dist::Zilla::Plugin::Test::Portability",
"config" : {
"Dist::Zilla::Plugin::Test::Portability" : {
"options" : ""
}
},
"name" : "@Author::ETHER/Test::Portability",
"version" : "2.001001"
},
{
"class" : "Dist::Zilla::Plugin::Git::Describe",
"name" : "@Author::ETHER/Git::Describe",
"version" : "0.008"
},
{
"class" : "Dist::Zilla::Plugin::PodWeaver",
"config" : {
"Dist::Zilla::Plugin::PodWeaver" : {
"config_plugins" : [
"@Author::ETHER"
],
"finder" : [
":InstallModules",
":PerlExecFiles"
],
"plugins" : [
{
"class" : "Pod::Weaver::Plugin::EnsurePod5",
"name" : "@Author::ETHER/EnsurePod5",
"version" : "4.020"
},
{
"class" : "Pod::Weaver::Plugin::H1Nester",
"name" : "@Author::ETHER/H1Nester",
"version" : "4.020"
},
{
"class" : "Pod::Weaver::Plugin::SingleEncoding",
"name" : "@Author::ETHER/SingleEncoding",
"version" : "4.020"
},
{
"class" : "Pod::Weaver::Plugin::Transformer",
"name" : "@Author::ETHER/List",
"version" : "4.020"
},
{
"class" : "Pod::Weaver::Plugin::Transformer",
"name" : "@Author::ETHER/Verbatim",
"version" : "4.020"
},
{
"class" : "Pod::Weaver::Section::Region",
"name" : "@Author::ETHER/header",
"version" : "4.020"
},
{
"class" : "Pod::Weaver::Section::Name",
"name" : "@Author::ETHER/Name",
"version" : "4.020"
},
{
"class" : "Pod::Weaver::Section::Version",
"name" : "@Author::ETHER/Version",
"version" : "4.020"
},
{
"class" : "Pod::Weaver::Section::Region",
"name" : "@Author::ETHER/prelude",
"version" : "4.020"
},
{
"class" : "Pod::Weaver::Section::Generic",
"name" : "SYNOPSIS",
"version" : "4.020"
},
{
"class" : "Pod::Weaver::Section::Generic",
"name" : "DESCRIPTION",
"version" : "4.020"
},
{
"class" : "Pod::Weaver::Section::Generic",
"name" : "OVERVIEW",
"version" : "4.020"
},
{
"class" : "Pod::Weaver::Section::Collect",
"name" : "ATTRIBUTES",
"version" : "4.020"
},
{
"class" : "Pod::Weaver::Section::Collect",
"name" : "METHODS",
"version" : "4.020"
},
{
"class" : "Pod::Weaver::Section::Collect",
"name" : "FUNCTIONS",
"version" : "4.020"
},
{
"class" : "Pod::Weaver::Section::Collect",
"name" : "TYPES",
"version" : "4.020"
},
{
"class" : "Pod::Weaver::Section::Leftovers",
"name" : "@Author::ETHER/Leftovers",
"version" : "4.020"
},
{
"class" : "Pod::Weaver::Section::Region",
"name" : "@Author::ETHER/postlude",
"version" : "4.020"
},
{
"class" : "Pod::Weaver::Section::GenerateSection",
"name" : "@Author::ETHER/generate SUPPORT",
"version" : "4.020"
},
{
"class" : "Pod::Weaver::Section::Authors",
"name" : "@Author::ETHER/Authors",
"version" : "4.020"
},
{
"class" : "Pod::Weaver::Section::AllowOverride",
"name" : "@Author::ETHER/allow override AUTHOR",
"version" : "0.05"
},
{
"class" : "Pod::Weaver::Section::Contributors",
"name" : "@Author::ETHER/Contributors",
"version" : "0.009"
},
{
"class" : "Pod::Weaver::Section::Legal",
"name" : "@Author::ETHER/Legal",
"version" : "4.020"
},
{
"class" : "Pod::Weaver::Section::Region",
"name" : "@Author::ETHER/footer",
"version" : "4.020"
}
]
}
},
"name" : "@Author::ETHER/PodWeaver",
"version" : "4.010"
},
{
"class" : "Dist::Zilla::Plugin::GithubMeta",
"name" : "@Author::ETHER/GithubMeta",
"version" : "0.58"
},
{
"class" : "Dist::Zilla::Plugin::AutoMetaResources",
"name" : "@Author::ETHER/AutoMetaResources",
"version" : "1.21"
},
{
"class" : "Dist::Zilla::Plugin::Authority",
"name" : "@Author::ETHER/Authority",
"version" : "1.009"
},
{
"class" : "Dist::Zilla::Plugin::MetaNoIndex",
"name" : "@Author::ETHER/MetaNoIndex",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::MetaProvides::Package",
"config" : {
"Dist::Zilla::Plugin::MetaProvides::Package" : {
"finder" : [
":InstallModules"
],
"finder_objects" : [
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":InstallModules",
"version" : "6.032"
}
],
"include_underscores" : 0
},
"Dist::Zilla::Role::MetaProvider::Provider" : {
"$Dist::Zilla::Role::MetaProvider::Provider::VERSION" : "2.002004",
"inherit_missing" : 0,
"inherit_version" : 0,
"meta_noindex" : 1
},
"Dist::Zilla::Role::ModuleMetadata" : {
"Module::Metadata" : "1.000038",
"version" : "0.006"
}
},
"name" : "@Author::ETHER/MetaProvides::Package",
"version" : "2.004003"
},
{
"class" : "Dist::Zilla::Plugin::MetaConfig",
"name" : "@Author::ETHER/MetaConfig",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::Keywords",
"config" : {
"Dist::Zilla::Plugin::Keywords" : {
"keywords" : []
}
},
"name" : "@Author::ETHER/Keywords",
"version" : "0.007"
},
{
"class" : "Dist::Zilla::Plugin::UseUnsafeInc",
"config" : {
"Dist::Zilla::Plugin::UseUnsafeInc" : {
"dot_in_INC" : 0
}
},
"name" : "@Author::ETHER/UseUnsafeInc",
"version" : "0.002"
},
{
"class" : "Dist::Zilla::Plugin::AutoPrereqs",
"name" : "@Author::ETHER/AutoPrereqs",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::Prereqs::AuthorDeps",
"name" : "@Author::ETHER/Prereqs::AuthorDeps",
"version" : "0.007"
},
{
"class" : "Dist::Zilla::Plugin::MinimumPerl",
"name" : "@Author::ETHER/MinimumPerl",
"version" : "1.006"
},
{
"class" : "Dist::Zilla::Plugin::MakeMaker",
"config" : {
"Dist::Zilla::Role::TestRunner" : {
"default_jobs" : 9
}
},
"name" : "@Author::ETHER/MakeMaker",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::Git::Contributors",
"config" : {
"Dist::Zilla::Plugin::Git::Contributors" : {
"git_version" : "2.45.2",
"include_authors" : 0,
"include_releaser" : 1,
"order_by" : "commits",
"paths" : []
}
},
"name" : "@Author::ETHER/Git::Contributors",
"version" : "0.037"
},
{
"class" : "Dist::Zilla::Plugin::StaticInstall",
"config" : {
"Dist::Zilla::Plugin::StaticInstall" : {
"dry_run" : 1,
"mode" : "auto"
}
},
"name" : "@Author::ETHER/StaticInstall",
"version" : "0.012"
},
{
"class" : "Dist::Zilla::Plugin::RunExtraTests",
"config" : {
"Dist::Zilla::Role::TestRunner" : {
"default_jobs" : 9
}
},
"name" : "@Author::ETHER/RunExtraTests",
"version" : "0.029"
},
{
"class" : "Dist::Zilla::Plugin::CheckSelfDependency",
"config" : {
"Dist::Zilla::Plugin::CheckSelfDependency" : {
"finder" : [
":InstallModules"
]
},
"Dist::Zilla::Role::ModuleMetadata" : {
"Module::Metadata" : "1.000038",
"version" : "0.006"
}
},
"name" : "@Author::ETHER/CheckSelfDependency",
"version" : "0.011"
},
{
"class" : "Dist::Zilla::Plugin::Run::AfterBuild",
"config" : {
"Dist::Zilla::Plugin::Run::Role::Runner" : {
"fatal_errors" : 1,
"quiet" : 1,
"run" : [
"bash -c \"test -e .ackrc && grep -q -- '--ignore-dir=.latest' .ackrc || echo '--ignore-dir=.latest' >> .ackrc; if [[ `dirname '%d'` != .build ]]; then test -e .ackrc && grep -q -- '--ignore-dir=%d' .ackrc || echo '--ignore-dir=%d' >> .ackrc; fi\""
],
"version" : "0.050"
}
},
"name" : "@Author::ETHER/.ackrc",
"version" : "0.050"
},
{
"class" : "Dist::Zilla::Plugin::Run::AfterBuild",
"config" : {
"Dist::Zilla::Plugin::Run::Role::Runner" : {
"eval" : [
"if ('%d' =~ /^%n-[.[:xdigit:]]+$/) { unlink '.latest'; symlink '%d', '.latest'; }"
],
"fatal_errors" : 0,
"quiet" : 1,
"version" : "0.050"
}
},
"name" : "@Author::ETHER/.latest",
"version" : "0.050"
},
{
"class" : "Dist::Zilla::Plugin::CheckStrictVersion",
"name" : "@Author::ETHER/CheckStrictVersion",
"version" : "0.001"
},
{
"class" : "Dist::Zilla::Plugin::CheckMetaResources",
"name" : "@Author::ETHER/CheckMetaResources",
"version" : "0.001"
},
{
"class" : "Dist::Zilla::Plugin::EnsureLatestPerl",
"config" : {
"Dist::Zilla::Plugin::EnsureLatestPerl" : {
"Module::CoreList" : "5.20240720"
}
},
"name" : "@Author::ETHER/EnsureLatestPerl",
"version" : "0.010"
},
{
"class" : "Dist::Zilla::Plugin::PromptIfStale",
"config" : {
"Dist::Zilla::Plugin::PromptIfStale" : {
"check_all_plugins" : 1,
"check_all_prereqs" : 1,
"modules" : [],
"phase" : "release",
"run_under_travis" : 0,
"skip" : []
}
},
"name" : "@Author::ETHER/stale modules, release",
"version" : "0.060"
},
{
"class" : "Dist::Zilla::Plugin::Git::Check",
"config" : {
"Dist::Zilla::Plugin::Git::Check" : {
"untracked_files" : "die"
},
"Dist::Zilla::Role::Git::DirtyFiles" : {
"allow_dirty" : [],
"allow_dirty_match" : [],
"changelog" : "Changes"
},
"Dist::Zilla::Role::Git::Repo" : {
"git_version" : "2.45.2",
"repo_root" : "."
}
},
"name" : "@Author::ETHER/initial check",
"version" : "2.051"
},
{
"class" : "Dist::Zilla::Plugin::Git::CheckFor::MergeConflicts",
"config" : {
"Dist::Zilla::Role::Git::Repo" : {
"git_version" : "2.45.2",
"repo_root" : "."
}
},
"name" : "@Author::ETHER/Git::CheckFor::MergeConflicts",
"version" : "0.014"
},
{
"class" : "Dist::Zilla::Plugin::Git::CheckFor::CorrectBranch",
"config" : {
"Dist::Zilla::Role::Git::Repo" : {
"git_version" : "2.45.2",
"repo_root" : "."
}
},
"name" : "@Author::ETHER/Git::CheckFor::CorrectBranch",
"version" : "0.014"
},
{
"class" : "Dist::Zilla::Plugin::Git::Remote::Check",
"name" : "@Author::ETHER/Git::Remote::Check",
"version" : "0.1.2"
},
{
"class" : "Dist::Zilla::Plugin::CheckPrereqsIndexed",
"name" : "@Author::ETHER/CheckPrereqsIndexed",
"version" : "0.022"
},
{
"class" : "Dist::Zilla::Plugin::TestRelease",
"name" : "@Author::ETHER/TestRelease",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::Git::Check",
"config" : {
"Dist::Zilla::Plugin::Git::Check" : {
"untracked_files" : "die"
},
"Dist::Zilla::Role::Git::DirtyFiles" : {
"allow_dirty" : [],
"allow_dirty_match" : [],
"changelog" : "Changes"
},
"Dist::Zilla::Role::Git::Repo" : {
"git_version" : "2.45.2",
"repo_root" : "."
}
},
"name" : "@Author::ETHER/after tests",
"version" : "2.051"
},
{
"class" : "Dist::Zilla::Plugin::CheckIssues",
"name" : "@Author::ETHER/CheckIssues",
"version" : "0.011"
},
{
"class" : "Dist::Zilla::Plugin::UploadToCPAN",
"name" : "@Author::ETHER/UploadToCPAN",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::CopyFilesFromRelease",
"config" : {
"Dist::Zilla::Plugin::CopyFilesFromRelease" : {
"filename" : [
"CONTRIBUTING",
"INSTALL",
"LICENCE",
"LICENSE",
"ppport.h"
],
"match" : []
}
},
"name" : "@Author::ETHER/copy generated files",
"version" : "0.007"
},
{
"class" : "Dist::Zilla::Plugin::ReadmeAnyFromPod",
"config" : {
"Dist::Zilla::Role::FileWatcher" : {
"version" : "0.006"
}
},
"name" : "@Author::ETHER/ReadmeAnyFromPod",
"version" : "0.163250"
},
{
"class" : "Dist::Zilla::Plugin::Prereqs",
"config" : {
"Dist::Zilla::Plugin::Prereqs" : {
"phase" : "develop",
"type" : "recommends"
}
},
"name" : "@Author::ETHER/@Git::VersionManager/pluginbundle version",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::RewriteVersion::Transitional",
"config" : {
"Dist::Zilla::Plugin::RewriteVersion" : {
"add_tarball_name" : 0,
"finders" : [
":ExecFiles",
":InstallModules"
],
"global" : 1,
"skip_version_provider" : 0
},
"Dist::Zilla::Plugin::RewriteVersion::Transitional" : {}
},
"name" : "@Author::ETHER/@Git::VersionManager/RewriteVersion::Transitional",
"version" : "0.009"
},
{
"class" : "Dist::Zilla::Plugin::MetaProvides::Update",
"name" : "@Author::ETHER/@Git::VersionManager/MetaProvides::Update",
"version" : "0.007"
},
{
"class" : "Dist::Zilla::Plugin::CopyFilesFromRelease",
"config" : {
"Dist::Zilla::Plugin::CopyFilesFromRelease" : {
"filename" : [
"Changes"
],
"match" : []
}
},
"name" : "@Author::ETHER/@Git::VersionManager/CopyFilesFromRelease",
"version" : "0.007"
},
{
"class" : "Dist::Zilla::Plugin::Git::Commit",
"config" : {
"Dist::Zilla::Plugin::Git::Commit" : {
"add_files_in" : [
"."
],
"commit_msg" : "%N-%v%t%n%n%c",
"signoff" : 0
},
"Dist::Zilla::Role::Git::DirtyFiles" : {
"allow_dirty" : [
"CONTRIBUTING",
"Changes",
"INSTALL",
"LICENCE",
"README.pod"
],
"allow_dirty_match" : [],
"changelog" : "Changes"
},
"Dist::Zilla::Role::Git::Repo" : {
"git_version" : "2.45.2",
"repo_root" : "."
},
"Dist::Zilla::Role::Git::StringFormatter" : {
"time_zone" : "local"
}
},
"name" : "@Author::ETHER/@Git::VersionManager/release snapshot",
"version" : "2.051"
},
{
"class" : "Dist::Zilla::Plugin::Git::Tag",
"config" : {
"Dist::Zilla::Plugin::Git::Tag" : {
"branch" : null,
"changelog" : "Changes",
"signed" : 0,
"tag" : "v0.32",
"tag_format" : "v%V",
"tag_message" : "v%v%t"
},
"Dist::Zilla::Role::Git::Repo" : {
"git_version" : "2.45.2",
"repo_root" : "."
},
"Dist::Zilla::Role::Git::StringFormatter" : {
"time_zone" : "local"
}
},
"name" : "@Author::ETHER/@Git::VersionManager/Git::Tag",
"version" : "2.051"
},
{
"class" : "Dist::Zilla::Plugin::BumpVersionAfterRelease::Transitional",
"config" : {
"Dist::Zilla::Plugin::BumpVersionAfterRelease" : {
"finders" : [
":InstallModules"
],
"global" : 1,
"munge_makefile_pl" : 1
},
"Dist::Zilla::Plugin::BumpVersionAfterRelease::Transitional" : {}
},
"name" : "@Author::ETHER/@Git::VersionManager/BumpVersionAfterRelease::Transitional",
"version" : "0.009"
},
{
"class" : "Dist::Zilla::Plugin::NextRelease",
"name" : "@Author::ETHER/@Git::VersionManager/NextRelease",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::Git::Commit",
"config" : {
"Dist::Zilla::Plugin::Git::Commit" : {
"add_files_in" : [],
"commit_msg" : "increment $VERSION after %v release",
"signoff" : 0
},
"Dist::Zilla::Role::Git::DirtyFiles" : {
"allow_dirty" : [
"Build.PL",
"Changes",
"Makefile.PL"
],
"allow_dirty_match" : [
"(?^:^lib/.*\\.pm$)"
],
"changelog" : "Changes"
},
"Dist::Zilla::Role::Git::Repo" : {
"git_version" : "2.45.2",
"repo_root" : "."
},
"Dist::Zilla::Role::Git::StringFormatter" : {
"time_zone" : "local"
}
},
"name" : "@Author::ETHER/@Git::VersionManager/post-release commit",
"version" : "2.051"
},
{
"class" : "Dist::Zilla::Plugin::Prereqs",
"config" : {
"Dist::Zilla::Plugin::Prereqs" : {
"phase" : "x_Dist_Zilla",
"type" : "requires"
}
},
"name" : "@Author::ETHER/@Git::VersionManager/prereqs for @Git::VersionManager",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::Git::Push",
"config" : {
"Dist::Zilla::Plugin::Git::Push" : {
"push_to" : [
"origin"
],
"remotes_must_exist" : 1
},
"Dist::Zilla::Role::Git::Repo" : {
"git_version" : "2.45.2",
"repo_root" : "."
}
},
"name" : "@Author::ETHER/Git::Push",
"version" : "2.051"
},
{
"class" : "Dist::Zilla::Plugin::GitHub::Update",
"config" : {
"Dist::Zilla::Plugin::GitHub::Update" : {
"metacpan" : 1
}
},
"name" : "@Author::ETHER/GitHub::Update",
"version" : "0.49"
},
{
"class" : "Dist::Zilla::Plugin::Run::AfterRelease",
"config" : {
"Dist::Zilla::Plugin::Run::Role::Runner" : {
"fatal_errors" : 0,
"quiet" : 0,
"run" : [
"REDACTED"
],
"version" : "0.050"
}
},
"name" : "@Author::ETHER/install release",
"version" : "0.050"
},
{
"class" : "Dist::Zilla::Plugin::Run::AfterRelease",
"config" : {
"Dist::Zilla::Plugin::Run::Role::Runner" : {
"eval" : [
"print \"release complete!\\xa\""
],
"fatal_errors" : 1,
"quiet" : 1,
"version" : "0.050"
}
},
"name" : "@Author::ETHER/release complete",
"version" : "0.050"
},
{
"class" : "Dist::Zilla::Plugin::ConfirmRelease",
"name" : "@Author::ETHER/ConfirmRelease",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::Prereqs",
"config" : {
"Dist::Zilla::Plugin::Prereqs" : {
"phase" : "x_Dist_Zilla",
"type" : "requires"
}
},
"name" : "@Author::ETHER/prereqs for @Author::ETHER",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::Substitute",
"name" : "Substitute",
"version" : "0.007"
},
{
"class" : "Dist::Zilla::Plugin::Prereqs::Soften",
"config" : {
"Dist::Zilla::Plugin::Prereqs::Soften" : {
"copy_to" : [
"develop.requires"
],
"modules" : [
"Capture::Tiny",
"Sub::Name",
"Sub::Util"
],
"modules_from_features" : null,
"to_relationship" : "suggests"
}
},
"name" : "Prereqs::Soften",
"version" : "0.006003"
},
{
"class" : "Dist::Zilla::Plugin::OnlyCorePrereqs",
"config" : {
"Dist::Zilla::Plugin::OnlyCorePrereqs" : {
"also_disallow" : [],
"check_dual_life_versions" : 0,
"deprecated_ok" : 0,
"phases" : [
"build",
"configure",
"runtime",
"test"
],
"skips" : [],
"starting_version" : "to be determined from perl prereq"
}
},
"name" : "OnlyCorePrereqs",
"version" : "0.025"
},
{
"class" : "Dist::Zilla::Plugin::Breaks",
"name" : "Breaks",
"version" : "0.004"
},
{
"class" : "Dist::Zilla::Plugin::Test::CheckBreaks",
"config" : {
"Dist::Zilla::Plugin::Test::CheckBreaks" : {
"conflicts_module" : [],
"no_forced_deps" : 1
},
"Dist::Zilla::Role::ModuleMetadata" : {
"Module::Metadata" : "1.000038",
"version" : "0.006"
}
},
"name" : "Test::CheckBreaks",
"version" : "0.019"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":InstallModules",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":IncModules",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":TestFiles",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":ExtraTestFiles",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":ExecFiles",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":PerlExecFiles",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":ShareFiles",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":MainModule",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":AllFiles",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":NoFiles",
"version" : "6.032"
},
{
"class" : "Dist::Zilla::Plugin::VerifyPhases",
"name" : "@Author::ETHER/PHASE VERIFICATION",
"version" : "0.016"
}
],
"zilla" : {
"class" : "Dist::Zilla::Dist::Builder",
"config" : {
"is_trial" : 0
},
"version" : "6.032"
}
},
"x_authority" : "cpan:NUFFIN",
"x_breaks" : {
"Try::Tiny::Except" : "<= 0.01"
},
"x_contributors" : [
"Karen Etheridge <ether@cpan.org>",
"Peter Rabbitson <ribasushi@cpan.org>",
"Ricardo Signes <rjbs@cpan.org>",
"Mark Fowler <mark@twoshortplanks.com>",
"Graham Knop <haarg@haarg.org>",
"Aristotle Pagaltzis <pagaltzis@gmx.de>",
"Dagfinn Ilmari Mannsåker <ilmari@ilmari.org>",
"Lukas Mai <l.mai@web.de>",
"Alex <alex@koban.(none)>",
"anaxagoras <walkeraj@gmail.com>",
"Andrew Yates <ayates@haddock.local>",
"awalker <awalker@sourcefire.com>",
"chromatic <chromatic@wgz.org>",
"cm-perl <cm-perl@users.noreply.github.com>",
"David Lowe <davidl@lokku.com>",
"Glenn Fowler <cebjyre@cpan.org>",
"Hans Dieter Pearcey <hdp@weftsoar.net>",
"Jens Berthold <jens@jebecs.de>",
"Jonathan Yu <JAWNSY@cpan.org>",
"Marc Mims <marc@questright.com>",
"Mark Stosberg <mark@stosberg.com>",
"Pali <pali@cpan.org>",
"Paul Howarth <paul@city-fan.org>",
"Rudolf Leermakers <rudolf@hatsuseno.org>"
],
"x_generated_by_perl" : "v5.41.2",
"x_serialization_backend" : "JSON::PP version 2.97001",
"x_spdx_expression" : "MIT",
"x_use_unsafe_inc" : 0
}
PK 2N%[�f^Z� � @ perl5/x86_64-linux-thread-multi/.meta/Try-Tiny-0.32/install.jsonnu ��6�$ {"target":"Try::Tiny","provides":{"Try::Tiny":{"version":"0.32","file":"lib/Try/Tiny.pm"}},"pathname":"E/ET/ETHER/Try-Tiny-0.32.tar.gz","name":"Try::Tiny","version":"0.32","dist":"Try-Tiny-0.32"}PK 2N%[�OS�w �w @ perl5/x86_64-linux-thread-multi/.meta/HTTP-Date-6.06/MYMETA.jsonnu ��6�$ {
"abstract" : "HTTP::Date - date conversion routines",
"author" : [
"Gisle Aas <gisle@activestate.com>"
],
"dynamic_config" : 0,
"generated_by" : "Dist::Zilla version 6.030, CPAN::Meta::Converter version 2.150010",
"license" : [
"perl_5"
],
"meta-spec" : {
"url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
"version" : 2
},
"name" : "HTTP-Date",
"no_index" : {
"directory" : [
"examples",
"t",
"xt"
]
},
"prereqs" : {
"configure" : {
"requires" : {
"ExtUtils::MakeMaker" : "0"
},
"suggests" : {
"JSON::PP" : "2.27300"
}
},
"develop" : {
"recommends" : {
"Dist::Zilla::PluginBundle::Git::VersionManager" : "0.007"
},
"requires" : {
"Code::TidyAll" : "0.71",
"Code::TidyAll::Plugin::SortLines::Naturally" : "0.000003",
"Code::TidyAll::Plugin::Test::Vars" : "0.04",
"Code::TidyAll::Plugin::UniqueLines" : "0.000003",
"Encode" : "0",
"Parallel::ForkManager" : "1.19",
"Perl::Critic" : "1.132",
"Perl::Tidy" : "20180220",
"Pod::Coverage::TrustPod" : "0",
"Pod::Wordlist" : "0",
"Test::CPAN::Changes" : "0.19",
"Test::EOL" : "0",
"Test::Mojibake" : "0",
"Test::More" : "0.96",
"Test::Pod" : "1.41",
"Test::Pod::Coverage" : "1.08",
"Test::Portability::Files" : "0",
"Test::Spelling" : "0.12",
"Test::Vars" : "0.014",
"Test::Version" : "1",
"warnings" : "0"
}
},
"runtime" : {
"requires" : {
"Exporter" : "0",
"Time::Local" : "1.28",
"Time::Zone" : "0",
"perl" : "5.006002",
"strict" : "0"
}
},
"test" : {
"recommends" : {
"CPAN::Meta" : "2.120900"
},
"requires" : {
"ExtUtils::MakeMaker" : "0",
"File::Spec" : "0",
"IO::Handle" : "0",
"IPC::Open3" : "0",
"Test::More" : "0",
"perl" : "5.006002",
"warnings" : "0"
}
}
},
"release_status" : "stable",
"resources" : {
"bugtracker" : {
"web" : "https://github.com/libwww-perl/HTTP-Date/issues"
},
"homepage" : "https://github.com/libwww-perl/HTTP-Date",
"repository" : {
"type" : "git",
"url" : "https://github.com/libwww-perl/HTTP-Date.git",
"web" : "https://github.com/libwww-perl/HTTP-Date"
},
"x_IRC" : "irc://irc.perl.org/#lwp",
"x_MailingList" : "mailto:libwww@perl.org"
},
"version" : "6.06",
"x_Dist_Zilla" : {
"perl" : {
"version" : "5.036000"
},
"plugins" : [
{
"class" : "Dist::Zilla::Plugin::PromptIfStale",
"config" : {
"Dist::Zilla::Plugin::PromptIfStale" : {
"check_all_plugins" : 0,
"check_all_prereqs" : 0,
"modules" : [
"Dist::Zilla::PluginBundle::Author::OALDERS"
],
"phase" : "build",
"run_under_travis" : 0,
"skip" : []
}
},
"name" : "@Author::OALDERS/stale modules, build",
"version" : "0.058"
},
{
"class" : "Dist::Zilla::Plugin::PromptIfStale",
"config" : {
"Dist::Zilla::Plugin::PromptIfStale" : {
"check_all_plugins" : 1,
"check_all_prereqs" : 1,
"modules" : [],
"phase" : "release",
"run_under_travis" : 0,
"skip" : []
}
},
"name" : "@Author::OALDERS/stale modules, release",
"version" : "0.058"
},
{
"class" : "Dist::Zilla::Plugin::AutoPrereqs",
"name" : "@Author::OALDERS/AutoPrereqs",
"version" : "6.030"
},
{
"class" : "Dist::Zilla::Plugin::CheckChangesHasContent",
"name" : "@Author::OALDERS/CheckChangesHasContent",
"version" : "0.011"
},
{
"class" : "Dist::Zilla::Plugin::MakeMaker",
"config" : {
"Dist::Zilla::Role::TestRunner" : {
"default_jobs" : "8"
}
},
"name" : "@Author::OALDERS/MakeMaker",
"version" : "6.030"
},
{
"class" : "Dist::Zilla::Plugin::CPANFile",
"name" : "@Author::OALDERS/CPANFile",
"version" : "6.030"
},
{
"class" : "Dist::Zilla::Plugin::ContributorsFile",
"name" : "@Author::OALDERS/ContributorsFile",
"version" : "0.3.0"
},
{
"class" : "Dist::Zilla::Plugin::MetaJSON",
"name" : "@Author::OALDERS/MetaJSON",
"version" : "6.030"
},
{
"class" : "Dist::Zilla::Plugin::MetaYAML",
"name" : "@Author::OALDERS/MetaYAML",
"version" : "6.030"
},
{
"class" : "Dist::Zilla::Plugin::Manifest",
"name" : "@Author::OALDERS/Manifest",
"version" : "6.030"
},
{
"class" : "Dist::Zilla::Plugin::MetaNoIndex",
"name" : "@Author::OALDERS/MetaNoIndex",
"version" : "6.030"
},
{
"class" : "Dist::Zilla::Plugin::MetaConfig",
"name" : "@Author::OALDERS/MetaConfig",
"version" : "6.030"
},
{
"class" : "Dist::Zilla::Plugin::MetaResources",
"name" : "@Author::OALDERS/MetaResources",
"version" : "6.030"
},
{
"class" : "Dist::Zilla::Plugin::License",
"name" : "@Author::OALDERS/License",
"version" : "6.030"
},
{
"class" : "Dist::Zilla::Plugin::InstallGuide",
"config" : {
"Dist::Zilla::Role::ModuleMetadata" : {
"Module::Metadata" : "1.000037",
"version" : "0.006"
}
},
"name" : "@Author::OALDERS/InstallGuide",
"version" : "1.200014"
},
{
"class" : "Dist::Zilla::Plugin::Prereqs",
"config" : {
"Dist::Zilla::Plugin::Prereqs" : {
"phase" : "develop",
"type" : "requires"
}
},
"name" : "@Author::OALDERS/Modules for use with tidyall",
"version" : "6.030"
},
{
"class" : "Dist::Zilla::Plugin::ExecDir",
"name" : "@Author::OALDERS/ExecDir",
"version" : "6.030"
},
{
"class" : "Dist::Zilla::Plugin::Test::PodSpelling",
"config" : {
"Dist::Zilla::Plugin::Test::PodSpelling" : {
"directories" : [
"bin",
"lib"
],
"spell_cmd" : "",
"stopwords" : [
"Alders",
"Alders'",
"TZ",
"YYYY"
],
"wordlist" : "Pod::Wordlist"
}
},
"name" : "@Author::OALDERS/Test::PodSpelling",
"version" : "2.007005"
},
{
"class" : "Dist::Zilla::Plugin::MojibakeTests",
"name" : "@Author::OALDERS/MojibakeTests",
"version" : "0.8"
},
{
"class" : "Dist::Zilla::Plugin::PodSyntaxTests",
"name" : "@Author::OALDERS/PodSyntaxTests",
"version" : "6.030"
},
{
"class" : "Dist::Zilla::Plugin::Test::CPAN::Changes",
"config" : {
"Dist::Zilla::Plugin::Test::CPAN::Changes" : {
"changelog" : "Changes"
}
},
"name" : "@Author::OALDERS/Test::CPAN::Changes",
"version" : "0.012"
},
{
"class" : "Dist::Zilla::Plugin::Test::EOL",
"config" : {
"Dist::Zilla::Plugin::Test::EOL" : {
"filename" : "xt/author/eol.t",
"finder" : [
":ExecFiles",
":InstallModules",
":TestFiles"
],
"trailing_whitespace" : 1
}
},
"name" : "@Author::OALDERS/Test::EOL",
"version" : "0.19"
},
{
"class" : "Dist::Zilla::Plugin::Test::Pod::Coverage::Configurable",
"name" : "@Author::OALDERS/Test::Pod::Coverage::Configurable",
"version" : "0.07"
},
{
"class" : "Dist::Zilla::Plugin::Test::Portability",
"config" : {
"Dist::Zilla::Plugin::Test::Portability" : {
"options" : ""
}
},
"name" : "@Author::OALDERS/Test::Portability",
"version" : "2.001001"
},
{
"class" : "Dist::Zilla::Plugin::TestRelease",
"name" : "@Author::OALDERS/TestRelease",
"version" : "6.030"
},
{
"class" : "Dist::Zilla::Plugin::Test::ReportPrereqs",
"name" : "@Author::OALDERS/Test::ReportPrereqs",
"version" : "0.029"
},
{
"class" : "Dist::Zilla::Plugin::Test::Version",
"name" : "@Author::OALDERS/Test::Version",
"version" : "1.09"
},
{
"class" : "Dist::Zilla::Plugin::RunExtraTests",
"config" : {
"Dist::Zilla::Role::TestRunner" : {
"default_jobs" : "8"
}
},
"name" : "@Author::OALDERS/RunExtraTests",
"version" : "0.029"
},
{
"class" : "Dist::Zilla::Plugin::PodWeaver",
"config" : {
"Dist::Zilla::Plugin::PodWeaver" : {
"finder" : [
":InstallModules",
":PerlExecFiles"
],
"plugins" : [
{
"class" : "Pod::Weaver::Plugin::EnsurePod5",
"name" : "@CorePrep/EnsurePod5",
"version" : "4.019"
},
{
"class" : "Pod::Weaver::Plugin::H1Nester",
"name" : "@CorePrep/H1Nester",
"version" : "4.019"
},
{
"class" : "Pod::Weaver::Plugin::SingleEncoding",
"name" : "@Default/SingleEncoding",
"version" : "4.019"
},
{
"class" : "Pod::Weaver::Section::Name",
"name" : "@Default/Name",
"version" : "4.019"
},
{
"class" : "Pod::Weaver::Section::Version",
"name" : "@Default/Version",
"version" : "4.019"
},
{
"class" : "Pod::Weaver::Section::Region",
"name" : "@Default/prelude",
"version" : "4.019"
},
{
"class" : "Pod::Weaver::Section::Generic",
"name" : "SYNOPSIS",
"version" : "4.019"
},
{
"class" : "Pod::Weaver::Section::Generic",
"name" : "DESCRIPTION",
"version" : "4.019"
},
{
"class" : "Pod::Weaver::Section::Generic",
"name" : "OVERVIEW",
"version" : "4.019"
},
{
"class" : "Pod::Weaver::Section::Collect",
"name" : "ATTRIBUTES",
"version" : "4.019"
},
{
"class" : "Pod::Weaver::Section::Collect",
"name" : "METHODS",
"version" : "4.019"
},
{
"class" : "Pod::Weaver::Section::Collect",
"name" : "FUNCTIONS",
"version" : "4.019"
},
{
"class" : "Pod::Weaver::Section::Leftovers",
"name" : "@Default/Leftovers",
"version" : "4.019"
},
{
"class" : "Pod::Weaver::Section::Region",
"name" : "@Default/postlude",
"version" : "4.019"
},
{
"class" : "Pod::Weaver::Section::Authors",
"name" : "@Default/Authors",
"version" : "4.019"
},
{
"class" : "Pod::Weaver::Section::Legal",
"name" : "@Default/Legal",
"version" : "4.019"
}
]
}
},
"name" : "@Author::OALDERS/PodWeaver",
"version" : "4.010"
},
{
"class" : "Dist::Zilla::Plugin::PruneCruft",
"name" : "@Author::OALDERS/PruneCruft",
"version" : "6.030"
},
{
"class" : "Dist::Zilla::Plugin::CopyFilesFromBuild",
"name" : "@Author::OALDERS/CopyFilesFromBuild",
"version" : "0.170880"
},
{
"class" : "Dist::Zilla::Plugin::GithubMeta",
"name" : "@Author::OALDERS/GithubMeta",
"version" : "0.58"
},
{
"class" : "Dist::Zilla::Plugin::Git::GatherDir",
"config" : {
"Dist::Zilla::Plugin::GatherDir" : {
"exclude_filename" : [
"Install",
"LICENSE",
"META.json",
"Makefile.PL",
"README.md",
"cpanfile"
],
"exclude_match" : [],
"follow_symlinks" : 0,
"include_dotfiles" : 0,
"prefix" : "",
"prune_directory" : [],
"root" : "."
},
"Dist::Zilla::Plugin::Git::GatherDir" : {
"include_untracked" : 0
}
},
"name" : "@Author::OALDERS/Git::GatherDir",
"version" : "2.048"
},
{
"class" : "Dist::Zilla::Plugin::CopyFilesFromRelease",
"config" : {
"Dist::Zilla::Plugin::CopyFilesFromRelease" : {
"filename" : [
"Install"
],
"match" : []
}
},
"name" : "@Author::OALDERS/CopyFilesFromRelease",
"version" : "0.007"
},
{
"class" : "Dist::Zilla::Plugin::Git::Check",
"config" : {
"Dist::Zilla::Plugin::Git::Check" : {
"untracked_files" : "die"
},
"Dist::Zilla::Role::Git::DirtyFiles" : {
"allow_dirty" : [
"Changes",
"Install",
"LICENSE",
"META.json",
"Makefile.PL",
"README.md",
"cpanfile",
"dist.ini"
],
"allow_dirty_match" : [],
"changelog" : "Changes"
},
"Dist::Zilla::Role::Git::Repo" : {
"git_version" : "2.41.0",
"repo_root" : "."
}
},
"name" : "@Author::OALDERS/Git::Check",
"version" : "2.048"
},
{
"class" : "Dist::Zilla::Plugin::Git::Contributors",
"config" : {
"Dist::Zilla::Plugin::Git::Contributors" : {
"git_version" : "2.41.0",
"include_authors" : 0,
"include_releaser" : 1,
"order_by" : "name",
"paths" : []
}
},
"name" : "@Author::OALDERS/Git::Contributors",
"version" : "0.036"
},
{
"class" : "Dist::Zilla::Plugin::ReadmeAnyFromPod",
"config" : {
"Dist::Zilla::Role::FileWatcher" : {
"version" : "0.006"
}
},
"name" : "@Author::OALDERS/ReadmeMdInBuild",
"version" : "0.163250"
},
{
"class" : "Dist::Zilla::Plugin::StaticInstall",
"config" : {
"Dist::Zilla::Plugin::StaticInstall" : {
"dry_run" : 0,
"mode" : "on"
}
},
"name" : "@Author::OALDERS/StaticInstall",
"version" : "0.012"
},
{
"class" : "Dist::Zilla::Plugin::ShareDir",
"name" : "@Author::OALDERS/ShareDir",
"version" : "6.030"
},
{
"class" : "Dist::Zilla::Plugin::CheckIssues",
"name" : "@Author::OALDERS/CheckIssues",
"version" : "0.011"
},
{
"class" : "Dist::Zilla::Plugin::ConfirmRelease",
"name" : "@Author::OALDERS/ConfirmRelease",
"version" : "6.030"
},
{
"class" : "Dist::Zilla::Plugin::UploadToCPAN",
"name" : "@Author::OALDERS/UploadToCPAN",
"version" : "6.030"
},
{
"class" : "Dist::Zilla::Plugin::Prereqs",
"config" : {
"Dist::Zilla::Plugin::Prereqs" : {
"phase" : "develop",
"type" : "recommends"
}
},
"name" : "@Author::OALDERS/@Git::VersionManager/pluginbundle version",
"version" : "6.030"
},
{
"class" : "Dist::Zilla::Plugin::RewriteVersion::Transitional",
"config" : {
"Dist::Zilla::Plugin::RewriteVersion" : {
"add_tarball_name" : 0,
"finders" : [
":ExecFiles",
":InstallModules"
],
"global" : 0,
"skip_version_provider" : 0
},
"Dist::Zilla::Plugin::RewriteVersion::Transitional" : {}
},
"name" : "@Author::OALDERS/@Git::VersionManager/RewriteVersion::Transitional",
"version" : "0.009"
},
{
"class" : "Dist::Zilla::Plugin::MetaProvides::Update",
"name" : "@Author::OALDERS/@Git::VersionManager/MetaProvides::Update",
"version" : "0.007"
},
{
"class" : "Dist::Zilla::Plugin::CopyFilesFromRelease",
"config" : {
"Dist::Zilla::Plugin::CopyFilesFromRelease" : {
"filename" : [
"Changes"
],
"match" : []
}
},
"name" : "@Author::OALDERS/@Git::VersionManager/CopyFilesFromRelease",
"version" : "0.007"
},
{
"class" : "Dist::Zilla::Plugin::Git::Commit",
"config" : {
"Dist::Zilla::Plugin::Git::Commit" : {
"add_files_in" : [],
"commit_msg" : "v%V%n%n%c",
"signoff" : 0
},
"Dist::Zilla::Role::Git::DirtyFiles" : {
"allow_dirty" : [
"Changes",
"Install",
"LICENSE",
"META.json",
"Makefile.PL",
"README.md",
"cpanfile",
"dist.ini"
],
"allow_dirty_match" : [],
"changelog" : "Changes"
},
"Dist::Zilla::Role::Git::Repo" : {
"git_version" : "2.41.0",
"repo_root" : "."
},
"Dist::Zilla::Role::Git::StringFormatter" : {
"time_zone" : "local"
}
},
"name" : "@Author::OALDERS/@Git::VersionManager/release snapshot",
"version" : "2.048"
},
{
"class" : "Dist::Zilla::Plugin::Git::Tag",
"config" : {
"Dist::Zilla::Plugin::Git::Tag" : {
"branch" : null,
"changelog" : "Changes",
"signed" : 0,
"tag" : "v6.06",
"tag_format" : "v%V",
"tag_message" : "v%V"
},
"Dist::Zilla::Role::Git::Repo" : {
"git_version" : "2.41.0",
"repo_root" : "."
},
"Dist::Zilla::Role::Git::StringFormatter" : {
"time_zone" : "local"
}
},
"name" : "@Author::OALDERS/@Git::VersionManager/Git::Tag",
"version" : "2.048"
},
{
"class" : "Dist::Zilla::Plugin::BumpVersionAfterRelease::Transitional",
"config" : {
"Dist::Zilla::Plugin::BumpVersionAfterRelease" : {
"finders" : [
":ExecFiles",
":InstallModules"
],
"global" : 0,
"munge_makefile_pl" : 1
},
"Dist::Zilla::Plugin::BumpVersionAfterRelease::Transitional" : {}
},
"name" : "@Author::OALDERS/@Git::VersionManager/BumpVersionAfterRelease::Transitional",
"version" : "0.009"
},
{
"class" : "Dist::Zilla::Plugin::NextRelease",
"name" : "@Author::OALDERS/@Git::VersionManager/NextRelease",
"version" : "6.030"
},
{
"class" : "Dist::Zilla::Plugin::Git::Commit",
"config" : {
"Dist::Zilla::Plugin::Git::Commit" : {
"add_files_in" : [],
"commit_msg" : "increment $VERSION after %v release",
"signoff" : 0
},
"Dist::Zilla::Role::Git::DirtyFiles" : {
"allow_dirty" : [
"Build.PL",
"Changes",
"Makefile.PL"
],
"allow_dirty_match" : [
"(?^:^lib/.*\\.pm$)"
],
"changelog" : "Changes"
},
"Dist::Zilla::Role::Git::Repo" : {
"git_version" : "2.41.0",
"repo_root" : "."
},
"Dist::Zilla::Role::Git::StringFormatter" : {
"time_zone" : "local"
}
},
"name" : "@Author::OALDERS/@Git::VersionManager/post-release commit",
"version" : "2.048"
},
{
"class" : "Dist::Zilla::Plugin::Git::Push",
"config" : {
"Dist::Zilla::Plugin::Git::Push" : {
"push_to" : [
"origin"
],
"remotes_must_exist" : 1
},
"Dist::Zilla::Role::Git::Repo" : {
"git_version" : "2.41.0",
"repo_root" : "."
}
},
"name" : "@Author::OALDERS/Git::Push",
"version" : "2.048"
},
{
"class" : "Dist::Zilla::Plugin::MetaResources",
"name" : "MetaResources",
"version" : "6.030"
},
{
"class" : "Dist::Zilla::Plugin::Prereqs",
"config" : {
"Dist::Zilla::Plugin::Prereqs" : {
"phase" : "runtime",
"type" : "requires"
}
},
"name" : "Prereqs",
"version" : "6.030"
},
{
"class" : "Dist::Zilla::Plugin::Test::ChangesHasContent",
"name" : "Test::ChangesHasContent",
"version" : "0.011"
},
{
"class" : "Dist::Zilla::Plugin::Substitute",
"name" : "changes_has_content.t",
"version" : "0.007"
},
{
"class" : "Dist::Zilla::Plugin::Test::Compile",
"config" : {
"Dist::Zilla::Plugin::Test::Compile" : {
"bail_out_on_fail" : 0,
"fail_on_warning" : "author",
"fake_home" : 0,
"filename" : "t/00-compile.t",
"module_finder" : [
":InstallModules"
],
"needs_display" : 0,
"phase" : "test",
"script_finder" : [
":PerlExecFiles"
],
"skips" : [],
"switch" : []
}
},
"name" : "Test::Compile",
"version" : "2.058"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":InstallModules",
"version" : "6.030"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":IncModules",
"version" : "6.030"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":TestFiles",
"version" : "6.030"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":ExtraTestFiles",
"version" : "6.030"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":ExecFiles",
"version" : "6.030"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":PerlExecFiles",
"version" : "6.030"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":ShareFiles",
"version" : "6.030"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":MainModule",
"version" : "6.030"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":AllFiles",
"version" : "6.030"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":NoFiles",
"version" : "6.030"
}
],
"zilla" : {
"class" : "Dist::Zilla::Dist::Builder",
"config" : {
"is_trial" : 0
},
"version" : "6.030"
}
},
"x_contributors" : [
"Adam Kennedy <adamk@cpan.org>",
"Adam Sjogren <asjo@koldfront.dk>",
"Alexey Tourbin <at@altlinux.ru>",
"Alex Kapranoff <ka@nadoby.ru>",
"amire80 <amir.aharoni@gmail.com>",
"Andreas J. Koenig <andreas.koenig@anima.de>",
"Bill Mann <wfmann@alum.mit.edu>",
"Bron Gondwana <brong@fastmail.fm>",
"Daniel Hedlund <Daniel.Hedlund@eprize.com>",
"David E. Wheeler <david@justatheory.com>",
"DAVIDRW <davidrw@cpan.org>",
"Father Chrysostomos <sprout@cpan.org>",
"FWILES <FWILES@cpan.org>",
"Gavin Peters <gpeters@deepsky.com>",
"Gisle Aas <aas@oslonett.no>",
"Gisle Aas <gisle.aas@it.uib.no>",
"Gisle Aas <gisle@aas.no>",
"Gisle Aas <gisle@baux-2.lan>",
"Graeme Thompson <Graeme.Thompson@mobilecohesion.com>",
"Hans-H. Froehlich <hfroehlich@co-de-co.de>",
"Ian Kilgore <iank@cpan.org>",
"Jacob J <waif@chaos2.org>",
"James Raspass <jraspass@gmail.com>",
"jefflee <shaohua@gmail.com>",
"john9art <john9art@yahoo.com>",
"Kyle Wright <kyle.wright@grantstreet.com>",
"Mark Stosberg <mark@stosberg.com>",
"Mark Stosberg <MARKSTOS@cpan.org>",
"Mark Stosberg <mark@summersault.com>",
"Mike Schilli <mschilli@yahoo-inc.com>",
"mschilli <github@perlmeister.com>",
"murphy <murphy@genome.chop.edu>",
"Olaf Alders <olaf@wundersolutions.com>",
"Ondrej Hanak <ondrej.hanak@ubs.com>",
"Peter Rabbitson <ribasushi@cpan.org>",
"Philip J. Ludlam <p.ludlam@cv-library.co.uk>",
"phrstbrn <phrstbrn@gmail.com>",
"pnull <github@jamit.de>",
"Robert Stone <talby@trap.mtview.ca.us>",
"Rolf Grossmann <rg@progtech.net>",
"ruff <ruff@ukrpost.net>",
"sasao <sasao@yugen.org>",
"Sean M. Burke <sburke@cpan.org>",
"Slaven Rezic <slaven@rezic.de>",
"Slaven Rezic <srezic@iconmobile.com>",
"Spiros Denaxas <s.denaxas@gmail.com>",
"Steve Hay <SteveHay@planit.com>",
"Todd Lipcon <todd@amiestreet.com>",
"Tom Hukins <tom@eborcom.com>",
"Tony Finch <dot@dotat.at>",
"Toru Yamaguchi <zigorou@cpan.org>",
"uid39246 <uid39246>",
"Ville Skyttä <ville.skytta@iki.fi>",
"Yuri Karaban <tech@askold.net>",
"Zefram <zefram@fysh.org>"
],
"x_generated_by_perl" : "v5.36.0",
"x_serialization_backend" : "JSON::PP version 2.97001",
"x_spdx_expression" : "Artistic-1.0-Perl OR GPL-1.0-or-later",
"x_static_install" : 1
}
PK 2N%[��PK� � A perl5/x86_64-linux-thread-multi/.meta/HTTP-Date-6.06/install.jsonnu ��6�$ {"target":"HTTP::Date","name":"HTTP::Date","provides":{"HTTP::Date":{"version":6.06,"file":"lib/HTTP/Date.pm"}},"pathname":"O/OA/OALDERS/HTTP-Date-6.06.tar.gz","version":6.06,"dist":"HTTP-Date-6.06"}PK 2N%[���� = perl5/x86_64-linux-thread-multi/.meta/Encode-3.21/MYMETA.jsonnu ��6�$ {
"abstract" : "character encodings in Perl",
"author" : [
"Dan Kogai <dankogai@dan.co.jp>"
],
"dynamic_config" : 0,
"generated_by" : "ExtUtils::MakeMaker version 7.70, CPAN::Meta::Converter version 2.150010",
"license" : [
"perl_5"
],
"meta-spec" : {
"url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
"version" : 2
},
"name" : "Encode",
"no_index" : {
"directory" : [
"t",
"inc"
]
},
"prereqs" : {
"build" : {
"requires" : {
"ExtUtils::MakeMaker" : "0"
}
},
"configure" : {
"requires" : {
"ExtUtils::MakeMaker" : "0"
}
},
"runtime" : {
"requires" : {
"Exporter" : "5.57",
"Storable" : "0",
"parent" : "0.221"
}
},
"test" : {
"requires" : {
"Test::More" : "0.92"
}
}
},
"release_status" : "stable",
"resources" : {
"repository" : {
"url" : "https://github.com/dankogai/p5-encode"
}
},
"version" : "3.21",
"x_contributors" : [
"Alex Davies <alex.davies@talktalk.net>",
"Alex Kapranoff <alex@kapranoff.ru>",
"Alex Vandiver <alex@chmrr.net>",
"Andreas J. Koenig <andreas.koenig@anima.de>",
"Andrew Pennebaker <andrew.pennebaker@networkedinsights.com>",
"Andy Grundman <andyg@activestate.com>",
"Anton Tagunov <tagunov@motor.ru>",
"Autrijus Tang <autrijus@autrijus.org>",
"Benjamin Goldberg <goldbb2@earthlink.net>",
"Bjoern Hoehrmann <derhoermi@gmx.net>",
"Bjoern Jacke <debianbugs@j3e.de>",
"bulk88 <bulk88@hotmail.com>",
"Craig A. Berry <craigberry@mac.com>",
"Curtis Jewell <csjewell@cpan.org>",
"Dan Kogai <dankogai@dan.co.jp>",
"Dave Evans <dave@rudolf.org.uk>",
"David Golden <dagolden@cpan.org>",
"David Steinbrunner <dsteinbrunner@pobox.com>",
"Deng Liu <dengliu@ntu.edu.tw>",
"Dominic Dunlop <domo@computer.org>",
"drry",
"Elizabeth Mattijsen <liz@dijkmat.nl>",
"Flavio Poletti <flavio@polettix.it>",
"Gerrit P. Haase <gp@familiehaase.de>",
"Gisle Aas <gisle@ActiveState.com>",
"Graham Barr <gbarr@pobox.com>",
"Graham Knop <haarg@haarg.org>",
"Graham Ollis <perl@wdlabs.com>",
"Gurusamy Sarathy <gsar@activestate.com>",
"H.Merijn Brand <h.m.brand@xs4all.nl>",
"Hugo van der Sanden <hv@crypt.org>",
"chansen <chansen@cpan.org>",
"Chris Nandor <pudge@pobox.com>",
"Inaba Hiroto <inaba@st.rim.or.jp>",
"Jarkko Hietaniemi <jhi@iki.fi>",
"Jesse Vincent <jesse@fsck.com>",
"Jungshik Shin <jshin@mailaps.org>",
"Karen Etheridge <ether@cpan.org>",
"Karl Williamson <khw@cpan.org>",
"Kenichi Ishigaki <ishigaki@cpan.org>",
"KONNO Hiroharu <hiroharu.konno@bowneglobal.co.jp>",
"Laszlo Molnar <ml1050@freemail.hu>",
"Makamaka <makamaka@donzoko.net>",
"Mark-Jason Dominus <mjd@plover.com>",
"Masahiro Iuchi <masahiro.iuchi@gmail.com>",
"MATSUNO Tokuhiro <tokuhirom+cpan@gmail.com>",
"Mattia Barbon <mbarbon@dsi.unive.it>",
"Michael G Schwern <schwern@pobox.com>",
"Michael LaGrasta <michael@lagrasta.com>",
"Miron Cuperman <miron@hyper.to>",
"Moritz Lenz <moritz@faui2k3.org>",
"MORIYAMA Masayuki <msyk@mtg.biglobe.ne.jp>",
"Nick Ing-Simmons <nick@ing-simmons.net>",
"Nicholas Clark <nick@ccl4.org>",
"Olivier Mengué <dolmen@cpan.org>",
"otsune",
"Pali <pali@cpan.org>",
"Paul Marquess <paul_marquess@yahoo.co.uk>",
"Peter Prymmer <pvhp@best.com>",
"Peter Rabbitson <ribasushi@cpan.org>",
"Philip Newton <pne@cpan.org>",
"Piotr Fusik <pfusik@op.pl>",
"Rafael Garcia-Suarez <rgarciasuarez@mandriva.com>",
"Randy Stauner <randy@magnificent-tears.com>",
"Reini Urban <rurban@cpan.org>",
"Robin Barker <rmb1@cise.npl.co.uk>",
"SADAHIRO Tomoyuki <SADAHIRO@cpan.org>",
"Simon Cozens <simon@netthink.co.uk>",
"Slaven Rezic <SREZIC@cpan.org>",
"Spider Boardman <spider@web.zk3.dec.com>",
"Steve Hay <steve.m.hay@googlemail.com>",
"Steve Peters <steve@fisharerojo.org>",
"SUGAWARA Hajime <sugawara@hdt.co.jp>",
"SUZUKI Norio <ZAP00217@nifty.com>",
"szr8 <blz.marcel@gmail.com>",
"Tatsuhiko Miyagawa <miyagawa@bulknews.net>",
"Tels <perl_dummy@bloodgate.com>",
"Tony Cook <tony@develop-help.com>",
"Vadim Konovalov <vkonovalov@peterstar.ru>",
"Victor <victor@vsespb.ru>",
"Ville Skyttä <ville.skytta@iki.fi>",
"Vincent van Dam <vvandam@sandvine.com>",
"Yitzchak Scott-Thoennes <sthoenna@efn.org>"
],
"x_serialization_backend" : "JSON::PP version 2.97001"
}
PK 2N%[A�=�S S >