Author: hhubner Date: 2007-11-14 00:24:08 -0500 (Wed, 14 Nov 2007) New Revision: 2274
Added: branches/trunk-reorg/thirdparty/chunga-0.4.1/ branches/trunk-reorg/thirdparty/chunga-0.4.1/CHANGELOG.txt branches/trunk-reorg/thirdparty/chunga-0.4.1/chunga.asd branches/trunk-reorg/thirdparty/chunga-0.4.1/doc/ branches/trunk-reorg/thirdparty/chunga-0.4.1/doc/index.html branches/trunk-reorg/thirdparty/chunga-0.4.1/input.lisp branches/trunk-reorg/thirdparty/chunga-0.4.1/output.lisp branches/trunk-reorg/thirdparty/chunga-0.4.1/packages.lisp branches/trunk-reorg/thirdparty/chunga-0.4.1/read.lisp branches/trunk-reorg/thirdparty/chunga-0.4.1/specials.lisp branches/trunk-reorg/thirdparty/chunga-0.4.1/streams.lisp branches/trunk-reorg/thirdparty/chunga-0.4.1/util.lisp branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/ branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/CHANGELOG branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/README branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/api.lisp branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/cl-ppcre-test.asd branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/cl-ppcre-test.system branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/cl-ppcre.asd branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/cl-ppcre.system branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/closures.lisp branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/convert.lisp branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/doc/ branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/doc/benchmarks.2002-12-22.txt branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/doc/index.html branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/errors.lisp branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/lexer.lisp branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/lispworks-defsystem.lisp branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/load.lisp branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/optimize.lisp branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/packages.lisp branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/parser.lisp branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/perltest.pl branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/ppcre-tests.lisp branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/regex-class.lisp branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/repetition-closures.lisp branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/scanner.lisp branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/specials.lisp branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/testdata branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/testinput branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/util.lisp branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/ branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/CHANGELOG branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/CHANGELOG_TBNL branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/README branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/conditions.lisp branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/cookie.lisp branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/doc/ branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/doc/LICENSE.txt branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/doc/hunchentoot.gif branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/doc/index.html branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/easy-handlers.lisp branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/headers.lisp branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/hunchentoot-test.asd branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/hunchentoot.asd branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/log.lisp branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/mime-types.lisp branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/misc.lisp branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/packages.lisp branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/port-acl.lisp branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/port-cmu.lisp branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/port-lw.lisp branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/port-mcl.lisp branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/port-sbcl.lisp branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/reply.lisp branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/request.lisp branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/server.lisp branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/session.lisp branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/specials.lisp branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/test/ branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/test/UTF-8-demo.html branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/test/favicon.ico branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/test/fz.jpg branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/test/packages.lisp branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/test/test.lisp branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/unix-acl.lisp branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/unix-cmu.lisp branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/unix-lw.lisp branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/unix-mcl.lisp branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/unix-sbcl.lisp branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/util.lisp Removed: branches/trunk-reorg/thirdparty/chunga-0.3.0/ branches/trunk-reorg/thirdparty/cl-ppcre-1.3.0/ branches/trunk-reorg/thirdparty/flexi-streams-0.11.2/ branches/trunk-reorg/thirdparty/hunchentoot-0.11.1/ branches/trunk-reorg/thirdparty/trivial-gray-streams-2006-09-16/ branches/trunk-reorg/thirdparty/trivial-http/ Log: updating
Added: branches/trunk-reorg/thirdparty/chunga-0.4.1/CHANGELOG.txt =================================================================== --- branches/trunk-reorg/thirdparty/chunga-0.4.1/CHANGELOG.txt 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/chunga-0.4.1/CHANGELOG.txt 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,50 @@ +Version 0.4.1 +2007-10-11 +Make Chunga work with AllegroCL's "modern" mode (patch by Ross Jekel) + +Version 0.4.0 +2007-09-18 +Added *TREAT-SEMICOLON-AS-CONTINUATION* + +Version 0.3.1 +2007-09-07 +Fixed bug in STREAM-LISTEN + +Version 0.3.0 +2007-05-08 +Added *ACCEPT-BOGUS-EOLS* (suggested by Sean Ross) + +Version 0.2.4 +2007-02-08 +Allow more characters in cookie names/values according to original Netscape spec +Robustified READ-COOKIE-VALUE + +Version 0.2.3 +2007-01-17 +Guard against stray semicolons when reading name/value pairs (thanks to B�lent Murtezaoglu) + +Version 0.2.2 +2007-01-10 +Faster vesion of READ-LINE* (provided by G�bor Melis) + +Version 0.2.1 +2006-10-26 +Added explicit element types for CLISP to fix problems reported by Anton Vodonosov + +Version 0.2.0 +2006-10-06 +Only wrap inner stream with flexi stream if really needed + +Version 0.1.2 +2006-09-05 +Exported CHUNKED-STREAM-STREAM +Mentioned Gentoo port in docs +Added info about mailing lists + +Version 0.1.1 +2006-09-02 +Added missing CRLF for output chunking + +Version 0.1.0 +2006-09-01 +First public release
Property changes on: branches/trunk-reorg/thirdparty/chunga-0.4.1/CHANGELOG.txt ___________________________________________________________________ Name: svn:executable + *
Added: branches/trunk-reorg/thirdparty/chunga-0.4.1/chunga.asd =================================================================== --- branches/trunk-reorg/thirdparty/chunga-0.4.1/chunga.asd 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/chunga-0.4.1/chunga.asd 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,40 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-USER; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/chunga/chunga.asd,v 1.15 2007/10/11 06:56:02 edi Exp $ + +;;; Copyright (c) 2006-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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. + +(asdf:defsystem :chunga + :serial t + :version "0.4.1" + :components ((:file "packages") + (:file "specials") + (:file "util") + (:file "read") + (:file "streams") + (:file "input") + (:file "output")) + :depends-on (:flexi-streams))
Property changes on: branches/trunk-reorg/thirdparty/chunga-0.4.1/chunga.asd ___________________________________________________________________ Name: svn:executable + *
Added: branches/trunk-reorg/thirdparty/chunga-0.4.1/doc/index.html =================================================================== --- branches/trunk-reorg/thirdparty/chunga-0.4.1/doc/index.html 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/chunga-0.4.1/doc/index.html 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,587 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<html> + +<head> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <title>CHUNGA - Portable chunked streams for Common Lisp</title> + <style type="text/css"> + pre { padding:5px; background-color:#e0e0e0 } + h3, h4 { text-decoration: underline; } + a { text-decoration: none; padding: 1px 2px 1px 2px; } + a:visited { text-decoration: none; padding: 1px 2px 1px 2px; } + a:hover { text-decoration: none; padding: 1px 1px 1px 1px; border: 1px solid #000000; } + a:focus { text-decoration: none; padding: 1px 2px 1px 2px; border: none; } + a.none { text-decoration: none; padding: 0; } + a.none:visited { text-decoration: none; padding: 0; } + a.none:hover { text-decoration: none; border: none; padding: 0; } + a.none:focus { text-decoration: none; border: none; padding: 0; } + a.noborder { text-decoration: none; padding: 0; } + a.noborder:visited { text-decoration: none; padding: 0; } + a.noborder:hover { text-decoration: none; border: none; padding: 0; } + a.noborder:focus { text-decoration: none; border: none; padding: 0; } + </style> +</head> + +<body bgcolor=white> + +<h2>CHUNGA - Portable chunked streams for Common Lisp</h2> + +<blockquote> +<br> <br><h3><a name=abstract class=none>Abstract</a></h3> Chunga +implements streams capable of chunked encoding on demand as defined in +RFC 2616. For an example of how these streams can be used +see <a href="http://weitz.de/drakma/">Drakma</a>. +<p> +The library needs a Common Lisp implementation that +supports <a +href="http://www.nhplace.com/kent/CL/Issues/stream-definition-by-user.html%22%3E<em>Gray +streams</em></a> and relies on David +Lichteblau's <a +href="http://www.cliki.net/trivial-gray-streams%22%3Etrivial-gray-streams</a> to offer portability between different Lisps. +<p> +Chunga is currently not optimized towards performance - it is +rather intended to be easy to use and (if possible) to behave correctly. +<p> +The code comes with +a <a +href="http://www.opensource.org/licenses/bsd-license.php%22%3EBSD-style +license</a> so you can basically do with it whatever you want. + +<p> +<font color=red>Download shortcut:</font> <a href="http://weitz.de/files/chunga.tar.gz">http://weitz.de/files/chunga.tar.gz</a>. +</blockquote> + +<br> <br><h3><a class=none name="contents">Contents</a></h3> +<ol> + <li><a href="#download">Download and installation</a> + <li><a href="#mail">Support and mailing lists</a> + <li><a href="#dictionary">The Chunga dictionary</a> + <ol> + <li><a href="#streams">Chunked streams</a> + <ol> + <li><a href="#chunked-stream"><code>chunked-stream</code></a> + <li><a href="#chunked-input-stream"><code>chunked-input-stream</code></a> + <li><a href="#chunked-output-stream"><code>chunked-output-stream</code></a> + <li><a href="#chunked-io-stream"><code>chunked-io-stream</code></a> + <li><a href="#make-chunked-stream"><code>make-chunked-stream</code></a> + <li><a href="#chunked-stream-stream"><code>chunked-stream-stream</code></a> + <li><a href="#chunked-stream-input-chunking-p"><code>chunked-stream-input-chunking-p</code></a> + <li><a href="#chunked-stream-output-chunking-p"><code>chunked-stream-output-chunking-p</code></a> + <li><a href="#chunked-input-stream-extensions"><code>chunked-input-stream-extensions</code></a> + <li><a href="#chunked-input-stream-trailers"><code>chunked-input-stream-trailers</code></a> + </ol> + <li><a href="#conditions">Conditions</a> + <ol> + <li><a href="#input-chunking-body-corrupted"><code>input-chunking-body-corrupted</code></a> + <li><a href="#input-chunking-unexpected-end-of-file"><code>input-chunking-unexpected-end-of-file</code></a> + </ol> + <li><a href="#parse">RFC 2616 parsing</a> + <ol> + <li><a href="#read-line*"><code>read-line*</code></a> + <li><a href="#read-http-headers"><code>read-http-headers</code></a> + <li><a href="#read-token"><code>read-token</code></a> + <li><a href="#read-name-value-pair"><code>read-name-value-pair</code></a> + <li><a href="#read-name-value-pairs"><code>read-name-value-pairs</code></a> + <li><a href="#assert-char"><code>assert-char</code></a> + <li><a href="#skip-whitespace"><code>skip-whitespace</code></a> + <li><a href="#trim-whitespace"><code>trim-whitespace</code></a> + <li><a href="#*current-error-message*"><code>*current-error-message*</code></a> + <li><a href="#*accept-bogus-eols*"><code>*accept-bogus-eols*</code></a> + <li><a href="#*treat-semicolon-as-continuation*"><code>*treat-semicolon-as-continuation*</code></a> + </ol> + </ol> + <li><a href="#ack">Acknowledgements</a> +</ol> + +<br> <br><h3><a class=none name="download">Download and installation</a></h3> + +Chunga together with this documentation can be downloaded from <a +href="http://weitz.de/files/chunga.tar.gz%22%3Ehttp://weitz.de/files/chunga.tar.gz</a>. The +current version is 0.4.1. +<p> +Chunga depends on +the <a href="http://weitz.de/flexi-streams/">FLEXI-STREAMS</a> +library. You can download and install Chunga and its dependencies +automatically +with <a href="http://www.cliki.net/ASDF-Install">ASDF-Install</a>, and +there's a port for <a href="http://www.gentoo.org/proj/en/common-lisp/index.xml">Gentoo +Linux</a> thanks to Matthew Kennedy. +<p> +A <a href="http://www.selenic.com/mercurial/wiki/">Mercurial</a> +repository of older versions is available +at <a +href="http://arcanes.fr.eu.org/~pierre/2007/02/weitz/%22%3Ehttp://arcanes.fr.eu.or...</a> +thanks to Pierre Thierry. +<p> +Luís Oliveira maintains a <a href="http://darcs.net/">darcs</a> +repository of Chunga +at <a +href="http://common-lisp.net/~loliveira/ediware/%22%3Ehttp://common-lisp.net/~loli...</a>. + +<br> <br><h3><a name="mail" class=none>Support and mailing lists</a></h3> + +For questions, bug reports, feature requests, improvements, or patches +please use the <a +href="http://common-lisp.net/mailman/listinfo/drakma-devel%22%3Edrakma-devel +mailing list</a>. If you want to be notified about future releases +subscribe to the <a +href="http://common-lisp.net/mailman/listinfo/drakma-announce%22%3Edrakma-announce +mailing list</a>. These mailing lists were made available thanks to +the services of <a href="http://common-lisp.net/">common-lisp.net</a>. +<p> +If you want to send patches, please <a href="http://weitz.de/patches.html">read this first</a>. + +<br> <br><h3><a class=none name="dictionary">The Chunga dictionary</a></h3> + +<h4><a name="streams" class=none>Chunked streams</a></h4> + +<em>Chunked streams</em> are the core of the <a href="http://globalia.net/donlope/fz/songs/Chunga's_Revenge.html">Chunga</a> library. You +create them using the +function <a +href="#make-chunked-stream"><code>MAKE-CHUNKED-STREAM</code></a> which +takes an open binary stream (called the <em>underlying</em> stream) as its single argument. +A <em>binary</em> stream in this context means that if it's an <a href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_i.htm#input">input +stream</a>, you can +apply <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/f_rd_seq.htm%22%3E<code>READ-SEQUENCE</code></a> +to it where the sequence is an array of element +type <a href="http://weitz.de/flexi-streams/#octet"><code>OCTET</code></a>, and similarly for <a href="http://www.lispworks.com/documentation/HyperSpec/Body/f_wr_seq.htm"><code>WRITE-SEQUENCE</code></a> and <a href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_o.htm#output">output streams</a>. (Note that this specifically holds for <a href="http://www.lispworks.com/documentation/lw50/LWRM/html/lwref-91.htm"><em>bivalent</em> streams</a> like socket streams.) +<p> +A chunked stream behaves like an ordinary Lisp stream +of <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_e.htm#element_t... +type</a> <a +href="http://weitz.de/flexi-streams/#octet%22%3E<code>OCTET</code></a> +with the addition that you can turn <em>chunking</em> on and off for +input as well as for output. With chunking turned on, data is read or +written according to +the <a href="http://www.rfc.net/rfc2616.html#s3.6.1">definition in RFC +2616</a>. + +<!-- Entry for CHUNKED-STREAM --> + +<p><br>[Standard class]<br><a class=none name='chunked-stream'><b>chunked-stream</b></a> +<blockquote><br> + +Every <a href="#stream">chunked stream</a> returned by +<a href="#make-chunked-stream"><code>MAKE-CHUNKED-STREAM</code></a> is of this type which is a subtype of +<a href="http://www.lispworks.com/documentation/HyperSpec/Body/t_stream.htm"><code>STREAM</code></a>. + +</blockquote> + +<!-- End of entry for CHUNKED-STREAM --> + + +<!-- Entry for CHUNKED-INPUT-STREAM --> + +<p><br>[Standard class]<br><a class=none name='chunked-input-stream'><b>chunked-input-stream</b></a> +<blockquote><br> + +A <a href="#stream">chunked stream</a> is of this type if its +underlying stream is an <a href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_i.htm#input">input +stream</a>. This is a subtype of +<a href="#chunked-stream"><code>CHUNKED-STREAM</code></a>. + +</blockquote> + +<!-- End of entry for CHUNKED-INPUT-STREAM --> + + + + +<!-- Entry for CHUNKED-OUTPUT-STREAM --> + +<p><br>[Standard class]<br><a class=none name='chunked-output-stream'><b>chunked-output-stream</b></a> +<blockquote><br> + +A <a href="#stream">chunked stream</a> is of this type if its +underlying stream is an <a href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_o.htm#output">output stream</a>. This is a subtype of +<a href="#chunked-stream"><code>CHUNKED-STREAM</code></a>. + +</blockquote> + +<!-- End of entry for CHUNKED-OUTPUT-STREAM --> + + +<!-- Entry for CHUNKED-IO-STREAM --> + +<p><br>[Standard class]<br><a class=none name='chunked-io-stream'><b>chunked-io-stream</b></a> +<blockquote><br> + +A <a href="#stream">chunked stream</a> is of this type if it is both +a <a href="#chunked-input-stream"><code>CHUNKED-INPUT-STREAM</code></a> as well as a <a href="#chunked-output-stream"><code>CHUNKED-OUTPUT-STREAM</code></a>. + +</blockquote> + +<!-- End of entry for CHUNKED-IO-STREAM --> + +<!-- Entry for MAKE-CHUNKED-STREAM --> + +<p><br>[Function]<br><a class=none name='make-chunked-stream'><b>make-chunked-stream</b> <i>stream</i> => <i>chunked-stream</i></a> +<blockquote><br> + +Creates and returns a <a href="#stream">chunked stream</a> (a stream of type +<a href="#chunked-stream"><code>CHUNKED-STREAM</code></a>) which wraps <code><i>stream</i></code>. <code><i>stream</i></code> must be an open +binary stream. + +</blockquote> + +<!-- End of entry for MAKE-CHUNKED-STREAM --> + + +<!-- Entry for CHUNKED-STREAM-STREAM --> + +<p><br>[Specialized reader]<br><a class=none name='chunked-stream-stream'><b>chunked-stream-stream</b> <i>(stream chunked-stream)</i> => <i>underlying-stream</i></a> +<blockquote><br> + +Returns the <a href="#stream">underlying stream</a> of the <a href="#chunked-stream">chunked stream</a> <code><i>stream</i></code>. + +</blockquote> + +<!-- End of entry for CHUNKED-STREAM-STREAM --> + + +<!-- Entry for CHUNKED-STREAM-INPUT-CHUNKING-P --> + +<p><br>[Generic reader]<br><a class=none name='chunked-stream-input-chunking-p'><b>chunked-stream-input-chunking-p</b> <i>object</i> => <i>generalized-boolean</i></a> + +<blockquote><br> + +Returns a true value if <code><i>object</i></code> is of type <a href="#chunked-input-stream"><code>CHUNKED-INPUT-STREAM</code></a> and if input chunking is currently enabled. + +</blockquote> + +<p><br>[Specialized writer]<br><a class=none><tt>(setf (</tt><b>chunked-stream-input-chunking-p</b> <i>(stream chunked-input-stream)</i><tt>)</tt> <i>new-value</i><tt>)</tt></a> + +<blockquote><br> + +This function is used to switch input chunking +on <code><i>stream</i></code> on or off. Note that input chunking will +usally be turned off automatically when the last chunk is read. + +</blockquote> + +<!-- End of entry for CHUNKED-STREAM-INPUT-CHUNKING-P --> + + + +<!-- Entry for CHUNKED-STREAM-OUTPUT-CHUNKING-P --> + +<p><br>[Generic reader]<br><a class=none name='chunked-stream-output-chunking-p'><b>chunked-stream-output-chunking-p</b> <i>object</i> => <i>generalized-boolean</i></a> + +<blockquote><br> + +Returns a true value if <code><i>object</i></code> is of type <a href="#chunked-output-stream"><code>CHUNKED-OUTPUT-STREAM</code></a> and if output chunking is currently enabled. + +</blockquote> + +<p><br>[Specialized writer]<br><a class=none><tt>(setf (</tt><b>chunked-stream-output-chunking-p</b> <i>(stream chunked-output-stream)</i><tt>)</tt> <i>new-value</i><tt>)</tt></a> + +<blockquote><br> + +This function is used to switch output chunking +on <code><i>stream</i></code> on or off. + +</blockquote> + +<!-- End of entry for CHUNKED-STREAM-OUTPUT-CHUNKING-P --> + + + + +<!-- Entry for CHUNKED-INPUT-STREAM-EXTENSIONS --> + +<p><br>[Specialized reader]<br><a class=none name='chunked-input-stream-extensions'><b>chunked-input-stream-extensions</b> <i>(stream chunked-input-stream)</i> => <i>extensions</i></a> +<blockquote><br> + +Returns +an <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_a.htm#alist%22%...</a> +of <a href="http://www.rfc.net/rfc2616.html#s3.6">attribute/value pairs</a> corresponding to the optional <a href="http://www.rfc.net/rfc2616.html#s3.6.1">"chunk +extensions"</a> which might have been encountered when reading +from <code><i>stream</i></code>. + +</blockquote> + +<!-- End of entry for CHUNKED-INPUT-STREAM-EXTENSIONS --> + + +<!-- Entry for CHUNKED-INPUT-STREAM-EXTENSIONS --> + +<p><br>[Specialized reader]<br><a class=none name='chunked-input-stream-trailers'><b>chunked-input-stream-trailers</b> <i>(stream chunked-input-stream)</i> => <i>trailers</i></a> +<blockquote><br> + +Returns the +optional <a href="http://www.rfc.net/rfc2616.html#s3.6.1">"trailer" +HTTP headers</a> which might have been sent after the last chunk, +i.e. directly before input chunking ended on <code><i>stream</i></code>. +The format of <code><i>trailers</i></code> is identical to that returned +by <a href="#read-http-headers"><code>READ-HTTP-HEADERS</code></a>. + +</blockquote> + +<!-- End of entry for CHUNKED-INPUT-STREAM-EXTENSIONS --> + + + + +<h4><a name="conditions" class=none>Conditions</a></h4> + +Here are two conditions which might be signaled if something bad +happens while reading from a chunked stream: + +<!-- Entry for INPUT-CHUNKING-BODY-CORRUPTED --> + +<p><br>[Condition type]<br><a class=none name='input-chunking-body-corrupted'><b>input-chunking-body-corrupted</b></a> +<blockquote><br> + +A condition of this type is signaled if an +unexpected character (octet) is read while reading from a +<a href="#stream">chunked stream</a> with input chunking enabled. This is a subtype of +<a +href="http://www.lispworks.com/documentation/HyperSpec/Body/e_stm_er.htm%22%3E<code>STREAM-ERROR</code></a>, +so <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/f_stm_er.htm%22%3E<code>STREAM-ERROR-STREAM</code></a> +can be used to access the offending stream. + +</blockquote> + +<!-- End of entry for INPUT-CHUNKING-BODY-CORRUPTED --> + + +<!-- Entry for INPUT-CHUNKING-UNEXPECTED-END-OF-FILE --> + +<p><br>[Condition type]<br><a class=none name='input-chunking-unexpected-end-of-file'><b>input-chunking-unexpected-end-of-file</b></a> +<blockquote><br> + +A condition of this type is signaled if we +reach an unexpected EOF on a <a href="#stream">chunked stream</a> with input chunking +enabled. This is a subtype of +<a +href="http://www.lispworks.com/documentation/HyperSpec/Body/e_stm_er.htm%22%3E<code>STREAM-ERROR</code></a>, +so <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/f_stm_er.htm%22%3E<code>STREAM-ERROR-STREAM</code></a> +can be used to access the offending stream. + +</blockquote> + +<!-- End of entry for INPUT-CHUNKING-UNEXPECTED-END-OF-FILE --> + + + + +<h4><a name="parse" class=none>RFC 2616 parsing</a></h4> + +Chunga needs to know a bit +about <a href="http://www.rfc.net/rfc2616.html">RFC 2616 syntax</a> in +order to cope +with <a href="#chunked-input-stream-extensions">extensions</a> +and <a href="#chunked-input-stream-trailers">trailers</a>. As these +functions are in there anyway, they're exported, so they can be used +by other code like for +example <a href="http://weitz.de/drakma/">Drakma</a>. + +<!-- Entry for READ-LINE* --> + +<p><br>[Function]<br><a class=none name='read-line*'><b>read-line*</b> <i>stream <tt>&optional</tt> log-stream</i> => <i>line</i></a> +<blockquote><br> + +Reads and assembles characters from <code><i>stream</i></code> until a <a href="http://en.wikipedia.org/wiki/Carriage_return">carriage +return</a> +is read. Makes sure that the following character is a <a href="http://en.wikipedia.org/wiki/Line_feed">linefeed</a>. If +<a href="#*accept-bogus-eols*"><code>*ACCEPT-BOGUS-EOLS*</code></a> is not <code>NIL</code>, then the function will also accept a +lone carriage return or linefeed as a line break. Returns +the string of characters read excluding the line break. Additionally +logs this string to <code><i>log-stream</i></code> if it is not <code>NIL</code>. + +</blockquote> + +<!-- End of entry for READ-LINE* --> + + +<!-- Entry for READ-HTTP-HEADERS --> + +<p><br>[Function]<br><a class=none name='read-http-headers'><b>read-http-headers</b> <i>stream <tt>&optional</tt> log-stream</i> => <i>headers</i></a> +<blockquote><br> + +Reads HTTP header lines from the stream <code><i>stream</i></code> +(except for the initial status line which is supposed to be read +already) and returns a +corresponding <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_a.htm#alist%22%...</a> +of names and values where the names are keywords and the values are +strings. Multiple lines with the same name are combined into one +value, the individual values separated by commas. Header lines which +are spread across multiple lines are recognized and treated correctly. (But see <a href="#*treat-semicolon-as-continuation*"><code>*TREAT-SEMICOLON-AS-CONTINUATION*</code></a>.) +Additonally logs the header lines to +<code><i>log-stream</i></code> if it is not <code>NIL</code>. + +</blockquote> + +<!-- End of entry for READ-HTTP-HEADERS --> + +<!-- Entry for READ-TOKEN --> + +<p><br>[Function]<br><a class=none name='read-token'><b>read-token</b> <i>stream</i> => <i>token</i></a> +<blockquote><br> + +Read characters from the stream <code><i>stream</i></code> while they +are <em>token</em> constituents (according +to <a href="http://www.rfc.net/rfc2616.html">RFC 2616</a>). It is +assumed that there's a token character at the current position. The +token read is returned as a string. Doesn't signal an error (but +simply stops reading) +if <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/e_end_of.htm%22%3E<code>END-OF-FILE</code></a> +is encountered after the first character. + +</blockquote> + +<!-- End of entry for READ-TOKEN --> + +<!-- Entry for READ-NAME-VALUE-PAIR --> + +<p><br>[Function]<br><a class=none name='read-name-value-pair'><b>read-name-value-pair</b> <i>stream <tt>&key</tt> value-required-p cookie-syntax</i> => <i>pair</i></a> +<blockquote><br> + +Reads a typical (in <a href="http://www.rfc.net/rfc2616.html">RFC +2616</a>) <a href="http://www.rfc.net/rfc2616.html#s3.6">name/value or +attribute/value combination</a> from the +stream <code><i>stream</i></code> - a <em>token</em> followed by +a <code>#=</code> character and another token or a <em>quoted +string</em>. Returns +a <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_c.htm#cons%22%3...</a> +of the name and the value, both as strings. +If <code><i>value-required-p</i></code> is <code>NIL</code> (the +default is <code>T</code>), the <code>#=</code> sign and the value +are optional. If <code><i>cookie-syntax</i></code> is true (the +default is <code>NIL</code>), the value is read like the value of +a <a href="http://weitz.de/drakma/#ccokies">cookie</a> header. + +</blockquote> + +<!-- End of entry for READ-NAME-VALUE-PAIR --> + + +<!-- Entry for READ-NAME-VALUE-PAIRS --> + +<p><br>[Function]<br><a class=none name='read-name-value-pairs'><b>read-name-value-pairs</b> <i>stream <tt>&key</tt> value-required-p cookie-syntax</i> => <i>pairs</i></a> +<blockquote><br> + +Uses <a href="#read-name-value-pair"><code>READ-NAME-VALUE-PAIR</code></a> to read and return an <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_a.htm#alist%22%...</a> of +name/value pairs from the stream <code><i>stream</i></code>. It is assumed that the pairs are +separated by semicolons and that the first char read (except for +whitespace) will be a semicolon. The parameters are used as in +<a href="#read-name-value-pair"><code>READ-NAME-VALUE-PAIR</code></a>. +Stops reading in case +of <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/e_end_of.htm%22%3E<code>END-OF-FILE</code></a> +(instead of signaling an error). + +</blockquote> + +<!-- End of entry for READ-NAME-VALUE-PAIRS --> + + + +<!-- Entry for ASSERT-CHAR --> + +<p><br>[Function]<br><a class=none name='assert-char'><b>assert-char</b> <i>stream expected-char</i> => <i>char</i></a> +<blockquote><br> + +Reads the next character from the stream <code><i>stream</i></code> and checks if it is the +character <code><i>expected-char</i></code>. Signals an error otherwise. + +</blockquote> + +<!-- End of entry for ASSERT-CHAR --> + + +<!-- Entry for SKIP-WHITESPACE --> + +<p><br>[Function]<br><a class=none name='skip-whitespace'><b>skip-whitespace</b> <i>stream</i> => <i>char-or-nil</i></a> +<blockquote><br> + +Consume characters from the stream <code><i>stream</i></code> until an <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/e_end_of.htm%22%3E<code>END-OF-FILE</code></a> is +encountered or a non-whitespace (according to <a href="http://www.rfc.net/rfc2616.html">RFC 2616</a>) +characters is seen. This character is returned (or <code>NIL</code> in case +of <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/e_end_of.htm%22%3E<code>END-OF-FILE</code></a>). + +</blockquote> + +<!-- End of entry for SKIP-WHITESPACE --> + + +<!-- Entry for TRIM-WHITESPACE --> + +<p><br>[Function]<br><a class=none name='trim-whitespace'><b>trim-whitespace</b> <i>string</i> => <i>string'</i></a> +<blockquote><br> + +Returns a version of the string <code><i>string</i></code> where spaces and tab +characters are trimmed from the start and the end. + +</blockquote> + +<!-- End of entry for TRIM-WHITESPACE --> + + +<!-- Entry for *CURRENT-ERROR-MESSAGE* --> + +<p><br>[Special variable]<br><a class=none name='*current-error-message*'><b>*current-error-message*</b></a> +<blockquote><br> + +Used by the parsing functions in <a href="#parse">this section</a> as +an introduction to a standardized error message. Must be a string if +one of these functions is called. + +</blockquote> + +<!-- End of entry for *CURRENT-ERROR-MESSAGE* --> + +<!-- Entry for *ACCEPT-BOGUS-EOLS* --> + +<p><br>[Special variable]<br><a class=none name='*accept-bogus-eols*'><b>*accept-bogus-eols*</b></a> +<blockquote><br> + +Some web servers do not respond with a correct CRLF line ending for +HTTP headers but with a lone linefeed or carriage return instead. If +this variable is bound to a true +value, <a href="#read-line*"><code>READ-LINE*</code></a> will treat a +lone LF or CR character as an acceptable end of line. The initial +value is <code>NIL</code>. + +</blockquote> +<!-- End of entry for *ACCEPT-BOGUS-EOLS* --> + +<!-- Entry for *TREAT-SEMICOLON-AS-CONTINUATION* --> + +<p><br>[Special variable]<br><a class=none name='*treat-semicolon-as-continuation*'><b>*treat-semicolon-as-continuation*</b></a> +<blockquote><br> + +According to John Foderaro, Netscape v3 web servers bogusly split +<code>Set-Cookie</code> headers over multiple lines which means that we'd have to +treat <code>Set-Cookie</code> headers ending with a semicolon as incomplete and +combine them with the next header. This will only be done if this +variable has a true value, though. Its default value is <code>NIL</code>. +</blockquote> + +<!-- End of entry for *TREAT-SEMICOLON-AS-CONTINUATION* --> + + + +<br> <br><h3><a class=none name="ack">Acknowledgements</a></h3> + +<p> +Thanks to Jochen Schmidt's chunking code in <a href="http://www.cliki.net/ACL-COMPAT">ACL-COMPAT</a> for inspiration. +This documentation was prepared with <a href="http://weitz.de/documentation-template/">DOCUMENTATION-TEMPLATE</a>. +</p> +<p> +$Header: /usr/local/cvsrep/chunga/doc/index.html,v 1.24 2007/10/11 06:56:04 edi Exp $ +<p><a href="http://weitz.de/index.html">BACK TO MY HOMEPAGE</a> + +</body> +</html>
Property changes on: branches/trunk-reorg/thirdparty/chunga-0.4.1/doc/index.html ___________________________________________________________________ Name: svn:executable + *
Added: branches/trunk-reorg/thirdparty/chunga-0.4.1/input.lisp =================================================================== --- branches/trunk-reorg/thirdparty/chunga-0.4.1/input.lisp 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/chunga-0.4.1/input.lisp 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,182 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CHUNGA; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/chunga/input.lisp,v 1.13 2007/09/06 23:01:27 edi Exp $ + +;;; Copyright (c) 2006-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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-package :chunga) + +(defmethod chunked-input-stream-extensions (object) + "The default method which always returns the empty list." + nil) + +(defmethod chunked-input-stream-trailers (object) + "The default method which always returns the empty list." + nil) + +(defmethod chunked-stream-input-chunking-p (object) + "The default method for all objects which are not of type +CHUNKED-INPUT-STREAM." + nil) + +(defmethod (setf chunked-stream-input-chunking-p) (new-value (stream chunked-input-stream)) + "Switches input chunking for STREAM on or off." + (unless (eq (not new-value) (not (chunked-stream-input-chunking-p stream))) + (with-slots (input-limit input-index expecting-crlf-p chunk-extensions chunk-trailers input-stream) + stream + (cond (new-value + (setq ;; wrap with flexi stream for header parsing + input-stream (make-flexi-stream input-stream :external-format +latin-1+) + expecting-crlf-p nil + input-limit 0 + input-index 0 + chunk-extensions nil + chunk-trailers nil)) + (t (when (< input-index input-limit) + (error "Not all chunks from ~S have been read completely." + stream)) + ;; switch back to original inner stream + (setq input-stream (flexi-stream-stream input-stream)))))) + (setf (slot-value stream 'input-chunking-p) new-value)) + +(defmethod stream-clear-input ((stream chunked-input-stream)) + "Implements CLEAR-INPUT by resetting the internal chunk buffer." + (when (chunked-stream-input-chunking-p stream) + (setf (chunked-stream-input-index stream) 0 + (chunked-stream-input-limit stream) 0)) + ;; clear input on inner stream + (clear-input (chunked-stream-input-stream stream)) + nil) + +(defmethod chunked-input-available-p ((stream chunked-input-stream)) + "Whether there's unread input waiting in the chunk buffer." + (< (chunked-stream-input-index stream) + (chunked-stream-input-limit stream))) + +(defmethod stream-listen ((stream chunked-input-stream)) + "We first check if input chunking is enabled and if there's +something in the buffer. Otherwise we poll the underlying stream." + (cond ((chunked-stream-input-chunking-p stream) + (or (chunked-input-available-p stream) + (fill-buffer stream))) + (t (listen (chunked-stream-input-stream stream))))) + +(defmethod fill-buffer ((stream chunked-input-stream)) + "Re-fills the chunk buffer. Returns NIL if chunking has ended." + (let ((inner-stream (chunked-stream-input-stream stream)) + ;; set up error function for the functions in `read.lisp' + (*current-error-function* + (lambda (last-char expected-chars) + "The function which is called when an unexpected +character is seen. Signals INPUT-CHUNKING-BODY-CORRUPTED." + (error 'input-chunking-body-corrupted + :stream stream + :last-char last-char + :expected-chars expected-chars)))) + (labels ((add-extensions () + "Reads chunk extensions (if there are any) and stores +them into the corresponding slot of the stream." + (when-let (extensions (read-name-value-pairs inner-stream)) + (warn "Adding uninterpreted extensions to stream ~S." stream) + (setf (slot-value stream 'chunk-extensions) + (append (chunked-input-stream-extensions stream) extensions))) + (assert-crlf inner-stream)) + (get-chunk-size () + "Reads chunk size header (including optional +extensions) and returns the size." + #+:clisp (setf (flexi-stream-element-type inner-stream) 'character) + (when (expecting-crlf-p stream) + (assert-crlf inner-stream)) + (setf (expecting-crlf-p stream) t) + ;; read hexadecimal number + (let (last-char) + (prog1 (loop for weight = (digit-char-p (setq last-char + (read-char inner-stream)) + 16) + for result = (if weight + (+ weight (* 16 (or result 0))) + (return result))) + ;; unread first octet which wasn't a digit + (unread-char last-char inner-stream) + (add-extensions) + #+:clisp (setf (flexi-stream-element-type inner-stream) 'octet))))) + (let ((chunk-size (get-chunk-size))) + (with-slots (input-buffer input-limit input-index) + stream + (setq input-index 0 + input-limit chunk-size) + (cond ((zerop chunk-size) + ;; turn chunking off + (setf (chunked-stream-input-chunking-p stream) nil + (slot-value stream 'chunk-trailers) (read-http-headers inner-stream) + input-limit 0) + ;; return NIL + (return-from fill-buffer)) + ((> chunk-size (length input-buffer)) + ;; replace buffer if it isn't big enough for the next chunk + (setq input-buffer (make-array chunk-size :element-type 'octet)))) + (unless (= (read-sequence input-buffer inner-stream + :start 0 :end chunk-size) + chunk-size) + (error 'input-chunking-unexpected-end-of-file + :stream stream)) + chunk-size))))) + +(defmethod stream-read-byte ((stream chunked-input-stream)) + "Reads one byte from STREAM. Checks the chunk buffer first, if +input chunking is enabled. Re-fills buffer is necessary." + (unless (chunked-stream-input-chunking-p stream) + (return-from stream-read-byte (read-byte (chunked-stream-input-stream stream) nil :eof))) + (unless (chunked-input-available-p stream) + (unless (fill-buffer stream) + (return-from stream-read-byte :eof))) + (with-slots (input-buffer input-index) + stream + (prog1 (aref input-buffer input-index) + (incf input-index)))) + +(defmethod stream-read-sequence ((stream chunked-input-stream) sequence start end &key) + "Fills SEQUENCE by adding data from the chunk buffer and re-filling +it until enough data was read. Works directly on the underlying +stream if input chunking is off." + (unless (chunked-stream-input-chunking-p stream) + (return-from stream-read-sequence + (read-sequence sequence (chunked-stream-input-stream stream) :start start :end end))) + (loop + (when (>= start end) + (return-from stream-read-sequence start)) + (unless (chunked-input-available-p stream) + (unless (fill-buffer stream) + (return-from stream-read-sequence start))) + (with-slots (input-buffer input-limit input-index) + stream + (replace sequence input-buffer + :start1 start :end1 end + :start2 input-index :end2 input-limit) + (let ((length (min (- input-limit input-index) + (- end start)))) + (incf start length) + (incf input-index length)))))
Property changes on: branches/trunk-reorg/thirdparty/chunga-0.4.1/input.lisp ___________________________________________________________________ Name: svn:executable + *
Added: branches/trunk-reorg/thirdparty/chunga-0.4.1/output.lisp =================================================================== --- branches/trunk-reorg/thirdparty/chunga-0.4.1/output.lisp 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/chunga-0.4.1/output.lisp 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,143 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CHUNGA; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/chunga/output.lisp,v 1.10 2007/01/01 23:39:36 edi Exp $ + +;;; Copyright (c) 2006-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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-package :chunga) + +(defmethod chunked-stream-output-chunking-p (object) + "The default method for all objects which are not of type +CHUNKED-OUTPUT-STREAM." + nil) + +(defmethod write-chunk ((stream chunked-output-stream) sequence + &key (start 0) + (end (length sequence))) + "Writes the contents of SEQUENCE from START to END to the +underlying stream of STREAM as one chunk." + (let ((output-stream (chunked-stream-output-stream stream))) + ;; chunk size + (format output-stream "~X" (- end start)) + ;; CRLF + (write-string #.(format nil "~C~C" #\Return #\Linefeed) output-stream) + ;; data + #+:clisp (setf (flexi-stream-element-type output-stream) 'octet) + (write-sequence sequence output-stream :start start :end end) + #+:clisp (setf (flexi-stream-element-type output-stream) 'character) + ;; CRLF + (write-string #.(format nil "~C~C" #\Return #\Linefeed) output-stream))) + +(defmethod flush-buffer ((stream chunked-output-stream)) + "Uses WRITE-CHUNK to empty the output buffer unless it is +already empty." + (with-slots (output-buffer output-index) + stream + (when (plusp output-index) + (write-chunk stream output-buffer :end output-index) + (setq output-index 0)))) + +(defmethod (setf chunked-stream-output-chunking-p) (new-value (stream chunked-output-stream)) + "Switches output chunking for STREAM on or off." + (unless (eq (not new-value) (not (chunked-stream-output-chunking-p stream))) + (with-slots (output-stream output-index) + stream + (cond (new-value + ;; get rid of "old" data + (force-output output-stream) + (setq ;; wrap with flexi stream for character output + output-stream (make-flexi-stream output-stream :external-format +latin-1+) + ;; initialize output buffer as being empty + output-index 0)) + (t (flush-buffer stream) + ;; last chunk to signal end of chunking + (write-string #.(format nil "0~C~C~C~C" + #\Return #\Linefeed #\Return #\Linefeed) + output-stream) + ;; switch back to original inner stream + (setq output-stream (flexi-stream-stream output-stream)))))) + (setf (slot-value stream 'output-chunking-p) new-value)) + +(defmethod stream-clear-output ((stream chunked-output-stream)) + "We clear output by resetting the output buffer and clearing +the underlying stream." + (when (chunked-stream-output-chunking-p stream) + (setf (slot-value stream 'output-index) 0)) + (clear-output (chunked-stream-output-stream stream))) + +(defmethod stream-finish-output ((stream chunked-output-stream)) + "Flush the output buffer if output chunking is on, then operate +on the underlying stream." + (when (chunked-stream-output-chunking-p stream) + (flush-buffer stream)) + (finish-output (chunked-stream-output-stream stream))) + +(defmethod stream-force-output ((stream chunked-output-stream)) + "Flush the output buffer if output chunking is on, then operate +on the underlying stream." + (when (chunked-stream-output-chunking-p stream) + (flush-buffer stream)) + (force-output (chunked-stream-output-stream stream))) + +(defmethod stream-write-byte ((stream chunked-output-stream) byte) + "Writes one byte by simply adding it to the end of the output +buffer (if output chunking is enabled). The buffer is flushed +if necessary." + (unless (chunked-stream-output-chunking-p stream) + (return-from stream-write-byte + (write-byte byte (chunked-stream-output-stream stream)))) + (with-slots (output-index output-buffer) + stream + (when (>= output-index +output-buffer-size+) + (flush-buffer stream)) + (setf (aref output-buffer output-index) byte) + (incf output-index) + byte)) + +(defmethod stream-write-sequence ((stream chunked-output-stream) sequence start end &key) + "Outputs SEQUENCE by appending it to the output buffer if it's +small enough. Large sequences are written directly using +WRITE-CHUNK." + (unless (chunked-stream-output-chunking-p stream) + (return-from stream-write-sequence + (write-sequence sequence (chunked-stream-output-stream stream) :start start :end end))) + (with-slots (output-buffer output-index) + stream + (let ((length (- end start))) + (cond ((<= length (- +output-buffer-size+ output-index)) + (replace output-buffer sequence :start1 output-index + :start2 start :end2 end) + (incf output-index length)) + (t (flush-buffer stream) + (write-chunk stream sequence :start start :end end))))) + sequence) + +(defmethod close ((stream chunked-output-stream) &key abort) + "When a stream is closed and ABORT isn't true we have to make +sure to send the last chunk." + (unless abort + (setf (chunked-stream-output-chunking-p stream) nil)) + (call-next-method))
Property changes on: branches/trunk-reorg/thirdparty/chunga-0.4.1/output.lisp ___________________________________________________________________ Name: svn:executable + *
Added: branches/trunk-reorg/thirdparty/chunga-0.4.1/packages.lisp =================================================================== --- branches/trunk-reorg/thirdparty/chunga-0.4.1/packages.lisp 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/chunga-0.4.1/packages.lisp 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,59 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-USER; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/chunga/packages.lisp,v 1.14 2007/09/18 07:00:39 edi Exp $ + +;;; Copyright (c) 2006-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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-package :cl-user) + +(defpackage :chunga + (:use :cl :trivial-gray-streams :flexi-streams) + #+:lispworks + (:import-from :lw :when-let) + (:export :*accept-bogus-eols* + :*current-error-message* + :*treat-semicolon-as-continuation* + :assert-char + :chunked-input-stream + :chunked-input-stream-extensions + :chunked-input-stream-trailers + :chunked-io-stream + :chunked-output-stream + :chunked-stream + :chunked-stream-input-chunking-p + :chunked-stream-output-chunking-p + :chunked-stream-stream + :input-chunking-body-corrupted + :input-chunking-unexpected-end-of-file + :make-chunked-stream + :read-http-headers + :read-line* + :read-name-value-pair + :read-name-value-pairs + :read-token + :skip-whitespace + :trim-whitespace)) +
Property changes on: branches/trunk-reorg/thirdparty/chunga-0.4.1/packages.lisp ___________________________________________________________________ Name: svn:executable + *
Added: branches/trunk-reorg/thirdparty/chunga-0.4.1/read.lisp =================================================================== --- branches/trunk-reorg/thirdparty/chunga-0.4.1/read.lisp 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/chunga-0.4.1/read.lisp 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,279 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CHUNGA; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/chunga/read.lisp,v 1.13 2007/10/11 06:56:02 edi Exp $ + +;;; Copyright (c) 2006-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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-package :chunga) + +(defmacro ignore-eof (&body body) + "This macro is similar to IGNORE-ERRORS but it only ignores +conditions of type END-OF-FILE." + `(handler-case + (progn ,@body) + (end-of-file () nil))) + +(defun signal-unexpected-chars (last-char expected-chars) + "Signals an error that LAST-CHAR was read although one of +EXPECTED-CHARS was expected. (Note that EXPECTED-CHARS, +despites its name, can also be a single character instead of a +list). Uses *CURRENT-ERROR-MESSAGE* if it's not NIL, or calls +*CURRENT-ERROR-FUNCTION* otherwise." + (cond (*current-error-message* + (error "~A~%Read character ~S, but expected ~:[a member of ~S~;~S~]." + *current-error-message* last-char (atom expected-chars) expected-chars)) + (t (funcall *current-error-function* last-char expected-chars)))) + +(defun charp (char) + "Returns true if the Lisp character CHAR is a CHAR according to RFC 2616." + (<= 0 (char-code char) 127)) + +(defun controlp (char) + "Returns true if the Lisp character CHAR is a CTL according to RFC 2616." + (or (<= 0 (char-code char) 31) + (= (char-code char) 127))) + +(defun separatorp (char) + "Returns true if the Lisp character CHAR is a separator +according to RFC 2616." + (find char #.(format nil " ()<>@,;:\"/[]?={}~C" #\Tab) + :test #'char=)) + +(defun whitespacep (char) + "Returns true if the Lisp character CHAR is whitespace +according to RFC 2616." + (member char '(#\Space #\Tab) :test #'char=)) + +(defun token-char-p (char) + "Returns true if the Lisp character CHAR is a token constituent +according to RFC 2616." + (and (charp char) + (not (or (controlp char) + (separatorp char))))) + +(defun assert-char (stream expected-char) + "Reads the next character from STREAM and checks if it is the +character EXPECTED-CHAR. Signals an error otherwise." + (let ((char (read-char stream))) + (unless (char= char expected-char) + (signal-unexpected-chars char expected-char)) + char)) + +(defun assert-crlf (stream) + "Reads the next two characters from STREAM and checks if these +are a carriage return and a linefeed. Signals an error +otherwise." + (assert-char stream #\Return) + (assert-char stream #\Linefeed)) + +(defun read-line* (stream &optional log-stream) + "Reads and assembles characters from STREAM until a carriage return +is read. Makes sure that the following character is a linefeed. If +*ACCEPT-BOGUS-EOLS* is not NIL, then the function will also accept a +lone carriage return or linefeed as an acceptable line break. Returns +the string of characters read excluding the line break. Additionally +logs this string to LOG-STREAM if it is not NIL." + (flet ((read-eol () + "Read a CRLF from STREAM. If *accept-bogus-eols* is non-nil +then accept a lone CR as a valid EOL." + (cond (*accept-bogus-eols* + (assert-char stream #\Return) + (when (eql (peek-char nil stream) #\Linefeed) + (assert-char stream #\Linefeed))))) + (t (assert-crlf stream))) + (let ((result + (with-output-to-string (line) + (loop for char = (read-char stream) + for is-cr-p = (char= char #\Return) + until (or is-cr-p + (and *accept-bogus-eols* + (char= char #\Linefeed))) + do (write-char char line) + finally (cond ((not *accept-bogus-eols*) + (assert-char stream #\Linefeed)) + (is-cr-p + (when (eql (peek-char nil stream) #\Linefeed) + (read-char stream)))))))) + (when log-stream + (write-line result log-stream) + (finish-output log-stream)) + result))) + +(defun trim-whitespace (string) + "Returns a version of the string STRING where spaces and tab +characters are trimmed from the start and the end." + (string-trim '(#\Space #\Tab) string)) + +(defun read-http-headers (stream &optional log-stream) + "Reads HTTP header lines from STREAM (except for the initial +status line which is supposed to be read already) and returns a +corresponding alist of names and values where the names are +keywords and the values are strings. Multiple lines with the +same name are combined into one value, the individual values +separated by commas. Header lines which are spread across +multiple lines are recognized and treated correctly. Additonally +logs the header lines to LOG-STREAM if it is not NIL." + (let (headers + (*current-error-message* "While reading HTTP headers:")) + (labels ((read-header-line () + "Reads one header line, considering continuations." + (with-output-to-string (header-line) + (loop + (let ((line (trim-whitespace (read-line* stream log-stream)))) + (when (zerop (length line)) + (return)) + (write-sequence (trim-whitespace line) header-line) + (let ((next (peek-char nil stream))) + (unless (whitespacep next) + (return))) + ;; we've seen whitespace starting a continutation, + ;; so we loop + (write-char #\Space header-line))))) + (split-header (line) + "Splits line at colon and converts it into a cons. +Returns NIL if LINE consists solely of whitespace." + (unless (zerop (length (trim-whitespace line))) + (let ((colon-pos (or (position #: line :test #'char=) + (error "Couldn't find colon in header line ~S." line)))) + (cons (as-keyword (subseq line 0 colon-pos)) + (trim-whitespace (subseq line (1+ colon-pos))))))) + (add-header (pair) + "Adds the name/value cons PAIR to HEADERS. Takes +care of multiple headers with the same name." + (let* ((name (car pair)) + (existing-header (assoc name headers :test #'eq)) + (existing-value (cdr existing-header))) + (cond (existing-header + (setf (cdr existing-header) + (format nil "~A~:[,~;~]~A" + existing-value + (and *treat-semicolon-as-continuation* + (eq name :set-cookie) + (ends-with-p (trim-whitespace existing-value) ";")) + (cdr pair)))) + (t (push pair headers)))))) + (loop for header-pair = (split-header (read-header-line)) + while header-pair + do (add-header header-pair))) + (nreverse headers))) + +(defun skip-whitespace (stream) + "Consume characters from STREAM until an END-OF-FILE is +encountered or a non-whitespace (according to RFC 2616) +characters is seen. This character is returned (or NIL in case +of END-OF-FILE)." + (loop for char = (ignore-eof (peek-char nil stream)) + while (and char (whitespacep char)) + do (read-char stream) + finally (return char))) + +(defun read-token (stream) + "Read characters from STREAM while they are token constituents +(according to RFC 2616). It is assumed that there's a token +character at the current position. The token read is returned as +a string. Doesn't signal an error (but simply stops reading) if +END-OF-FILE is encountered after the first character." + (with-output-to-string (out) + (loop for first = t then nil + for char = (if first + (peek-char nil stream) + (or (ignore-eof (peek-char nil stream)) (return))) + while (token-char-p char) + do (write-char (read-char stream) out)))) + +(defun read-quoted-string (stream) + "Reads a quoted string (according to RFC 2616). It is assumed +that the character at the current position is the opening quote +character. Returns the string read without quotes and escape +characters." + (read-char stream) + (with-output-to-string (out) + (loop for char = (read-char stream) + until (char= char #") + do (case char + (#\ (write-char (read-char stream) out)) + (#\Return (assert-char stream #\Linefeed) + (let ((char (read-char stream))) + (unless (whitespacep char) + (signal-unexpected-chars char '(#\Space #\Tab))))) + (otherwise (write-char char out)))))) + +(defun read-cookie-value (stream &key name separators) + "Reads a cookie parameter value from STREAM which is returned as a +string. Simply reads until a comma or a semicolon is seen (or an +element of SEPARATORS)." + (when (eql #, (ignore-eof (peek-char nil stream))) + (return-from read-cookie-value "")) + (trim-whitespace + (with-output-to-string (out) + ;; special case for the `Expires' parameter - maybe skip the first comma + (loop with separators% = (cond (separators) + ((equalp name "Expires") ";") + (t ",;")) + for char = (ignore-eof (peek-char nil stream)) + until (or (null char) (find char separators% :test #'char=)) + when (and (null separators) + (or (char= char #,) + (digit-char-p char))) + do (setq separators% '(#, #;)) + do (write-char (read-char stream) out))))) + +(defun read-name-value-pair (stream &key (value-required-p t) cookie-syntax) + "Reads a typical (in RFC 2616) name/value or attribute/value +combination from STREAM - a token followed by a #\= character and +another token or a quoted string. Returns a cons of name and value, +both as strings. If VALUE-REQUIRED-P is NIL, the #\= sign and the +value are optional. If COOKIE-SYNTAX is true, the uses +READ-COOKIE-VALUE internally." + (skip-whitespace stream) + (let ((name (if cookie-syntax + (read-cookie-value stream :separators "=,") + (read-token stream)))) + (skip-whitespace stream) + (cons name + (when (or value-required-p + (eql (ignore-eof (peek-char nil stream)) #=)) + (assert-char stream #=) + (skip-whitespace stream) + (cond (cookie-syntax (read-cookie-value stream :name name)) + ((char= (peek-char nil stream) #") (read-quoted-string stream)) + (t (read-token stream))))))) + +(defun read-name-value-pairs (stream &key (value-required-p t) cookie-syntax) + "Uses READ-NAME-VALUE-PAIR to read and return an alist of +name/value pairs from STREAM. It is assumed that the pairs are +separated by semicolons and that the first char read (except for +whitespace) will be a semicolon. The parameters are used as in +READ-NAME-VALUE-PAIR. Stops reading in case of END-OF-FILE +(instead of signaling an error)." + (loop for char = (skip-whitespace stream) + while (and char (char= char #;)) + do (read-char stream) + ;; guard against a stray semicolon at the end + when (skip-whitespace stream) + collect (read-name-value-pair stream + :value-required-p value-required-p + :cookie-syntax cookie-syntax)))
Property changes on: branches/trunk-reorg/thirdparty/chunga-0.4.1/read.lisp ___________________________________________________________________ Name: svn:executable + *
Added: branches/trunk-reorg/thirdparty/chunga-0.4.1/specials.lisp =================================================================== --- branches/trunk-reorg/thirdparty/chunga-0.4.1/specials.lisp 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/chunga-0.4.1/specials.lisp 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,87 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CHUNGA; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/chunga/specials.lisp,v 1.9 2007/09/18 07:00:39 edi Exp $ + +;;; Copyright (c) 2006-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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-package :chunga) + +(defmacro define-constant (name value &optional doc) + "A version of DEFCONSTANT for, cough, /strict/ CL implementations." + ;; See http://www.sbcl.org/manual/Defining-Constants.html + `(defconstant ,name (if (boundp ',name) (symbol-value ',name) ,value) + ,@(when doc (list doc)))) + +(defconstant +output-buffer-size+ 8192 + "Size of the initial output buffer for chunked output.") + +(define-constant +latin-1+ (make-external-format :iso-8859-1 :eol-style :lf) + "Default external format used when reading headers.") + +(defvar *current-error-message* nil + "Used by the parsing functions in `read.lisp' as an +introduction to a standardized error message about unexpected +characters unless it is NIL.") + +(defvar *current-error-function* nil + "Used by the functions in `read.lisp' as a function to signal +errors about unexpected characters when *CURRENT-ERROR-MESSAGE* +is NIL.") + +(defvar *accept-bogus-eols* nil + "Some web servers do not respond with a correct CRLF line ending for +HTTP headers but with a lone linefeed or carriage return instead. If +this variable is bound to a true value, READ-LINE* will treat a lone +LF or CR character as an acceptable end of line. The initial value is +NIL.") + +(defvar *treat-semicolon-as-continuation* nil + "According to John Foderaro, Netscape v3 web servers bogusly split +Set-Cookie headers over multiple lines which means that we'd have to +treat Set-Cookie headers ending with a semicolon as incomplete and +combine them with the next header. This will only be done if this +variable has a true value, though.") + +(pushnew :chunga *features*) + +;; stuff for Nikodemus Siivola's HYPERDOC +;; see http://common-lisp.net/project/hyperdoc/ +;; and http://www.cliki.net/hyperdoc +;; also used by LW-ADD-ONS + +(defvar *hyperdoc-base-uri* "http://weitz.de/chunga/") + +(let ((exported-symbols-alist + (loop for symbol being the external-symbols of :chunga + collect (cons symbol + (concatenate 'string + "#" + (string-downcase symbol)))))) + (defun hyperdoc-lookup (symbol type) + (declare (ignore type)) + (cdr (assoc symbol + exported-symbols-alist + :test #'eq))))
Property changes on: branches/trunk-reorg/thirdparty/chunga-0.4.1/specials.lisp ___________________________________________________________________ Name: svn:executable + *
Added: branches/trunk-reorg/thirdparty/chunga-0.4.1/streams.lisp =================================================================== --- branches/trunk-reorg/thirdparty/chunga-0.4.1/streams.lisp 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/chunga-0.4.1/streams.lisp 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,173 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CHUNGA; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/chunga/streams.lisp,v 1.7 2007/01/01 23:39:36 edi Exp $ + +;;; Copyright (c) 2006-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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-package :chunga) + +(defclass chunked-stream (trivial-gray-stream-mixin) + ((real-stream :initarg :real-stream + :reader chunked-stream-stream + :documentation "The actual stream that's used for +input and/or output.")) + (:documentation "Every chunked stream returned by +MAKE-CHUNKED-STREAM is of this type which is a subtype of +STREAM.")) + +(defclass chunked-input-stream (chunked-stream fundamental-binary-input-stream) + ((input-stream :accessor chunked-stream-input-stream + :documentation "The underlying stream (see +REAL-STREAM) used for input, maybe wrapped with a flexi stream.") + (input-chunking-p :initform nil + :reader chunked-stream-input-chunking-p + :documentation "Whether input chunking is currently enabled.") + (input-buffer :initform nil + :documentation "A vector containing the binary +data from the most recent chunk that was read.") + (input-index :initform 0 + :accessor chunked-stream-input-index + :documentation "The current position within INPUT-BUFFER.") + (input-limit :initform 0 + :accessor chunked-stream-input-limit + :documentation "Only the content in INPUT-BUFFER +up to INPUT-LIMIT belongs to the current chunk.") + (chunk-extensions :initform nil + :reader chunked-input-stream-extensions + :documentation "An alist of attribute/value +pairs corresponding to the optional `chunk extensions' which +might be encountered when reading from a chunked stream.") + (chunk-trailers :initform nil + :reader chunked-input-stream-trailers + :documentation "An alist of attribute/value +pairs corresponding to the optional `trailer' HTTP headers which +might be encountered at the end of a chunked stream.") + (expecting-crlf-p :initform nil + :accessor expecting-crlf-p + :documentation "Whether we expect to see +CRLF before we can read the next chunk-size header part from the +stream. (This will actually be the CRLF from the end of the +last chunk-data part.)")) + (:documentation "A chunked stream is of this type if its +underlying stream is an input stream. This is a subtype of +CHUNKED-STREAM.")) + +(defclass chunked-output-stream (chunked-stream fundamental-binary-output-stream) + ((output-stream :accessor chunked-stream-output-stream + :documentation "The underlying stream (see +REAL-STREAM) used for output, maybe wrapped with a flexi stream.") + (output-chunking-p :initform nil + :reader chunked-stream-output-chunking-p + :documentation "Whether output chunking is +currently enabled.") + (output-buffer :initform (make-array +output-buffer-size+ :element-type 'octet) + :accessor output-buffer + :documentation "A vector used to temporary +store data which will output in one chunk.") + (output-index :initform 0 + :accessor output-index + :documentation "The current end of OUTPUT-BUFFER.")) + (:documentation "A chunked stream is of this type if its +underlying stream is an output stream. This is a subtype of +CHUNKED-STREAM.")) + +(defclass chunked-io-stream (chunked-input-stream chunked-output-stream) + () + (:documentation "A chunked stream is of this type if it is both +a CHUNKED-INPUT-STREAM as well as a CHUNKED-OUTPUT-STREAM.")) + +(defmethod stream-element-type ((stream chunked-stream)) + "Chunked streams are always binary streams. Wrap them with +flexi streams if you need a character stream." + 'octet) + +(defmethod open-stream-p ((stream chunked-stream)) + "A chunked stream is open if its underlying stream is open." + (open-stream-p (chunked-stream-stream stream))) + +(defmethod close ((stream chunked-stream) &key abort) + "If a chunked stream is closed, we close the underlying stream as well." + (with-slots (real-stream) + stream + (cond ((open-stream-p real-stream) + (close real-stream :abort abort)) + (t nil)))) + +(define-condition input-chunking-unexpected-end-of-file (stream-error) + () + (:documentation "A condition of this type is signaled if we +reach an unexpected EOF on a chunked stream with input chunking +enabled. This is a subtype of STREAM-ERROR, so +STREAM-ERROR-STREAM can be used to access the offending +stream.")) + +(define-condition input-chunking-body-corrupted (stream-error) + ((last-char :initarg :last-char + :documentation "The (unexpected) character which was read.") + (expected-chars :initarg :expected-chars + :documentation "The characters which were +expected. A list of characters or one single character.")) + (:report (lambda (condition stream) + (with-slots (last-char expected-chars) + condition + (format stream "Chunked stream ~S seems to be corrupted. +Read character ~S, but expected ~:[a member of ~S~;~S~]." + (stream-error-stream condition) + last-char (atom expected-chars) expected-chars)))) + (:documentation "A condition of this type is signaled if an +unexpected character (octet) is read while reading from a +chunked stream with input chunking enabled. This is a subtype of +STREAM-ERROR, so STREAM-ERROR-STREAM can be used to access the +offending stream.")) + +(defmethod initialize-instance :after ((stream chunked-input-stream) &rest initargs) + "Initializes the INPUT-STREAM slot." + (declare (ignore initargs)) + (setf (chunked-stream-input-stream stream) + (chunked-stream-stream stream))) + +(defmethod initialize-instance :after ((stream chunked-output-stream) &rest initargs) + "Initializes the INPUT-STREAM slot." + (declare (ignore initargs)) + (setf (chunked-stream-output-stream stream) + (chunked-stream-stream stream))) + +(defun make-chunked-stream (stream) + "Creates and returns a chunked stream (a stream of type +CHUNKED-STREAM) which wraps STREAM. STREAM must be an open +binary stream." + (unless (and (streamp stream) + (open-stream-p stream)) + (error "~S should have been an open stream." stream)) + (make-instance ;; actual type depends on STREAM + (cond ((and (input-stream-p stream) + (output-stream-p stream)) + 'chunked-io-stream) + ((input-stream-p stream) + 'chunked-input-stream) + ((output-stream-p stream) + 'chunked-output-stream)) + :real-stream stream)) \ No newline at end of file
Property changes on: branches/trunk-reorg/thirdparty/chunga-0.4.1/streams.lisp ___________________________________________________________________ Name: svn:executable + *
Added: branches/trunk-reorg/thirdparty/chunga-0.4.1/util.lisp =================================================================== --- branches/trunk-reorg/thirdparty/chunga-0.4.1/util.lisp 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/chunga-0.4.1/util.lisp 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,55 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CHUNGA; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/chunga/util.lisp,v 1.5 2007/10/11 06:56:02 edi Exp $ + +;;; Copyright (c) 2006-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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-package :chunga) + +#-:lispworks +(defmacro when-let ((var expr) &body body) + "Evaluates EXPR, binds it to VAR, and executes BODY if VAR has +a true value." + `(let ((,var ,expr)) + (when ,var ,@body))) + +(defun ends-with-p (seq suffix &key (test #'char-equal)) + "Returns true if the sequence SEQ ends with the sequence +SUFFIX. Individual elements are compared with TEST." + (let ((mismatch (mismatch seq suffix :from-end t :test test))) + (or (null mismatch) + (= mismatch (- (length seq) (length suffix)))))) + +(defun as-keyword (string) + "Converts the string STRING to a keyword where all characters are +uppercase or lowercase, taking into account the current readtable +case." + (intern (funcall + (if (eq (readtable-case *readtable*) :upcase) + #'string-upcase + #'string-downcase) + string) + :keyword))
Property changes on: branches/trunk-reorg/thirdparty/chunga-0.4.1/util.lisp ___________________________________________________________________ Name: svn:executable + *
Added: branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/CHANGELOG =================================================================== --- branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/CHANGELOG 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/CHANGELOG 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,320 @@ +Version 1.3.2 +2007-09-13 +Updated docs and ChangeLog to be really in sync with 1.3.1 changes (thanks to S�bastien Saint-Sevin) + +Version 1.3.1 +2007-08-24 +Second return value for REGEX-REPLACE and REGEX-REPLACE-ALL (patch by Matthew Sachs) + +Version 1.3.0 +2007-03-24 +Optional support for named registers (patch by Ondrej Svitek) + +Version 1.2.19 +2007-01-16 +Fixed behaviour of look-behind in repeated scans (caught by RegexCoach user Hans Jud) + +Version 1.2.18 +2006-10-12 +Changed default element type for LispWorks +Fixed documentation for REGEX-REPLACE-ALL + +Version 1.2.17 +2006-10-11 +Fixed bug in DO-SCANS which affected anchors (caught by RegexCoach user Laurent Taupiac) +Update link for 'man perlre' (thanks to Ricardo Boccato Alves) + +Version 1.2.16 +2006-07-16 +Added :ELEMENT-TYPE to REGEX-REPLACE(-ALL) + +Version 1.2.15 +2006-07-03 +Added :REGEX tag to parse tree syntax (thanks to Fr�d�ric Jolliton) + +Version 1.2.14 +2006-05-24 +Added missing </code> tag in docs (thanks to Wojciech Kaczmarek) +Fixed IMPORT statement for LW + +Version 1.2.13 +2005-12-06 +Fixed bug involving *REAL-START-POS* (caught by "tichy") + +Version 1.2.12 +2005-11-01 +REGEX-APROPOS-AUX now also uses :INHERITED +Fixed typo in parser.lisp (thanks to Derek Peschel) +Fixed value of *REGEX-CHAR-CODE-LIMIT* in docs and test (thanks to Christophe Rhodes) + +Version 1.2.11 +2005-08-01 +Added external format for SBCL in ppcre-tests.lisp (thanks to Christophe Rhodes) + +Version 1.2.10 +2005-07-20 +Fixed bug in CHAR-SEARCHER-AUX (caught by Peter Schuller) +Don't redefine what's already there (for LispWorks) + +Version 1.2.9 +2005-06-27 +Hide compiler macros from CCL (thanks to Karsten Poeck) + +Version 1.2.8 +2005-06-10 +Change EQ to EQL in REGEX-LENGTH for ANSI conformance and ABCL compatibility (thanks to Peter Graves) + +Version 1.2.7 +2005-05-16 +Added lispworks-defsystem.lisp (thanks to Wade Humeniuk) +Fixed bug in WORD-BOUNDARY-P + +Version 1.2.6 +2005-04-13 +Added some DEFGENERICs to appease SBCL (thanks to Alan Shields) +Removed wrong FTYPE declaration for STR (thanks to Alan Shields) + +Version 1.2.5 +2005-03-09 +Customizable optimize qualities (thanks to Damien Kick) + +Version 1.2.4 +2005-03-07 +Changed DEBUG optimize quality from 0 to 1 + +Version 1.2.3 +2005-02-02 +Wrapped WITH-COMPILATION-UNIT around loop in load.lisp + +Version 1.2.2 +2005-02-02 +Fixed bug in hash table optimization (introduced in 1.1.0) + +Version 1.2.1 +2005-01-25 +There was a wrong read-time conditional in api.lisp, sorry + +Version 1.2.0 +2005-01-24 +AllegroCL compatibility mode +Fixed broken load.lisp file (caught by Jim Prewett and Zach Beane) + +Version 1.1.0 +2005-01-23 +Cleaned up load.lisp and cl-ppcre.asd +Make large hash tables smaller, if possible +Correct treatment of constant regular expressions in DO-SCANS + +Version 1.0.0 +2004-12-22 +Special anniversary release... :) + +Version 0.9.4 +2004-12-18 +Fixed bug in NORMALIZE-VAR-LIST (caught by Dave Roberts) + +Version 0.9.3 +2004-12-09 +Fixed bug in CREATE-SCANNER-AUX (caught by Allan Ruttenberg and Gary Byers) + +Version 0.9.2 +2004-12-06 +More compiler macros (thanks to Allan Ruttenberg) + +Version 0.9.1 +2004-11-29 +Shortcuts for REGISTER-GROUPS-BIND and DO-REGISTER-GROUPS (suggested by Alexander Kjeldaas) + +Version 0.9.0 +2004-10-14 +Experimental support for "filters" +Bugfix for standalone regular expressions (ACCUMULATE-START-P wasn't set to NIL) + +Version 0.8.1 +2004-09-30 +Patches for Genera 8.5 (thanks to Patrick O'Donnell) + +Version 0.8.0 +2004-09-16 +Added parse tree synonyms (thanks to Patrick O'Donnell) + +Version 0.7.9 +2004-07-13 +Fixed bug in DO-SCANS (caught by Jan Rychter) + +Version 0.7.8 +2004-07-13 +New SIMPLE-CALLS keyword argument for REGEX-REPLACE(-ALL) +Added environment parameter to compiler macros (thanks to c.l.l article aczhx5hj.fsf@ccs.neu.edu by Joe Marshall) +Added compiler macros for SCAN-TO-STRINGS and REGEX-REPLACE(-ALL) (they somehow got lost) + +Version 0.7.7 +2004-05-19 +Fixed bug in NEWLINE-SKIPPER (caught by RegexCoach user Thomas-Paz Hartman) +Added doc strings for PPCRE-SYNTAX-ERROR and friends (after playing with slime-apropos-package) +Added hyperdoc support + +Version 0.7.6 +2004-04-20 +The closures created by CREATE-BMH-MATCHER now cleanly cope with negative arguments (bug caught by Damien Kick) + +Version 0.7.5 +2004-04-19 +Fixed a bug with constant-length repetitions of . (dot) in single-line mode (caught by RegexCoach user Lee Gold) + +Version 0.7.4 +2004-02-16 +Fixed wrong call to SIGNAL-PPCRE-SIGNAL-ERROR in lexer.lisp (caught by Peter Graves) +Added :CL-PPCRE to *FEATURES* (for CL-INTERPOL) +Compiler macro for SPLIT + +Version 0.7.3 +2004-01-28 +Fixed bug in CURRENT-MIN-REST for lookaheads (reported by RegexCoach user Thomas-Paz Hartman) +Added tests for this bug + +Version 0.7.2 +2004-01-27 +Fixed typo (SUBSEQ/NSUBSEQ) in SPLIT (thanks to Alan Ruttenberg) +Updated docs with respect to ECL (thanks to Alex Mizrahi) +Mention FreeBSD port in docs + +Version 0.7.1 +2003-10-24 +Fixed version numbers in docs (thanks to S�bastien Saint-Sevin) + +Version 0.7.0 +2003-10-23 +New macros REGISTER-GROUPS-BIND and DO-REGISTER-GROUPS +Added SHAREP keyword argument to most API functions and macros +Mention CL-INTERPOL in docs +Partial code cleanup (using WITH-UNIQUE-NAMES and REBINDING) + +Version 0.6.1 +2003-10-11 +Added EXTERNAL-FORMAT keyword args to CL-PPCRE-TEST:TEST for some CLs (thanks to JP Massar and Scott D. Kalter) +Fixed bug with REGEX-REPLACE and REGEX-REPLACE-ALL when (= START END) was true +Added doc sections for quoting problems and backslash confusions (thanks to conversations with Peter Seibel) +Disable quoting in definition of QUOTE-SECTIONS so you can always safely rebuild CL-PPCRE + +Version 0.6.0 +2003-10-07 +CL-PPCRE now has its own condition types +Added support for Perl's \Q and \E (Peter Seibel convinced me to do it) - see QUOTE-META-CHARS and *ALLOW-QUOTING* +Added tests for this new feature +Threaded tests are more verbose now and use only keyword args + +Version 0.5.9 +2003-10-03 +Changed "^" optimizations with respect to constant end strings with offsets (bug caught by Yexuan Gui) +Added tests for this bug +Removed *.dos files from CL-PPCRE-TEST tests (thanks to JP Massar) +Added threaded tests for SBCL (thanks to Christophe Rhodes) + +Version 0.5.8 +2003-09-17 +Optimizations for ".*" were too optimistic when look-behinds were involved +Added tests for this bug +Removed *.dos files + +Version 0.5.7 +2003-08-20 +Fixed (CL-PPCRE:SCAN "(.)X$" "ABCX" :START 4) bug (spotted by Tibor Simko) +Forgot to export *REGEX-CHAR-CODE-LIMIT* in Corman version of DEFPACKAGE +Removed Emacs local variables from source code (finally...) +Mention Gentoo in docs + +Version 0.5.6 +2003-06-30 +Replaced wrong COPY-REGEX code for WORD-BOUNDARY objects (detected by Max Goldberg) +Added info about possible TRUENAME problems with ACL in README (thanks to Kevin Layer for providing a patch for this) + +Version 0.5.5 +2003-06-09 +Patch for SBCL/Debian compatibility by Kevin Rosenberg +Simpler version of compiler macro +Availability through asdf-install + +Version 0.5.4 +2003-04-09 +Added DESTRUCTIVE keyword to CREATE-SCANNER + +Version 0.5.3 +2003-03-31 +Fixed bug in REGEX-REPLACE (replacement string couldn't contain literal backslash) +Fixed bug in definition of CHAR-CLASS (since 0.5.0 the hash slot may be NIL - CMUCL's new PCL detects this) +Micro-optimization in INSERT-CHAR-CLASS-TESTER: CHAR-NOT-GREATERP instead of CHAR-DOWNCASE + +Version 0.5.2 +2003-03-28 +Better compiler macro (thanks to Kent M. Pitman) + +Version 0.5.1 +2003-03-27 +Removed compiler macro + +Version 0.5.0 +2003-03-27 +Lexer, parser, and converter mostly re-written to reduce consing and increase speed +Get rid of FIX-POS in lexer and parser, "ism" flags are handled after parsing now +Smaller test suite (again) due to literal embedding of line breaks +Seperate test files for DOS line endings +Replaced constant +REGEX-CHAR-CODE-LIMIT+ with special variable *REGEX-CHAR-CODE-LIMIT* + +Version 0.4.1 +2003-03-19 +Added compiler macro for SCAN +Changed test suite to be nicer to Corman Lisp and ECL (see docs for new syntax) +Incorporated visual feedback (dots) in test suite (thanks to JP Massar) +Added README file +Replaced STRING-LIST-TO-SIMPLE-STRING with a much improved version by JP Massar + +Version 0.4.0 +2003-02-27 +Added *USE-BMH-MATCHER* + +Version 0.3.2 +2003-02-21 +Added load.lisp +Various minor changes for Corman Lisp compatibility (thanks to Karsten Poeck and JP Massar) + +Version 0.3.1 +2003-01-18 +Bugfix in CREATE-SCANNER (didn't work if flags were given and arg was a parse-tree) + +Version 0.3.0 +2003-01-12 +Added new features to REGEX-REPLACE and REGEX-REPLACE-ALL + +Version 0.2.0 +2003-01-11 +Make SPLIT more Perl-compatible, including new keyword parameters + +Version 0.1.4 +2003-01-10 +Don't move "^" and "\A" while iterating with DO-SCANS +Added link to Debian package + +Version 0.1.3 +2002-12-25 +More usable MK:DEFSYSTEM files (courtesy of Hannu Koivisto) +Fixed typo in documentation + +Version 0.1.2 +2002-12-22 +Added version numbers for Debian packaging +Be friendly to case-sensitive ACL images (courtesy of Kevin Rosenberg and Douglas Crosher) +"Fixed" two cases where declarations came after docstrings (because of bugs in Corman Lisp and older CMUCL versions) +Added #-cormanlisp to hide (INCF (THE FIXNUM POS)) from Corman Lisp +Added file doc/benchmarks.2002-12-22.txt + +Version 0.1.1 +2002-12-21 +Added asdf system definitions by Marco Baringer +Small additions to documentation +Correct (Emacs) local variables list in closures.lisp and api.lisp +Added this CHANGELOG + +Version 0.1.0 +2002-12-20 +Initial release
Added: branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/README =================================================================== --- branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/README 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/README 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,62 @@ +Complete documentation for CL-PPCRE can be found in the 'doc' +directory. + +CL-PPCRE also supports Nikodemus Siivola's HYPERDOC, see +http://common-lisp.net/project/hyperdoc/ and +http://www.cliki.net/hyperdoc. + +1. Installation + +1.1. Probably the easiest way is + + (load "/path/to/cl-ppcre/load.lisp") + + This should compile and load CL-PPCRE on most Common Lisp + implementations. + +1.2. With MK:DEFSYSTEM you can make a symbolic link from + 'cl-ppcre.system' and 'cl-ppcre-test.system' to your central registry + (which by default is in '/usr/local/lisp/Registry/') and then issue + the command + + (mk:compile-system "cl-ppcre") + + Note that this relies on TRUENAME returning the original file a + symbolic link is pointing to. This will only work with AllegroCL + 6.2 if you've applied all patches with (SYS:UPDATE-ALLEGRO). + +1.3. You can also use ASDF instead of MK:DEFSYSTEM in a similar way + (use the .asd files instead of the .system files). + +1.4. For LispWorks there's a file 'lispworks-defsystem.lisp' which includes + a system definition for LispWork's Common Defsystem. + +2. Test + +CL-PPCRE comes with a test suite that can be used to check its +compatibility with Perl's regex syntax. See the documentation on how +to use this test suite for benchmarks and on how to write your own +tests. + +2.1. If you've used 'load.lisp' to load CL-PPCRE you already have the + test suite loaded and can start the default tests with + + (cl-ppcre-test:test) + +2.2. With MK:DEFSYSTEM you need to compile the 'cl-ppcre-test' system + as well before you can proceed as in 2.1. + +2.3. Same for ASDF. + +Depending on your machine and your CL implementation the default test +will take between a few seconds and a couple of minutes. (It will +print a dot for every tenth test case while it proceeds to give some +visual feedback.) It should exactly report three 'errors' (662, 790, +and 1439) which are explained in the documentation. + +MCL might report an error for the ninth test case which is also +explained in the docs. + +Genera notes (thanks to Patrick O'Donnell): Some more tests will fail +because characters like #\Return, #\Linefeed, or #\Tab have encodings +which differ from Perl's (and thus CL-PPCRE's) expectations.
Added: branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/api.lisp =================================================================== --- branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/api.lisp 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/api.lisp 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,1264 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-PPCRE; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/cl-ppcre/api.lisp,v 1.75 2007/09/13 07:52:13 edi Exp $ + +;;; The external API for creating and using scanners. + +;;; Copyright (c) 2002-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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-package #:cl-ppcre) + +(defgeneric create-scanner (regex &key case-insensitive-mode + multi-line-mode + single-line-mode + extended-mode + destructive) + (:documentation "Accepts a regular expression - either as a +parse-tree or as a string - and returns a scan closure which will scan +strings for this regular expression and a list mapping registers to +their names (NIL stands for unnamed ones). The "mode" keyboard +arguments are equivalent to the imsx modifiers in Perl. If DESTRUCTIVE +is not NIL the function is allowed to destructively modify its first +argument (but only if it's a parse tree).")) + +#-:use-acl-regexp2-engine +(defmethod create-scanner ((regex-string string) &key case-insensitive-mode + multi-line-mode + single-line-mode + extended-mode + destructive) + (declare #.*standard-optimize-settings*) + (declare (ignore destructive)) + ;; parse the string into a parse-tree and then call CREATE-SCANNER + ;; again + (let* ((*extended-mode-p* extended-mode) + (quoted-regex-string (if *allow-quoting* + (quote-sections (clean-comments regex-string extended-mode)) + regex-string)) + (*syntax-error-string* (copy-seq quoted-regex-string))) + ;; wrap the result with :GROUP to avoid infinite loops for + ;; constant strings + (create-scanner (cons :group (list (parse-string quoted-regex-string))) + :case-insensitive-mode case-insensitive-mode + :multi-line-mode multi-line-mode + :single-line-mode single-line-mode + :destructive t))) + +#-:use-acl-regexp2-engine +(defmethod create-scanner ((scanner function) &key case-insensitive-mode + multi-line-mode + single-line-mode + extended-mode + destructive) + (declare #.*standard-optimize-settings*) + (declare (ignore destructive)) + (when (or case-insensitive-mode multi-line-mode single-line-mode extended-mode) + (signal-ppcre-invocation-error + "You can't use the keyword arguments to modify an existing scanner.")) + scanner) + +#-:use-acl-regexp2-engine +(defmethod create-scanner ((parse-tree t) &key case-insensitive-mode + multi-line-mode + single-line-mode + extended-mode + destructive) + (declare #.*standard-optimize-settings*) + (when extended-mode + (signal-ppcre-invocation-error + "Extended mode doesn't make sense in parse trees.")) + ;; convert parse-tree into internal representation REGEX and at the + ;; same time compute the number of registers and the constant string + ;; (or anchor) the regex starts with (if any) + (unless destructive + (setq parse-tree (copy-tree parse-tree))) + (let (flags) + (if single-line-mode + (push :single-line-mode-p flags)) + (if multi-line-mode + (push :multi-line-mode-p flags)) + (if case-insensitive-mode + (push :case-insensitive-p flags)) + (when flags + (setq parse-tree (list :group (cons :flags flags) parse-tree)))) + (let ((*syntax-error-string* nil)) + (multiple-value-bind (regex reg-num starts-with reg-names) + (convert parse-tree) + ;; simplify REGEX by flattening nested SEQ and ALTERNATION + ;; constructs and gathering STR objects + (let ((regex (gather-strings (flatten regex)))) + ;; set the MIN-REST slots of the REPETITION objects + (compute-min-rest regex 0) + ;; set the OFFSET slots of the STR objects + (compute-offsets regex 0) + (let* (end-string-offset + end-anchored-p + ;; compute the constant string the regex ends with (if + ;; any) and at the same time set the special variables + ;; END-STRING-OFFSET and END-ANCHORED-P + (end-string (end-string regex)) + ;; if we found a non-zero-length end-string we create an + ;; efficient search function for it + (end-string-test (and end-string + (plusp (len end-string)) + (if (= 1 (len end-string)) + (create-char-searcher + (schar (str end-string) 0) + (case-insensitive-p end-string)) + (create-bmh-matcher + (str end-string) + (case-insensitive-p end-string))))) + ;; initialize the counters for CREATE-MATCHER-AUX + (*rep-num* 0) + (*zero-length-num* 0) + ;; create the actual matcher function (which does all the + ;; work of matching the regular expression) corresponding + ;; to REGEX and at the same time set the special + ;; variables *REP-NUM* and *ZERO-LENGTH-NUM* + (match-fn (create-matcher-aux regex #'identity)) + ;; if the regex starts with a string we create an + ;; efficient search function for it + (start-string-test (and (typep starts-with 'str) + (plusp (len starts-with)) + (if (= 1 (len starts-with)) + (create-char-searcher + (schar (str starts-with) 0) + (case-insensitive-p starts-with)) + (create-bmh-matcher + (str starts-with) + (case-insensitive-p starts-with)))))) + (declare (special end-string-offset end-anchored-p end-string)) + ;; now create the scanner and return it + (values (create-scanner-aux match-fn + (regex-min-length regex) + (or (start-anchored-p regex) + ;; a dot in single-line-mode also + ;; implicitly anchors the regex at + ;; the start, i.e. if we can't match + ;; from the first position we won't + ;; match at all + (and (typep starts-with 'everything) + (single-line-p starts-with))) + starts-with + start-string-test + ;; only mark regex as end-anchored if we + ;; found a non-zero-length string before + ;; the anchor + (and end-string-test end-anchored-p) + end-string-test + (if end-string-test + (len end-string) + nil) + end-string-offset + *rep-num* + *zero-length-num* + reg-num) + reg-names)))))) + +#+:use-acl-regexp2-engine +(declaim (inline create-scanner)) + +#+:use-acl-regexp2-engine +(defmethod create-scanner ((scanner regexp::regular-expression) &key case-insensitive-mode + multi-line-mode + single-line-mode + extended-mode + destructive) + (declare #.*standard-optimize-settings*) + (declare (ignore destructive)) + (when (or case-insensitive-mode multi-line-mode single-line-mode extended-mode) + (signal-ppcre-invocation-error + "You can't use the keyword arguments to modify an existing scanner.")) + scanner) + +#+:use-acl-regexp2-engine +(defmethod create-scanner ((parse-tree t) &key case-insensitive-mode + multi-line-mode + single-line-mode + extended-mode + destructive) + (declare #.*standard-optimize-settings*) + (declare (ignore destructive)) + (excl:compile-re parse-tree + :case-fold case-insensitive-mode + :ignore-whitespace extended-mode + :multiple-lines multi-line-mode + :single-line single-line-mode + :return :index)) + +(defgeneric scan (regex target-string &key start end real-start-pos) + (:documentation "Searches TARGET-STRING from START to END and tries +to match REGEX. On success returns four values - the start of the +match, the end of the match, and two arrays denoting the beginnings +and ends of register matches. On failure returns NIL. REGEX can be a +string which will be parsed according to Perl syntax, a parse tree, or +a pre-compiled scanner created by CREATE-SCANNER. TARGET-STRING will +be coerced to a simple string if it isn't one already. The +REAL-START-POS parameter should be ignored - it exists only for +internal purposes.")) + +#-:use-acl-regexp2-engine +(defmethod scan ((regex-string string) target-string + &key (start 0) + (end (length target-string)) + ((:real-start-pos *real-start-pos*) nil)) + (declare #.*standard-optimize-settings*) + ;; note that the scanners are optimized for simple strings so we + ;; have to coerce TARGET-STRING into one if it isn't already + (funcall (create-scanner regex-string) + (maybe-coerce-to-simple-string target-string) + start end)) + +#-:use-acl-regexp2-engine +(defmethod scan ((scanner function) target-string + &key (start 0) + (end (length target-string)) + ((:real-start-pos *real-start-pos*) nil)) + (declare #.*standard-optimize-settings*) + (funcall scanner + (maybe-coerce-to-simple-string target-string) + start end)) + +#-:use-acl-regexp2-engine +(defmethod scan ((parse-tree t) target-string + &key (start 0) + (end (length target-string)) + ((:real-start-pos *real-start-pos*) nil)) + (declare #.*standard-optimize-settings*) + (funcall (create-scanner parse-tree) + (maybe-coerce-to-simple-string target-string) + start end)) + +#+:use-acl-regexp2-engine +(declaim (inline scan)) + +#+:use-acl-regexp2-engine +(defmethod scan ((parse-tree t) target-string + &key (start 0) + (end (length target-string)) + ((:real-start-pos *real-start-pos*) nil)) + (declare #.*standard-optimize-settings*) + (when (< end start) + (return-from scan nil)) + (let ((results (multiple-value-list (excl:match-re parse-tree target-string + :start start + :end end + :return :index)))) + (declare (dynamic-extent results)) + (cond ((null (first results)) nil) + (t (let* ((no-of-regs (- (length results) 2)) + (reg-starts (make-array no-of-regs + :element-type '(or null fixnum))) + (reg-ends (make-array no-of-regs + :element-type '(or null fixnum))) + (match (second results))) + (loop for (start . end) in (cddr results) + for i from 0 + do (setf (aref reg-starts i) start + (aref reg-ends i) end)) + (values (car match) (cdr match) reg-starts reg-ends)))))) + +#-:cormanlisp +(define-compiler-macro scan (&whole form &environment env regex target-string &rest rest) + "Make sure that constant forms are compiled into scanners at compile time." + (cond ((constantp regex env) + `(scan (load-time-value (create-scanner ,regex)) + ,target-string ,@rest)) + (t form))) + +(defun scan-to-strings (regex target-string &key (start 0) + (end (length target-string)) + sharedp) + (declare #.*standard-optimize-settings*) + "Like SCAN but returns substrings of TARGET-STRING instead of +positions, i.e. this function returns two values on success: the whole +match as a string plus an array of substrings (or NILs) corresponding +to the matched registers. If SHAREDP is true, the substrings may share +structure with TARGET-STRING." + (multiple-value-bind (match-start match-end reg-starts reg-ends) + (scan regex target-string :start start :end end) + (unless match-start + (return-from scan-to-strings nil)) + (let ((substr-fn (if sharedp #'nsubseq #'subseq))) + (values (funcall substr-fn + target-string match-start match-end) + (map 'vector + (lambda (reg-start reg-end) + (if reg-start + (funcall substr-fn + target-string reg-start reg-end) + nil)) + reg-starts + reg-ends))))) + +#-:cormanlisp +(define-compiler-macro scan-to-strings + (&whole form &environment env regex target-string &rest rest) + "Make sure that constant forms are compiled into scanners at compile time." + (cond ((constantp regex env) + `(scan-to-strings (load-time-value (create-scanner ,regex)) + ,target-string ,@rest)) + (t form))) + +(defmacro register-groups-bind (var-list (regex target-string + &key start end sharedp) + &body body) + "Executes BODY with the variables in VAR-LIST bound to the +corresponding register groups after TARGET-STRING has been matched +against REGEX, i.e. each variable is either bound to a string or to +NIL. If there is no match, BODY is _not_ executed. For each element of +VAR-LIST which is NIL there's no binding to the corresponding register +group. The number of variables in VAR-LIST must not be greater than +the number of register groups. If SHAREDP is true, the substrings may +share structure with TARGET-STRING." + (with-rebinding (target-string) + (with-unique-names (match-start match-end reg-starts reg-ends + start-index substr-fn) + `(multiple-value-bind (,match-start ,match-end ,reg-starts ,reg-ends) + (scan ,regex ,target-string :start (or ,start 0) + :end (or ,end (length ,target-string))) + (declare (ignore ,match-end)) + (when ,match-start + (let* ,(cons + `(,substr-fn (if ,sharedp + #'nsubseq + #'subseq)) + (loop for (function var) in (normalize-var-list var-list) + for counter from 0 + when var + collect `(,var (let ((,start-index + (aref ,reg-starts ,counter))) + (if ,start-index + (funcall ,function + (funcall ,substr-fn + ,target-string + ,start-index + (aref ,reg-ends ,counter))) + nil))))) + ,@body)))))) + +(defmacro do-scans ((match-start match-end reg-starts reg-ends regex + target-string + &optional result-form + &key start end) + &body body + &environment env) + "Iterates over TARGET-STRING and tries to match REGEX as often as +possible evaluating BODY with MATCH-START, MATCH-END, REG-STARTS, and +REG-ENDS bound to the four return values of each match in turn. After +the last match, returns RESULT-FORM if provided or NIL otherwise. An +implicit block named NIL surrounds DO-SCANS; RETURN may be used to +terminate the loop immediately. If REGEX matches an empty string the +scan is continued one position behind this match. BODY may start with +declarations." + (with-rebinding (target-string) + (with-unique-names (%start %end %regex scanner loop-tag block-name) + (declare (ignorable %regex scanner)) + ;; the NIL BLOCK to enable exits via (RETURN ...) + `(block nil + (let* ((,%start (or ,start 0)) + (,%end (or ,end (length ,target-string))) + ,@(unless (constantp regex env) + ;; leave constant regular expressions as they are - + ;; SCAN's compiler macro will take care of them; + ;; otherwise create a scanner unless the regex is + ;; already a function (otherwise SCAN will do this + ;; on each iteration) + `((,%regex ,regex) + (,scanner (typecase ,%regex + (function ,%regex) + (t (create-scanner ,%regex))))))) + ;; coerce TARGET-STRING to a simple string unless it is one + ;; already (otherwise SCAN will do this on each iteration) + (setq ,target-string + (maybe-coerce-to-simple-string ,target-string)) + ;; a named BLOCK so we can exit the TAGBODY + (block ,block-name + (tagbody + ,loop-tag + ;; invoke SCAN and bind the returned values to the + ;; provided variables + (multiple-value-bind + (,match-start ,match-end ,reg-starts ,reg-ends) + (scan ,(cond ((constantp regex env) regex) + (t scanner)) + ,target-string :start ,%start :end ,%end + :real-start-pos (or ,start 0)) + ;; declare the variables to be IGNORABLE to prevent the + ;; compiler from issuing warnings + (declare + (ignorable ,match-start ,match-end ,reg-starts ,reg-ends)) + (unless ,match-start + ;; stop iteration on first failure + (return-from ,block-name ,result-form)) + ;; execute BODY (wrapped in LOCALLY so it can start with + ;; declarations) + (locally + ,@body) + ;; advance by one position if we had a zero-length match + (setq ,%start (if (= ,match-start ,match-end) + (1+ ,match-end) + ,match-end))) + (go ,loop-tag)))))))) + +(defmacro do-matches ((match-start match-end regex + target-string + &optional result-form + &key start end) + &body body) + "Iterates over TARGET-STRING and tries to match REGEX as often as +possible evaluating BODY with MATCH-START and MATCH-END bound to the +start/end positions of each match in turn. After the last match, +returns RESULT-FORM if provided or NIL otherwise. An implicit block +named NIL surrounds DO-MATCHES; RETURN may be used to terminate the +loop immediately. If REGEX matches an empty string the scan is +continued one position behind this match. BODY may start with +declarations." + ;; this is a simplified form of DO-SCANS - we just provide two dummy + ;; vars and ignore them + (with-unique-names (reg-starts reg-ends) + `(do-scans (,match-start ,match-end + ,reg-starts ,reg-ends + ,regex ,target-string + ,result-form + :start ,start :end ,end) + ,@body))) + +(defmacro do-matches-as-strings ((match-var regex + target-string + &optional result-form + &key start end sharedp) + &body body) + "Iterates over TARGET-STRING and tries to match REGEX as often as +possible evaluating BODY with MATCH-VAR bound to the substring of +TARGET-STRING corresponding to each match in turn. After the last +match, returns RESULT-FORM if provided or NIL otherwise. An implicit +block named NIL surrounds DO-MATCHES-AS-STRINGS; RETURN may be used to +terminate the loop immediately. If REGEX matches an empty string the +scan is continued one position behind this match. If SHAREDP is true, +the substrings may share structure with TARGET-STRING. BODY may start +with declarations." + (with-rebinding (target-string) + (with-unique-names (match-start match-end substr-fn) + `(let ((,substr-fn (if ,sharedp #'nsubseq #'subseq))) + ;; simple use DO-MATCHES to extract the substrings + (do-matches (,match-start ,match-end ,regex ,target-string + ,result-form :start ,start :end ,end) + (let ((,match-var + (funcall ,substr-fn + ,target-string ,match-start ,match-end))) + ,@body)))))) + +(defmacro do-register-groups (var-list (regex target-string + &optional result-form + &key start end sharedp) + &body body) + "Iterates over TARGET-STRING and tries to match REGEX as often as +possible evaluating BODY with the variables in VAR-LIST bound to the +corresponding register groups for each match in turn, i.e. each +variable is either bound to a string or to NIL. For each element of +VAR-LIST which is NIL there's no binding to the corresponding register +group. The number of variables in VAR-LIST must not be greater than +the number of register groups. After the last match, returns +RESULT-FORM if provided or NIL otherwise. An implicit block named NIL +surrounds DO-REGISTER-GROUPS; RETURN may be used to terminate the loop +immediately. If REGEX matches an empty string the scan is continued +one position behind this match. If SHAREDP is true, the substrings may +share structure with TARGET-STRING. BODY may start with declarations." + (with-rebinding (target-string) + (with-unique-names (substr-fn match-start match-end + reg-starts reg-ends start-index) + `(let ((,substr-fn (if ,sharedp + #'nsubseq + #'subseq))) + (do-scans (,match-start ,match-end ,reg-starts ,reg-ends + ,regex ,target-string + ,result-form :start ,start :end ,end) + (let ,(loop for (function var) in (normalize-var-list var-list) + for counter from 0 + when var + collect `(,var (let ((,start-index + (aref ,reg-starts ,counter))) + (if ,start-index + (funcall ,function + (funcall ,substr-fn + ,target-string + ,start-index + (aref ,reg-ends ,counter))) + nil)))) + ,@body)))))) + +(defun all-matches (regex target-string + &key (start 0) + (end (length target-string))) + (declare #.*standard-optimize-settings*) + "Returns a list containing the start and end positions of all +matches of REGEX against TARGET-STRING, i.e. if there are N matches +the list contains (* 2 N) elements. If REGEX matches an empty string +the scan is continued one position behind this match." + (let (result-list) + (do-matches (match-start match-end + regex target-string + (nreverse result-list) + :start start :end end) + (push match-start result-list) + (push match-end result-list)))) + +#-:cormanlisp +(define-compiler-macro all-matches (&whole form &environment env regex &rest rest) + "Make sure that constant forms are compiled into scanners at +compile time." + (cond ((constantp regex env) + `(all-matches (load-time-value (create-scanner ,regex)) + ,@rest)) + (t form))) + +(defun all-matches-as-strings (regex target-string + &key (start 0) + (end (length target-string)) + sharedp) + (declare #.*standard-optimize-settings*) + "Returns a list containing all substrings of TARGET-STRING which +match REGEX. If REGEX matches an empty string the scan is continued +one position behind this match. If SHAREDP is true, the substrings may +share structure with TARGET-STRING." + (let (result-list) + (do-matches-as-strings (match regex target-string (nreverse result-list) + :start start :end end :sharedp sharedp) + (push match result-list)))) + +#-:cormanlisp +(define-compiler-macro all-matches-as-strings (&whole form &environment env regex &rest rest) + "Make sure that constant forms are compiled into scanners at +compile time." + (cond ((constantp regex env) + `(all-matches-as-strings + (load-time-value (create-scanner ,regex)) + ,@rest)) + (t form))) + +(defun split (regex target-string + &key (start 0) + (end (length target-string)) + limit + with-registers-p + omit-unmatched-p + sharedp) + (declare #.*standard-optimize-settings*) + "Matches REGEX against TARGET-STRING as often as possible and +returns a list of the substrings between the matches. If +WITH-REGISTERS-P is true, substrings corresponding to matched +registers are inserted into the list as well. If OMIT-UNMATCHED-P is +true, unmatched registers will simply be left out, otherwise they will +show up as NIL. LIMIT limits the number of elements returned - +registers aren't counted. If LIMIT is NIL (or 0 which is equivalent), +trailing empty strings are removed from the result list. If REGEX +matches an empty string the scan is continued one position behind this +match. If SHAREDP is true, the substrings may share structure with +TARGET-STRING." + ;; initialize list of positions POS-LIST to extract substrings with + ;; START so that the start of the next match will mark the end of + ;; the first substring + (let ((pos-list (list start)) + (counter 0)) + ;; how would Larry Wall do it? + (when (eql limit 0) + (setq limit nil)) + (do-scans (match-start match-end + reg-starts reg-ends + regex target-string nil + :start start :end end) + (unless (and (= match-start match-end) + (= match-start (car pos-list))) + ;; push start of match on list unless this would be an empty + ;; string adjacent to the last element pushed onto the list + (when (and limit + (>= (incf counter) limit)) + (return)) + (push match-start pos-list) + (when with-registers-p + ;; optionally insert matched registers + (loop for reg-start across reg-starts + for reg-end across reg-ends + if reg-start + ;; but only if they've matched + do (push reg-start pos-list) + (push reg-end pos-list) + else unless omit-unmatched-p + ;; or if we're allowed to insert NIL instead + do (push nil pos-list) + (push nil pos-list))) + ;; now end of match + (push match-end pos-list))) + ;; end of whole string + (push end pos-list) + ;; now collect substrings + (nreverse + (loop with substr-fn = (if sharedp #'nsubseq #'subseq) + with string-seen = nil + for (this-end this-start) on pos-list by #'cddr + ;; skip empty strings from end of list + if (or limit + (setq string-seen + (or string-seen + (and this-start + (> this-end this-start))))) + collect (if this-start + (funcall substr-fn + target-string this-start this-end) + nil))))) + +#-:cormanlisp +(define-compiler-macro split (&whole form &environment env regex target-string &rest rest) + "Make sure that constant forms are compiled into scanners at compile time." + (cond ((constantp regex env) + `(split (load-time-value (create-scanner ,regex)) + ,target-string ,@rest)) + (t form))) + +(defun string-case-modifier (str from to start end) + (declare #.*standard-optimize-settings*) + (declare (type fixnum from to start end)) + "Checks whether all words in STR between FROM and TO are upcased, +downcased or capitalized and returns a function which applies a +corresponding case modification to strings. Returns #'IDENTITY +otherwise, especially if words in the target area extend beyond FROM +or TO. STR is supposed to be bounded by START and END. It is assumed +that (<= START FROM TO END)." + (case + (if (or (<= to from) + (and (< start from) + (alphanumericp (char str (1- from))) + (alphanumericp (char str from))) + (and (< to end) + (alphanumericp (char str to)) + (alphanumericp (char str (1- to))))) + ;; if it's a zero-length string or if words extend beyond FROM + ;; or TO we return NIL, i.e. #'IDENTITY + nil + ;; otherwise we loop through STR from FROM to TO + (loop with last-char-both-case + with current-result + for index of-type fixnum from from below to + for chr = (char str index) + do (cond ((not #-:cormanlisp (both-case-p chr) + #+:cormanlisp (or (upper-case-p chr) + (lower-case-p chr))) + ;; this character doesn't have a case so we + ;; consider it as a word boundary (note that + ;; this differs from how \b works in Perl) + (setq last-char-both-case nil)) + ((upper-case-p chr) + ;; an uppercase character + (setq current-result + (if last-char-both-case + ;; not the first character in a + (case current-result + ((:undecided) :upcase) + ((:downcase :capitalize) (return nil)) + ((:upcase) current-result)) + (case current-result + ((nil) :undecided) + ((:downcase) (return nil)) + ((:capitalize :upcase) current-result))) + last-char-both-case t)) + (t + ;; a lowercase character + (setq current-result + (case current-result + ((nil) :downcase) + ((:undecided) :capitalize) + ((:downcase) current-result) + ((:capitalize) (if last-char-both-case + current-result + (return nil))) + ((:upcase) (return nil))) + last-char-both-case t))) + finally (return current-result))) + ((nil) #'identity) + ((:undecided :upcase) #'string-upcase) + ((:downcase) #'string-downcase) + ((:capitalize) #'string-capitalize))) + +;; first create a scanner to identify the special parts of the +;; replacement string (eat your own dog food...) + +(defgeneric build-replacement-template (replacement-string) + (declare #.*standard-optimize-settings*) + (:documentation "Converts a replacement string for REGEX-REPLACE or +REGEX-REPLACE-ALL into a replacement template which is an +S-expression.")) + +#-:cormanlisp +(let* ((*use-bmh-matchers* nil) + (reg-scanner (create-scanner "\\(?:\\|\{\d+\}|\d+|&|`|')"))) + (defmethod build-replacement-template ((replacement-string string)) + (declare #.*standard-optimize-settings*) + (let ((from 0) + ;; COLLECTOR will hold the (reversed) template + (collector '())) + ;; scan through all special parts of the replacement string + (do-matches (match-start match-end reg-scanner replacement-string) + (when (< from match-start) + ;; strings between matches are copied verbatim + (push (subseq replacement-string from match-start) collector)) + ;; PARSE-START is true if the pattern matched a number which + ;; refers to a register + (let* ((parse-start (position-if #'digit-char-p + replacement-string + :start match-start + :end match-end)) + (token (if parse-start + (1- (parse-integer replacement-string + :start parse-start + :junk-allowed t)) + ;; if we didn't match a number we convert the + ;; character to a symbol + (case (char replacement-string (1+ match-start)) + ((#&) :match) + ((#`) :before-match) + ((#') :after-match) + ((#\) :backslash))))) + (when (and (numberp token) (< token 0)) + ;; make sure we don't accept something like "\0" + (signal-ppcre-invocation-error + "Illegal substring ~S in replacement string" + (subseq replacement-string match-start match-end))) + (push token collector)) + ;; remember where the match ended + (setq from match-end)) + (when (< from (length replacement-string)) + ;; push the rest of the replacement string onto the list + (push (subseq replacement-string from) collector)) + (nreverse collector)))) + +#-:cormanlisp +(defmethod build-replacement-template ((replacement-function function)) + (declare #.*standard-optimize-settings*) + (list replacement-function)) + +#-:cormanlisp +(defmethod build-replacement-template ((replacement-function-symbol symbol)) + (declare #.*standard-optimize-settings*) + (list replacement-function-symbol)) + +#-:cormanlisp +(defmethod build-replacement-template ((replacement-list list)) + (declare #.*standard-optimize-settings*) + replacement-list) + +;;; Corman Lisp's methods can't be closures... :( +#+:cormanlisp +(let* ((*use-bmh-matchers* nil) + (reg-scanner (create-scanner "\\(?:\\|\{\d+\}|\d+|&|`|')"))) + (defun build-replacement-template (replacement) + (declare #.*standard-optimize-settings*) + (typecase replacement + (string + (let ((from 0) + ;; COLLECTOR will hold the (reversed) template + (collector '())) + ;; scan through all special parts of the replacement string + (do-matches (match-start match-end reg-scanner replacement) + (when (< from match-start) + ;; strings between matches are copied verbatim + (push (subseq replacement from match-start) collector)) + ;; PARSE-START is true if the pattern matched a number which + ;; refers to a register + (let* ((parse-start (position-if #'digit-char-p + replacement + :start match-start + :end match-end)) + (token (if parse-start + (1- (parse-integer replacement + :start parse-start + :junk-allowed t)) + ;; if we didn't match a number we convert the + ;; character to a symbol + (case (char replacement (1+ match-start)) + ((#&) :match) + ((#`) :before-match) + ((#') :after-match) + ((#\) :backslash))))) + (when (and (numberp token) (< token 0)) + ;; make sure we don't accept something like "\0" + (signal-ppcre-invocation-error + "Illegal substring ~S in replacement string" + (subseq replacement match-start match-end))) + (push token collector)) + ;; remember where the match ended + (setq from match-end)) + (when (< from (length replacement)) + ;; push the rest of the replacement string onto the list + (push (nsubseq replacement from) collector)) + (nreverse collector))) + (list + replacement) + (t + (list replacement))))) + +(defun build-replacement (replacement-template + target-string + start end + match-start match-end + reg-starts reg-ends + simple-calls + element-type) + (declare #.*standard-optimize-settings*) + "Accepts a replacement template and the current values from the +matching process in REGEX-REPLACE or REGEX-REPLACE-ALL and returns the +corresponding string." + ;; the upper exclusive bound of the register numbers in the regular + ;; expression + (let ((reg-bound (if reg-starts + (array-dimension reg-starts 0) + 0))) + (with-output-to-string (s nil :element-type element-type) + (loop for token in replacement-template + do (typecase token + (string + ;; transfer string parts verbatim + (write-string token s)) + (integer + ;; replace numbers with the corresponding registers + (when (>= token reg-bound) + ;; but only if the register was referenced in the + ;; regular expression + (signal-ppcre-invocation-error + "Reference to non-existent register ~A in replacement string" + (1+ token))) + (when (svref reg-starts token) + ;; and only if it matched, i.e. no match results + ;; in an empty string + (write-string target-string s + :start (svref reg-starts token) + :end (svref reg-ends token)))) + (function + (write-string + (cond (simple-calls + (apply token + (nsubseq target-string match-start match-end) + (map 'list + (lambda (reg-start reg-end) + (and reg-start + (nsubseq target-string reg-start reg-end))) + reg-starts reg-ends))) + (t + (funcall token + target-string + start end + match-start match-end + reg-starts reg-ends))) + s)) + (symbol + (case token + ((:backslash) + ;; just a backslash + (write-char #\ s)) + ((:match) + ;; the whole match + (write-string target-string s + :start match-start + :end match-end)) + ((:before-match) + ;; the part of the target string before the match + (write-string target-string s + :start start + :end match-start)) + ((:after-match) + ;; the part of the target string after the match + (write-string target-string s + :start match-end + :end end)) + (otherwise + (write-string + (cond (simple-calls + (apply token + (nsubseq target-string match-start match-end) + (map 'list + (lambda (reg-start reg-end) + (and reg-start + (nsubseq target-string reg-start reg-end))) + reg-starts reg-ends))) + (t + (funcall token + target-string + start end + match-start match-end + reg-starts reg-ends))) + s))))))))) + +(defun replace-aux (target-string replacement pos-list reg-list start end + preserve-case simple-calls element-type) + (declare #.*standard-optimize-settings*) + "Auxiliary function used by REGEX-REPLACE and +REGEX-REPLACE-ALL. POS-LIST contains a list with the start and end +positions of all matches while REG-LIST contains a list of arrays +representing the corresponding register start and end positions." + ;; build the template once before we start the loop + (let ((replacement-template (build-replacement-template replacement))) + (with-output-to-string (s nil :element-type element-type) + ;; loop through all matches and take the start and end of the + ;; whole string into account + (loop for (from to) on (append (list start) pos-list (list end)) + ;; alternate between replacement and no replacement + for replace = nil then (and (not replace) to) + for reg-starts = (if replace (pop reg-list) nil) + for reg-ends = (if replace (pop reg-list) nil) + for curr-replacement = (if replace + ;; build the replacement string + (build-replacement replacement-template + target-string + start end + from to + reg-starts reg-ends + simple-calls + element-type) + nil) + while to + if replace + do (write-string (if preserve-case + ;; modify the case of the replacement + ;; string if necessary + (funcall (string-case-modifier target-string + from to + start end) + curr-replacement) + curr-replacement) + s) + else + ;; no replacement + do (write-string target-string s :start from :end to))))) + +(defun regex-replace (regex target-string replacement + &key (start 0) + (end (length target-string)) + preserve-case + simple-calls + (element-type #+:lispworks 'lw:simple-char #-:lispworks 'character)) + (declare #.*standard-optimize-settings*) + "Try to match TARGET-STRING between START and END against REGEX and +replace the first match with REPLACEMENT. Two values are returned; +the modified string, and T if REGEX matched or NIL otherwise. + + REPLACEMENT can be a string which may contain the special substrings +"\&" for the whole match, "\`" for the part of TARGET-STRING +before the match, "\'" for the part of TARGET-STRING after the +match, "\N" or "\{N}" for the Nth register where N is a positive +integer. + + REPLACEMENT can also be a function designator in which case the +match will be replaced with the result of calling the function +designated by REPLACEMENT with the arguments TARGET-STRING, START, +END, MATCH-START, MATCH-END, REG-STARTS, and REG-ENDS. (REG-STARTS and +REG-ENDS are arrays holding the start and end positions of matched +registers or NIL - the meaning of the other arguments should be +obvious.) + + Finally, REPLACEMENT can be a list where each element is a string, +one of the symbols :MATCH, :BEFORE-MATCH, or :AFTER-MATCH - +corresponding to "\&", "\`", and "\'" above -, an integer N - +representing register (1+ N) -, or a function designator. + + If PRESERVE-CASE is true, the replacement will try to preserve the +case (all upper case, all lower case, or capitalized) of the +match. The result will always be a fresh string, even if REGEX doesn't +match. + + ELEMENT-TYPE is the element type of the resulting string." + (multiple-value-bind (match-start match-end reg-starts reg-ends) + (scan regex target-string :start start :end end) + (if match-start + (values (replace-aux target-string replacement + (list match-start match-end) + (list reg-starts reg-ends) + start end preserve-case + simple-calls element-type) + t) + (values (subseq target-string start end) + nil)))) + +#-:cormanlisp +(define-compiler-macro regex-replace + (&whole form &environment env regex target-string replacement &rest rest) + "Make sure that constant forms are compiled into scanners at compile time." + (cond ((constantp regex env) + `(regex-replace (load-time-value (create-scanner ,regex)) + ,target-string ,replacement ,@rest)) + (t form))) + +(defun regex-replace-all (regex target-string replacement + &key (start 0) + (end (length target-string)) + preserve-case + simple-calls + (element-type #+:lispworks 'lw:simple-char #-:lispworks 'character)) + (declare #.*standard-optimize-settings*) + "Try to match TARGET-STRING between START and END against REGEX and +replace all matches with REPLACEMENT. Two values are returned; the +modified string, and T if REGEX matched or NIL otherwise. + + REPLACEMENT can be a string which may contain the special substrings +"\&" for the whole match, "\`" for the part of TARGET-STRING +before the match, "\'" for the part of TARGET-STRING after the +match, "\N" or "\{N}" for the Nth register where N is a positive +integer. + + REPLACEMENT can also be a function designator in which case the +match will be replaced with the result of calling the function +designated by REPLACEMENT with the arguments TARGET-STRING, START, +END, MATCH-START, MATCH-END, REG-STARTS, and REG-ENDS. (REG-STARTS and +REG-ENDS are arrays holding the start and end positions of matched +registers or NIL - the meaning of the other arguments should be +obvious.) + + Finally, REPLACEMENT can be a list where each element is a string, +one of the symbols :MATCH, :BEFORE-MATCH, or :AFTER-MATCH - +corresponding to "\&", "\`", and "\'" above -, an integer N - +representing register (1+ N) -, or a function designator. + + If PRESERVE-CASE is true, the replacement will try to preserve the +case (all upper case, all lower case, or capitalized) of the +match. The result will always be a fresh string, even if REGEX doesn't +match. + + ELEMENT-TYPE is the element type of the resulting string." + (let ((pos-list '()) + (reg-list '())) + (do-scans (match-start match-end reg-starts reg-ends regex target-string + nil + :start start :end end) + (push match-start pos-list) + (push match-end pos-list) + (push reg-starts reg-list) + (push reg-ends reg-list)) + (if pos-list + (values (replace-aux target-string replacement + (nreverse pos-list) + (nreverse reg-list) + start end preserve-case + simple-calls element-type) + t) + (values (subseq target-string start end) + nil)))) + +#-:cormanlisp +(define-compiler-macro regex-replace-all + (&whole form &environment env regex target-string replacement &rest rest) + "Make sure that constant forms are compiled into scanners at compile time." + (cond ((constantp regex env) + `(regex-replace-all (load-time-value (create-scanner ,regex)) + ,target-string ,replacement ,@rest)) + (t form))) + +#-:cormanlisp +(defmacro regex-apropos-aux ((regex packages case-insensitive &optional return-form) + &body body) + "Auxiliary macro used by REGEX-APROPOS and REGEX-APROPOS-LIST. Loops +through PACKAGES and executes BODY with SYMBOL bound to each symbol +which matches REGEX. Optionally evaluates and returns RETURN-FORM at +the end. If CASE-INSENSITIVE is true and REGEX isn't already a +scanner, a case-insensitive scanner is used." + (with-rebinding (regex) + (with-unique-names (scanner %packages next morep) + `(let* ((,scanner (create-scanner ,regex + :case-insensitive-mode + (and ,case-insensitive + (not (functionp ,regex))))) + (,%packages (or ,packages + (list-all-packages)))) + (with-package-iterator (,next ,%packages :external :internal :inherited) + (loop + (multiple-value-bind (,morep symbol) + (,next) + (unless ,morep + (return ,return-form)) + (when (scan ,scanner (symbol-name symbol)) + ,@body)))))))) + +;;; The following two functions were provided by Karsten Poeck + +#+:cormanlisp +(defmacro do-with-all-symbols ((variable package-packagelist) &body body) + (with-unique-names (pack-var iter-sym) + `(if (listp ,package-packagelist) + (dolist (,pack-var ,package-packagelist) + (do-symbols (,iter-sym ,pack-var) + ,@body)) + (do-symbols (,iter-sym ,package-packagelist) + ,@body)))) + +#+:cormanlisp +(defmacro regex-apropos-aux ((regex packages case-insensitive &optional return-form) + &body body) + "Auxiliary macro used by REGEX-APROPOS and REGEX-APROPOS-LIST. Loops +through PACKAGES and executes BODY with SYMBOL bound to each symbol +which matches REGEX. Optionally evaluates and returns RETURN-FORM at +the end. If CASE-INSENSITIVE is true and REGEX isn't already a +scanner, a case-insensitive scanner is used." + (with-rebinding (regex) + (with-unique-names (scanner %packages) + `(let* ((,scanner (create-scanner ,regex + :case-insensitive-mode + (and ,case-insensitive + (not (functionp ,regex))))) + (,%packages (or ,packages + (list-all-packages)))) + (do-with-all-symbols (symbol ,%packages) + (when (scan ,scanner (symbol-name symbol)) + ,@body)) + ,return-form)))) + +(defun regex-apropos-list (regex &optional packages &key (case-insensitive t)) + (declare #.*standard-optimize-settings*) + "Similar to the standard function APROPOS-LIST but returns a list of +all symbols which match the regular expression REGEX. If +CASE-INSENSITIVE is true and REGEX isn't already a scanner, a +case-insensitive scanner is used." + (let ((collector '())) + (regex-apropos-aux (regex packages case-insensitive collector) + (push symbol collector)))) + +(defun print-symbol-info (symbol) + "Auxiliary function used by REGEX-APROPOS. Tries to print some +meaningful information about a symbol." + (declare #.*standard-optimize-settings*) + (handler-case + (let ((output-list '())) + (cond ((special-operator-p symbol) + (push "[special operator]" output-list)) + ((macro-function symbol) + (push "[macro]" output-list)) + ((fboundp symbol) + (let* ((function (symbol-function symbol)) + (compiledp (compiled-function-p function))) + (multiple-value-bind (lambda-expr closurep) + (function-lambda-expression function) + (push + (format nil + "[~:[~;compiled ~]~:[function~;closure~]]~:[~; ~A~]" + compiledp closurep lambda-expr (cadr lambda-expr)) + output-list))))) + (let ((class (find-class symbol nil))) + (when class + (push (format nil "[class] ~S" class) output-list))) + (cond ((keywordp symbol) + (push "[keyword]" output-list)) + ((constantp symbol) + (push (format nil "[constant]~:[~; value: ~S~]" + (boundp symbol) (symbol-value symbol)) output-list)) + ((boundp symbol) + (push #+(or :lispworks :clisp) "[variable]" + #-(or :lispworks :clisp) (format nil "[variable] value: ~S" + (symbol-value symbol)) + output-list))) + #-(or :cormanlisp :clisp) + (format t "~&~S ~<~;~^~A~@{~:@_~A~}~;~:>" symbol output-list) + #+(or :cormanlisp :clisp) + (loop for line in output-list + do (format t "~&~S ~A" symbol line))) + (condition () + ;; this seems to be necessary due to some errors I encountered + ;; with LispWorks + (format t "~&~S [an error occured while trying to print more info]" symbol)))) + +(defun regex-apropos (regex &optional packages &key (case-insensitive t)) + "Similar to the standard function APROPOS but returns a list of all +symbols which match the regular expression REGEX. If CASE-INSENSITIVE +is true and REGEX isn't already a scanner, a case-insensitive scanner +is used." + (declare #.*standard-optimize-settings*) + (regex-apropos-aux (regex packages case-insensitive) + (print-symbol-info symbol)) + (values)) + +(let* ((*use-bmh-matchers* nil) + (non-word-char-scanner (create-scanner "[^a-zA-Z_0-9]"))) + (defun quote-meta-chars (string &key (start 0) (end (length string))) + "Quote, i.e. prefix with #\\, all non-word characters in STRING." + (regex-replace-all non-word-char-scanner string "\\\&" + :start start :end end))) + +(let* ((*use-bmh-matchers* nil) + (*allow-quoting* nil) + (quote-char-scanner (create-scanner "\\Q")) + (section-scanner (create-scanner "\\Q((?:[^\\]|\\(?!Q))*?)(?:\\E|$)"))) + (defun quote-sections (string) + "Replace sections inside of STRING which are enclosed by \Q and +\E with the quoted equivalent of these sections (see +QUOTE-META-CHARS). Repeat this as long as there are such +sections. These sections may nest." + (flet ((quote-substring (target-string start end match-start + match-end reg-starts reg-ends) + (declare (ignore start end match-start match-end)) + (quote-meta-chars target-string + :start (svref reg-starts 0) + :end (svref reg-ends 0)))) + (loop for result = string then (regex-replace-all section-scanner + result + #'quote-substring) + while (scan quote-char-scanner result) + finally (return result))))) + +(let* ((*use-bmh-matchers* nil) + (comment-scanner (create-scanner "(?s)\(\?#.*?\)")) + (extended-comment-scanner (create-scanner "(?m:#.*?$)|(?s:\(\?#.*?\))")) + (quote-token-scanner "\\[QE]") + (quote-token-replace-scanner "\\([QE])")) + (defun clean-comments (string &optional extended-mode) + "Clean (?#...) comments within STRING for quoting, i.e. convert +\Q to Q and \E to E. If EXTENDED-MODE is true, also clean +end-of-line comments, i.e. those starting with #\# and ending with +#\Newline." + (flet ((remove-tokens (target-string start end match-start + match-end reg-starts reg-ends) + (declare (ignore start end reg-starts reg-ends)) + (loop for result = (nsubseq target-string match-start match-end) + then (regex-replace-all quote-token-replace-scanner result "\1") + ;; we must probably repeat this because the comment + ;; can contain substrings like \Q + while (scan quote-token-scanner result) + finally (return result)))) + (regex-replace-all (if extended-mode + extended-comment-scanner + comment-scanner) + string + #'remove-tokens)))) + +(defun parse-tree-synonym (symbol) + "Returns the parse tree the SYMBOL symbol is a synonym for. Returns +NIL is SYMBOL wasn't yet defined to be a synonym." + (get symbol 'parse-tree-synonym)) + +(defun (setf parse-tree-synonym) (new-parse-tree symbol) + "Defines SYMBOL to be a synonm for the parse tree NEW-PARSE-TREE." + (setf (get symbol 'parse-tree-synonym) new-parse-tree)) + +(defmacro define-parse-tree-synonym (name parse-tree) + "Defines the symbol NAME to be a synonym for the parse tree +PARSE-TREE. Both arguments are quoted." + `(eval-when (:compile-toplevel :load-toplevel :execute) + (setf (parse-tree-synonym ',name) ',parse-tree)))
Added: branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/cl-ppcre-test.asd =================================================================== --- branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/cl-ppcre-test.asd 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/cl-ppcre-test.asd 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,34 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-USER; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/cl-ppcre/cl-ppcre-test.asd,v 1.13 2007/01/01 23:43:10 edi Exp $ + +;;; This ASDF system definition was kindly provided by Marco Baringer. + +;;; Copyright (c) 2002-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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. + +(asdf:defsystem :cl-ppcre-test + :depends-on (:cl-ppcre) + :components ((:file "ppcre-tests")))
Added: branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/cl-ppcre-test.system =================================================================== --- branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/cl-ppcre-test.system 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/cl-ppcre-test.system 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,40 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-USER; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/cl-ppcre/cl-ppcre-test.system,v 1.11 2007/01/01 23:43:10 edi Exp $ + +;;; Copyright (c) 2002-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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-package #:cl-user) + +(defparameter *cl-ppcre-test-base-directory* + (make-pathname :name nil :type nil :version nil + :defaults (parse-namestring *load-truename*))) + +(mk:defsystem #:cl-ppcre-test + :source-pathname *cl-ppcre-test-base-directory* + :source-extension "lisp" + :depends-on (#:cl-ppcre) + :components ((:file "ppcre-tests")))
Added: branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/cl-ppcre.asd =================================================================== --- branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/cl-ppcre.asd 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/cl-ppcre.asd 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,55 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-USER; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/cl-ppcre/cl-ppcre.asd,v 1.26 2007/09/13 07:52:13 edi Exp $ + +;;; This ASDF system definition was kindly provided by Marco Baringer. + +;;; Copyright (c) 2002-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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. + +(asdf:defsystem :cl-ppcre + :version "1.3.2" + :serial t + :components ((:file "packages") + (:file "specials") + (:file "util") + (:file "errors") + #-:use-acl-regexp2-engine + (:file "lexer") + #-:use-acl-regexp2-engine + (:file "parser") + #-:use-acl-regexp2-engine + (:file "regex-class") + #-:use-acl-regexp2-engine + (:file "convert") + #-:use-acl-regexp2-engine + (:file "optimize") + #-:use-acl-regexp2-engine + (:file "closures") + #-:use-acl-regexp2-engine + (:file "repetition-closures") + #-:use-acl-regexp2-engine + (:file "scanner") + (:file "api")))
Added: branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/cl-ppcre.system =================================================================== --- branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/cl-ppcre.system 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/cl-ppcre.system 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,59 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-USER; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/cl-ppcre/cl-ppcre.system,v 1.13 2007/01/01 23:43:10 edi Exp $ + +;;; Copyright (c) 2002-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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-package #:cl-user) + +(defparameter *cl-ppcre-base-directory* + (make-pathname :name nil :type nil :version nil + :defaults (parse-namestring *load-truename*))) + +(mk:defsystem #:cl-ppcre + :source-pathname *cl-ppcre-base-directory* + :source-extension "lisp" + :components ((:file "packages") + (:file "specials" :depends-on ("packages")) + (:file "util" :depends-on ("packages")) + (:file "errors" :depends-on ("util")) + #-:use-acl-regexp2-engine + (:file "lexer" :depends-on ("errors" "specials")) + #-:use-acl-regexp2-engine + (:file "parser" :depends-on ("lexer")) + #-:use-acl-regexp2-engine + (:file "regex-class" :depends-on ("parser")) + #-:use-acl-regexp2-engine + (:file "convert" :depends-on ("regex-class")) + #-:use-acl-regexp2-engine + (:file "optimize" :depends-on ("convert")) + #-:use-acl-regexp2-engine + (:file "closures" :depends-on ("optimize" "specials")) + #-:use-acl-regexp2-engine + (:file "repetition-closures" :depends-on ("closures")) + #-:use-acl-regexp2-engine + (:file "scanner" :depends-on ("repetition-closures")) + (:file "api" :depends-on ("scanner"))))
Added: branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/closures.lisp =================================================================== --- branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/closures.lisp 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/closures.lisp 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,579 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-PPCRE; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/cl-ppcre/closures.lisp,v 1.34 2007/01/15 23:57:41 edi Exp $ + +;;; Here we create the closures which together build the final +;;; scanner. + +;;; Copyright (c) 2002-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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-package #:cl-ppcre) + +(declaim (inline *string*= *string*-equal)) + +(defun *string*= (string2 start1 end1 start2 end2) + "Like STRING=, i.e. compares the special string *STRING* from START1 +to END1 with STRING2 from START2 to END2. Note that there's no +boundary check - this has to be implemented by the caller." + (declare #.*standard-optimize-settings*) + (declare (type fixnum start1 end1 start2 end2)) + (loop for string1-idx of-type fixnum from start1 below end1 + for string2-idx of-type fixnum from start2 below end2 + always (char= (schar *string* string1-idx) + (schar string2 string2-idx)))) + +(defun *string*-equal (string2 start1 end1 start2 end2) + "Like STRING-EQUAL, i.e. compares the special string *STRING* from +START1 to END1 with STRING2 from START2 to END2. Note that there's no +boundary check - this has to be implemented by the caller." + (declare #.*standard-optimize-settings*) + (declare (type fixnum start1 end1 start2 end2)) + (loop for string1-idx of-type fixnum from start1 below end1 + for string2-idx of-type fixnum from start2 below end2 + always (char-equal (schar *string* string1-idx) + (schar string2 string2-idx)))) + +(defgeneric create-matcher-aux (regex next-fn) + (declare #.*standard-optimize-settings*) + (:documentation "Creates a closure which takes one parameter, +START-POS, and tests whether REGEX can match *STRING* at START-POS +such that the call to NEXT-FN after the match would succeed.")) + +(defmethod create-matcher-aux ((seq seq) next-fn) + (declare #.*standard-optimize-settings*) + ;; the closure for a SEQ is a chain of closures for the elements of + ;; this sequence which call each other in turn; the last closure + ;; calls NEXT-FN + (loop for element in (reverse (elements seq)) + for curr-matcher = next-fn then next-matcher + for next-matcher = (create-matcher-aux element curr-matcher) + finally (return next-matcher))) + +(defmethod create-matcher-aux ((alternation alternation) next-fn) + (declare #.*standard-optimize-settings*) + ;; first create closures for all alternations of ALTERNATION + (let ((all-matchers (mapcar #'(lambda (choice) + (create-matcher-aux choice next-fn)) + (choices alternation)))) + ;; now create a closure which checks if one of the closures + ;; created above can succeed + (lambda (start-pos) + (declare (type fixnum start-pos)) + (loop for matcher in all-matchers + thereis (funcall (the function matcher) start-pos))))) + +(defmethod create-matcher-aux ((register register) next-fn) + (declare #.*standard-optimize-settings*) + ;; the position of this REGISTER within the whole regex; we start to + ;; count at 0 + (let ((num (num register))) + (declare (type fixnum num)) + ;; STORE-END-OF-REG is a thin wrapper around NEXT-FN which will + ;; update the corresponding values of *REGS-START* and *REGS-END* + ;; after the inner matcher has succeeded + (flet ((store-end-of-reg (start-pos) + (declare (type fixnum start-pos) + (type function next-fn)) + (setf (svref *reg-starts* num) (svref *regs-maybe-start* num) + (svref *reg-ends* num) start-pos) + (funcall next-fn start-pos))) + ;; the inner matcher is a closure corresponding to the regex + ;; wrapped by this REGISTER + (let ((inner-matcher (create-matcher-aux (regex register) + #'store-end-of-reg))) + (declare (type function inner-matcher)) + ;; here comes the actual closure for REGISTER + (lambda (start-pos) + (declare (type fixnum start-pos)) + ;; remember the old values of *REGS-START* and friends in + ;; case we cannot match + (let ((old-*reg-starts* (svref *reg-starts* num)) + (old-*regs-maybe-start* (svref *regs-maybe-start* num)) + (old-*reg-ends* (svref *reg-ends* num))) + ;; we cannot use *REGS-START* here because Perl allows + ;; regular expressions like /(a|\1x)*/ + (setf (svref *regs-maybe-start* num) start-pos) + (let ((next-pos (funcall inner-matcher start-pos))) + (unless next-pos + ;; restore old values on failure + (setf (svref *reg-starts* num) old-*reg-starts* + (svref *regs-maybe-start* num) old-*regs-maybe-start* + (svref *reg-ends* num) old-*reg-ends*)) + next-pos))))))) + +(defmethod create-matcher-aux ((lookahead lookahead) next-fn) + (declare #.*standard-optimize-settings*) + ;; create a closure which just checks for the inner regex and + ;; doesn't care about NEXT-FN + (let ((test-matcher (create-matcher-aux (regex lookahead) #'identity))) + (declare (type function next-fn test-matcher)) + (if (positivep lookahead) + ;; positive look-ahead: check success of inner regex, then call + ;; NEXT-FN + (lambda (start-pos) + (and (funcall test-matcher start-pos) + (funcall next-fn start-pos))) + ;; negative look-ahead: check failure of inner regex, then call + ;; NEXT-FN + (lambda (start-pos) + (and (not (funcall test-matcher start-pos)) + (funcall next-fn start-pos)))))) + +(defmethod create-matcher-aux ((lookbehind lookbehind) next-fn) + (declare #.*standard-optimize-settings*) + (let ((len (len lookbehind)) + ;; create a closure which just checks for the inner regex and + ;; doesn't care about NEXT-FN + (test-matcher (create-matcher-aux (regex lookbehind) #'identity))) + (declare (type function next-fn test-matcher) + (type fixnum len)) + (if (positivep lookbehind) + ;; positive look-behind: check success of inner regex (if we're + ;; far enough from the start of *STRING*), then call NEXT-FN + (lambda (start-pos) + (declare (type fixnum start-pos)) + (and (>= (- start-pos (or *real-start-pos* *start-pos*)) len) + (funcall test-matcher (- start-pos len)) + (funcall next-fn start-pos))) + ;; negative look-behind: check failure of inner regex (if we're + ;; far enough from the start of *STRING*), then call NEXT-FN + (lambda (start-pos) + (declare (type fixnum start-pos)) + (and (or (< (- start-pos (or *real-start-pos* *start-pos*)) len) + (not (funcall test-matcher (- start-pos len)))) + (funcall next-fn start-pos)))))) + +(defmacro insert-char-class-tester ((char-class chr-expr) &body body) + "Utility macro to replace each occurence of '(CHAR-CLASS-TEST) +within BODY with the correct test (corresponding to CHAR-CLASS) +against CHR-EXPR." + (with-unique-names (%char-class) + ;; the actual substitution is done here: replace + ;; '(CHAR-CLASS-TEST) with NEW + (flet ((substitute-char-class-tester (new) + (subst new '(char-class-test) body + :test #'equalp))) + `(let* ((,%char-class ,char-class) + (hash (hash ,%char-class)) + (count (if hash + (hash-table-count hash) + most-positive-fixnum)) + ;; collect a list of "all" characters in the hash if + ;; there aren't more than two + (key-list (if (<= count 2) + (loop for chr being the hash-keys of hash + collect chr) + nil)) + downcasedp) + (declare (type fixnum count)) + ;; check if we can partition the hash into three ranges (or + ;; less) + (multiple-value-bind (min1 max1 min2 max2 min3 max3) + (create-ranges-from-hash hash) + ;; if that didn't work and CHAR-CLASS is case-insensitive we + ;; try it again with every character downcased + (when (and (not min1) + (case-insensitive-p ,%char-class)) + (multiple-value-setq (min1 max1 min2 max2 min3 max3) + (create-ranges-from-hash hash :downcasep t)) + (setq downcasedp t)) + (cond ((= count 1) + ;; hash contains exactly one character so we just + ;; check for this single character; (note that this + ;; actually can't happen because this case is + ;; optimized away in CONVERT already...) + (let ((chr1 (first key-list))) + ,@(substitute-char-class-tester + `(char= ,chr-expr chr1)))) + ((= count 2) + ;; hash contains exactly two characters + (let ((chr1 (first key-list)) + (chr2 (second key-list))) + ,@(substitute-char-class-tester + `(let ((chr ,chr-expr)) + (or (char= chr chr1) + (char= chr chr2)))))) + ((word-char-class-p ,%char-class) + ;; special-case: hash is \w, \W, [\w], [\W] or + ;; something equivalent + ,@(substitute-char-class-tester + `(word-char-p ,chr-expr))) + ((= count *regex-char-code-limit*) + ;; according to the ANSI standard we might have all + ;; possible characters in the hash even if it + ;; doesn't contain CHAR-CODE-LIMIT characters but + ;; this doesn't seem to be the case for current + ;; implementations (also note that this optimization + ;; implies that you must not have characters with + ;; character codes beyond *REGEX-CHAR-CODE-LIMIT* in + ;; your regexes if you've changed this limit); we + ;; expect the compiler to optimize this T "test" + ;; away + ,@(substitute-char-class-tester t)) + ((and downcasedp min1 min2 min3) + ;; three different ranges, downcased + ,@(substitute-char-class-tester + `(let ((chr ,chr-expr)) + (or (char-not-greaterp min1 chr max1) + (char-not-greaterp min2 chr max2) + (char-not-greaterp min3 chr max3))))) + ((and downcasedp min1 min2) + ;; two ranges, downcased + ,@(substitute-char-class-tester + `(let ((chr ,chr-expr)) + (or (char-not-greaterp min1 chr max1) + (char-not-greaterp min2 chr max2))))) + ((and downcasedp min1) + ;; one downcased range + ,@(substitute-char-class-tester + `(char-not-greaterp min1 ,chr-expr max1))) + ((and min1 min2 min3) + ;; three ranges + ,@(substitute-char-class-tester + `(let ((chr ,chr-expr)) + (or (char<= min1 chr max1) + (char<= min2 chr max2) + (char<= min3 chr max3))))) + ((and min1 min2) + ;; two ranges + ,@(substitute-char-class-tester + `(let ((chr ,chr-expr)) + (or (char<= min1 chr max1) + (char<= min2 chr max2))))) + (min1 + ;; one range + ,@(substitute-char-class-tester + `(char<= min1 ,chr-expr max1))) + (t + ;; the general case; note that most of the above + ;; "optimizations" are based on experiences and + ;; benchmarks with CMUCL - if you're really + ;; concerned with speed you might find out that the + ;; general case is almost always the best one for + ;; other implementations (because the speed of their + ;; hash-table access in relation to other operations + ;; might be better than in CMUCL) + ,@(substitute-char-class-tester + `(gethash ,chr-expr hash))))))))) + +(defmethod create-matcher-aux ((char-class char-class) next-fn) + (declare #.*standard-optimize-settings*) + (declare (type function next-fn)) + ;; insert a test against the current character within *STRING* + (insert-char-class-tester (char-class (schar *string* start-pos)) + (if (invertedp char-class) + (lambda (start-pos) + (declare (type fixnum start-pos)) + (and (< start-pos *end-pos*) + (not (char-class-test)) + (funcall next-fn (1+ start-pos)))) + (lambda (start-pos) + (declare (type fixnum start-pos)) + (and (< start-pos *end-pos*) + (char-class-test) + (funcall next-fn (1+ start-pos))))))) + +(defmethod create-matcher-aux ((str str) next-fn) + (declare #.*standard-optimize-settings*) + (declare (type fixnum *end-string-pos*) + (type function next-fn) + ;; this special value is set by CREATE-SCANNER when the + ;; closures are built + (special end-string)) + (let* ((len (len str)) + (case-insensitive-p (case-insensitive-p str)) + (start-of-end-string-p (start-of-end-string-p str)) + (skip (skip str)) + (str (str str)) + (chr (schar str 0)) + (end-string (and end-string (str end-string))) + (end-string-len (if end-string + (length end-string) + nil))) + (declare (type fixnum len)) + (cond ((and start-of-end-string-p case-insensitive-p) + ;; closure for the first STR which belongs to the constant + ;; string at the end of the regular expression; + ;; case-insensitive version + (lambda (start-pos) + (declare (type fixnum start-pos end-string-len)) + (let ((test-end-pos (+ start-pos end-string-len))) + (declare (type fixnum test-end-pos)) + ;; either we're at *END-STRING-POS* (which means that + ;; it has already been confirmed that end-string + ;; starts here) or we really have to test + (and (or (= start-pos *end-string-pos*) + (and (<= test-end-pos *end-pos*) + (*string*-equal end-string start-pos test-end-pos + 0 end-string-len))) + (funcall next-fn (+ start-pos len)))))) + (start-of-end-string-p + ;; closure for the first STR which belongs to the constant + ;; string at the end of the regular expression; + ;; case-sensitive version + (lambda (start-pos) + (declare (type fixnum start-pos end-string-len)) + (let ((test-end-pos (+ start-pos end-string-len))) + (declare (type fixnum test-end-pos)) + ;; either we're at *END-STRING-POS* (which means that + ;; it has already been confirmed that end-string + ;; starts here) or we really have to test + (and (or (= start-pos *end-string-pos*) + (and (<= test-end-pos *end-pos*) + (*string*= end-string start-pos test-end-pos + 0 end-string-len))) + (funcall next-fn (+ start-pos len)))))) + (skip + ;; a STR which can be skipped because some other function + ;; has already confirmed that it matches + (lambda (start-pos) + (declare (type fixnum start-pos)) + (funcall next-fn (+ start-pos len)))) + ((and (= len 1) case-insensitive-p) + ;; STR represent exactly one character; case-insensitive + ;; version + (lambda (start-pos) + (declare (type fixnum start-pos)) + (and (< start-pos *end-pos*) + (char-equal (schar *string* start-pos) chr) + (funcall next-fn (1+ start-pos))))) + ((= len 1) + ;; STR represent exactly one character; case-sensitive + ;; version + (lambda (start-pos) + (declare (type fixnum start-pos)) + (and (< start-pos *end-pos*) + (char= (schar *string* start-pos) chr) + (funcall next-fn (1+ start-pos))))) + (case-insensitive-p + ;; general case, case-insensitive version + (lambda (start-pos) + (declare (type fixnum start-pos)) + (let ((next-pos (+ start-pos len))) + (declare (type fixnum next-pos)) + (and (<= next-pos *end-pos*) + (*string*-equal str start-pos next-pos 0 len) + (funcall next-fn next-pos))))) + (t + ;; general case, case-sensitive version + (lambda (start-pos) + (declare (type fixnum start-pos)) + (let ((next-pos (+ start-pos len))) + (declare (type fixnum next-pos)) + (and (<= next-pos *end-pos*) + (*string*= str start-pos next-pos 0 len) + (funcall next-fn next-pos)))))))) + +(declaim (inline word-boundary-p)) + +(defun word-boundary-p (start-pos) + "Check whether START-POS is a word-boundary within *STRING*." + (declare #.*standard-optimize-settings*) + (declare (type fixnum start-pos)) + (let ((1-start-pos (1- start-pos)) + (*start-pos* (or *real-start-pos* *start-pos*))) + ;; either the character before START-POS is a word-constituent and + ;; the character at START-POS isn't... + (or (and (or (= start-pos *end-pos*) + (and (< start-pos *end-pos*) + (not (word-char-p (schar *string* start-pos))))) + (and (< 1-start-pos *end-pos*) + (<= *start-pos* 1-start-pos) + (word-char-p (schar *string* 1-start-pos)))) + ;; ...or vice versa + (and (or (= start-pos *start-pos*) + (and (< 1-start-pos *end-pos*) + (<= *start-pos* 1-start-pos) + (not (word-char-p (schar *string* 1-start-pos))))) + (and (< start-pos *end-pos*) + (word-char-p (schar *string* start-pos))))))) + +(defmethod create-matcher-aux ((word-boundary word-boundary) next-fn) + (declare #.*standard-optimize-settings*) + (declare (type function next-fn)) + (if (negatedp word-boundary) + (lambda (start-pos) + (and (not (word-boundary-p start-pos)) + (funcall next-fn start-pos))) + (lambda (start-pos) + (and (word-boundary-p start-pos) + (funcall next-fn start-pos))))) + +(defmethod create-matcher-aux ((everything everything) next-fn) + (declare #.*standard-optimize-settings*) + (declare (type function next-fn)) + (if (single-line-p everything) + ;; closure for single-line-mode: we really match everything, so we + ;; just advance the index into *STRING* by one and carry on + (lambda (start-pos) + (declare (type fixnum start-pos)) + (and (< start-pos *end-pos*) + (funcall next-fn (1+ start-pos)))) + ;; not single-line-mode, so we have to make sure we don't match + ;; #\Newline + (lambda (start-pos) + (declare (type fixnum start-pos)) + (and (< start-pos *end-pos*) + (char/= (schar *string* start-pos) #\Newline) + (funcall next-fn (1+ start-pos)))))) + +(defmethod create-matcher-aux ((anchor anchor) next-fn) + (declare #.*standard-optimize-settings*) + (declare (type function next-fn)) + (let ((startp (startp anchor)) + (multi-line-p (multi-line-p anchor))) + (cond ((no-newline-p anchor) + ;; this must be an end-anchor and it must be modeless, so + ;; we just have to check whether START-POS equals + ;; *END-POS* + (lambda (start-pos) + (declare (type fixnum start-pos)) + (and (= start-pos *end-pos*) + (funcall next-fn start-pos)))) + ((and startp multi-line-p) + ;; a start-anchor in multi-line-mode: check if we're at + ;; *START-POS* or if the last character was #\Newline + (lambda (start-pos) + (declare (type fixnum start-pos)) + (let ((*start-pos* (or *real-start-pos* *start-pos*))) + (and (or (= start-pos *start-pos*) + (and (<= start-pos *end-pos*) + (> start-pos *start-pos*) + (char= #\Newline + (schar *string* (1- start-pos))))) + (funcall next-fn start-pos))))) + (startp + ;; a start-anchor which is not in multi-line-mode, so just + ;; check whether we're at *START-POS* + (lambda (start-pos) + (declare (type fixnum start-pos)) + (and (= start-pos (or *real-start-pos* *start-pos*)) + (funcall next-fn start-pos)))) + (multi-line-p + ;; an end-anchor in multi-line-mode: check if we're at + ;; *END-POS* or if the character we're looking at is + ;; #\Newline + (lambda (start-pos) + (declare (type fixnum start-pos)) + (and (or (= start-pos *end-pos*) + (and (< start-pos *end-pos*) + (char= #\Newline + (schar *string* start-pos)))) + (funcall next-fn start-pos)))) + (t + ;; an end-anchor which is not in multi-line-mode, so just + ;; check if we're at *END-POS* or if we're looking at + ;; #\Newline and there's nothing behind it + (lambda (start-pos) + (declare (type fixnum start-pos)) + (and (or (= start-pos *end-pos*) + (and (= start-pos (1- *end-pos*)) + (char= #\Newline + (schar *string* start-pos)))) + (funcall next-fn start-pos))))))) + +(defmethod create-matcher-aux ((back-reference back-reference) next-fn) + (declare #.*standard-optimize-settings*) + (declare (type function next-fn)) + ;; the position of the corresponding REGISTER within the whole + ;; regex; we start to count at 0 + (let ((num (num back-reference))) + (if (case-insensitive-p back-reference) + ;; the case-insensitive version + (lambda (start-pos) + (declare (type fixnum start-pos)) + (let ((reg-start (svref *reg-starts* num)) + (reg-end (svref *reg-ends* num))) + ;; only bother to check if the corresponding REGISTER as + ;; matched successfully already + (and reg-start + (let ((next-pos (+ start-pos (- (the fixnum reg-end) + (the fixnum reg-start))))) + (declare (type fixnum next-pos)) + (and + (<= next-pos *end-pos*) + (*string*-equal *string* start-pos next-pos + reg-start reg-end) + (funcall next-fn next-pos)))))) + ;; the case-sensitive version + (lambda (start-pos) + (declare (type fixnum start-pos)) + (let ((reg-start (svref *reg-starts* num)) + (reg-end (svref *reg-ends* num))) + ;; only bother to check if the corresponding REGISTER as + ;; matched successfully already + (and reg-start + (let ((next-pos (+ start-pos (- (the fixnum reg-end) + (the fixnum reg-start))))) + (declare (type fixnum next-pos)) + (and + (<= next-pos *end-pos*) + (*string*= *string* start-pos next-pos + reg-start reg-end) + (funcall next-fn next-pos))))))))) + +(defmethod create-matcher-aux ((branch branch) next-fn) + (declare #.*standard-optimize-settings*) + (let* ((test (test branch)) + (then-matcher (create-matcher-aux (then-regex branch) next-fn)) + (else-matcher (create-matcher-aux (else-regex branch) next-fn))) + (declare (type function then-matcher else-matcher)) + (cond ((numberp test) + (lambda (start-pos) + (declare (type fixnum test)) + (if (and (< test (length *reg-starts*)) + (svref *reg-starts* test)) + (funcall then-matcher start-pos) + (funcall else-matcher start-pos)))) + (t + (let ((test-matcher (create-matcher-aux test #'identity))) + (declare (type function test-matcher)) + (lambda (start-pos) + (if (funcall test-matcher start-pos) + (funcall then-matcher start-pos) + (funcall else-matcher start-pos)))))))) + +(defmethod create-matcher-aux ((standalone standalone) next-fn) + (declare #.*standard-optimize-settings*) + (let ((inner-matcher (create-matcher-aux (regex standalone) #'identity))) + (declare (type function next-fn inner-matcher)) + (lambda (start-pos) + (let ((next-pos (funcall inner-matcher start-pos))) + (and next-pos + (funcall next-fn next-pos)))))) + +(defmethod create-matcher-aux ((filter filter) next-fn) + (declare #.*standard-optimize-settings*) + (let ((fn (fn filter))) + (lambda (start-pos) + (let ((next-pos (funcall fn start-pos))) + (and next-pos + (funcall next-fn next-pos)))))) + +(defmethod create-matcher-aux ((void void) next-fn) + (declare #.*standard-optimize-settings*) + ;; optimize away VOIDs: don't create a closure, just return NEXT-FN + next-fn)
Added: branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/convert.lisp =================================================================== --- branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/convert.lisp 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/convert.lisp 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,811 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-PPCRE; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/cl-ppcre/convert.lisp,v 1.27 2007/06/04 19:22:08 edi Exp $ + +;;; Here the parse tree is converted into its internal representation +;;; using REGEX objects. At the same time some optimizations are +;;; already applied. + +;;; Copyright (c) 2002-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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-package #:cl-ppcre) + +;;; The flags that represent the "ism" modifiers are always kept +;;; together in a three-element list. We use the following macros to +;;; access individual elements. + +(defmacro case-insensitive-mode-p (flags) + "Accessor macro to extract the first flag out of a three-element flag list." + `(first ,flags)) + +(defmacro multi-line-mode-p (flags) + "Accessor macro to extract the second flag out of a three-element flag list." + `(second ,flags)) + +(defmacro single-line-mode-p (flags) + "Accessor macro to extract the third flag out of a three-element flag list." + `(third ,flags)) + +(defun set-flag (token) + (declare #.*standard-optimize-settings*) + (declare (special flags)) + "Reads a flag token and sets or unsets the corresponding entry in +the special FLAGS list." + (case token + ((:case-insensitive-p) + (setf (case-insensitive-mode-p flags) t)) + ((:case-sensitive-p) + (setf (case-insensitive-mode-p flags) nil)) + ((:multi-line-mode-p) + (setf (multi-line-mode-p flags) t)) + ((:not-multi-line-mode-p) + (setf (multi-line-mode-p flags) nil)) + ((:single-line-mode-p) + (setf (single-line-mode-p flags) t)) + ((:not-single-line-mode-p) + (setf (single-line-mode-p flags) nil)) + (otherwise + (signal-ppcre-syntax-error "Unknown flag token ~A" token)))) + +(defun add-range-to-hash (hash from to) + (declare #.*standard-optimize-settings*) + (declare (special flags)) + "Adds all characters from character FROM to character TO (inclusive) +to the char class hash HASH. Does the right thing with respect to +case-(in)sensitivity as specified by the special variable FLAGS." + (let ((from-code (char-code from)) + (to-code (char-code to))) + (when (> from-code to-code) + (signal-ppcre-syntax-error "Invalid range from ~A to ~A in char-class" + from to)) + (cond ((case-insensitive-mode-p flags) + (loop for code from from-code to to-code + for chr = (code-char code) + do (setf (gethash (char-upcase chr) hash) t + (gethash (char-downcase chr) hash) t))) + (t + (loop for code from from-code to to-code + do (setf (gethash (code-char code) hash) t)))) + hash)) + +(defun convert-char-class-to-hash (list) + (declare #.*standard-optimize-settings*) + "Combines all items in LIST into one char class hash and returns it. +Items can be single characters, character ranges like (:RANGE #\A +#\E), or special character classes like :DIGIT-CLASS. Does the right +thing with respect to case-(in)sensitivity as specified by the +special variable FLAGS." + (loop with hash = (make-hash-table :size (ceiling (expt *regex-char-code-limit* (/ 1 4))) + :rehash-size (float (expt *regex-char-code-limit* (/ 1 4))) + :rehash-threshold #-genera 1.0 #+genera 0.99) + for item in list + if (characterp item) + ;; treat a single character C like a range (:RANGE C C) + do (add-range-to-hash hash item item) + else if (symbolp item) + ;; special character classes + do (setq hash + (case item + ((:digit-class) + (merge-hash hash +digit-hash+)) + ((:non-digit-class) + (merge-inverted-hash hash +digit-hash+)) + ((:whitespace-char-class) + (merge-hash hash +whitespace-char-hash+)) + ((:non-whitespace-char-class) + (merge-inverted-hash hash +whitespace-char-hash+)) + ((:word-char-class) + (merge-hash hash +word-char-hash+)) + ((:non-word-char-class) + (merge-inverted-hash hash +word-char-hash+)) + (otherwise + (signal-ppcre-syntax-error + "Unknown symbol ~A in character class" + item)))) + else if (and (consp item) + (eq (car item) :range)) + ;; proper ranges + do (add-range-to-hash hash + (second item) + (third item)) + else do (signal-ppcre-syntax-error "Unknown item ~A in char-class list" + item) + finally (return hash))) + +(defun maybe-split-repetition (regex + greedyp + minimum + maximum + min-len + length + reg-seen) + (declare #.*standard-optimize-settings*) + (declare (type fixnum minimum) + (type (or fixnum null) maximum)) + "Splits a REPETITION object into a constant and a varying part if +applicable, i.e. something like + a{3,} -> a{3}a* +The arguments to this function correspond to the REPETITION slots of +the same name." + ;; note the usage of COPY-REGEX here; we can't use the same REGEX + ;; object in both REPETITIONS because they will have different + ;; offsets + (when maximum + (when (zerop maximum) + ;; trivial case: don't repeat at all + (return-from maybe-split-repetition + (make-instance 'void))) + (when (= 1 minimum maximum) + ;; another trivial case: "repeat" exactly once + (return-from maybe-split-repetition + regex))) + ;; first set up the constant part of the repetition + ;; maybe that's all we need + (let ((constant-repetition (if (plusp minimum) + (make-instance 'repetition + :regex (copy-regex regex) + :greedyp greedyp + :minimum minimum + :maximum minimum + :min-len min-len + :len length + :contains-register-p reg-seen) + ;; don't create garbage if minimum is 0 + nil))) + (when (and maximum + (= maximum minimum)) + (return-from maybe-split-repetition + ;; no varying part needed because min = max + constant-repetition)) + ;; now construct the varying part + (let ((varying-repetition + (make-instance 'repetition + :regex regex + :greedyp greedyp + :minimum 0 + :maximum (if maximum (- maximum minimum) nil) + :min-len min-len + :len length + :contains-register-p reg-seen))) + (cond ((zerop minimum) + ;; min = 0, no constant part needed + varying-repetition) + ((= 1 minimum) + ;; min = 1, constant part needs no REPETITION wrapped around + (make-instance 'seq + :elements (list (copy-regex regex) + varying-repetition))) + (t + ;; general case + (make-instance 'seq + :elements (list constant-repetition + varying-repetition))))))) + +;; During the conversion of the parse tree we keep track of the start +;; of the parse tree in the special variable STARTS-WITH which'll +;; either hold a STR object or an EVERYTHING object. The latter is the +;; case if the regex starts with ".*" which implicitly anchors the +;; regex at the start (perhaps modulo #\Newline). + +(defun maybe-accumulate (str) + (declare #.*standard-optimize-settings*) + (declare (special accumulate-start-p starts-with)) + (declare (ftype (function (t) fixnum) len)) + "Accumulate STR into the special variable STARTS-WITH if +ACCUMULATE-START-P (also special) is true and STARTS-WITH is either +NIL or a STR object of the same case mode. Always returns NIL." + (when accumulate-start-p + (etypecase starts-with + (str + ;; STARTS-WITH already holds a STR, so we check if we can + ;; concatenate + (cond ((eq (case-insensitive-p starts-with) + (case-insensitive-p str)) + ;; we modify STARTS-WITH in place + (setf (len starts-with) + (+ (len starts-with) (len str))) + ;; note that we use SLOT-VALUE because the accessor + ;; STR has a declared FTYPE which doesn't fit here + (adjust-array (slot-value starts-with 'str) + (len starts-with) + :fill-pointer t) + (setf (subseq (slot-value starts-with 'str) + (- (len starts-with) (len str))) + (str str) + ;; STR objects that are parts of STARTS-WITH + ;; always have their SKIP slot set to true + ;; because the SCAN function will take care of + ;; them, i.e. the matcher can ignore them + (skip str) t)) + (t (setq accumulate-start-p nil)))) + (null + ;; STARTS-WITH is still empty, so we create a new STR object + (setf starts-with + (make-instance 'str + :str "" + :case-insensitive-p (case-insensitive-p str)) + ;; INITIALIZE-INSTANCE will coerce the STR to a simple + ;; string, so we have to fill it afterwards + (slot-value starts-with 'str) + (make-array (len str) + :initial-contents (str str) + :element-type 'character + :fill-pointer t + :adjustable t) + (len starts-with) + (len str) + ;; see remark about SKIP above + (skip str) t)) + (everything + ;; STARTS-WITH already holds an EVERYTHING object - we can't + ;; concatenate + (setq accumulate-start-p nil)))) + nil) + +(defun convert-aux (parse-tree) + (declare #.*standard-optimize-settings*) + (declare (special flags reg-num reg-names accumulate-start-p starts-with max-back-ref)) + "Converts the parse tree PARSE-TREE into a REGEX object and returns it. + +Will also + - split and optimize repetitions, + - accumulate strings or EVERYTHING objects into the special variable + STARTS-WITH, + - keep track of all registers seen in the special variable REG-NUM, + - keep track of all named registers seen in the special variable REG-NAMES + - keep track of the highest backreference seen in the special + variable MAX-BACK-REF, + - maintain and adher to the currently applicable modifiers in the special + variable FLAGS, and + - maybe even wash your car..." + (cond ((consp parse-tree) + (case (first parse-tree) + ;; (:SEQUENCE {<regex>}*) + ((:sequence) + (cond ((cddr parse-tree) + ;; this is essentially like + ;; (MAPCAR 'CONVERT-AUX (REST PARSE-TREE)) + ;; but we don't cons a new list + (loop for parse-tree-rest on (rest parse-tree) + while parse-tree-rest + do (setf (car parse-tree-rest) + (convert-aux (car parse-tree-rest)))) + (make-instance 'seq + :elements (rest parse-tree))) + (t (convert-aux (second parse-tree))))) + ;; (:GROUP {<regex>}*) + ;; this is a syntactical construct equivalent to :SEQUENCE + ;; intended to keep the effect of modifiers local + ((:group) + ;; make a local copy of FLAGS and shadow the global + ;; value while we descend into the enclosed regexes + (let ((flags (copy-list flags))) + (declare (special flags)) + (cond ((cddr parse-tree) + (loop for parse-tree-rest on (rest parse-tree) + while parse-tree-rest + do (setf (car parse-tree-rest) + (convert-aux (car parse-tree-rest)))) + (make-instance 'seq + :elements (rest parse-tree))) + (t (convert-aux (second parse-tree)))))) + ;; (:ALTERNATION {<regex>}*) + ((:alternation) + ;; we must stop accumulating objects into STARTS-WITH + ;; once we reach an alternation + (setq accumulate-start-p nil) + (loop for parse-tree-rest on (rest parse-tree) + while parse-tree-rest + do (setf (car parse-tree-rest) + (convert-aux (car parse-tree-rest)))) + (make-instance 'alternation + :choices (rest parse-tree))) + ;; (:BRANCH <test> <regex>) + ;; <test> must be look-ahead, look-behind or number; + ;; if <regex> is an alternation it must have one or two + ;; choices + ((:branch) + (setq accumulate-start-p nil) + (let* ((test-candidate (second parse-tree)) + (test (cond ((numberp test-candidate) + (when (zerop (the fixnum test-candidate)) + (signal-ppcre-syntax-error + "Register 0 doesn't exist: ~S" + parse-tree)) + (1- (the fixnum test-candidate))) + (t (convert-aux test-candidate)))) + (alternations (convert-aux (third parse-tree)))) + (when (and (not (numberp test)) + (not (typep test 'lookahead)) + (not (typep test 'lookbehind))) + (signal-ppcre-syntax-error + "Branch test must be look-ahead, look-behind or number: ~S" + parse-tree)) + (typecase alternations + (alternation + (case (length (choices alternations)) + ((0) + (signal-ppcre-syntax-error "No choices in branch: ~S" + parse-tree)) + ((1) + (make-instance 'branch + :test test + :then-regex (first + (choices alternations)))) + ((2) + (make-instance 'branch + :test test + :then-regex (first + (choices alternations)) + :else-regex (second + (choices alternations)))) + (otherwise + (signal-ppcre-syntax-error + "Too much choices in branch: ~S" + parse-tree)))) + (t + (make-instance 'branch + :test test + :then-regex alternations))))) + ;; (:POSITIVE-LOOKAHEAD|:NEGATIVE-LOOKAHEAD <regex>) + ((:positive-lookahead :negative-lookahead) + ;; keep the effect of modifiers local to the enclosed + ;; regex and stop accumulating into STARTS-WITH + (setq accumulate-start-p nil) + (let ((flags (copy-list flags))) + (declare (special flags)) + (make-instance 'lookahead + :regex (convert-aux (second parse-tree)) + :positivep (eq (first parse-tree) + :positive-lookahead)))) + ;; (:POSITIVE-LOOKBEHIND|:NEGATIVE-LOOKBEHIND <regex>) + ((:positive-lookbehind :negative-lookbehind) + ;; keep the effect of modifiers local to the enclosed + ;; regex and stop accumulating into STARTS-WITH + (setq accumulate-start-p nil) + (let* ((flags (copy-list flags)) + (regex (convert-aux (second parse-tree))) + (len (regex-length regex))) + (declare (special flags)) + ;; lookbehind assertions must be of fixed length + (unless len + (signal-ppcre-syntax-error + "Variable length look-behind not implemented (yet): ~S" + parse-tree)) + (make-instance 'lookbehind + :regex regex + :positivep (eq (first parse-tree) + :positive-lookbehind) + :len len))) + ;; (:GREEDY-REPETITION|:NON-GREEDY-REPETITION <min> <max> <regex>) + ((:greedy-repetition :non-greedy-repetition) + ;; remember the value of ACCUMULATE-START-P upon entering + (let ((local-accumulate-start-p accumulate-start-p)) + (let ((minimum (second parse-tree)) + (maximum (third parse-tree))) + (declare (type fixnum minimum)) + (declare (type (or null fixnum) maximum)) + (unless (and maximum + (= 1 minimum maximum)) + ;; set ACCUMULATE-START-P to NIL for the rest of + ;; the conversion because we can't continue to + ;; accumulate inside as well as after a proper + ;; repetition + (setq accumulate-start-p nil)) + (let* (reg-seen + (regex (convert-aux (fourth parse-tree))) + (min-len (regex-min-length regex)) + (greedyp (eq (first parse-tree) :greedy-repetition)) + (length (regex-length regex))) + ;; note that this declaration already applies to + ;; the call to CONVERT-AUX above + (declare (special reg-seen)) + (when (and local-accumulate-start-p + (not starts-with) + (zerop minimum) + (not maximum)) + ;; if this repetition is (equivalent to) ".*" + ;; and if we're at the start of the regex we + ;; remember it for ADVANCE-FN (see the SCAN + ;; function) + (setq starts-with (everythingp regex))) + (if (or (not reg-seen) + (not greedyp) + (not length) + (zerop length) + (and maximum (= minimum maximum))) + ;; the repetition doesn't enclose a register, or + ;; it's not greedy, or we can't determine it's + ;; (inner) length, or the length is zero, or the + ;; number of repetitions is fixed; in all of + ;; these cases we don't bother to optimize + (maybe-split-repetition regex + greedyp + minimum + maximum + min-len + length + reg-seen) + ;; otherwise we make a transformation that looks + ;; roughly like one of + ;; <regex>* -> (?:<regex'>*<regex>)? + ;; <regex>+ -> <regex'>*<regex> + ;; where the trick is that as much as possible + ;; registers from <regex> are removed in + ;; <regex'> + (let* (reg-seen ; new instance for REMOVE-REGISTERS + (remove-registers-p t) + (inner-regex (remove-registers regex)) + (inner-repetition + ;; this is the "<regex'>" part + (maybe-split-repetition inner-regex + ;; always greedy + t + ;; reduce minimum by 1 + ;; unless it's already 0 + (if (zerop minimum) + 0 + (1- minimum)) + ;; reduce maximum by 1 + ;; unless it's NIL + (and maximum + (1- maximum)) + min-len + length + reg-seen)) + (inner-seq + ;; this is the "<regex'>*<regex>" part + (make-instance 'seq + :elements (list inner-repetition + regex)))) + ;; note that this declaration already applies + ;; to the call to REMOVE-REGISTERS above + (declare (special remove-registers-p reg-seen)) + ;; wrap INNER-SEQ with a greedy + ;; {0,1}-repetition (i.e. "?") if necessary + (if (plusp minimum) + inner-seq + (maybe-split-repetition inner-seq + t + 0 + 1 + min-len + nil + t)))))))) + ;; (:REGISTER <regex>) + ;; (:NAMED-REGISTER <name> <regex>) + ((:register :named-register) + ;; keep the effect of modifiers local to the enclosed + ;; regex; also, assign the current value of REG-NUM to + ;; the corresponding slot of the REGISTER object and + ;; increase this counter afterwards; for named register + ;; update REG-NAMES and set the corresponding name slot + ;; of the REGISTER object too + (let ((flags (copy-list flags)) + (stored-reg-num reg-num) + (reg-name (when (eq (first parse-tree) :named-register) + (copy-seq (second parse-tree))))) + (declare (special flags reg-seen named-reg-seen)) + (setq reg-seen t) + (when reg-name + (setq named-reg-seen t)) + (incf (the fixnum reg-num)) + (push reg-name + reg-names) + (make-instance 'register + :regex (convert-aux (if (eq (first parse-tree) :named-register) + (third parse-tree) + (second parse-tree))) + :num stored-reg-num + :name reg-name))) + ;; (:FILTER <function> &optional <length>) + ((:filter) + ;; stop accumulating into STARTS-WITH + (setq accumulate-start-p nil) + (make-instance 'filter + :fn (second parse-tree) + :len (third parse-tree))) + ;; (:STANDALONE <regex>) + ((:standalone) + ;; stop accumulating into STARTS-WITH + (setq accumulate-start-p nil) + ;; keep the effect of modifiers local to the enclosed + ;; regex + (let ((flags (copy-list flags))) + (declare (special flags)) + (make-instance 'standalone + :regex (convert-aux (second parse-tree))))) + ;; (:BACK-REFERENCE <number>) + ;; (:BACK-REFERENCE <name>) + ((:back-reference) + (locally (declare (special reg-names reg-num)) + (let* ((backref-name (and (stringp (second parse-tree)) + (second parse-tree))) + (referred-regs + (when backref-name + ;; find which register corresponds to the given name + ;; we have to deal with case where several registers share + ;; the same name and collect their respective numbers + (loop + for name in reg-names + for reg-index from 0 + when (string= name backref-name) + ;; NOTE: REG-NAMES stores register names in reversed order + ;; REG-NUM contains number of (any) registers seen so far + ;; 1- will be done later + collect (- reg-num reg-index)))) + ;; store the register number for the simple case + (backref-number (or (first referred-regs) + (second parse-tree)))) + (declare (type (or fixnum null) backref-number)) + (when (or (not (typep backref-number 'fixnum)) + (<= backref-number 0)) + (signal-ppcre-syntax-error + "Illegal back-reference: ~S" + parse-tree)) + ;; stop accumulating into STARTS-WITH and increase + ;; MAX-BACK-REF if necessary + (setq accumulate-start-p nil + max-back-ref (max (the fixnum max-back-ref) + backref-number)) + (flet ((make-back-ref (backref-number) + (make-instance 'back-reference + ;; we start counting from 0 internally + :num (1- backref-number) + :case-insensitive-p (case-insensitive-mode-p flags) + ;; backref-name is NIL or string, safe to copy + :name (copy-seq backref-name)))) + (cond + ((cdr referred-regs) + ;; several registers share the same name + ;; we will try to match any of them, starting + ;; with the most recent first + ;; alternation is used to accomplish matching + (make-instance 'alternation + :choices (loop + for reg-index in referred-regs + collect (make-back-ref reg-index)))) + ;; simple case - backref corresponds to only one register + (t + (make-back-ref backref-number))))))) + ;; (:REGEX <string>) + ((:regex) + (let ((regex (second parse-tree))) + (convert-aux (parse-string regex)))) + ;; (:CHAR-CLASS|:INVERTED-CHAR-CLASS {<item>}*) + ;; where item is one of + ;; - a character + ;; - a character range: (:RANGE <char1> <char2>) + ;; - a special char class symbol like :DIGIT-CHAR-CLASS + ((:char-class :inverted-char-class) + ;; first create the hash-table and some auxiliary values + (let* (hash + hash-keys + (count most-positive-fixnum) + (item-list (rest parse-tree)) + (invertedp (eq (first parse-tree) :inverted-char-class)) + word-char-class-p) + (cond ((every (lambda (item) (eq item :word-char-class)) + item-list) + ;; treat "[\w]" like "\w" + (setq word-char-class-p t)) + ((every (lambda (item) (eq item :non-word-char-class)) + item-list) + ;; treat "[\W]" like "\W" + (setq word-char-class-p t) + (setq invertedp (not invertedp))) + (t + (setq hash (convert-char-class-to-hash item-list) + count (hash-table-count hash)) + (when (<= count 2) + ;; collect the hash-table keys into a list if + ;; COUNT is smaller than 3 + (setq hash-keys + (loop for chr being the hash-keys of hash + collect chr))))) + (cond ((and (not invertedp) + (= count 1)) + ;; convert one-element hash table into a STR + ;; object and try to accumulate into + ;; STARTS-WITH + (let ((str (make-instance 'str + :str (string + (first hash-keys)) + :case-insensitive-p nil))) + (maybe-accumulate str) + str)) + ((and (not invertedp) + (= count 2) + (char-equal (first hash-keys) (second hash-keys))) + ;; convert two-element hash table into a + ;; case-insensitive STR object and try to + ;; accumulate into STARTS-WITH if the two + ;; characters are CHAR-EQUAL + (let ((str (make-instance 'str + :str (string + (first hash-keys)) + :case-insensitive-p t))) + (maybe-accumulate str) + str)) + (t + ;; the general case; stop accumulating into STARTS-WITH + (setq accumulate-start-p nil) + (make-instance 'char-class + :hash hash + :case-insensitive-p + (case-insensitive-mode-p flags) + :invertedp invertedp + :word-char-class-p word-char-class-p))))) + ;; (:FLAGS {<flag>}*) + ;; where flag is a modifier symbol like :CASE-INSENSITIVE-P + ((:flags) + ;; set/unset the flags corresponding to the symbols + ;; following :FLAGS + (mapc #'set-flag (rest parse-tree)) + ;; we're only interested in the side effect of + ;; setting/unsetting the flags and turn this syntactical + ;; construct into a VOID object which'll be optimized + ;; away when creating the matcher + (make-instance 'void)) + (otherwise + (signal-ppcre-syntax-error + "Unknown token ~A in parse-tree" + (first parse-tree))))) + ((or (characterp parse-tree) (stringp parse-tree)) + ;; turn characters or strings into STR objects and try to + ;; accumulate into STARTS-WITH + (let ((str (make-instance 'str + :str (string parse-tree) + :case-insensitive-p + (case-insensitive-mode-p flags)))) + (maybe-accumulate str) + str)) + (t + ;; and now for the tokens which are symbols + (case parse-tree + ((:void) + (make-instance 'void)) + ((:word-boundary) + (make-instance 'word-boundary :negatedp nil)) + ((:non-word-boundary) + (make-instance 'word-boundary :negatedp t)) + ;; the special character classes + ((:digit-class + :non-digit-class + :word-char-class + :non-word-char-class + :whitespace-char-class + :non-whitespace-char-class) + ;; stop accumulating into STARTS-WITH + (setq accumulate-start-p nil) + (make-instance 'char-class + ;; use the constants defined in util.lisp + :hash (case parse-tree + ((:digit-class + :non-digit-class) + +digit-hash+) + ((:word-char-class + :non-word-char-class) + nil) + ((:whitespace-char-class + :non-whitespace-char-class) + +whitespace-char-hash+)) + ;; this value doesn't really matter but + ;; NIL should result in slightly faster + ;; matchers + :case-insensitive-p nil + :invertedp (member parse-tree + '(:non-digit-class + :non-word-char-class + :non-whitespace-char-class) + :test #'eq) + :word-char-class-p (member parse-tree + '(:word-char-class + :non-word-char-class) + :test #'eq))) + ((:start-anchor ; Perl's "^" + :end-anchor ; Perl's "$" + :modeless-end-anchor-no-newline + ; Perl's "\z" + :modeless-start-anchor ; Perl's "\A" + :modeless-end-anchor) ; Perl's "\Z" + (make-instance 'anchor + :startp (member parse-tree + '(:start-anchor + :modeless-start-anchor) + :test #'eq) + ;; set this value according to the + ;; current settings of FLAGS (unless it's + ;; a modeless anchor) + :multi-line-p + (and (multi-line-mode-p flags) + (not (member parse-tree + '(:modeless-start-anchor + :modeless-end-anchor + :modeless-end-anchor-no-newline) + :test #'eq))) + :no-newline-p + (eq parse-tree + :modeless-end-anchor-no-newline))) + ((:everything) + ;; stop accumulating into STARTS-WITHS + (setq accumulate-start-p nil) + (make-instance 'everything + :single-line-p (single-line-mode-p flags))) + ;; special tokens corresponding to Perl's "ism" modifiers + ((:case-insensitive-p + :case-sensitive-p + :multi-line-mode-p + :not-multi-line-mode-p + :single-line-mode-p + :not-single-line-mode-p) + ;; we're only interested in the side effect of + ;; setting/unsetting the flags and turn these tokens + ;; into VOID objects which'll be optimized away when + ;; creating the matcher + (set-flag parse-tree) + (make-instance 'void)) + (otherwise + (let ((translation (and (symbolp parse-tree) + (parse-tree-synonym parse-tree)))) + (if translation + (convert-aux (copy-tree translation)) + (signal-ppcre-syntax-error "Unknown token ~A in parse-tree" + parse-tree)))))))) + +(defun convert (parse-tree) + (declare #.*standard-optimize-settings*) + "Converts the parse tree PARSE-TREE into an equivalent REGEX object +and returns three values: the REGEX object, the number of registers +seen and an object the regex starts with which is either a STR object +or an EVERYTHING object (if the regex starts with something like +".*") or NIL." + ;; this function basically just initializes the special variables + ;; and then calls CONVERT-AUX to do all the work + (let* ((flags (list nil nil nil)) + (reg-num 0) + reg-names + named-reg-seen + (accumulate-start-p t) + starts-with + (max-back-ref 0) + (converted-parse-tree (convert-aux parse-tree))) + (declare (special flags reg-num reg-names named-reg-seen + accumulate-start-p starts-with max-back-ref)) + ;; make sure we don't reference registers which aren't there + (when (> (the fixnum max-back-ref) + (the fixnum reg-num)) + (signal-ppcre-syntax-error + "Backreference to register ~A which has not been defined" + max-back-ref)) + (when (typep starts-with 'str) + (setf (slot-value starts-with 'str) + (coerce (slot-value starts-with 'str) 'simple-string))) + (values converted-parse-tree reg-num starts-with + ;; we can't simply use *ALLOW-NAMED-REGISTERS* + ;; since parse-tree syntax ignores it + (when named-reg-seen + (nreverse reg-names)))))
Added: branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/doc/benchmarks.2002-12-22.txt =================================================================== --- branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/doc/benchmarks.2002-12-22.txt 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/doc/benchmarks.2002-12-22.txt 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,1546 @@ + 1: 0.2862 (100000 repetitions, Perl: 0.2097 seconds, CL-PPCRE: 0.0600 seconds) + 2: 0.4161 (1000000 repetitions, Perl: 0.7690 seconds, CL-PPCRE: 0.3200 seconds) + 3: 0.3939 (100000 repetitions, Perl: 0.2031 seconds, CL-PPCRE: 0.0800 seconds) + 4: 0.4639 (1000000 repetitions, Perl: 0.7976 seconds, CL-PPCRE: 0.3700 seconds) + 5: 0.4400 (100000 repetitions, Perl: 0.1591 seconds, CL-PPCRE: 0.0700 seconds) + 6: 0.5106 (100000 repetitions, Perl: 0.1567 seconds, CL-PPCRE: 0.0800 seconds) + 7: 0.4928 (100000 repetitions, Perl: 0.1826 seconds, CL-PPCRE: 0.0900 seconds) + 8: 0.5934 (100000 repetitions, Perl: 0.1854 seconds, CL-PPCRE: 0.1100 seconds) + 9: 0.3450 (100000 repetitions, Perl: 0.2029 seconds, CL-PPCRE: 0.0700 seconds) + 10: 0.5261 (100000 repetitions, Perl: 0.3231 seconds, CL-PPCRE: 0.1700 seconds) + 11: 0.5556 (100000 repetitions, Perl: 0.3240 seconds, CL-PPCRE: 0.1800 seconds) + 12: 0.5490 (100000 repetitions, Perl: 0.3279 seconds, CL-PPCRE: 0.1800 seconds) + 13: 0.5595 (100000 repetitions, Perl: 0.3217 seconds, CL-PPCRE: 0.1800 seconds) + 14: 0.5917 (100000 repetitions, Perl: 0.3211 seconds, CL-PPCRE: 0.1900 seconds) + 15: 0.5164 (100000 repetitions, Perl: 0.3292 seconds, CL-PPCRE: 0.1700 seconds) + 16: 0.5552 (100000 repetitions, Perl: 0.3242 seconds, CL-PPCRE: 0.1800 seconds) + 17: 0.5273 (100000 repetitions, Perl: 0.3224 seconds, CL-PPCRE: 0.1700 seconds) + 18: 0.5886 (100000 repetitions, Perl: 0.3228 seconds, CL-PPCRE: 0.1900 seconds) + 19: 0.5524 (100000 repetitions, Perl: 0.3259 seconds, CL-PPCRE: 0.1800 seconds) + 20: 0.5860 (100000 repetitions, Perl: 0.3242 seconds, CL-PPCRE: 0.1900 seconds) + 21: 0.5569 (100000 repetitions, Perl: 0.3232 seconds, CL-PPCRE: 0.1800 seconds) + 22: 0.6129 (100000 repetitions, Perl: 0.3263 seconds, CL-PPCRE: 0.2000 seconds) + 23: 0.5789 (100000 repetitions, Perl: 0.3282 seconds, CL-PPCRE: 0.1900 seconds) + 24: 0.5516 (100000 repetitions, Perl: 0.3263 seconds, CL-PPCRE: 0.1800 seconds) + 25: 0.4861 (100000 repetitions, Perl: 0.3291 seconds, CL-PPCRE: 0.1600 seconds) + 26: 0.4879 (100000 repetitions, Perl: 0.3279 seconds, CL-PPCRE: 0.1600 seconds) + 27: 0.4929 (100000 repetitions, Perl: 0.3246 seconds, CL-PPCRE: 0.1600 seconds) + 28: 0.5633 (100000 repetitions, Perl: 0.3195 seconds, CL-PPCRE: 0.1800 seconds) + 29: 0.4901 (100000 repetitions, Perl: 0.3264 seconds, CL-PPCRE: 0.1600 seconds) + 30: 0.5145 (100000 repetitions, Perl: 0.3304 seconds, CL-PPCRE: 0.1700 seconds) + 31: 0.5286 (100000 repetitions, Perl: 0.3216 seconds, CL-PPCRE: 0.1700 seconds) + 32: 0.5306 (100000 repetitions, Perl: 0.3204 seconds, CL-PPCRE: 0.1700 seconds) + 33: 0.5213 (100000 repetitions, Perl: 0.3261 seconds, CL-PPCRE: 0.1700 seconds) + 34: 0.5221 (100000 repetitions, Perl: 0.3256 seconds, CL-PPCRE: 0.1700 seconds) + 35: 0.5858 (100000 repetitions, Perl: 0.3243 seconds, CL-PPCRE: 0.1900 seconds) + 36: 0.5556 (100000 repetitions, Perl: 0.3240 seconds, CL-PPCRE: 0.1800 seconds) + 37: 0.6985 (100000 repetitions, Perl: 0.3293 seconds, CL-PPCRE: 0.2300 seconds) + 38: 0.5760 (100000 repetitions, Perl: 0.3299 seconds, CL-PPCRE: 0.1900 seconds) + 39: 0.6964 (100000 repetitions, Perl: 0.3303 seconds, CL-PPCRE: 0.2300 seconds) + 40: 1.2660 (1000000 repetitions, Perl: 0.7662 seconds, CL-PPCRE: 0.9700 seconds) + 41: 1.5983 (1000000 repetitions, Perl: 0.8509 seconds, CL-PPCRE: 1.3600 seconds) + 42: 1.3381 (1000000 repetitions, Perl: 0.7697 seconds, CL-PPCRE: 1.0300 seconds) + 43: 1.0846 (100000 repetitions, Perl: 0.7284 seconds, CL-PPCRE: 0.7900 seconds) + 44: 0.9248 (100000 repetitions, Perl: 0.7029 seconds, CL-PPCRE: 0.6500 seconds) + 45: 0.9872 (100000 repetitions, Perl: 0.6281 seconds, CL-PPCRE: 0.6200 seconds) + 46: 0.4932 (100000 repetitions, Perl: 0.1622 seconds, CL-PPCRE: 0.0800 seconds) + 47: 0.5567 (100000 repetitions, Perl: 0.1617 seconds, CL-PPCRE: 0.0900 seconds) + 48: 0.7445 (1000000 repetitions, Perl: 0.6179 seconds, CL-PPCRE: 0.4600 seconds) + 49: 1.4152 (1000000 repetitions, Perl: 0.8055 seconds, CL-PPCRE: 1.1400 seconds) + 50: 0.6042 (100000 repetitions, Perl: 0.1324 seconds, CL-PPCRE: 0.0800 seconds) + 51: 0.3376 (100000 repetitions, Perl: 0.2370 seconds, CL-PPCRE: 0.0800 seconds) + 52: 0.3549 (100000 repetitions, Perl: 0.3099 seconds, CL-PPCRE: 0.1100 seconds) + 53: 0.3404 (100000 repetitions, Perl: 0.3525 seconds, CL-PPCRE: 0.1200 seconds) + 54: 0.3398 (100000 repetitions, Perl: 0.3237 seconds, CL-PPCRE: 0.1100 seconds) + 55: 0.3516 (100000 repetitions, Perl: 0.4551 seconds, CL-PPCRE: 0.1600 seconds) + 56: 0.3069 (100000 repetitions, Perl: 0.3258 seconds, CL-PPCRE: 0.1000 seconds) + 57: 0.3032 (100000 repetitions, Perl: 0.6925 seconds, CL-PPCRE: 0.2100 seconds) + 58: 0.3515 (10000 repetitions, Perl: 0.3130 seconds, CL-PPCRE: 0.1100 seconds) + 59: 0.3563 (100000 repetitions, Perl: 0.3088 seconds, CL-PPCRE: 0.1100 seconds) + 60: 0.3429 (100000 repetitions, Perl: 0.6708 seconds, CL-PPCRE: 0.2300 seconds) + 61: 0.3169 (100000 repetitions, Perl: 0.2840 seconds, CL-PPCRE: 0.0900 seconds) + 62: 0.3519 (100000 repetitions, Perl: 0.2842 seconds, CL-PPCRE: 0.1000 seconds) + 63: 0.3443 (100000 repetitions, Perl: 0.2904 seconds, CL-PPCRE: 0.1000 seconds) + 64: 0.3917 (100000 repetitions, Perl: 0.2808 seconds, CL-PPCRE: 0.1100 seconds) + 65: 0.3474 (100000 repetitions, Perl: 0.2878 seconds, CL-PPCRE: 0.1000 seconds) + 66: 0.3473 (100000 repetitions, Perl: 0.2879 seconds, CL-PPCRE: 0.1000 seconds) + 67: 0.4047 (100000 repetitions, Perl: 0.2965 seconds, CL-PPCRE: 0.1200 seconds) + 68: 0.4057 (100000 repetitions, Perl: 0.2958 seconds, CL-PPCRE: 0.1200 seconds) + 69: 0.4091 (100000 repetitions, Perl: 0.2689 seconds, CL-PPCRE: 0.1100 seconds) + 70: 0.4841 (100000 repetitions, Perl: 0.4751 seconds, CL-PPCRE: 0.2300 seconds) + 71: 0.2327 (100000 repetitions, Perl: 0.3438 seconds, CL-PPCRE: 0.0800 seconds) + 72: 0.4767 (100000 repetitions, Perl: 0.3986 seconds, CL-PPCRE: 0.1900 seconds) + 73: 0.3673 (100000 repetitions, Perl: 0.5174 seconds, CL-PPCRE: 0.1900 seconds) + 74: 0.5311 (100000 repetitions, Perl: 0.5460 seconds, CL-PPCRE: 0.2900 seconds) + 75: 0.5722 (100000 repetitions, Perl: 0.5068 seconds, CL-PPCRE: 0.2900 seconds) + 76: 0.5913 (100000 repetitions, Perl: 0.5074 seconds, CL-PPCRE: 0.3000 seconds) + 77: 0.3544 (100000 repetitions, Perl: 0.2257 seconds, CL-PPCRE: 0.0800 seconds) + 78: 0.3919 (100000 repetitions, Perl: 0.4593 seconds, CL-PPCRE: 0.1800 seconds) + 79: 0.4080 (100000 repetitions, Perl: 0.2941 seconds, CL-PPCRE: 0.1200 seconds) + 80: 0.5635 (100000 repetitions, Perl: 0.5147 seconds, CL-PPCRE: 0.2900 seconds) + 81: 0.5616 (100000 repetitions, Perl: 0.5163 seconds, CL-PPCRE: 0.2900 seconds) + 82: 0.4216 (100000 repetitions, Perl: 0.1423 seconds, CL-PPCRE: 0.0600 seconds) + 83: 0.2502 (100000 repetitions, Perl: 0.1199 seconds, CL-PPCRE: 0.0300 seconds) + 84: 0.2546 (100000 repetitions, Perl: 0.1178 seconds, CL-PPCRE: 0.0300 seconds) + 85: 0.2515 (100000 repetitions, Perl: 0.1193 seconds, CL-PPCRE: 0.0300 seconds) + 86: 0.2545 (100000 repetitions, Perl: 0.1179 seconds, CL-PPCRE: 0.0300 seconds) + 87: 0.2535 (100000 repetitions, Perl: 0.1184 seconds, CL-PPCRE: 0.0300 seconds) + 88: 0.2522 (100000 repetitions, Perl: 0.1189 seconds, CL-PPCRE: 0.0300 seconds) + 89: 0.3010 (1000000 repetitions, Perl: 0.8971 seconds, CL-PPCRE: 0.2700 seconds) + 90: 0.2906 (1000000 repetitions, Perl: 0.8947 seconds, CL-PPCRE: 0.2600 seconds) + 91: 0.2800 (1000000 repetitions, Perl: 0.8928 seconds, CL-PPCRE: 0.2500 seconds) + 92: 0.3329 (100000 repetitions, Perl: 0.1202 seconds, CL-PPCRE: 0.0400 seconds) + 93: 0.3394 (100000 repetitions, Perl: 0.1178 seconds, CL-PPCRE: 0.0400 seconds) + 94: 0.2516 (100000 repetitions, Perl: 0.1193 seconds, CL-PPCRE: 0.0300 seconds) + 95: 0.3393 (100000 repetitions, Perl: 0.1179 seconds, CL-PPCRE: 0.0400 seconds) + 96: 0.2891 (1000000 repetitions, Perl: 0.8994 seconds, CL-PPCRE: 0.2600 seconds) + 97: 0.3026 (1000000 repetitions, Perl: 0.8922 seconds, CL-PPCRE: 0.2700 seconds) + 98: 0.2508 (100000 repetitions, Perl: 0.1196 seconds, CL-PPCRE: 0.0300 seconds) + 99: 0.2546 (100000 repetitions, Perl: 0.1178 seconds, CL-PPCRE: 0.0300 seconds) + 100: 0.2493 (100000 repetitions, Perl: 0.1204 seconds, CL-PPCRE: 0.0300 seconds) + 101: 0.3002 (1000000 repetitions, Perl: 0.8994 seconds, CL-PPCRE: 0.2700 seconds) + 102: 0.2904 (1000000 repetitions, Perl: 0.8954 seconds, CL-PPCRE: 0.2600 seconds) + 103: 0.2904 (1000000 repetitions, Perl: 0.8952 seconds, CL-PPCRE: 0.2600 seconds) + 104: 0.2976 (1000000 repetitions, Perl: 0.9073 seconds, CL-PPCRE: 0.2700 seconds) + 105: 0.2999 (1000000 repetitions, Perl: 0.9004 seconds, CL-PPCRE: 0.2700 seconds) + 106: 0.2885 (1000000 repetitions, Perl: 0.9012 seconds, CL-PPCRE: 0.2600 seconds) + 107: 0.2505 (100000 repetitions, Perl: 0.1198 seconds, CL-PPCRE: 0.0300 seconds) + 108: 0.3368 (100000 repetitions, Perl: 0.1188 seconds, CL-PPCRE: 0.0400 seconds) + 109: 0.3018 (1000000 repetitions, Perl: 0.8945 seconds, CL-PPCRE: 0.2700 seconds) + 110: 0.2893 (1000000 repetitions, Perl: 0.8988 seconds, CL-PPCRE: 0.2600 seconds) + 111: 0.3013 (1000000 repetitions, Perl: 0.8963 seconds, CL-PPCRE: 0.2700 seconds) + 112: 0.2876 (1000000 repetitions, Perl: 0.9039 seconds, CL-PPCRE: 0.2600 seconds) + 113: 0.4585 (100000 repetitions, Perl: 0.1309 seconds, CL-PPCRE: 0.0600 seconds) + 114: 0.3816 (100000 repetitions, Perl: 0.1310 seconds, CL-PPCRE: 0.0500 seconds) + 115: 0.2148 (100000 repetitions, Perl: 0.1397 seconds, CL-PPCRE: 0.0300 seconds) + 116: 0.2182 (100000 repetitions, Perl: 0.1375 seconds, CL-PPCRE: 0.0300 seconds) + 117: 0.2147 (100000 repetitions, Perl: 0.1397 seconds, CL-PPCRE: 0.0300 seconds) + 118: 0.2154 (100000 repetitions, Perl: 0.1393 seconds, CL-PPCRE: 0.0300 seconds) + 119: 0.2180 (100000 repetitions, Perl: 0.1376 seconds, CL-PPCRE: 0.0300 seconds) + 120: 0.2171 (100000 repetitions, Perl: 0.1382 seconds, CL-PPCRE: 0.0300 seconds) + 121: 0.2145 (100000 repetitions, Perl: 0.1398 seconds, CL-PPCRE: 0.0300 seconds) + 122: 0.2184 (100000 repetitions, Perl: 0.1374 seconds, CL-PPCRE: 0.0300 seconds) + 123: 0.2172 (100000 repetitions, Perl: 0.1381 seconds, CL-PPCRE: 0.0300 seconds) + 124: 0.2124 (100000 repetitions, Perl: 0.1412 seconds, CL-PPCRE: 0.0300 seconds) + 125: 0.2146 (100000 repetitions, Perl: 0.1398 seconds, CL-PPCRE: 0.0300 seconds) + 126: 0.2834 (100000 repetitions, Perl: 0.1412 seconds, CL-PPCRE: 0.0400 seconds) + 127: 0.2649 (1000000 repetitions, Perl: 0.9439 seconds, CL-PPCRE: 0.2500 seconds) + 128: 0.3613 (100000 repetitions, Perl: 0.1384 seconds, CL-PPCRE: 0.0500 seconds) + 129: 0.2925 (100000 repetitions, Perl: 0.1367 seconds, CL-PPCRE: 0.0400 seconds) + 130: 0.2868 (100000 repetitions, Perl: 0.1394 seconds, CL-PPCRE: 0.0400 seconds) + 131: 0.3982 (100000 repetitions, Perl: 0.1758 seconds, CL-PPCRE: 0.0700 seconds) + 132: 0.3910 (100000 repetitions, Perl: 0.1790 seconds, CL-PPCRE: 0.0700 seconds) + 133: 0.4550 (1000000 repetitions, Perl: 0.6154 seconds, CL-PPCRE: 0.2800 seconds) + 134: 0.2943 (100000 repetitions, Perl: 0.1699 seconds, CL-PPCRE: 0.0500 seconds) + 135: 0.2965 (100000 repetitions, Perl: 0.1686 seconds, CL-PPCRE: 0.0500 seconds) + 136: 0.2959 (100000 repetitions, Perl: 0.1690 seconds, CL-PPCRE: 0.0500 seconds) + 137: 0.3398 (1000000 repetitions, Perl: 0.6180 seconds, CL-PPCRE: 0.2100 seconds) + 138: 0.2963 (100000 repetitions, Perl: 0.1687 seconds, CL-PPCRE: 0.0500 seconds) + 139: 0.3538 (100000 repetitions, Perl: 0.1413 seconds, CL-PPCRE: 0.0500 seconds) + 140: 0.3339 (100000 repetitions, Perl: 0.1498 seconds, CL-PPCRE: 0.0500 seconds) + 141: 0.3863 (100000 repetitions, Perl: 0.1812 seconds, CL-PPCRE: 0.0700 seconds) + 142: 0.3245 (1000000 repetitions, Perl: 0.6163 seconds, CL-PPCRE: 0.2000 seconds) + 143: 0.3688 (100000 repetitions, Perl: 0.1627 seconds, CL-PPCRE: 0.0600 seconds) + 144: 0.3063 (100000 repetitions, Perl: 0.4571 seconds, CL-PPCRE: 0.1400 seconds) + 145: 0.7234 (100000 repetitions, Perl: 0.1244 seconds, CL-PPCRE: 0.0900 seconds) + 146: 0.2700 (100000 repetitions, Perl: 0.4074 seconds, CL-PPCRE: 0.1100 seconds) + 147: 0.8323 (1000000 repetitions, Perl: 0.8771 seconds, CL-PPCRE: 0.7300 seconds) + 148: 0.6980 (1000000 repetitions, Perl: 0.7880 seconds, CL-PPCRE: 0.5500 seconds) + 149: 0.4197 (100000 repetitions, Perl: 0.1668 seconds, CL-PPCRE: 0.0700 seconds) + 150: 0.5716 (1000000 repetitions, Perl: 0.8223 seconds, CL-PPCRE: 0.4700 seconds) + 151: 0.5047 (100000 repetitions, Perl: 0.1585 seconds, CL-PPCRE: 0.0800 seconds) + 152: 0.5141 (100000 repetitions, Perl: 0.1556 seconds, CL-PPCRE: 0.0800 seconds) + 153: 0.5116 (100000 repetitions, Perl: 0.1564 seconds, CL-PPCRE: 0.0800 seconds) + 154: 0.4508 (100000 repetitions, Perl: 0.1553 seconds, CL-PPCRE: 0.0700 seconds) + 155: 0.5214 (100000 repetitions, Perl: 0.1534 seconds, CL-PPCRE: 0.0800 seconds) + 156: 0.6360 (100000 repetitions, Perl: 0.1730 seconds, CL-PPCRE: 0.1100 seconds) + 157: 0.9536 (100000 repetitions, Perl: 0.2202 seconds, CL-PPCRE: 0.2100 seconds) + 158: 1.0349 (100000 repetitions, Perl: 0.2416 seconds, CL-PPCRE: 0.2500 seconds) + 159: 1.0302 (100000 repetitions, Perl: 0.1262 seconds, CL-PPCRE: 0.1300 seconds) + 160: 1.1893 (1000000 repetitions, Perl: 0.8325 seconds, CL-PPCRE: 0.9900 seconds) + 161: 1.2895 (100000 repetitions, Perl: 0.1473 seconds, CL-PPCRE: 0.1900 seconds) + 162: 1.3938 (100000 repetitions, Perl: 0.2152 seconds, CL-PPCRE: 0.3000 seconds) + 163: 0.3708 (100000 repetitions, Perl: 0.3505 seconds, CL-PPCRE: 0.1300 seconds) + 164: 0.4182 (100000 repetitions, Perl: 0.3826 seconds, CL-PPCRE: 0.1600 seconds) + 165: 0.4926 (100000 repetitions, Perl: 0.4060 seconds, CL-PPCRE: 0.2000 seconds) + 166: 0.9852 (1000000 repetitions, Perl: 0.6192 seconds, CL-PPCRE: 0.6100 seconds) + 167: 0.9454 (1000000 repetitions, Perl: 0.8039 seconds, CL-PPCRE: 0.7600 seconds) + 168: 0.7178 (100000 repetitions, Perl: 0.3483 seconds, CL-PPCRE: 0.2500 seconds) + 169: 0.8758 (100000 repetitions, Perl: 0.3426 seconds, CL-PPCRE: 0.3000 seconds) + 170: 1.0131 (1000000 repetitions, Perl: 0.8292 seconds, CL-PPCRE: 0.8400 seconds) + 171: 0.3196 (100000 repetitions, Perl: 0.2503 seconds, CL-PPCRE: 0.0800 seconds) + 172: 0.3538 (100000 repetitions, Perl: 0.2544 seconds, CL-PPCRE: 0.0900 seconds) + 173: 0.3592 (100000 repetitions, Perl: 0.2506 seconds, CL-PPCRE: 0.0900 seconds) + 174: 0.6737 (100000 repetitions, Perl: 0.3117 seconds, CL-PPCRE: 0.2100 seconds) + 175: 0.5639 (100000 repetitions, Perl: 0.4078 seconds, CL-PPCRE: 0.2300 seconds) + 176: 0.5225 (100000 repetitions, Perl: 0.3062 seconds, CL-PPCRE: 0.1600 seconds) + 177: 0.4419 (100000 repetitions, Perl: 0.1131 seconds, CL-PPCRE: 0.0500 seconds) + 178: 0.4992 (100000 repetitions, Perl: 0.2604 seconds, CL-PPCRE: 0.1300 seconds) + 179: 0.4653 (100000 repetitions, Perl: 0.3009 seconds, CL-PPCRE: 0.1400 seconds) + 180: 0.4438 (100000 repetitions, Perl: 0.4056 seconds, CL-PPCRE: 0.1800 seconds) + 181: 0.4672 (100000 repetitions, Perl: 0.4281 seconds, CL-PPCRE: 0.2000 seconds) + 182: 0.7833 (100000 repetitions, Perl: 0.1149 seconds, CL-PPCRE: 0.0900 seconds) + 183: 0.5458 (100000 repetitions, Perl: 0.2382 seconds, CL-PPCRE: 0.1300 seconds) + 184: 0.4734 (100000 repetitions, Perl: 0.4436 seconds, CL-PPCRE: 0.2100 seconds) + 185: 0.5420 (100000 repetitions, Perl: 0.3137 seconds, CL-PPCRE: 0.1700 seconds) + 186: 0.7234 (100000 repetitions, Perl: 0.2074 seconds, CL-PPCRE: 0.1500 seconds) + 187: 0.7521 (100000 repetitions, Perl: 0.2393 seconds, CL-PPCRE: 0.1800 seconds) + 188: 0.6819 (100000 repetitions, Perl: 0.2053 seconds, CL-PPCRE: 0.1400 seconds) + 189: 0.4950 (100000 repetitions, Perl: 0.2020 seconds, CL-PPCRE: 0.1000 seconds) + 190: 0.4918 (100000 repetitions, Perl: 0.2033 seconds, CL-PPCRE: 0.1000 seconds) + 191: 0.5343 (100000 repetitions, Perl: 0.2433 seconds, CL-PPCRE: 0.1300 seconds) + 192: 0.4148 (100000 repetitions, Perl: 0.2411 seconds, CL-PPCRE: 0.1000 seconds) + 193: 0.4709 (100000 repetitions, Perl: 0.2761 seconds, CL-PPCRE: 0.1300 seconds) + 194: 0.5928 (100000 repetitions, Perl: 0.2868 seconds, CL-PPCRE: 0.1700 seconds) + 195: 0.5643 (100000 repetitions, Perl: 0.2835 seconds, CL-PPCRE: 0.1600 seconds) + 196: 0.2465 (100000 repetitions, Perl: 0.1217 seconds, CL-PPCRE: 0.0300 seconds) + 197: 0.4772 (100000 repetitions, Perl: 0.1467 seconds, CL-PPCRE: 0.0700 seconds) + 198: 0.4983 (1000000 repetitions, Perl: 0.6221 seconds, CL-PPCRE: 0.3100 seconds) + 199: 0.2375 (100000 repetitions, Perl: 0.1263 seconds, CL-PPCRE: 0.0300 seconds) + 200: 0.4759 (100000 repetitions, Perl: 0.1471 seconds, CL-PPCRE: 0.0700 seconds) + 201: 0.4963 (1000000 repetitions, Perl: 0.6247 seconds, CL-PPCRE: 0.3100 seconds) + 202: 0.2370 (100000 repetitions, Perl: 0.1266 seconds, CL-PPCRE: 0.0300 seconds) + 203: 0.5375 (100000 repetitions, Perl: 0.1488 seconds, CL-PPCRE: 0.0800 seconds) + 204: 0.4682 (100000 repetitions, Perl: 0.1495 seconds, CL-PPCRE: 0.0700 seconds) + 205: 0.4859 (1000000 repetitions, Perl: 0.6174 seconds, CL-PPCRE: 0.3000 seconds) + 206: 0.5685 (1000000 repetitions, Perl: 0.6156 seconds, CL-PPCRE: 0.3500 seconds) + 207: 1.1822 (100000 repetitions, Perl: 0.2622 seconds, CL-PPCRE: 0.3100 seconds) + 208: 0.8749 (100000 repetitions, Perl: 0.2400 seconds, CL-PPCRE: 0.2100 seconds) + 209: 0.8621 (100000 repetitions, Perl: 0.1392 seconds, CL-PPCRE: 0.1200 seconds) + 210: 2.0520 (100000 repetitions, Perl: 0.1511 seconds, CL-PPCRE: 0.3100 seconds) + 211: 0.2312 (100000 repetitions, Perl: 0.1297 seconds, CL-PPCRE: 0.0300 seconds) + 212: 0.3110 (100000 repetitions, Perl: 0.1286 seconds, CL-PPCRE: 0.0400 seconds) + 213: 0.3096 (100000 repetitions, Perl: 0.1292 seconds, CL-PPCRE: 0.0400 seconds) + 214: 0.2972 (100000 repetitions, Perl: 0.1346 seconds, CL-PPCRE: 0.0400 seconds) + 215: 0.2916 (100000 repetitions, Perl: 0.1372 seconds, CL-PPCRE: 0.0400 seconds) + 216: 0.2908 (100000 repetitions, Perl: 0.1376 seconds, CL-PPCRE: 0.0400 seconds) + 217: 0.3625 (100000 repetitions, Perl: 0.1379 seconds, CL-PPCRE: 0.0500 seconds) + 218: 0.2910 (100000 repetitions, Perl: 0.1374 seconds, CL-PPCRE: 0.0400 seconds) + 219: 0.2351 (100000 repetitions, Perl: 0.1276 seconds, CL-PPCRE: 0.0300 seconds) + 220: 0.3128 (100000 repetitions, Perl: 0.1279 seconds, CL-PPCRE: 0.0400 seconds) + 221: 0.3099 (100000 repetitions, Perl: 0.1291 seconds, CL-PPCRE: 0.0400 seconds) + 222: 0.3134 (100000 repetitions, Perl: 0.1277 seconds, CL-PPCRE: 0.0400 seconds) + 223: 0.3118 (100000 repetitions, Perl: 0.1283 seconds, CL-PPCRE: 0.0400 seconds) + 224: 0.3115 (100000 repetitions, Perl: 0.1284 seconds, CL-PPCRE: 0.0400 seconds) + 225: 0.3098 (100000 repetitions, Perl: 0.1291 seconds, CL-PPCRE: 0.0400 seconds) + 226: 0.3118 (100000 repetitions, Perl: 0.1283 seconds, CL-PPCRE: 0.0400 seconds) + 227: 0.2644 (100000 repetitions, Perl: 0.1513 seconds, CL-PPCRE: 0.0400 seconds) + 228: 0.2621 (100000 repetitions, Perl: 0.1526 seconds, CL-PPCRE: 0.0400 seconds) + 229: 0.1883 (100000 repetitions, Perl: 0.1593 seconds, CL-PPCRE: 0.0300 seconds) + 230: 0.2480 (100000 repetitions, Perl: 0.1613 seconds, CL-PPCRE: 0.0400 seconds) + 231: 0.2458 (100000 repetitions, Perl: 0.1627 seconds, CL-PPCRE: 0.0400 seconds) + 232: 0.1954 (100000 repetitions, Perl: 0.1535 seconds, CL-PPCRE: 0.0300 seconds) + 233: 0.1929 (100000 repetitions, Perl: 0.1555 seconds, CL-PPCRE: 0.0300 seconds) + 234: 0.1934 (100000 repetitions, Perl: 0.1551 seconds, CL-PPCRE: 0.0300 seconds) + 235: 0.2597 (100000 repetitions, Perl: 0.1540 seconds, CL-PPCRE: 0.0400 seconds) + 236: 0.2556 (100000 repetitions, Perl: 0.1565 seconds, CL-PPCRE: 0.0400 seconds) + 237: 0.3496 (100000 repetitions, Perl: 0.1430 seconds, CL-PPCRE: 0.0500 seconds) + 238: 0.3485 (100000 repetitions, Perl: 0.1435 seconds, CL-PPCRE: 0.0500 seconds) + 239: 0.3473 (100000 repetitions, Perl: 0.1440 seconds, CL-PPCRE: 0.0500 seconds) + 240: 0.3362 (1000000 repetitions, Perl: 0.6246 seconds, CL-PPCRE: 0.2100 seconds) + 241: 0.9108 (100000 repetitions, Perl: 0.1427 seconds, CL-PPCRE: 0.1300 seconds) + 242: 0.8320 (100000 repetitions, Perl: 0.1442 seconds, CL-PPCRE: 0.1200 seconds) + 243: 0.9578 (100000 repetitions, Perl: 0.1462 seconds, CL-PPCRE: 0.1400 seconds) + 244: 0.9571 (100000 repetitions, Perl: 0.1463 seconds, CL-PPCRE: 0.1400 seconds) + 245: 1.3241 (100000 repetitions, Perl: 0.1133 seconds, CL-PPCRE: 0.1500 seconds) + 246: 0.8377 (100000 repetitions, Perl: 0.1433 seconds, CL-PPCRE: 0.1200 seconds) + 247: 0.8486 (100000 repetitions, Perl: 0.1414 seconds, CL-PPCRE: 0.1200 seconds) + 248: 0.8450 (100000 repetitions, Perl: 0.1420 seconds, CL-PPCRE: 0.1200 seconds) + 249: 0.8369 (100000 repetitions, Perl: 0.1434 seconds, CL-PPCRE: 0.1200 seconds) + 250: 0.8463 (100000 repetitions, Perl: 0.1418 seconds, CL-PPCRE: 0.1200 seconds) + 251: 0.6517 (100000 repetitions, Perl: 0.2762 seconds, CL-PPCRE: 0.1800 seconds) + 252: 0.6811 (100000 repetitions, Perl: 0.2937 seconds, CL-PPCRE: 0.2000 seconds) + 253: 0.6578 (100000 repetitions, Perl: 0.1824 seconds, CL-PPCRE: 0.1200 seconds) + 254: 0.8682 (100000 repetitions, Perl: 0.3571 seconds, CL-PPCRE: 0.3100 seconds) + 255: 0.7904 (100000 repetitions, Perl: 0.4175 seconds, CL-PPCRE: 0.3300 seconds) + 256: 0.8379 (100000 repetitions, Perl: 0.2745 seconds, CL-PPCRE: 0.2300 seconds) + 257: 0.7974 (100000 repetitions, Perl: 0.3010 seconds, CL-PPCRE: 0.2400 seconds) + 258: 0.8064 (100000 repetitions, Perl: 0.2852 seconds, CL-PPCRE: 0.2300 seconds) + 259: 0.7055 (100000 repetitions, Perl: 0.2977 seconds, CL-PPCRE: 0.2100 seconds) + 260: 0.8818 (100000 repetitions, Perl: 0.3515 seconds, CL-PPCRE: 0.3100 seconds) + 261: 0.8762 (100000 repetitions, Perl: 0.3652 seconds, CL-PPCRE: 0.3200 seconds) + 262: 0.8611 (100000 repetitions, Perl: 0.3020 seconds, CL-PPCRE: 0.2600 seconds) + 263: 0.5267 (100000 repetitions, Perl: 0.1519 seconds, CL-PPCRE: 0.0800 seconds) + 264: 0.5322 (100000 repetitions, Perl: 0.1503 seconds, CL-PPCRE: 0.0800 seconds) + 265: 0.9607 (100000 repetitions, Perl: 0.3123 seconds, CL-PPCRE: 0.3000 seconds) + 266: 0.4526 (100000 repetitions, Perl: 0.2872 seconds, CL-PPCRE: 0.1300 seconds) + 267: 0.6699 (100000 repetitions, Perl: 0.5673 seconds, CL-PPCRE: 0.3800 seconds) + 268: 0.5854 (100000 repetitions, Perl: 0.2221 seconds, CL-PPCRE: 0.1300 seconds) + 269: 0.5397 (100000 repetitions, Perl: 0.2223 seconds, CL-PPCRE: 0.1200 seconds) + 270: 0.5484 (100000 repetitions, Perl: 0.2188 seconds, CL-PPCRE: 0.1200 seconds) + 271: 0.4907 (100000 repetitions, Perl: 0.1834 seconds, CL-PPCRE: 0.0900 seconds) + 272: 0.5724 (100000 repetitions, Perl: 0.1922 seconds, CL-PPCRE: 0.1100 seconds) + 273: 0.4339 (100000 repetitions, Perl: 0.1383 seconds, CL-PPCRE: 0.0600 seconds) + 274: 0.4306 (100000 repetitions, Perl: 0.1394 seconds, CL-PPCRE: 0.0600 seconds) + 275: 0.2869 (100000 repetitions, Perl: 0.1743 seconds, CL-PPCRE: 0.0500 seconds) + 276: 0.4362 (100000 repetitions, Perl: 0.1376 seconds, CL-PPCRE: 0.0600 seconds) + 277: 0.7754 (100000 repetitions, Perl: 0.2321 seconds, CL-PPCRE: 0.1800 seconds) + 278: 0.7791 (100000 repetitions, Perl: 0.2310 seconds, CL-PPCRE: 0.1800 seconds) + 279: 0.7789 (100000 repetitions, Perl: 0.2311 seconds, CL-PPCRE: 0.1800 seconds) + 280: 0.7811 (100000 repetitions, Perl: 0.2305 seconds, CL-PPCRE: 0.1800 seconds) + 281: 0.2450 (100000 repetitions, Perl: 0.2040 seconds, CL-PPCRE: 0.0500 seconds) + 282: 0.2661 (100000 repetitions, Perl: 0.1503 seconds, CL-PPCRE: 0.0400 seconds) + 283: 0.2589 (100000 repetitions, Perl: 0.1931 seconds, CL-PPCRE: 0.0500 seconds) + 284: 0.3521 (100000 repetitions, Perl: 0.1420 seconds, CL-PPCRE: 0.0500 seconds) + 285: 0.3907 (100000 repetitions, Perl: 0.1791 seconds, CL-PPCRE: 0.0700 seconds) + 286: 0.4476 (100000 repetitions, Perl: 0.1787 seconds, CL-PPCRE: 0.0800 seconds) + 287: 0.4616 (100000 repetitions, Perl: 0.1733 seconds, CL-PPCRE: 0.0800 seconds) + 288: 0.4378 (100000 repetitions, Perl: 0.1827 seconds, CL-PPCRE: 0.0800 seconds) + 289: 0.6693 (10000 repetitions, Perl: 0.1643 seconds, CL-PPCRE: 0.1100 seconds) + 290: 0.6433 (100000 repetitions, Perl: 0.9328 seconds, CL-PPCRE: 0.6000 seconds) + 291: 0.5793 (100000 repetitions, Perl: 0.7940 seconds, CL-PPCRE: 0.4600 seconds) + 292: 0.6398 (10000 repetitions, Perl: 0.2657 seconds, CL-PPCRE: 0.1700 seconds) + 293: 0.7511 (10000 repetitions, Perl: 0.3062 seconds, CL-PPCRE: 0.2300 seconds) + 294: 0.7114 (10000 repetitions, Perl: 0.2249 seconds, CL-PPCRE: 0.1600 seconds) + 295: 0.8033 (1000 repetitions, Perl: 0.2739 seconds, CL-PPCRE: 0.2200 seconds) + 296: 0.6041 (1000 repetitions, Perl: 0.1655 seconds, CL-PPCRE: 0.1000 seconds) + 297: 0.8512 (10000 repetitions, Perl: 0.1175 seconds, CL-PPCRE: 0.1000 seconds) + 298: 0.6747 (100000 repetitions, Perl: 0.7707 seconds, CL-PPCRE: 0.5200 seconds) + 299: 0.6291 (100000 repetitions, Perl: 0.6359 seconds, CL-PPCRE: 0.4000 seconds) + 300: 0.7881 (10000 repetitions, Perl: 0.1650 seconds, CL-PPCRE: 0.1300 seconds) + 301: 0.8624 (10000 repetitions, Perl: 0.2087 seconds, CL-PPCRE: 0.1800 seconds) + 302: 1.6513 (100000 repetitions, Perl: 0.7509 seconds, CL-PPCRE: 1.2400 seconds) + 303: 0.8539 (1000 repetitions, Perl: 0.2342 seconds, CL-PPCRE: 0.2000 seconds) + 304: 0.5071 (1000 repetitions, Perl: 0.1578 seconds, CL-PPCRE: 0.0800 seconds) + 305: 0.2994 (100000 repetitions, Perl: 0.2004 seconds, CL-PPCRE: 0.0600 seconds) + 306: 0.3442 (100000 repetitions, Perl: 0.2034 seconds, CL-PPCRE: 0.0700 seconds) + 307: 0.3386 (100000 repetitions, Perl: 0.2067 seconds, CL-PPCRE: 0.0700 seconds) + 308: 0.4439 (100000 repetitions, Perl: 0.2027 seconds, CL-PPCRE: 0.0900 seconds) + 309: 0.2541 (100000 repetitions, Perl: 0.1181 seconds, CL-PPCRE: 0.0300 seconds) + 310: 0.2507 (100000 repetitions, Perl: 0.1197 seconds, CL-PPCRE: 0.0300 seconds) + 311: 0.2546 (100000 repetitions, Perl: 0.1178 seconds, CL-PPCRE: 0.0300 seconds) + 312: 0.3225 (100000 repetitions, Perl: 0.1240 seconds, CL-PPCRE: 0.0400 seconds) + 313: 0.2763 (100000 repetitions, Perl: 0.2171 seconds, CL-PPCRE: 0.0600 seconds) + 314: 0.3364 (100000 repetitions, Perl: 0.2081 seconds, CL-PPCRE: 0.0700 seconds) + 315: 0.5995 (1000000 repetitions, Perl: 0.6171 seconds, CL-PPCRE: 0.3700 seconds) + 316: 0.6933 (100000 repetitions, Perl: 0.1010 seconds, CL-PPCRE: 0.0700 seconds) + 317: 0.7320 (100000 repetitions, Perl: 0.1639 seconds, CL-PPCRE: 0.1200 seconds) + 318: 0.6441 (100000 repetitions, Perl: 0.1708 seconds, CL-PPCRE: 0.1100 seconds) + 319: 0.7726 (100000 repetitions, Perl: 0.1553 seconds, CL-PPCRE: 0.1200 seconds) + 320: 0.2550 (100000 repetitions, Perl: 0.1176 seconds, CL-PPCRE: 0.0300 seconds) + 321: 0.2523 (100000 repetitions, Perl: 0.1189 seconds, CL-PPCRE: 0.0300 seconds) + 322: 0.3355 (100000 repetitions, Perl: 0.1192 seconds, CL-PPCRE: 0.0400 seconds) + 323: 0.2535 (100000 repetitions, Perl: 0.1184 seconds, CL-PPCRE: 0.0300 seconds) + 324: 0.2537 (100000 repetitions, Perl: 0.1182 seconds, CL-PPCRE: 0.0300 seconds) + 325: 0.3130 (1000000 repetitions, Perl: 0.8945 seconds, CL-PPCRE: 0.2800 seconds) + 326: 0.4343 (100000 repetitions, Perl: 0.1381 seconds, CL-PPCRE: 0.0600 seconds) + 327: 0.4595 (100000 repetitions, Perl: 0.1959 seconds, CL-PPCRE: 0.0900 seconds) + 328: 0.5075 (100000 repetitions, Perl: 0.2562 seconds, CL-PPCRE: 0.1300 seconds) + 329: 0.4848 (100000 repetitions, Perl: 0.2063 seconds, CL-PPCRE: 0.1000 seconds) + 330: 0.5754 (100000 repetitions, Perl: 0.2259 seconds, CL-PPCRE: 0.1300 seconds) + 331: 0.4784 (100000 repetitions, Perl: 0.2090 seconds, CL-PPCRE: 0.1000 seconds) + 332: 0.4854 (100000 repetitions, Perl: 0.2472 seconds, CL-PPCRE: 0.1200 seconds) + 333: 0.5108 (100000 repetitions, Perl: 0.1958 seconds, CL-PPCRE: 0.1000 seconds) + 334: 0.5869 (100000 repetitions, Perl: 0.1874 seconds, CL-PPCRE: 0.1100 seconds) + 335: 0.4115 (100000 repetitions, Perl: 0.1944 seconds, CL-PPCRE: 0.0800 seconds) + 336: 0.4591 (100000 repetitions, Perl: 0.1960 seconds, CL-PPCRE: 0.0900 seconds) + 337: 0.4391 (100000 repetitions, Perl: 0.2050 seconds, CL-PPCRE: 0.0900 seconds) + 338: 0.4906 (100000 repetitions, Perl: 0.2242 seconds, CL-PPCRE: 0.1100 seconds) + 339: 0.6043 (100000 repetitions, Perl: 0.1986 seconds, CL-PPCRE: 0.1200 seconds) + 340: 0.6038 (100000 repetitions, Perl: 0.1988 seconds, CL-PPCRE: 0.1200 seconds) + 341: 0.6465 (100000 repetitions, Perl: 0.2011 seconds, CL-PPCRE: 0.1300 seconds) + 342: 0.7695 (100000 repetitions, Perl: 0.2079 seconds, CL-PPCRE: 0.1600 seconds) + 343: 0.7205 (100000 repetitions, Perl: 0.2221 seconds, CL-PPCRE: 0.1600 seconds) + 344: 0.6924 (100000 repetitions, Perl: 0.2166 seconds, CL-PPCRE: 0.1500 seconds) + 345: 0.6438 (100000 repetitions, Perl: 0.2174 seconds, CL-PPCRE: 0.1400 seconds) + 346: 0.7015 (100000 repetitions, Perl: 0.1996 seconds, CL-PPCRE: 0.1400 seconds) + 347: 0.7526 (100000 repetitions, Perl: 0.1993 seconds, CL-PPCRE: 0.1500 seconds) + 348: 0.8079 (100000 repetitions, Perl: 0.2104 seconds, CL-PPCRE: 0.1700 seconds) + 349: 0.7955 (100000 repetitions, Perl: 0.2514 seconds, CL-PPCRE: 0.2000 seconds) + 350: 0.4692 (100000 repetitions, Perl: 0.1492 seconds, CL-PPCRE: 0.0700 seconds) + 351: 0.4673 (100000 repetitions, Perl: 0.1498 seconds, CL-PPCRE: 0.0700 seconds) + 352: 0.4633 (100000 repetitions, Perl: 0.1511 seconds, CL-PPCRE: 0.0700 seconds) + 353: 0.6346 (1000000 repetitions, Perl: 0.6145 seconds, CL-PPCRE: 0.3900 seconds) + 354: 1.1542 (1000000 repetitions, Perl: 0.9097 seconds, CL-PPCRE: 1.0500 seconds) + 355: 0.4759 (100000 repetitions, Perl: 0.2732 seconds, CL-PPCRE: 0.1300 seconds) + 356: 0.6078 (100000 repetitions, Perl: 0.2303 seconds, CL-PPCRE: 0.1400 seconds) + 357: 0.6025 (100000 repetitions, Perl: 0.2324 seconds, CL-PPCRE: 0.1400 seconds) + 358: 0.3389 (100000 repetitions, Perl: 0.1475 seconds, CL-PPCRE: 0.0500 seconds) + 359: 0.2653 (1000000 repetitions, Perl: 0.9424 seconds, CL-PPCRE: 0.2500 seconds) + 360: 0.3383 (100000 repetitions, Perl: 0.1478 seconds, CL-PPCRE: 0.0500 seconds) + 361: 0.4024 (100000 repetitions, Perl: 0.1491 seconds, CL-PPCRE: 0.0600 seconds) + 362: 0.3396 (100000 repetitions, Perl: 0.1472 seconds, CL-PPCRE: 0.0500 seconds) + 363: 0.4028 (100000 repetitions, Perl: 0.1489 seconds, CL-PPCRE: 0.0600 seconds) + 364: 0.2647 (100000 repetitions, Perl: 0.1511 seconds, CL-PPCRE: 0.0400 seconds) + 365: 0.3107 (100000 repetitions, Perl: 0.1609 seconds, CL-PPCRE: 0.0500 seconds) + 366: 0.3260 (100000 repetitions, Perl: 0.1534 seconds, CL-PPCRE: 0.0500 seconds) + 367: 0.3047 (100000 repetitions, Perl: 0.1641 seconds, CL-PPCRE: 0.0500 seconds) + 368: 0.4269 (100000 repetitions, Perl: 0.1405 seconds, CL-PPCRE: 0.0600 seconds) + 369: 0.6208 (1000000 repetitions, Perl: 0.7249 seconds, CL-PPCRE: 0.4500 seconds) + 370: 0.7444 (1000000 repetitions, Perl: 0.7254 seconds, CL-PPCRE: 0.5400 seconds) + 371: 0.6080 (1000000 repetitions, Perl: 0.7237 seconds, CL-PPCRE: 0.4400 seconds) + 372: 0.4148 (100000 repetitions, Perl: 0.1446 seconds, CL-PPCRE: 0.0600 seconds) + 373: 0.3998 (100000 repetitions, Perl: 0.1501 seconds, CL-PPCRE: 0.0600 seconds) + 374: 0.5947 (1000000 repetitions, Perl: 0.7903 seconds, CL-PPCRE: 0.4700 seconds) + 375: 0.6556 (1000000 repetitions, Perl: 0.7932 seconds, CL-PPCRE: 0.5200 seconds) + 376: 0.5811 (1000000 repetitions, Perl: 0.7916 seconds, CL-PPCRE: 0.4600 seconds) + 377: 0.5095 (100000 repetitions, Perl: 0.1374 seconds, CL-PPCRE: 0.0700 seconds) + 378: 0.7533 (100000 repetitions, Perl: 0.1327 seconds, CL-PPCRE: 0.1000 seconds) + 379: 0.2212 (100000 repetitions, Perl: 0.1356 seconds, CL-PPCRE: 0.0300 seconds) + 380: 0.2732 (100000 repetitions, Perl: 0.1830 seconds, CL-PPCRE: 0.0500 seconds) + 381: 0.3535 (100000 repetitions, Perl: 0.1414 seconds, CL-PPCRE: 0.0500 seconds) + 382: 0.3386 (1000000 repetitions, Perl: 0.7974 seconds, CL-PPCRE: 0.2700 seconds) + 383: 0.3481 (100000 repetitions, Perl: 0.1436 seconds, CL-PPCRE: 0.0500 seconds) + 384: 0.3376 (1000000 repetitions, Perl: 0.7998 seconds, CL-PPCRE: 0.2700 seconds) + 385: 0.2810 (100000 repetitions, Perl: 0.1424 seconds, CL-PPCRE: 0.0400 seconds) + 386: 0.3465 (1000000 repetitions, Perl: 0.8081 seconds, CL-PPCRE: 0.2800 seconds) + 387: 0.2732 (100000 repetitions, Perl: 0.1464 seconds, CL-PPCRE: 0.0400 seconds) + 388: 0.2781 (100000 repetitions, Perl: 0.1438 seconds, CL-PPCRE: 0.0400 seconds) + 389: 0.4344 (1000000 repetitions, Perl: 0.8288 seconds, CL-PPCRE: 0.3600 seconds) + 390: 0.3457 (100000 repetitions, Perl: 0.1446 seconds, CL-PPCRE: 0.0500 seconds) + 391: 0.5038 (1000000 repetitions, Perl: 0.8337 seconds, CL-PPCRE: 0.4200 seconds) + 392: 0.2577 (100000 repetitions, Perl: 0.1552 seconds, CL-PPCRE: 0.0400 seconds) + 393: 0.2542 (100000 repetitions, Perl: 0.1573 seconds, CL-PPCRE: 0.0400 seconds) + 394: 0.4403 (1000000 repetitions, Perl: 0.7722 seconds, CL-PPCRE: 0.3400 seconds) + 395: 0.5672 (100000 repetitions, Perl: 0.1587 seconds, CL-PPCRE: 0.0900 seconds) + 396: 0.6214 (100000 repetitions, Perl: 0.1609 seconds, CL-PPCRE: 0.1000 seconds) + 397: 0.5460 (100000 repetitions, Perl: 0.1648 seconds, CL-PPCRE: 0.0900 seconds) + 398: 0.2812 (100000 repetitions, Perl: 0.1778 seconds, CL-PPCRE: 0.0500 seconds) + 399: 0.2775 (100000 repetitions, Perl: 0.1802 seconds, CL-PPCRE: 0.0500 seconds) + 400: 0.3287 (100000 repetitions, Perl: 0.1825 seconds, CL-PPCRE: 0.0600 seconds) + 401: 0.2684 (100000 repetitions, Perl: 0.1863 seconds, CL-PPCRE: 0.0500 seconds) + 402: 0.4942 (100000 repetitions, Perl: 0.1416 seconds, CL-PPCRE: 0.0700 seconds) + 403: 0.5378 (100000 repetitions, Perl: 0.1116 seconds, CL-PPCRE: 0.0600 seconds) + 404: 0.2952 (100000 repetitions, Perl: 0.1694 seconds, CL-PPCRE: 0.0500 seconds) + 405: 0.2887 (100000 repetitions, Perl: 0.1732 seconds, CL-PPCRE: 0.0500 seconds) + 406: 0.6374 (1000000 repetitions, Perl: 0.7844 seconds, CL-PPCRE: 0.5000 seconds) + 407: 0.4260 (100000 repetitions, Perl: 0.1878 seconds, CL-PPCRE: 0.0800 seconds) + 408: 0.4368 (100000 repetitions, Perl: 0.1832 seconds, CL-PPCRE: 0.0800 seconds) + 409: 0.4269 (100000 repetitions, Perl: 0.1874 seconds, CL-PPCRE: 0.0800 seconds) + 410: 0.3848 (100000 repetitions, Perl: 0.1819 seconds, CL-PPCRE: 0.0700 seconds) + 411: 0.4387 (100000 repetitions, Perl: 0.1824 seconds, CL-PPCRE: 0.0800 seconds) + 412: 0.4306 (100000 repetitions, Perl: 0.1858 seconds, CL-PPCRE: 0.0800 seconds) + 413: 0.4817 (100000 repetitions, Perl: 0.1868 seconds, CL-PPCRE: 0.0900 seconds) + 414: 0.4738 (100000 repetitions, Perl: 0.1900 seconds, CL-PPCRE: 0.0900 seconds) + 415: 0.4302 (100000 repetitions, Perl: 0.1860 seconds, CL-PPCRE: 0.0800 seconds) + 416: 0.4258 (100000 repetitions, Perl: 0.1879 seconds, CL-PPCRE: 0.0800 seconds) + 417: 0.4302 (100000 repetitions, Perl: 0.1860 seconds, CL-PPCRE: 0.0800 seconds) + 418: 0.2241 (100000 repetitions, Perl: 0.1785 seconds, CL-PPCRE: 0.0400 seconds) + 419: 0.2783 (100000 repetitions, Perl: 0.1796 seconds, CL-PPCRE: 0.0500 seconds) + 420: 0.2807 (100000 repetitions, Perl: 0.1781 seconds, CL-PPCRE: 0.0500 seconds) + 421: 0.2787 (100000 repetitions, Perl: 0.1794 seconds, CL-PPCRE: 0.0500 seconds) + 422: 0.7300 (100000 repetitions, Perl: 0.3425 seconds, CL-PPCRE: 0.2500 seconds) + 423: 0.8544 (100000 repetitions, Perl: 0.3160 seconds, CL-PPCRE: 0.2700 seconds) + 424: 0.2787 (100000 repetitions, Perl: 0.1794 seconds, CL-PPCRE: 0.0500 seconds) + 425: 0.2306 (100000 repetitions, Perl: 0.1734 seconds, CL-PPCRE: 0.0400 seconds) + 426: 0.3410 (100000 repetitions, Perl: 0.2053 seconds, CL-PPCRE: 0.0700 seconds) + 427: 0.2799 (100000 repetitions, Perl: 0.1786 seconds, CL-PPCRE: 0.0500 seconds) + 428: 0.2829 (100000 repetitions, Perl: 0.1767 seconds, CL-PPCRE: 0.0500 seconds) + 429: 0.4273 (100000 repetitions, Perl: 0.1872 seconds, CL-PPCRE: 0.0800 seconds) + 431: 0.6052 (100000 repetitions, Perl: 0.1983 seconds, CL-PPCRE: 0.1200 seconds) + 432: 0.6033 (100000 repetitions, Perl: 0.1989 seconds, CL-PPCRE: 0.1200 seconds) + 433: 0.6306 (100000 repetitions, Perl: 0.2220 seconds, CL-PPCRE: 0.1400 seconds) + 434: 0.6084 (100000 repetitions, Perl: 0.1972 seconds, CL-PPCRE: 0.1200 seconds) + 435: 0.7267 (1000000 repetitions, Perl: 0.9632 seconds, CL-PPCRE: 0.7000 seconds) + 436: 0.9658 (1000000 repetitions, Perl: 0.6316 seconds, CL-PPCRE: 0.6100 seconds) + 437: 0.7902 (100000 repetitions, Perl: 0.1519 seconds, CL-PPCRE: 0.1200 seconds) + 438: 0.2423 (100000 repetitions, Perl: 0.1238 seconds, CL-PPCRE: 0.0300 seconds) + 439: 0.3170 (100000 repetitions, Perl: 0.1262 seconds, CL-PPCRE: 0.0400 seconds) + 440: 0.2741 (100000 repetitions, Perl: 0.1459 seconds, CL-PPCRE: 0.0400 seconds) + 441: 0.4055 (100000 repetitions, Perl: 0.1480 seconds, CL-PPCRE: 0.0600 seconds) + 442: 0.2719 (100000 repetitions, Perl: 0.1471 seconds, CL-PPCRE: 0.0400 seconds) + 443: 0.2952 (100000 repetitions, Perl: 0.1355 seconds, CL-PPCRE: 0.0400 seconds) + 444: 0.3922 (1000000 repetitions, Perl: 0.8924 seconds, CL-PPCRE: 0.3500 seconds) + 445: 0.2694 (100000 repetitions, Perl: 0.1485 seconds, CL-PPCRE: 0.0400 seconds) + 446: 0.2717 (100000 repetitions, Perl: 0.1472 seconds, CL-PPCRE: 0.0400 seconds) + 447: 0.2136 (100000 repetitions, Perl: 0.1872 seconds, CL-PPCRE: 0.0400 seconds) + 448: 0.2401 (100000 repetitions, Perl: 0.1249 seconds, CL-PPCRE: 0.0300 seconds) + 449: 0.2930 (100000 repetitions, Perl: 0.1024 seconds, CL-PPCRE: 0.0300 seconds) + 450: 0.2929 (100000 repetitions, Perl: 0.1024 seconds, CL-PPCRE: 0.0300 seconds) + 451: 0.2989 (100000 repetitions, Perl: 0.2007 seconds, CL-PPCRE: 0.0600 seconds) + 452: 0.3008 (100000 repetitions, Perl: 0.1995 seconds, CL-PPCRE: 0.0600 seconds) + 453: 0.3715 (100000 repetitions, Perl: 0.2153 seconds, CL-PPCRE: 0.0800 seconds) + 454: 0.4187 (1000000 repetitions, Perl: 0.8120 seconds, CL-PPCRE: 0.3400 seconds) + 455: 0.7238 (100000 repetitions, Perl: 0.3039 seconds, CL-PPCRE: 0.2200 seconds) + 456: 0.7574 (100000 repetitions, Perl: 0.3301 seconds, CL-PPCRE: 0.2500 seconds) + 457: 0.9668 (100000 repetitions, Perl: 0.6309 seconds, CL-PPCRE: 0.6100 seconds) + 458: 0.3100 (100000 repetitions, Perl: 0.1290 seconds, CL-PPCRE: 0.0400 seconds) + 459: 0.3207 (100000 repetitions, Perl: 0.1247 seconds, CL-PPCRE: 0.0400 seconds) + 460: 0.3861 (100000 repetitions, Perl: 0.1295 seconds, CL-PPCRE: 0.0500 seconds) + 461: 0.3780 (100000 repetitions, Perl: 0.1323 seconds, CL-PPCRE: 0.0500 seconds) + 462: 0.3066 (100000 repetitions, Perl: 0.1305 seconds, CL-PPCRE: 0.0400 seconds) + 463: 0.3195 (100000 repetitions, Perl: 0.1252 seconds, CL-PPCRE: 0.0400 seconds) + 464: 0.4669 (100000 repetitions, Perl: 0.1285 seconds, CL-PPCRE: 0.0600 seconds) + 465: 0.4623 (100000 repetitions, Perl: 0.1298 seconds, CL-PPCRE: 0.0600 seconds) + 466: 0.4711 (100000 repetitions, Perl: 0.6580 seconds, CL-PPCRE: 0.3100 seconds) + 467: 0.3991 (100000 repetitions, Perl: 0.2756 seconds, CL-PPCRE: 0.1100 seconds) + 468: 0.4139 (100000 repetitions, Perl: 0.2657 seconds, CL-PPCRE: 0.1100 seconds) + 469: 0.5015 (100000 repetitions, Perl: 0.2193 seconds, CL-PPCRE: 0.1100 seconds) + 470: 0.4581 (100000 repetitions, Perl: 0.2183 seconds, CL-PPCRE: 0.1000 seconds) + 471: 0.3853 (100000 repetitions, Perl: 0.2336 seconds, CL-PPCRE: 0.0900 seconds) + 472: 0.5455 (100000 repetitions, Perl: 0.2200 seconds, CL-PPCRE: 0.1200 seconds) + 473: 0.5154 (100000 repetitions, Perl: 0.2522 seconds, CL-PPCRE: 0.1300 seconds) + 474: 0.6171 (100000 repetitions, Perl: 0.1945 seconds, CL-PPCRE: 0.1200 seconds) + 475: 0.3168 (100000 repetitions, Perl: 0.1578 seconds, CL-PPCRE: 0.0500 seconds) + 476: 0.5424 (100000 repetitions, Perl: 0.4241 seconds, CL-PPCRE: 0.2300 seconds) + 477: 0.4988 (100000 repetitions, Perl: 0.3007 seconds, CL-PPCRE: 0.1500 seconds) + 478: 0.6218 (100000 repetitions, Perl: 0.4342 seconds, CL-PPCRE: 0.2700 seconds) + 479: 0.5608 (100000 repetitions, Perl: 0.1605 seconds, CL-PPCRE: 0.0900 seconds) + 480: 0.5581 (100000 repetitions, Perl: 0.1792 seconds, CL-PPCRE: 0.1000 seconds) + 481: 0.5284 (100000 repetitions, Perl: 0.1514 seconds, CL-PPCRE: 0.0800 seconds) + 482: 0.5586 (100000 repetitions, Perl: 0.3222 seconds, CL-PPCRE: 0.1800 seconds) + 483: 0.4873 (100000 repetitions, Perl: 0.2052 seconds, CL-PPCRE: 0.1000 seconds) + 484: 0.5479 (100000 repetitions, Perl: 0.6388 seconds, CL-PPCRE: 0.3500 seconds) + 485: 0.5229 (100000 repetitions, Perl: 0.2869 seconds, CL-PPCRE: 0.1500 seconds) + 486: 0.5340 (100000 repetitions, Perl: 0.2247 seconds, CL-PPCRE: 0.1200 seconds) + 487: 0.3397 (100000 repetitions, Perl: 0.1766 seconds, CL-PPCRE: 0.0600 seconds) + 488: 0.4438 (100000 repetitions, Perl: 0.1803 seconds, CL-PPCRE: 0.0800 seconds) + 489: 0.5042 (100000 repetitions, Perl: 0.1983 seconds, CL-PPCRE: 0.1000 seconds) + 490: 0.2714 (100000 repetitions, Perl: 0.1474 seconds, CL-PPCRE: 0.0400 seconds) + 491: 0.2673 (100000 repetitions, Perl: 0.1497 seconds, CL-PPCRE: 0.0400 seconds) + 492: 0.3556 (1000000 repetitions, Perl: 0.7312 seconds, CL-PPCRE: 0.2600 seconds) + 493: 0.3586 (1000000 repetitions, Perl: 0.7250 seconds, CL-PPCRE: 0.2600 seconds) + 494: 0.3417 (1000000 repetitions, Perl: 0.6145 seconds, CL-PPCRE: 0.2100 seconds) + 495: 0.4060 (1000000 repetitions, Perl: 0.7390 seconds, CL-PPCRE: 0.3000 seconds) + 496: 0.3838 (1000000 repetitions, Perl: 0.7296 seconds, CL-PPCRE: 0.2800 seconds) + 497: 0.3394 (100000 repetitions, Perl: 0.1179 seconds, CL-PPCRE: 0.0400 seconds) + 498: 0.2507 (100000 repetitions, Perl: 0.1196 seconds, CL-PPCRE: 0.0300 seconds) + 499: 0.2521 (100000 repetitions, Perl: 0.1190 seconds, CL-PPCRE: 0.0300 seconds) + 500: 0.2512 (100000 repetitions, Perl: 0.1194 seconds, CL-PPCRE: 0.0300 seconds) + 501: 0.3337 (100000 repetitions, Perl: 0.1199 seconds, CL-PPCRE: 0.0400 seconds) + 502: 0.3380 (100000 repetitions, Perl: 0.1183 seconds, CL-PPCRE: 0.0400 seconds) + 503: 0.3385 (100000 repetitions, Perl: 0.1182 seconds, CL-PPCRE: 0.0400 seconds) + 504: 0.3383 (100000 repetitions, Perl: 0.1182 seconds, CL-PPCRE: 0.0400 seconds) + 505: 0.2934 (1000000 repetitions, Perl: 0.9203 seconds, CL-PPCRE: 0.2700 seconds) + 506: 0.3109 (1000000 repetitions, Perl: 0.9005 seconds, CL-PPCRE: 0.2800 seconds) + 507: 0.3253 (100000 repetitions, Perl: 0.1845 seconds, CL-PPCRE: 0.0600 seconds) + 508: 0.6707 (100000 repetitions, Perl: 0.6709 seconds, CL-PPCRE: 0.4500 seconds) + 509: 0.8568 (1000000 repetitions, Perl: 0.8753 seconds, CL-PPCRE: 0.7500 seconds) + 510: 1.0720 (100000 repetitions, Perl: 0.1119 seconds, CL-PPCRE: 0.1200 seconds) + 511: 0.3961 (100000 repetitions, Perl: 0.1262 seconds, CL-PPCRE: 0.0500 seconds) + 512: 0.3948 (100000 repetitions, Perl: 0.1266 seconds, CL-PPCRE: 0.0500 seconds) + 513: 0.3915 (100000 repetitions, Perl: 0.1277 seconds, CL-PPCRE: 0.0500 seconds) + 514: 0.5436 (100000 repetitions, Perl: 0.1288 seconds, CL-PPCRE: 0.0700 seconds) + 515: 0.5481 (100000 repetitions, Perl: 0.1277 seconds, CL-PPCRE: 0.0700 seconds) + 516: 0.4678 (100000 repetitions, Perl: 0.1283 seconds, CL-PPCRE: 0.0600 seconds) + 517: 0.5499 (100000 repetitions, Perl: 0.1273 seconds, CL-PPCRE: 0.0700 seconds) + 518: 0.6267 (100000 repetitions, Perl: 0.1277 seconds, CL-PPCRE: 0.0800 seconds) + 519: 0.5435 (100000 repetitions, Perl: 0.1288 seconds, CL-PPCRE: 0.0700 seconds) + 520: 0.5474 (100000 repetitions, Perl: 0.1279 seconds, CL-PPCRE: 0.0700 seconds) + 521: 0.6194 (100000 repetitions, Perl: 0.1292 seconds, CL-PPCRE: 0.0800 seconds) + 522: 0.6198 (100000 repetitions, Perl: 0.1291 seconds, CL-PPCRE: 0.0800 seconds) + 523: 0.5402 (100000 repetitions, Perl: 0.1296 seconds, CL-PPCRE: 0.0700 seconds) + 524: 0.5440 (100000 repetitions, Perl: 0.1287 seconds, CL-PPCRE: 0.0700 seconds) + 525: 0.6254 (100000 repetitions, Perl: 0.1279 seconds, CL-PPCRE: 0.0800 seconds) + 526: 0.6277 (100000 repetitions, Perl: 0.1274 seconds, CL-PPCRE: 0.0800 seconds) + 527: 0.5386 (100000 repetitions, Perl: 0.1300 seconds, CL-PPCRE: 0.0700 seconds) + 528: 0.5282 (100000 repetitions, Perl: 0.1325 seconds, CL-PPCRE: 0.0700 seconds) + 529: 1.0026 (1000000 repetitions, Perl: 0.7181 seconds, CL-PPCRE: 0.7200 seconds) + 530: 0.5673 (100000 repetitions, Perl: 0.1587 seconds, CL-PPCRE: 0.0900 seconds) + 531: 0.5812 (100000 repetitions, Perl: 0.1549 seconds, CL-PPCRE: 0.0900 seconds) + 532: 0.6859 (1000000 repetitions, Perl: 0.7436 seconds, CL-PPCRE: 0.5100 seconds) + 533: 0.5101 (100000 repetitions, Perl: 0.1568 seconds, CL-PPCRE: 0.0800 seconds) + 534: 0.4462 (100000 repetitions, Perl: 0.1569 seconds, CL-PPCRE: 0.0700 seconds) + 535: 0.7151 (1000000 repetitions, Perl: 0.7132 seconds, CL-PPCRE: 0.5100 seconds) + 536: 0.5707 (100000 repetitions, Perl: 0.1577 seconds, CL-PPCRE: 0.0900 seconds) + 537: 0.5677 (100000 repetitions, Perl: 0.1585 seconds, CL-PPCRE: 0.0900 seconds) + 538: 0.5097 (100000 repetitions, Perl: 0.1570 seconds, CL-PPCRE: 0.0800 seconds) + 539: 0.6915 (1000000 repetitions, Perl: 0.7375 seconds, CL-PPCRE: 0.5100 seconds) + 540: 0.5089 (100000 repetitions, Perl: 0.1572 seconds, CL-PPCRE: 0.0800 seconds) + 541: 0.5087 (100000 repetitions, Perl: 0.1573 seconds, CL-PPCRE: 0.0800 seconds) + 542: 0.4399 (100000 repetitions, Perl: 0.1591 seconds, CL-PPCRE: 0.0700 seconds) + 543: 0.4417 (100000 repetitions, Perl: 0.1585 seconds, CL-PPCRE: 0.0700 seconds) + 544: 0.8613 (100000 repetitions, Perl: 0.1741 seconds, CL-PPCRE: 0.1500 seconds) + 545: 0.4573 (100000 repetitions, Perl: 0.2843 seconds, CL-PPCRE: 0.1300 seconds) + 546: 0.7665 (100000 repetitions, Perl: 0.1827 seconds, CL-PPCRE: 0.1400 seconds) + 547: 0.5560 (100000 repetitions, Perl: 0.1439 seconds, CL-PPCRE: 0.0800 seconds) + 548: 0.5507 (100000 repetitions, Perl: 0.1453 seconds, CL-PPCRE: 0.0800 seconds) + 549: 0.6166 (100000 repetitions, Perl: 0.1946 seconds, CL-PPCRE: 0.1200 seconds) + 550: 0.2937 (100000 repetitions, Perl: 0.1362 seconds, CL-PPCRE: 0.0400 seconds) + 551: 0.3012 (100000 repetitions, Perl: 0.1328 seconds, CL-PPCRE: 0.0400 seconds) + 552: 0.2268 (100000 repetitions, Perl: 0.1323 seconds, CL-PPCRE: 0.0300 seconds) + 553: 0.6824 (100000 repetitions, Perl: 0.1905 seconds, CL-PPCRE: 0.1300 seconds) + 554: 0.2956 (100000 repetitions, Perl: 0.1353 seconds, CL-PPCRE: 0.0400 seconds) + 555: 0.2234 (100000 repetitions, Perl: 0.1343 seconds, CL-PPCRE: 0.0300 seconds) + 556: 0.2264 (100000 repetitions, Perl: 0.1325 seconds, CL-PPCRE: 0.0300 seconds) + 557: 0.6351 (100000 repetitions, Perl: 0.4409 seconds, CL-PPCRE: 0.2800 seconds) + 558: 0.5139 (100000 repetitions, Perl: 0.1751 seconds, CL-PPCRE: 0.0900 seconds) + 559: 0.6258 (100000 repetitions, Perl: 0.5274 seconds, CL-PPCRE: 0.3300 seconds) + 560: 0.6464 (100000 repetitions, Perl: 0.4487 seconds, CL-PPCRE: 0.2900 seconds) + 561: 0.5391 (100000 repetitions, Perl: 0.1855 seconds, CL-PPCRE: 0.1000 seconds) + 562: 0.6338 (100000 repetitions, Perl: 0.4576 seconds, CL-PPCRE: 0.2900 seconds) + 563: 0.4424 (100000 repetitions, Perl: 0.1582 seconds, CL-PPCRE: 0.0700 seconds) + 564: 0.4890 (100000 repetitions, Perl: 0.1840 seconds, CL-PPCRE: 0.0900 seconds) + 565: 0.6256 (100000 repetitions, Perl: 0.5435 seconds, CL-PPCRE: 0.3400 seconds) + 566: 0.4351 (100000 repetitions, Perl: 0.1609 seconds, CL-PPCRE: 0.0700 seconds) + 567: 0.4919 (100000 repetitions, Perl: 0.1830 seconds, CL-PPCRE: 0.0900 seconds) + 568: 0.6910 (100000 repetitions, Perl: 0.4631 seconds, CL-PPCRE: 0.3200 seconds) + 569: 0.4384 (100000 repetitions, Perl: 0.1597 seconds, CL-PPCRE: 0.0700 seconds) + 570: 0.4962 (100000 repetitions, Perl: 0.1814 seconds, CL-PPCRE: 0.0900 seconds) + 571: 0.6262 (100000 repetitions, Perl: 0.5429 seconds, CL-PPCRE: 0.3400 seconds) + 572: 0.3394 (100000 repetitions, Perl: 0.1473 seconds, CL-PPCRE: 0.0500 seconds) + 573: 0.3720 (100000 repetitions, Perl: 0.1613 seconds, CL-PPCRE: 0.0600 seconds) + 574: 0.5290 (100000 repetitions, Perl: 0.4915 seconds, CL-PPCRE: 0.2600 seconds) + 575: 0.5686 (100000 repetitions, Perl: 0.1055 seconds, CL-PPCRE: 0.0600 seconds) + 576: 0.2902 (100000 repetitions, Perl: 0.1378 seconds, CL-PPCRE: 0.0400 seconds) + 577: 0.3304 (100000 repetitions, Perl: 0.2421 seconds, CL-PPCRE: 0.0800 seconds) + 578: 0.3620 (100000 repetitions, Perl: 0.1381 seconds, CL-PPCRE: 0.0500 seconds) + 579: 0.3452 (100000 repetitions, Perl: 0.1448 seconds, CL-PPCRE: 0.0500 seconds) + 580: 0.2969 (100000 repetitions, Perl: 0.1684 seconds, CL-PPCRE: 0.0500 seconds) + 581: 0.4167 (100000 repetitions, Perl: 0.1440 seconds, CL-PPCRE: 0.0600 seconds) + 582: 0.4219 (100000 repetitions, Perl: 0.1422 seconds, CL-PPCRE: 0.0600 seconds) + 583: 0.4820 (100000 repetitions, Perl: 0.1452 seconds, CL-PPCRE: 0.0700 seconds) + 584: 0.2670 (100000 repetitions, Perl: 0.1498 seconds, CL-PPCRE: 0.0400 seconds) + 585: 0.2672 (100000 repetitions, Perl: 0.1497 seconds, CL-PPCRE: 0.0400 seconds) + 586: 0.8320 (100000 repetitions, Perl: 0.4207 seconds, CL-PPCRE: 0.3500 seconds) + 587: 0.3310 (100000 repetitions, Perl: 0.1208 seconds, CL-PPCRE: 0.0400 seconds) + 588: 0.3001 (1000000 repetitions, Perl: 0.8997 seconds, CL-PPCRE: 0.2700 seconds) + 589: 0.2536 (100000 repetitions, Perl: 0.1972 seconds, CL-PPCRE: 0.0500 seconds) + 590: 0.4693 (1000000 repetitions, Perl: 0.7671 seconds, CL-PPCRE: 0.3600 seconds) + 591: 0.2681 (100000 repetitions, Perl: 0.1865 seconds, CL-PPCRE: 0.0500 seconds) + 592: 0.2581 (100000 repetitions, Perl: 0.1550 seconds, CL-PPCRE: 0.0400 seconds) + 593: 0.4175 (100000 repetitions, Perl: 0.1916 seconds, CL-PPCRE: 0.0800 seconds) + 594: 0.4450 (100000 repetitions, Perl: 0.1573 seconds, CL-PPCRE: 0.0700 seconds) + 595: 0.4296 (100000 repetitions, Perl: 0.1862 seconds, CL-PPCRE: 0.0800 seconds) + 596: 0.4277 (100000 repetitions, Perl: 0.1871 seconds, CL-PPCRE: 0.0800 seconds) + 597: 0.4308 (100000 repetitions, Perl: 0.1857 seconds, CL-PPCRE: 0.0800 seconds) + 598: 0.7786 (1000000 repetitions, Perl: 0.7835 seconds, CL-PPCRE: 0.6100 seconds) + 599: 0.3235 (100000 repetitions, Perl: 0.1854 seconds, CL-PPCRE: 0.0600 seconds) + 600: 0.3302 (100000 repetitions, Perl: 0.1514 seconds, CL-PPCRE: 0.0500 seconds) + 601: 0.3100 (100000 repetitions, Perl: 0.3871 seconds, CL-PPCRE: 0.1200 seconds) + 602: 0.3929 (100000 repetitions, Perl: 0.5853 seconds, CL-PPCRE: 0.2300 seconds) + 603: 0.2478 (100000 repetitions, Perl: 0.1211 seconds, CL-PPCRE: 0.0300 seconds) + 604: 0.3026 (100000 repetitions, Perl: 0.1322 seconds, CL-PPCRE: 0.0400 seconds) + 605: 0.2324 (100000 repetitions, Perl: 0.1291 seconds, CL-PPCRE: 0.0300 seconds) + 606: 0.2566 (100000 repetitions, Perl: 0.1169 seconds, CL-PPCRE: 0.0300 seconds) + 607: 0.7426 (10000 repetitions, Perl: 0.6598 seconds, CL-PPCRE: 0.4900 seconds) + 608: 0.3101 (100000 repetitions, Perl: 0.1612 seconds, CL-PPCRE: 0.0500 seconds) + 609: 0.3097 (100000 repetitions, Perl: 0.1614 seconds, CL-PPCRE: 0.0500 seconds) + 610: 0.3080 (100000 repetitions, Perl: 0.1624 seconds, CL-PPCRE: 0.0500 seconds) + 611: 0.3044 (100000 repetitions, Perl: 0.1314 seconds, CL-PPCRE: 0.0400 seconds) + 612: 0.2972 (100000 repetitions, Perl: 0.1682 seconds, CL-PPCRE: 0.0500 seconds) + 613: 0.2979 (100000 repetitions, Perl: 0.1678 seconds, CL-PPCRE: 0.0500 seconds) + 614: 0.3004 (100000 repetitions, Perl: 0.1664 seconds, CL-PPCRE: 0.0500 seconds) + 615: 0.2998 (100000 repetitions, Perl: 0.1668 seconds, CL-PPCRE: 0.0500 seconds) + 616: 0.3094 (100000 repetitions, Perl: 0.3232 seconds, CL-PPCRE: 0.1000 seconds) + 617: 0.3499 (100000 repetitions, Perl: 0.4572 seconds, CL-PPCRE: 0.1600 seconds) + 618: 0.3665 (100000 repetitions, Perl: 0.6275 seconds, CL-PPCRE: 0.2300 seconds) + 619: 0.3663 (100000 repetitions, Perl: 0.8190 seconds, CL-PPCRE: 0.3000 seconds) + 620: 0.3761 (10000 repetitions, Perl: 0.1063 seconds, CL-PPCRE: 0.0400 seconds) + 621: 0.3691 (100000 repetitions, Perl: 0.3251 seconds, CL-PPCRE: 0.1200 seconds) + 622: 0.3314 (100000 repetitions, Perl: 0.3319 seconds, CL-PPCRE: 0.1100 seconds) + 623: 0.3612 (100000 repetitions, Perl: 0.3323 seconds, CL-PPCRE: 0.1200 seconds) + 624: 0.3560 (100000 repetitions, Perl: 0.3370 seconds, CL-PPCRE: 0.1200 seconds) + 625: 0.3616 (100000 repetitions, Perl: 0.3319 seconds, CL-PPCRE: 0.1200 seconds) + 626: 0.3517 (100000 repetitions, Perl: 0.1422 seconds, CL-PPCRE: 0.0500 seconds) + 627: 0.2692 (100000 repetitions, Perl: 0.1857 seconds, CL-PPCRE: 0.0500 seconds) + 628: 0.2865 (100000 repetitions, Perl: 0.1745 seconds, CL-PPCRE: 0.0500 seconds) + 630: 0.4441 (100000 repetitions, Perl: 0.1801 seconds, CL-PPCRE: 0.0800 seconds) + 632: 0.6037 (100000 repetitions, Perl: 0.1822 seconds, CL-PPCRE: 0.1100 seconds) + 635: 0.5615 (100000 repetitions, Perl: 0.4096 seconds, CL-PPCRE: 0.2300 seconds) + 636: 0.0000 (10 repetitions, Perl: 6.2984 seconds, CL-PPCRE: 0.0000 seconds) + 637: 0.5417 (100000 repetitions, Perl: 0.4061 seconds, CL-PPCRE: 0.2200 seconds) + 638: 0.0000 (100 repetitions, Perl: 0.1005 seconds, CL-PPCRE: 0.0000 seconds) + 639: 0.5243 (100000 repetitions, Perl: 0.1526 seconds, CL-PPCRE: 0.0800 seconds) + 640: 0.5098 (100000 repetitions, Perl: 0.1373 seconds, CL-PPCRE: 0.0700 seconds) + 641: 0.4568 (100000 repetitions, Perl: 0.2408 seconds, CL-PPCRE: 0.1100 seconds) + 642: 0.4462 (100000 repetitions, Perl: 0.2017 seconds, CL-PPCRE: 0.0900 seconds) + 643: 0.7628 (1000000 repetitions, Perl: 0.7735 seconds, CL-PPCRE: 0.5900 seconds) + 644: 0.4939 (100000 repetitions, Perl: 0.4656 seconds, CL-PPCRE: 0.2300 seconds) + 645: 0.3290 (100000 repetitions, Perl: 0.2128 seconds, CL-PPCRE: 0.0700 seconds) + 646: 0.4070 (100000 repetitions, Perl: 0.3686 seconds, CL-PPCRE: 0.1500 seconds) + 647: 0.4161 (100000 repetitions, Perl: 0.4086 seconds, CL-PPCRE: 0.1700 seconds) + 648: 0.2592 (100000 repetitions, Perl: 0.1158 seconds, CL-PPCRE: 0.0300 seconds) + 649: 0.3547 (100000 repetitions, Perl: 0.3101 seconds, CL-PPCRE: 0.1100 seconds) + 650: 0.4569 (1000000 repetitions, Perl: 0.7879 seconds, CL-PPCRE: 0.3600 seconds) + 651: 0.3252 (100000 repetitions, Perl: 0.1230 seconds, CL-PPCRE: 0.0400 seconds) + 652: 0.3773 (1000000 repetitions, Perl: 0.7950 seconds, CL-PPCRE: 0.3000 seconds) + 653: 0.3258 (100000 repetitions, Perl: 0.1228 seconds, CL-PPCRE: 0.0400 seconds) + 654: 1.4129 (1000000 repetitions, Perl: 0.8140 seconds, CL-PPCRE: 1.1500 seconds) + 655: 1.4957 (1000000 repetitions, Perl: 0.7622 seconds, CL-PPCRE: 1.1400 seconds) + 656: 0.3204 (100000 repetitions, Perl: 0.1560 seconds, CL-PPCRE: 0.0500 seconds) + 659: 0.4925 (100000 repetitions, Perl: 0.1218 seconds, CL-PPCRE: 0.0600 seconds) + 660: 0.3800 (1000000 repetitions, Perl: 0.7895 seconds, CL-PPCRE: 0.3000 seconds) + 661: 0.3298 (100000 repetitions, Perl: 0.1213 seconds, CL-PPCRE: 0.0400 seconds) + 663: 0.4117 (100000 repetitions, Perl: 0.1700 seconds, CL-PPCRE: 0.0700 seconds) + 664: 0.4841 (100000 repetitions, Perl: 0.1239 seconds, CL-PPCRE: 0.0600 seconds) + 665: 0.3108 (100000 repetitions, Perl: 0.1609 seconds, CL-PPCRE: 0.0500 seconds) + 666: 0.3096 (100000 repetitions, Perl: 0.1615 seconds, CL-PPCRE: 0.0500 seconds) + 667: 0.3054 (100000 repetitions, Perl: 0.1310 seconds, CL-PPCRE: 0.0400 seconds) + 668: 0.4166 (100000 repetitions, Perl: 0.1680 seconds, CL-PPCRE: 0.0700 seconds) + 669: 0.4020 (100000 repetitions, Perl: 0.1741 seconds, CL-PPCRE: 0.0700 seconds) + 670: 0.5613 (1000000 repetitions, Perl: 0.7660 seconds, CL-PPCRE: 0.4300 seconds) + 671: 0.3964 (100000 repetitions, Perl: 0.1513 seconds, CL-PPCRE: 0.0600 seconds) + 672: 0.5896 (1000000 repetitions, Perl: 0.7633 seconds, CL-PPCRE: 0.4500 seconds) + 673: 0.4650 (1000000 repetitions, Perl: 0.7742 seconds, CL-PPCRE: 0.3600 seconds) + 674: 0.2537 (100000 repetitions, Perl: 0.1577 seconds, CL-PPCRE: 0.0400 seconds) + 675: 0.5987 (1000000 repetitions, Perl: 0.7683 seconds, CL-PPCRE: 0.4600 seconds) + 676: 0.4043 (1000000 repetitions, Perl: 0.7667 seconds, CL-PPCRE: 0.3100 seconds) + 677: 0.3906 (1000000 repetitions, Perl: 0.7681 seconds, CL-PPCRE: 0.3000 seconds) + 678: 0.2633 (100000 repetitions, Perl: 0.1519 seconds, CL-PPCRE: 0.0400 seconds) + 679: 0.2444 (100000 repetitions, Perl: 0.1227 seconds, CL-PPCRE: 0.0300 seconds) + 680: 0.3258 (100000 repetitions, Perl: 0.1228 seconds, CL-PPCRE: 0.0400 seconds) + 681: 0.3292 (1000000 repetitions, Perl: 0.7897 seconds, CL-PPCRE: 0.2600 seconds) + 682: 0.2429 (100000 repetitions, Perl: 0.1235 seconds, CL-PPCRE: 0.0300 seconds) + 683: 0.3308 (100000 repetitions, Perl: 0.1209 seconds, CL-PPCRE: 0.0400 seconds) + 684: 0.3541 (1000000 repetitions, Perl: 0.7906 seconds, CL-PPCRE: 0.2800 seconds) + 685: 0.3376 (1000000 repetitions, Perl: 0.7996 seconds, CL-PPCRE: 0.2700 seconds) + 686: 0.3260 (100000 repetitions, Perl: 0.1227 seconds, CL-PPCRE: 0.0400 seconds) + 687: 0.2467 (100000 repetitions, Perl: 0.1216 seconds, CL-PPCRE: 0.0300 seconds) + 688: 0.3422 (1000000 repetitions, Perl: 0.7891 seconds, CL-PPCRE: 0.2700 seconds) + 689: 0.3388 (1000000 repetitions, Perl: 0.7970 seconds, CL-PPCRE: 0.2700 seconds) + 690: 0.2430 (100000 repetitions, Perl: 0.1235 seconds, CL-PPCRE: 0.0300 seconds) + 691: 0.3268 (100000 repetitions, Perl: 0.1224 seconds, CL-PPCRE: 0.0400 seconds) + 692: 0.2475 (100000 repetitions, Perl: 0.1212 seconds, CL-PPCRE: 0.0300 seconds) + 694: 0.2583 (100000 repetitions, Perl: 0.1549 seconds, CL-PPCRE: 0.0400 seconds) + 695: 0.3891 (1000000 repetitions, Perl: 0.7710 seconds, CL-PPCRE: 0.3000 seconds) + 697: 0.2431 (100000 repetitions, Perl: 0.1234 seconds, CL-PPCRE: 0.0300 seconds) + 698: 0.2484 (100000 repetitions, Perl: 0.1208 seconds, CL-PPCRE: 0.0300 seconds) + 699: 0.2462 (100000 repetitions, Perl: 0.1218 seconds, CL-PPCRE: 0.0300 seconds) + 700: 0.3274 (1000000 repetitions, Perl: 0.7941 seconds, CL-PPCRE: 0.2600 seconds) + 701: 0.3268 (100000 repetitions, Perl: 0.1224 seconds, CL-PPCRE: 0.0400 seconds) + 702: 0.2446 (100000 repetitions, Perl: 0.1226 seconds, CL-PPCRE: 0.0300 seconds) + 703: 0.2474 (100000 repetitions, Perl: 0.1212 seconds, CL-PPCRE: 0.0300 seconds) + 704: 0.3152 (1000000 repetitions, Perl: 0.7931 seconds, CL-PPCRE: 0.2500 seconds) + 705: 0.3720 (1000000 repetitions, Perl: 0.8065 seconds, CL-PPCRE: 0.3000 seconds) + 706: 0.3264 (100000 repetitions, Perl: 0.1226 seconds, CL-PPCRE: 0.0400 seconds) + 707: 0.3935 (1000000 repetitions, Perl: 0.7878 seconds, CL-PPCRE: 0.3100 seconds) + 708: 0.3254 (100000 repetitions, Perl: 0.1229 seconds, CL-PPCRE: 0.0400 seconds) + 709: 0.3775 (1000000 repetitions, Perl: 0.7948 seconds, CL-PPCRE: 0.3000 seconds) + 710: 0.3276 (100000 repetitions, Perl: 0.1221 seconds, CL-PPCRE: 0.0400 seconds) + 711: 0.2444 (100000 repetitions, Perl: 0.1228 seconds, CL-PPCRE: 0.0300 seconds) + 712: 0.2476 (100000 repetitions, Perl: 0.1212 seconds, CL-PPCRE: 0.0300 seconds) + 713: 0.3040 (1000000 repetitions, Perl: 0.7894 seconds, CL-PPCRE: 0.2400 seconds) + 715: 0.3191 (100000 repetitions, Perl: 0.1567 seconds, CL-PPCRE: 0.0500 seconds) + 716: 0.3000 (100000 repetitions, Perl: 0.1667 seconds, CL-PPCRE: 0.0500 seconds) + 717: 0.2954 (100000 repetitions, Perl: 0.1692 seconds, CL-PPCRE: 0.0500 seconds) + 718: 0.2865 (100000 repetitions, Perl: 0.1745 seconds, CL-PPCRE: 0.0500 seconds) + 719: 0.4718 (1000000 repetitions, Perl: 0.6147 seconds, CL-PPCRE: 0.2900 seconds) + 720: 0.2761 (100000 repetitions, Perl: 0.1811 seconds, CL-PPCRE: 0.0500 seconds) + 721: 0.4707 (1000000 repetitions, Perl: 0.6161 seconds, CL-PPCRE: 0.2900 seconds) + 722: 0.2801 (100000 repetitions, Perl: 0.1785 seconds, CL-PPCRE: 0.0500 seconds) + 723: 0.4566 (1000000 repetitions, Perl: 0.7885 seconds, CL-PPCRE: 0.3600 seconds) + 724: 0.4874 (1000000 repetitions, Perl: 0.6155 seconds, CL-PPCRE: 0.3000 seconds) + 725: 0.5016 (1000000 repetitions, Perl: 0.6180 seconds, CL-PPCRE: 0.3100 seconds) + 726: 0.2828 (100000 repetitions, Perl: 0.1768 seconds, CL-PPCRE: 0.0500 seconds) + 727: 0.5010 (1000000 repetitions, Perl: 0.6188 seconds, CL-PPCRE: 0.3100 seconds) + 728: 0.2833 (100000 repetitions, Perl: 0.1765 seconds, CL-PPCRE: 0.0500 seconds) + 729: 0.4384 (1000000 repetitions, Perl: 0.7756 seconds, CL-PPCRE: 0.3400 seconds) + 730: 0.5023 (1000000 repetitions, Perl: 0.6172 seconds, CL-PPCRE: 0.3100 seconds) + 731: 0.2386 (100000 repetitions, Perl: 0.1676 seconds, CL-PPCRE: 0.0400 seconds) + 732: 0.5181 (1000000 repetitions, Perl: 0.6177 seconds, CL-PPCRE: 0.3200 seconds) + 733: 0.4159 (1000000 repetitions, Perl: 0.7694 seconds, CL-PPCRE: 0.3200 seconds) + 734: 0.2543 (100000 repetitions, Perl: 0.1573 seconds, CL-PPCRE: 0.0400 seconds) + 735: 0.4703 (1000000 repetitions, Perl: 0.6166 seconds, CL-PPCRE: 0.2900 seconds) + 736: 0.2996 (100000 repetitions, Perl: 0.1669 seconds, CL-PPCRE: 0.0500 seconds) + 737: 0.4858 (1000000 repetitions, Perl: 0.6175 seconds, CL-PPCRE: 0.3000 seconds) + 738: 0.4444 (1000000 repetitions, Perl: 0.7876 seconds, CL-PPCRE: 0.3500 seconds) + 739: 0.2519 (100000 repetitions, Perl: 0.1588 seconds, CL-PPCRE: 0.0400 seconds) + 740: 0.4139 (1000000 repetitions, Perl: 0.7731 seconds, CL-PPCRE: 0.3200 seconds) + 741: 0.4308 (1000000 repetitions, Perl: 0.7660 seconds, CL-PPCRE: 0.3300 seconds) + 742: 0.4158 (1000000 repetitions, Perl: 0.7696 seconds, CL-PPCRE: 0.3200 seconds) + 743: 0.4542 (1000000 repetitions, Perl: 0.6165 seconds, CL-PPCRE: 0.2800 seconds) + 744: 0.4251 (100000 repetitions, Perl: 0.1411 seconds, CL-PPCRE: 0.0600 seconds) + 745: 0.4541 (1000000 repetitions, Perl: 0.6166 seconds, CL-PPCRE: 0.2800 seconds) + 746: 0.5009 (1000000 repetitions, Perl: 0.6189 seconds, CL-PPCRE: 0.3100 seconds) + 747: 0.6469 (1000000 repetitions, Perl: 0.7265 seconds, CL-PPCRE: 0.4700 seconds) + 748: 0.4178 (100000 repetitions, Perl: 0.1436 seconds, CL-PPCRE: 0.0600 seconds) + 749: 0.2556 (100000 repetitions, Perl: 0.1565 seconds, CL-PPCRE: 0.0400 seconds) + 750: 0.4699 (1000000 repetitions, Perl: 0.6171 seconds, CL-PPCRE: 0.2900 seconds) + 753: 0.2326 (100000 repetitions, Perl: 0.1290 seconds, CL-PPCRE: 0.0300 seconds) + 754: 0.2557 (100000 repetitions, Perl: 0.1564 seconds, CL-PPCRE: 0.0400 seconds) + 755: 0.3206 (100000 repetitions, Perl: 0.1559 seconds, CL-PPCRE: 0.0500 seconds) + 756: 0.3706 (100000 repetitions, Perl: 0.1349 seconds, CL-PPCRE: 0.0500 seconds) + 757: 0.3777 (100000 repetitions, Perl: 0.1324 seconds, CL-PPCRE: 0.0500 seconds) + 760: 0.2308 (100000 repetitions, Perl: 0.2167 seconds, CL-PPCRE: 0.0500 seconds) + 761: 0.4950 (1000000 repetitions, Perl: 0.7677 seconds, CL-PPCRE: 0.3800 seconds) + 762: 0.4656 (1000000 repetitions, Perl: 0.7731 seconds, CL-PPCRE: 0.3600 seconds) + 763: 0.2372 (100000 repetitions, Perl: 0.2108 seconds, CL-PPCRE: 0.0500 seconds) + 764: 0.4701 (1000000 repetitions, Perl: 0.7658 seconds, CL-PPCRE: 0.3600 seconds) + 765: 0.4926 (1000000 repetitions, Perl: 0.7714 seconds, CL-PPCRE: 0.3800 seconds) + 766: 0.6695 (100000 repetitions, Perl: 0.1792 seconds, CL-PPCRE: 0.1200 seconds) + 767: 1.1548 (1000000 repetitions, Perl: 0.7621 seconds, CL-PPCRE: 0.8800 seconds) + 768: 1.1199 (1000000 repetitions, Perl: 0.7679 seconds, CL-PPCRE: 0.8600 seconds) + 769: 0.3325 (100000 repetitions, Perl: 0.1804 seconds, CL-PPCRE: 0.0600 seconds) + 770: 0.5164 (1000000 repetitions, Perl: 0.7745 seconds, CL-PPCRE: 0.4000 seconds) + 771: 0.2703 (100000 repetitions, Perl: 0.1850 seconds, CL-PPCRE: 0.0500 seconds) + 772: 0.6408 (1000000 repetitions, Perl: 0.7646 seconds, CL-PPCRE: 0.4900 seconds) + 773: 0.4346 (1000000 repetitions, Perl: 0.8284 seconds, CL-PPCRE: 0.3600 seconds) + 774: 0.2671 (100000 repetitions, Perl: 0.1872 seconds, CL-PPCRE: 0.0500 seconds) + 775: 0.6119 (1000000 repetitions, Perl: 0.7681 seconds, CL-PPCRE: 0.4700 seconds) + 776: 0.4309 (1000000 repetitions, Perl: 0.8355 seconds, CL-PPCRE: 0.3600 seconds) + 777: 0.5830 (100000 repetitions, Perl: 0.1544 seconds, CL-PPCRE: 0.0900 seconds) + 778: 1.4436 (1000000 repetitions, Perl: 0.7620 seconds, CL-PPCRE: 1.1000 seconds) + 779: 0.8700 (1000000 repetitions, Perl: 0.8390 seconds, CL-PPCRE: 0.7300 seconds) + 780: 0.3165 (100000 repetitions, Perl: 0.1580 seconds, CL-PPCRE: 0.0500 seconds) + 781: 0.6059 (1000000 repetitions, Perl: 0.7756 seconds, CL-PPCRE: 0.4700 seconds) + 782: 0.4393 (1000000 repetitions, Perl: 0.8194 seconds, CL-PPCRE: 0.3600 seconds) + 783: 0.3732 (1000000 repetitions, Perl: 0.8307 seconds, CL-PPCRE: 0.3100 seconds) + 784: 0.2886 (100000 repetitions, Perl: 0.1733 seconds, CL-PPCRE: 0.0500 seconds) + 785: 0.4761 (1000000 repetitions, Perl: 0.7771 seconds, CL-PPCRE: 0.3700 seconds) + 786: 0.4285 (100000 repetitions, Perl: 0.2567 seconds, CL-PPCRE: 0.1100 seconds) + 787: 0.4003 (100000 repetitions, Perl: 0.2748 seconds, CL-PPCRE: 0.1100 seconds) + 788: 0.4010 (100000 repetitions, Perl: 0.2244 seconds, CL-PPCRE: 0.0900 seconds) + 789: 0.4943 (100000 repetitions, Perl: 0.4451 seconds, CL-PPCRE: 0.2200 seconds) + 791: 0.4275 (100000 repetitions, Perl: 0.4444 seconds, CL-PPCRE: 0.1900 seconds) + 792: 0.5687 (100000 repetitions, Perl: 0.4748 seconds, CL-PPCRE: 0.2700 seconds) + 793: 0.6169 (100000 repetitions, Perl: 0.4539 seconds, CL-PPCRE: 0.2800 seconds) + 794: 0.6400 (100000 repetitions, Perl: 0.4531 seconds, CL-PPCRE: 0.2900 seconds) + 795: 0.2678 (100000 repetitions, Perl: 0.2240 seconds, CL-PPCRE: 0.0600 seconds) + 796: 0.3119 (100000 repetitions, Perl: 0.1924 seconds, CL-PPCRE: 0.0600 seconds) + 797: 0.5787 (100000 repetitions, Perl: 0.3801 seconds, CL-PPCRE: 0.2200 seconds) + 798: 0.6085 (100000 repetitions, Perl: 0.3287 seconds, CL-PPCRE: 0.2000 seconds) + 799: 0.4050 (1000000 repetitions, Perl: 0.8149 seconds, CL-PPCRE: 0.3300 seconds) + 800: 0.3213 (100000 repetitions, Perl: 0.1556 seconds, CL-PPCRE: 0.0500 seconds) + 801: 0.2587 (100000 repetitions, Perl: 0.1546 seconds, CL-PPCRE: 0.0400 seconds) + 802: 0.3436 (100000 repetitions, Perl: 0.1455 seconds, CL-PPCRE: 0.0500 seconds) + 803: 0.4407 (100000 repetitions, Perl: 0.1361 seconds, CL-PPCRE: 0.0600 seconds) + 804: 0.6222 (1000000 repetitions, Perl: 0.7233 seconds, CL-PPCRE: 0.4500 seconds) + 805: 0.4411 (100000 repetitions, Perl: 0.1360 seconds, CL-PPCRE: 0.0600 seconds) + 806: 0.6147 (1000000 repetitions, Perl: 0.7158 seconds, CL-PPCRE: 0.4400 seconds) + 807: 0.2206 (100000 repetitions, Perl: 0.1814 seconds, CL-PPCRE: 0.0400 seconds) + 808: 0.2470 (100000 repetitions, Perl: 0.2024 seconds, CL-PPCRE: 0.0500 seconds) + 809: 0.2735 (100000 repetitions, Perl: 0.1828 seconds, CL-PPCRE: 0.0500 seconds) + 810: 0.2674 (100000 repetitions, Perl: 0.1870 seconds, CL-PPCRE: 0.0500 seconds) + 811: 0.3405 (100000 repetitions, Perl: 0.1468 seconds, CL-PPCRE: 0.0500 seconds) + 812: 0.4059 (100000 repetitions, Perl: 0.1478 seconds, CL-PPCRE: 0.0600 seconds) + 813: 0.2085 (100000 repetitions, Perl: 0.2398 seconds, CL-PPCRE: 0.0500 seconds) + 814: 0.4373 (1000000 repetitions, Perl: 0.6174 seconds, CL-PPCRE: 0.2700 seconds) + 815: 0.2669 (100000 repetitions, Perl: 0.1874 seconds, CL-PPCRE: 0.0500 seconds) + 816: 0.7040 (100000 repetitions, Perl: 0.1847 seconds, CL-PPCRE: 0.1300 seconds) + 817: 0.4656 (100000 repetitions, Perl: 0.2148 seconds, CL-PPCRE: 0.1000 seconds) + 818: 0.4928 (100000 repetitions, Perl: 0.1420 seconds, CL-PPCRE: 0.0700 seconds) + 819: 0.6155 (100000 repetitions, Perl: 0.1625 seconds, CL-PPCRE: 0.1000 seconds) + 820: 0.4187 (100000 repetitions, Perl: 0.1433 seconds, CL-PPCRE: 0.0600 seconds) + 821: 0.4519 (100000 repetitions, Perl: 0.1328 seconds, CL-PPCRE: 0.0600 seconds) + 822: 0.5520 (1000000 repetitions, Perl: 0.7970 seconds, CL-PPCRE: 0.4400 seconds) + 823: 0.6456 (1000000 repetitions, Perl: 0.7899 seconds, CL-PPCRE: 0.5100 seconds) + 824: 0.5695 (1000000 repetitions, Perl: 0.7901 seconds, CL-PPCRE: 0.4500 seconds) + 825: 5.6157 (100000 repetitions, Perl: 0.1086 seconds, CL-PPCRE: 0.6100 seconds) + 826: 0.4859 (100000 repetitions, Perl: 0.1852 seconds, CL-PPCRE: 0.0900 seconds) + 827: 0.4928 (100000 repetitions, Perl: 0.2232 seconds, CL-PPCRE: 0.1100 seconds) + 828: 0.4467 (100000 repetitions, Perl: 0.2238 seconds, CL-PPCRE: 0.1000 seconds) + 829: 0.4870 (100000 repetitions, Perl: 0.1848 seconds, CL-PPCRE: 0.0900 seconds) + 830: 0.4523 (10000 repetitions, Perl: 0.2432 seconds, CL-PPCRE: 0.1100 seconds) + 831: 0.4011 (10000 repetitions, Perl: 0.1994 seconds, CL-PPCRE: 0.0800 seconds) + 832: 0.5870 (100000 repetitions, Perl: 0.1533 seconds, CL-PPCRE: 0.0900 seconds) + 833: 0.6449 (100000 repetitions, Perl: 0.1706 seconds, CL-PPCRE: 0.1100 seconds) + 834: 0.5824 (100000 repetitions, Perl: 0.1717 seconds, CL-PPCRE: 0.1000 seconds) + 835: 0.7363 (100000 repetitions, Perl: 0.3259 seconds, CL-PPCRE: 0.2400 seconds) + 836: 0.3287 (100000 repetitions, Perl: 0.1521 seconds, CL-PPCRE: 0.0500 seconds) + 837: 0.4946 (100000 repetitions, Perl: 0.1617 seconds, CL-PPCRE: 0.0800 seconds) + 838: 0.4950 (100000 repetitions, Perl: 0.1616 seconds, CL-PPCRE: 0.0800 seconds) + 839: 0.2466 (100000 repetitions, Perl: 0.2839 seconds, CL-PPCRE: 0.0700 seconds) + 840: 0.2690 (100000 repetitions, Perl: 0.4832 seconds, CL-PPCRE: 0.1300 seconds) + 841: 0.4333 (100000 repetitions, Perl: 0.8077 seconds, CL-PPCRE: 0.3500 seconds) + 842: 0.3721 (100000 repetitions, Perl: 0.3763 seconds, CL-PPCRE: 0.1400 seconds) + 843: 0.3971 (100000 repetitions, Perl: 0.5288 seconds, CL-PPCRE: 0.2100 seconds) + 844: 0.4906 (100000 repetitions, Perl: 0.4077 seconds, CL-PPCRE: 0.2000 seconds) + 845: 0.3136 (100000 repetitions, Perl: 0.1595 seconds, CL-PPCRE: 0.0500 seconds) + 847: 0.4496 (1000000 repetitions, Perl: 0.7786 seconds, CL-PPCRE: 0.3500 seconds) + 848: 0.4622 (1000000 repetitions, Perl: 0.7789 seconds, CL-PPCRE: 0.3600 seconds) + 849: 0.4740 (100000 repetitions, Perl: 0.1899 seconds, CL-PPCRE: 0.0900 seconds) + 850: 0.8123 (1000000 repetitions, Perl: 0.8002 seconds, CL-PPCRE: 0.6500 seconds) + 851: 0.9209 (1000000 repetitions, Perl: 0.6190 seconds, CL-PPCRE: 0.5700 seconds) + 852: 0.8913 (1000000 repetitions, Perl: 0.6171 seconds, CL-PPCRE: 0.5500 seconds) + 853: 0.4788 (100000 repetitions, Perl: 0.1880 seconds, CL-PPCRE: 0.0900 seconds) + 854: 0.9083 (1000000 repetitions, Perl: 0.6165 seconds, CL-PPCRE: 0.5600 seconds) + 855: 0.5293 (100000 repetitions, Perl: 0.1700 seconds, CL-PPCRE: 0.0900 seconds) + 856: 0.5205 (100000 repetitions, Perl: 0.1729 seconds, CL-PPCRE: 0.0900 seconds) + 857: 0.4842 (100000 repetitions, Perl: 0.1446 seconds, CL-PPCRE: 0.0700 seconds) + 858: 0.4118 (100000 repetitions, Perl: 0.1457 seconds, CL-PPCRE: 0.0600 seconds) + 859: 0.8257 (1000000 repetitions, Perl: 0.7630 seconds, CL-PPCRE: 0.6300 seconds) + 860: 0.7571 (1000000 repetitions, Perl: 0.7661 seconds, CL-PPCRE: 0.5800 seconds) + 861: 0.8254 (1000000 repetitions, Perl: 0.7633 seconds, CL-PPCRE: 0.6300 seconds) + 862: 0.7463 (1000000 repetitions, Perl: 0.7637 seconds, CL-PPCRE: 0.5700 seconds) + 863: 0.3740 (100000 repetitions, Perl: 0.1604 seconds, CL-PPCRE: 0.0600 seconds) + 864: 0.3688 (100000 repetitions, Perl: 0.1627 seconds, CL-PPCRE: 0.0600 seconds) + 865: 0.4717 (1000000 repetitions, Perl: 0.7632 seconds, CL-PPCRE: 0.3600 seconds) + 866: 0.3015 (100000 repetitions, Perl: 0.1327 seconds, CL-PPCRE: 0.0400 seconds) + 867: 0.3042 (100000 repetitions, Perl: 0.1315 seconds, CL-PPCRE: 0.0400 seconds) + 868: 0.4176 (100000 repetitions, Perl: 0.1437 seconds, CL-PPCRE: 0.0600 seconds) + 869: 0.4879 (100000 repetitions, Perl: 0.1435 seconds, CL-PPCRE: 0.0700 seconds) + 870: 0.4843 (1000000 repetitions, Perl: 0.7640 seconds, CL-PPCRE: 0.3700 seconds) + 871: 0.5737 (1000000 repetitions, Perl: 0.7669 seconds, CL-PPCRE: 0.4400 seconds) + 872: 0.4173 (100000 repetitions, Perl: 0.1917 seconds, CL-PPCRE: 0.0800 seconds) + 873: 0.3683 (100000 repetitions, Perl: 0.1900 seconds, CL-PPCRE: 0.0700 seconds) + 874: 0.3494 (100000 repetitions, Perl: 0.1431 seconds, CL-PPCRE: 0.0500 seconds) + 875: 0.2311 (100000 repetitions, Perl: 0.1731 seconds, CL-PPCRE: 0.0400 seconds) + 876: 0.3566 (100000 repetitions, Perl: 0.2804 seconds, CL-PPCRE: 0.1000 seconds) + 877: 0.3548 (100000 repetitions, Perl: 0.2819 seconds, CL-PPCRE: 0.1000 seconds) + 878: 0.3539 (100000 repetitions, Perl: 0.2826 seconds, CL-PPCRE: 0.1000 seconds) + 879: 0.4957 (1000000 repetitions, Perl: 0.7666 seconds, CL-PPCRE: 0.3800 seconds) + 880: 0.6677 (100000 repetitions, Perl: 0.2396 seconds, CL-PPCRE: 0.1600 seconds) + 881: 0.3568 (100000 repetitions, Perl: 0.2803 seconds, CL-PPCRE: 0.1000 seconds) + 882: 0.3561 (100000 repetitions, Perl: 0.2808 seconds, CL-PPCRE: 0.1000 seconds) + 883: 0.3531 (100000 repetitions, Perl: 0.2832 seconds, CL-PPCRE: 0.1000 seconds) + 884: 0.4939 (1000000 repetitions, Perl: 0.7693 seconds, CL-PPCRE: 0.3800 seconds) + 885: 0.6675 (100000 repetitions, Perl: 0.2397 seconds, CL-PPCRE: 0.1600 seconds) + 886: 0.1878 (100000 repetitions, Perl: 0.2662 seconds, CL-PPCRE: 0.0500 seconds) + 887: 0.2227 (100000 repetitions, Perl: 0.2694 seconds, CL-PPCRE: 0.0600 seconds) + 888: 0.1826 (100000 repetitions, Perl: 0.2738 seconds, CL-PPCRE: 0.0500 seconds) + 889: 0.2220 (100000 repetitions, Perl: 0.1352 seconds, CL-PPCRE: 0.0300 seconds) + 890: 0.3370 (1000000 repetitions, Perl: 0.7715 seconds, CL-PPCRE: 0.2600 seconds) + 891: 0.3276 (1000000 repetitions, Perl: 0.7632 seconds, CL-PPCRE: 0.2500 seconds) + 892: 0.3100 (100000 repetitions, Perl: 0.1936 seconds, CL-PPCRE: 0.0600 seconds) + 893: 0.2601 (100000 repetitions, Perl: 0.1923 seconds, CL-PPCRE: 0.0500 seconds) + 894: 0.4041 (1000000 repetitions, Perl: 0.6187 seconds, CL-PPCRE: 0.2500 seconds) + 895: 0.3268 (1000000 repetitions, Perl: 0.7651 seconds, CL-PPCRE: 0.2500 seconds) + 896: 0.3254 (1000000 repetitions, Perl: 0.7683 seconds, CL-PPCRE: 0.2500 seconds) + 897: 0.4751 (100000 repetitions, Perl: 0.2105 seconds, CL-PPCRE: 0.1000 seconds) + 898: 0.4364 (100000 repetitions, Perl: 0.2062 seconds, CL-PPCRE: 0.0900 seconds) + 899: 0.4444 (100000 repetitions, Perl: 0.1350 seconds, CL-PPCRE: 0.0600 seconds) + 900: 0.5022 (100000 repetitions, Perl: 0.1394 seconds, CL-PPCRE: 0.0700 seconds) + 901: 0.7035 (1000000 repetitions, Perl: 0.7676 seconds, CL-PPCRE: 0.5400 seconds) + 902: 0.4586 (100000 repetitions, Perl: 0.1527 seconds, CL-PPCRE: 0.0700 seconds) + 903: 0.4671 (100000 repetitions, Perl: 0.1713 seconds, CL-PPCRE: 0.0800 seconds) + 904: 0.3907 (100000 repetitions, Perl: 0.1792 seconds, CL-PPCRE: 0.0700 seconds) + 905: 0.3864 (100000 repetitions, Perl: 0.1812 seconds, CL-PPCRE: 0.0700 seconds) + 906: 0.3806 (100000 repetitions, Perl: 0.2102 seconds, CL-PPCRE: 0.0800 seconds) + 907: 0.3776 (100000 repetitions, Perl: 0.2118 seconds, CL-PPCRE: 0.0800 seconds) + 908: 0.3921 (100000 repetitions, Perl: 0.2295 seconds, CL-PPCRE: 0.0900 seconds) + 909: 0.4301 (100000 repetitions, Perl: 0.1860 seconds, CL-PPCRE: 0.0800 seconds) + 910: 0.3195 (100000 repetitions, Perl: 0.1878 seconds, CL-PPCRE: 0.0600 seconds) + 911: 0.2436 (100000 repetitions, Perl: 0.1642 seconds, CL-PPCRE: 0.0400 seconds) + 912: 0.3041 (100000 repetitions, Perl: 0.1315 seconds, CL-PPCRE: 0.0400 seconds) + 913: 0.2414 (100000 repetitions, Perl: 0.1243 seconds, CL-PPCRE: 0.0300 seconds) + 914: 0.2742 (100000 repetitions, Perl: 0.1823 seconds, CL-PPCRE: 0.0500 seconds) + 915: 0.2971 (100000 repetitions, Perl: 0.1683 seconds, CL-PPCRE: 0.0500 seconds) + 916: 0.3023 (100000 repetitions, Perl: 0.1323 seconds, CL-PPCRE: 0.0400 seconds) + 917: 0.2352 (100000 repetitions, Perl: 0.1276 seconds, CL-PPCRE: 0.0300 seconds) + 918: 0.3308 (100000 repetitions, Perl: 0.2418 seconds, CL-PPCRE: 0.0800 seconds) + 919: 0.2534 (100000 repetitions, Perl: 0.1578 seconds, CL-PPCRE: 0.0400 seconds) + 920: 0.2807 (100000 repetitions, Perl: 0.1781 seconds, CL-PPCRE: 0.0500 seconds) + 921: 0.3005 (100000 repetitions, Perl: 0.1997 seconds, CL-PPCRE: 0.0600 seconds) + 922: 0.3028 (100000 repetitions, Perl: 0.2312 seconds, CL-PPCRE: 0.0700 seconds) + 923: 0.3821 (100000 repetitions, Perl: 0.2355 seconds, CL-PPCRE: 0.0900 seconds) + 924: 0.2499 (100000 repetitions, Perl: 0.1601 seconds, CL-PPCRE: 0.0400 seconds) + 925: 0.2759 (100000 repetitions, Perl: 0.1813 seconds, CL-PPCRE: 0.0500 seconds) + 926: 0.2996 (100000 repetitions, Perl: 0.2003 seconds, CL-PPCRE: 0.0600 seconds) + 927: 0.3238 (100000 repetitions, Perl: 0.2162 seconds, CL-PPCRE: 0.0700 seconds) + 928: 0.4485 (100000 repetitions, Perl: 0.1784 seconds, CL-PPCRE: 0.0800 seconds) + 929: 0.5143 (100000 repetitions, Perl: 0.1750 seconds, CL-PPCRE: 0.0900 seconds) + 930: 0.4808 (100000 repetitions, Perl: 0.1872 seconds, CL-PPCRE: 0.0900 seconds) + 931: 0.5237 (100000 repetitions, Perl: 0.2864 seconds, CL-PPCRE: 0.1500 seconds) + 932: 0.4539 (100000 repetitions, Perl: 0.1763 seconds, CL-PPCRE: 0.0800 seconds) + 933: 0.5025 (100000 repetitions, Perl: 0.1791 seconds, CL-PPCRE: 0.0900 seconds) + 934: 0.4820 (100000 repetitions, Perl: 0.1867 seconds, CL-PPCRE: 0.0900 seconds) + 935: 0.5277 (100000 repetitions, Perl: 0.2843 seconds, CL-PPCRE: 0.1500 seconds) + 936: 0.4468 (100000 repetitions, Perl: 0.2238 seconds, CL-PPCRE: 0.1000 seconds) + 937: 0.3800 (100000 repetitions, Perl: 0.2631 seconds, CL-PPCRE: 0.1000 seconds) + 938: 0.4090 (100000 repetitions, Perl: 0.2934 seconds, CL-PPCRE: 0.1200 seconds) + 939: 0.4672 (100000 repetitions, Perl: 0.1926 seconds, CL-PPCRE: 0.0900 seconds) + 940: 0.6314 (100000 repetitions, Perl: 0.1742 seconds, CL-PPCRE: 0.1100 seconds) + 941: 0.6664 (100000 repetitions, Perl: 0.1801 seconds, CL-PPCRE: 0.1200 seconds) + 942: 0.6355 (100000 repetitions, Perl: 0.1731 seconds, CL-PPCRE: 0.1100 seconds) + 943: 0.6240 (100000 repetitions, Perl: 0.1763 seconds, CL-PPCRE: 0.1100 seconds) + 944: 0.6861 (100000 repetitions, Perl: 0.1749 seconds, CL-PPCRE: 0.1200 seconds) + 945: 0.7400 (100000 repetitions, Perl: 0.1757 seconds, CL-PPCRE: 0.1300 seconds) + 946: 0.7302 (100000 repetitions, Perl: 0.1780 seconds, CL-PPCRE: 0.1300 seconds) + 947: 0.6298 (100000 repetitions, Perl: 0.1747 seconds, CL-PPCRE: 0.1100 seconds) + 948: 0.6705 (100000 repetitions, Perl: 0.1790 seconds, CL-PPCRE: 0.1200 seconds) + 949: 0.6259 (100000 repetitions, Perl: 0.1758 seconds, CL-PPCRE: 0.1100 seconds) + 950: 0.6232 (100000 repetitions, Perl: 0.1765 seconds, CL-PPCRE: 0.1100 seconds) + 951: 0.6639 (100000 repetitions, Perl: 0.1807 seconds, CL-PPCRE: 0.1200 seconds) + 952: 0.7448 (100000 repetitions, Perl: 0.1745 seconds, CL-PPCRE: 0.1300 seconds) + 953: 0.6846 (100000 repetitions, Perl: 0.1753 seconds, CL-PPCRE: 0.1200 seconds) + 954: 0.2594 (100000 repetitions, Perl: 0.2313 seconds, CL-PPCRE: 0.0600 seconds) + 955: 0.2587 (100000 repetitions, Perl: 0.2319 seconds, CL-PPCRE: 0.0600 seconds) + 956: 0.3055 (100000 repetitions, Perl: 0.2291 seconds, CL-PPCRE: 0.0700 seconds) + 957: 0.4766 (100000 repetitions, Perl: 0.2308 seconds, CL-PPCRE: 0.1100 seconds) + 958: 0.4771 (100000 repetitions, Perl: 0.2725 seconds, CL-PPCRE: 0.1300 seconds) + 959: 0.4772 (100000 repetitions, Perl: 0.3144 seconds, CL-PPCRE: 0.1500 seconds) + 960: 0.6517 (100000 repetitions, Perl: 0.1841 seconds, CL-PPCRE: 0.1200 seconds) + 961: 0.4511 (100000 repetitions, Perl: 0.2217 seconds, CL-PPCRE: 0.1000 seconds) + 962: 0.3977 (100000 repetitions, Perl: 0.2263 seconds, CL-PPCRE: 0.0900 seconds) + 963: 0.4044 (100000 repetitions, Perl: 0.2226 seconds, CL-PPCRE: 0.0900 seconds) + 964: 0.4084 (100000 repetitions, Perl: 0.2204 seconds, CL-PPCRE: 0.0900 seconds) + 965: 0.4408 (100000 repetitions, Perl: 0.2269 seconds, CL-PPCRE: 0.1000 seconds) + 966: 0.4340 (100000 repetitions, Perl: 0.2304 seconds, CL-PPCRE: 0.1000 seconds) + 967: 0.4000 (100000 repetitions, Perl: 0.2250 seconds, CL-PPCRE: 0.0900 seconds) + 968: 0.4063 (100000 repetitions, Perl: 0.2215 seconds, CL-PPCRE: 0.0900 seconds) + 969: 0.4449 (100000 repetitions, Perl: 0.2248 seconds, CL-PPCRE: 0.1000 seconds) + 970: 0.4263 (100000 repetitions, Perl: 0.1877 seconds, CL-PPCRE: 0.0800 seconds) + 971: 0.4445 (100000 repetitions, Perl: 0.2250 seconds, CL-PPCRE: 0.1000 seconds) + 972: 0.4297 (100000 repetitions, Perl: 0.1862 seconds, CL-PPCRE: 0.0800 seconds) + 973: 0.3937 (100000 repetitions, Perl: 0.1778 seconds, CL-PPCRE: 0.0700 seconds) + 974: 0.3974 (100000 repetitions, Perl: 0.1761 seconds, CL-PPCRE: 0.0700 seconds) + 975: 0.3941 (100000 repetitions, Perl: 0.1776 seconds, CL-PPCRE: 0.0700 seconds) + 976: 0.3917 (100000 repetitions, Perl: 0.1787 seconds, CL-PPCRE: 0.0700 seconds) + 977: 0.3929 (100000 repetitions, Perl: 0.1781 seconds, CL-PPCRE: 0.0700 seconds) + 978: 0.3915 (100000 repetitions, Perl: 0.1788 seconds, CL-PPCRE: 0.0700 seconds) + 979: 0.3970 (100000 repetitions, Perl: 0.1763 seconds, CL-PPCRE: 0.0700 seconds) + 980: 0.3956 (100000 repetitions, Perl: 0.1770 seconds, CL-PPCRE: 0.0700 seconds) + 981: 0.3936 (100000 repetitions, Perl: 0.1779 seconds, CL-PPCRE: 0.0700 seconds) + 982: 0.3955 (100000 repetitions, Perl: 0.1770 seconds, CL-PPCRE: 0.0700 seconds) + 983: 0.3928 (100000 repetitions, Perl: 0.1782 seconds, CL-PPCRE: 0.0700 seconds) + 984: 0.3968 (100000 repetitions, Perl: 0.1764 seconds, CL-PPCRE: 0.0700 seconds) + 985: 0.2590 (100000 repetitions, Perl: 0.2317 seconds, CL-PPCRE: 0.0600 seconds) + 986: 0.3023 (100000 repetitions, Perl: 0.2315 seconds, CL-PPCRE: 0.0700 seconds) + 987: 0.4364 (100000 repetitions, Perl: 0.2521 seconds, CL-PPCRE: 0.1100 seconds) + 988: 0.3976 (100000 repetitions, Perl: 0.2515 seconds, CL-PPCRE: 0.1000 seconds) + 989: 0.3863 (100000 repetitions, Perl: 0.2071 seconds, CL-PPCRE: 0.0800 seconds) + 990: 0.3864 (100000 repetitions, Perl: 0.2070 seconds, CL-PPCRE: 0.0800 seconds) + 991: 0.2795 (100000 repetitions, Perl: 0.2504 seconds, CL-PPCRE: 0.0700 seconds) + 992: 0.3350 (100000 repetitions, Perl: 0.2686 seconds, CL-PPCRE: 0.0900 seconds) + 993: 0.1875 (100000 repetitions, Perl: 0.2133 seconds, CL-PPCRE: 0.0400 seconds) + 994: 0.4958 (100000 repetitions, Perl: 0.2218 seconds, CL-PPCRE: 0.1100 seconds) + 995: 0.4927 (100000 repetitions, Perl: 0.2233 seconds, CL-PPCRE: 0.1100 seconds) + 996: 0.4889 (100000 repetitions, Perl: 0.1841 seconds, CL-PPCRE: 0.0900 seconds) + 997: 0.4658 (100000 repetitions, Perl: 0.1503 seconds, CL-PPCRE: 0.0700 seconds) + 998: 0.3414 (100000 repetitions, Perl: 0.1464 seconds, CL-PPCRE: 0.0500 seconds) + 999: 0.3149 (100000 repetitions, Perl: 0.1588 seconds, CL-PPCRE: 0.0500 seconds) +1000: 0.3993 (100000 repetitions, Perl: 0.1503 seconds, CL-PPCRE: 0.0600 seconds) +1001: 0.3749 (100000 repetitions, Perl: 0.1600 seconds, CL-PPCRE: 0.0600 seconds) +1002: 0.4008 (100000 repetitions, Perl: 0.1497 seconds, CL-PPCRE: 0.0600 seconds) +1003: 0.3744 (100000 repetitions, Perl: 0.1603 seconds, CL-PPCRE: 0.0600 seconds) +1004: 0.3792 (100000 repetitions, Perl: 0.1582 seconds, CL-PPCRE: 0.0600 seconds) +1005: 0.5061 (100000 repetitions, Perl: 0.1581 seconds, CL-PPCRE: 0.0800 seconds) +1006: 0.5539 (100000 repetitions, Perl: 0.1625 seconds, CL-PPCRE: 0.0900 seconds) +1007: 0.5210 (100000 repetitions, Perl: 0.1727 seconds, CL-PPCRE: 0.0900 seconds) +1008: 0.5835 (100000 repetitions, Perl: 0.1714 seconds, CL-PPCRE: 0.1000 seconds) +1009: 0.6770 (1000000 repetitions, Perl: 0.7681 seconds, CL-PPCRE: 0.5200 seconds) +1010: 0.6788 (1000000 repetitions, Perl: 0.7660 seconds, CL-PPCRE: 0.5200 seconds) +1011: 0.6545 (1000000 repetitions, Perl: 0.7640 seconds, CL-PPCRE: 0.5000 seconds) +1012: 0.6682 (1000000 repetitions, Perl: 0.7632 seconds, CL-PPCRE: 0.5100 seconds) +1013: 0.4885 (100000 repetitions, Perl: 0.1433 seconds, CL-PPCRE: 0.0700 seconds) +1014: 0.4995 (100000 repetitions, Perl: 0.1401 seconds, CL-PPCRE: 0.0700 seconds) +1015: 0.4964 (100000 repetitions, Perl: 0.1410 seconds, CL-PPCRE: 0.0700 seconds) +1016: 0.4570 (100000 repetitions, Perl: 0.1532 seconds, CL-PPCRE: 0.0700 seconds) +1017: 0.4607 (100000 repetitions, Perl: 0.1519 seconds, CL-PPCRE: 0.0700 seconds) +1018: 0.4578 (100000 repetitions, Perl: 0.1529 seconds, CL-PPCRE: 0.0700 seconds) +1019: 0.4573 (100000 repetitions, Perl: 0.1531 seconds, CL-PPCRE: 0.0700 seconds) +1020: 0.4685 (100000 repetitions, Perl: 0.1281 seconds, CL-PPCRE: 0.0600 seconds) +1021: 0.5708 (100000 repetitions, Perl: 0.1402 seconds, CL-PPCRE: 0.0800 seconds) +1022: 0.4815 (100000 repetitions, Perl: 0.1661 seconds, CL-PPCRE: 0.0800 seconds) +1023: 0.4868 (100000 repetitions, Perl: 0.1643 seconds, CL-PPCRE: 0.0800 seconds) +1024: 0.4939 (100000 repetitions, Perl: 0.1620 seconds, CL-PPCRE: 0.0800 seconds) +1025: 0.5472 (100000 repetitions, Perl: 0.1645 seconds, CL-PPCRE: 0.0900 seconds) +1026: 0.5505 (100000 repetitions, Perl: 0.1635 seconds, CL-PPCRE: 0.0900 seconds) +1027: 0.5315 (100000 repetitions, Perl: 0.1505 seconds, CL-PPCRE: 0.0800 seconds) +1028: 0.5022 (100000 repetitions, Perl: 0.1394 seconds, CL-PPCRE: 0.0700 seconds) +1029: 0.3264 (100000 repetitions, Perl: 0.2145 seconds, CL-PPCRE: 0.0700 seconds) +1030: 0.3346 (100000 repetitions, Perl: 0.1494 seconds, CL-PPCRE: 0.0500 seconds) +1031: 0.4008 (100000 repetitions, Perl: 0.1497 seconds, CL-PPCRE: 0.0600 seconds) +1032: 0.2813 (100000 repetitions, Perl: 0.2133 seconds, CL-PPCRE: 0.0600 seconds) +1033: 0.3560 (100000 repetitions, Perl: 0.2247 seconds, CL-PPCRE: 0.0800 seconds) +1034: 0.3124 (100000 repetitions, Perl: 0.2241 seconds, CL-PPCRE: 0.0700 seconds) +1035: 0.2817 (100000 repetitions, Perl: 0.1420 seconds, CL-PPCRE: 0.0400 seconds) +1036: 0.3732 (100000 repetitions, Perl: 0.1608 seconds, CL-PPCRE: 0.0600 seconds) +1037: 0.8908 (1000000 repetitions, Perl: 0.6174 seconds, CL-PPCRE: 0.5500 seconds) +1038: 0.8891 (1000000 repetitions, Perl: 0.6186 seconds, CL-PPCRE: 0.5500 seconds) +1039: 0.9084 (1000000 repetitions, Perl: 0.6164 seconds, CL-PPCRE: 0.5600 seconds) +1040: 0.4134 (100000 repetitions, Perl: 0.5080 seconds, CL-PPCRE: 0.2100 seconds) +1041: 0.3771 (100000 repetitions, Perl: 0.3978 seconds, CL-PPCRE: 0.1500 seconds) +1042: 0.4070 (100000 repetitions, Perl: 0.4423 seconds, CL-PPCRE: 0.1800 seconds) +1043: 0.3686 (100000 repetitions, Perl: 0.4069 seconds, CL-PPCRE: 0.1500 seconds) +1044: 0.4354 (100000 repetitions, Perl: 0.7580 seconds, CL-PPCRE: 0.3300 seconds) +1045: 0.4202 (100000 repetitions, Perl: 0.7616 seconds, CL-PPCRE: 0.3200 seconds) +1046: 0.4074 (100000 repetitions, Perl: 0.4173 seconds, CL-PPCRE: 0.1700 seconds) +1047: 0.4346 (100000 repetitions, Perl: 0.7823 seconds, CL-PPCRE: 0.3400 seconds) +1048: 0.4338 (100000 repetitions, Perl: 0.7837 seconds, CL-PPCRE: 0.3400 seconds) +1049: 0.4215 (100000 repetitions, Perl: 0.7829 seconds, CL-PPCRE: 0.3300 seconds) +1050: 0.4348 (100000 repetitions, Perl: 0.7819 seconds, CL-PPCRE: 0.3400 seconds) +1051: 0.4342 (100000 repetitions, Perl: 0.7831 seconds, CL-PPCRE: 0.3400 seconds) +1052: 0.4315 (100000 repetitions, Perl: 0.7879 seconds, CL-PPCRE: 0.3400 seconds) +1053: 1.1017 (1000000 repetitions, Perl: 0.6172 seconds, CL-PPCRE: 0.6800 seconds) +1054: 1.1006 (1000000 repetitions, Perl: 0.6179 seconds, CL-PPCRE: 0.6800 seconds) +1055: 1.1014 (1000000 repetitions, Perl: 0.6174 seconds, CL-PPCRE: 0.6800 seconds) +1056: 0.4202 (100000 repetitions, Perl: 0.4997 seconds, CL-PPCRE: 0.2100 seconds) +1057: 0.4627 (100000 repetitions, Perl: 0.3890 seconds, CL-PPCRE: 0.1800 seconds) +1058: 0.4481 (100000 repetitions, Perl: 0.4240 seconds, CL-PPCRE: 0.1900 seconds) +1059: 0.4822 (100000 repetitions, Perl: 0.3941 seconds, CL-PPCRE: 0.1900 seconds) +1060: 0.4665 (100000 repetitions, Perl: 0.6645 seconds, CL-PPCRE: 0.3100 seconds) +1061: 0.4661 (100000 repetitions, Perl: 0.6651 seconds, CL-PPCRE: 0.3100 seconds) +1062: 0.4250 (100000 repetitions, Perl: 0.4000 seconds, CL-PPCRE: 0.1700 seconds) +1063: 0.4645 (100000 repetitions, Perl: 0.6889 seconds, CL-PPCRE: 0.3200 seconds) +1064: 0.4515 (100000 repetitions, Perl: 0.6866 seconds, CL-PPCRE: 0.3100 seconds) +1065: 0.4666 (100000 repetitions, Perl: 0.6858 seconds, CL-PPCRE: 0.3200 seconds) +1066: 0.4514 (100000 repetitions, Perl: 0.6867 seconds, CL-PPCRE: 0.3100 seconds) +1067: 0.4803 (100000 repetitions, Perl: 0.6871 seconds, CL-PPCRE: 0.3300 seconds) +1068: 0.4521 (100000 repetitions, Perl: 0.6857 seconds, CL-PPCRE: 0.3100 seconds) +1069: 0.2367 (100000 repetitions, Perl: 0.1690 seconds, CL-PPCRE: 0.0400 seconds) +1070: 0.2927 (100000 repetitions, Perl: 0.1708 seconds, CL-PPCRE: 0.0500 seconds) +1071: 0.2937 (100000 repetitions, Perl: 0.1702 seconds, CL-PPCRE: 0.0500 seconds) +1072: 0.4285 (1000000 repetitions, Perl: 0.7935 seconds, CL-PPCRE: 0.3400 seconds) +1073: 0.4273 (1000000 repetitions, Perl: 0.7958 seconds, CL-PPCRE: 0.3400 seconds) +1074: 0.4155 (1000000 repetitions, Perl: 0.7702 seconds, CL-PPCRE: 0.3200 seconds) +1075: 0.3433 (100000 repetitions, Perl: 0.1456 seconds, CL-PPCRE: 0.0500 seconds) +1076: 0.3420 (100000 repetitions, Perl: 0.1462 seconds, CL-PPCRE: 0.0500 seconds) +1077: 0.4112 (100000 repetitions, Perl: 0.1459 seconds, CL-PPCRE: 0.0600 seconds) +1078: 0.4726 (100000 repetitions, Perl: 0.1481 seconds, CL-PPCRE: 0.0700 seconds) +1079: 0.2441 (100000 repetitions, Perl: 0.1229 seconds, CL-PPCRE: 0.0300 seconds) +1080: 0.3215 (100000 repetitions, Perl: 0.1244 seconds, CL-PPCRE: 0.0400 seconds) +1081: 0.4700 (100000 repetitions, Perl: 0.1489 seconds, CL-PPCRE: 0.0700 seconds) +1082: 0.4060 (100000 repetitions, Perl: 0.1478 seconds, CL-PPCRE: 0.0600 seconds) +1083: 0.6335 (1000000 repetitions, Perl: 0.6156 seconds, CL-PPCRE: 0.3900 seconds) +1084: 0.5988 (1000000 repetitions, Perl: 0.6179 seconds, CL-PPCRE: 0.3700 seconds) +1085: 0.4737 (100000 repetitions, Perl: 0.1478 seconds, CL-PPCRE: 0.0700 seconds) +1086: 0.4662 (100000 repetitions, Perl: 0.1502 seconds, CL-PPCRE: 0.0700 seconds) +1087: 0.4698 (100000 repetitions, Perl: 0.1490 seconds, CL-PPCRE: 0.0700 seconds) +1088: 0.4444 (100000 repetitions, Perl: 0.1575 seconds, CL-PPCRE: 0.0700 seconds) +1089: 0.6147 (1000000 repetitions, Perl: 0.6181 seconds, CL-PPCRE: 0.3800 seconds) +1090: 0.7628 (1000000 repetitions, Perl: 0.6162 seconds, CL-PPCRE: 0.4700 seconds) +1091: 0.4155 (100000 repetitions, Perl: 0.1444 seconds, CL-PPCRE: 0.0600 seconds) +1092: 0.3413 (100000 repetitions, Perl: 0.1465 seconds, CL-PPCRE: 0.0500 seconds) +1093: 0.3394 (100000 repetitions, Perl: 0.1473 seconds, CL-PPCRE: 0.0500 seconds) +1094: 0.4168 (100000 repetitions, Perl: 0.1439 seconds, CL-PPCRE: 0.0600 seconds) +1095: 0.4189 (100000 repetitions, Perl: 0.1432 seconds, CL-PPCRE: 0.0600 seconds) +1096: 0.4240 (100000 repetitions, Perl: 0.1415 seconds, CL-PPCRE: 0.0600 seconds) +1097: 0.6320 (1000000 repetitions, Perl: 0.7278 seconds, CL-PPCRE: 0.4600 seconds) +1098: 0.7439 (1000000 repetitions, Perl: 0.7259 seconds, CL-PPCRE: 0.5400 seconds) +1099: 0.4353 (100000 repetitions, Perl: 0.1378 seconds, CL-PPCRE: 0.0600 seconds) +1100: 0.2869 (100000 repetitions, Perl: 0.1743 seconds, CL-PPCRE: 0.0500 seconds) +1101: 0.2916 (100000 repetitions, Perl: 0.1714 seconds, CL-PPCRE: 0.0500 seconds) +1102: 0.6549 (1000000 repetitions, Perl: 0.7787 seconds, CL-PPCRE: 0.5100 seconds) +1103: 0.2606 (100000 repetitions, Perl: 0.1151 seconds, CL-PPCRE: 0.0300 seconds) +1104: 0.3060 (100000 repetitions, Perl: 0.1307 seconds, CL-PPCRE: 0.0400 seconds) +1105: 0.3699 (100000 repetitions, Perl: 0.1622 seconds, CL-PPCRE: 0.0600 seconds) +1106: 0.3107 (100000 repetitions, Perl: 0.1609 seconds, CL-PPCRE: 0.0500 seconds) +1107: 0.4186 (100000 repetitions, Perl: 0.1433 seconds, CL-PPCRE: 0.0600 seconds) +1108: 0.3705 (100000 repetitions, Perl: 0.1620 seconds, CL-PPCRE: 0.0600 seconds) +1109: 0.3070 (100000 repetitions, Perl: 0.1303 seconds, CL-PPCRE: 0.0400 seconds) +1110: 0.2271 (100000 repetitions, Perl: 0.1321 seconds, CL-PPCRE: 0.0300 seconds) +1111: 0.3084 (100000 repetitions, Perl: 0.1621 seconds, CL-PPCRE: 0.0500 seconds) +1112: 0.2849 (100000 repetitions, Perl: 0.1755 seconds, CL-PPCRE: 0.0500 seconds) +1113: 0.2561 (100000 repetitions, Perl: 0.1562 seconds, CL-PPCRE: 0.0400 seconds) +1114: 0.2522 (100000 repetitions, Perl: 0.1586 seconds, CL-PPCRE: 0.0400 seconds) +1115: 0.3156 (100000 repetitions, Perl: 0.1584 seconds, CL-PPCRE: 0.0500 seconds) +1116: 0.2411 (100000 repetitions, Perl: 0.1659 seconds, CL-PPCRE: 0.0400 seconds) +1117: 0.3145 (100000 repetitions, Perl: 0.1590 seconds, CL-PPCRE: 0.0500 seconds) +1118: 0.3867 (100000 repetitions, Perl: 0.1293 seconds, CL-PPCRE: 0.0500 seconds) +1119: 0.4624 (100000 repetitions, Perl: 0.1298 seconds, CL-PPCRE: 0.0600 seconds) +1120: 0.3085 (100000 repetitions, Perl: 0.1621 seconds, CL-PPCRE: 0.0500 seconds) +1121: 0.3127 (100000 repetitions, Perl: 0.1599 seconds, CL-PPCRE: 0.0500 seconds) +1122: 0.3696 (100000 repetitions, Perl: 0.1623 seconds, CL-PPCRE: 0.0600 seconds) +1123: 0.3817 (100000 repetitions, Perl: 0.1310 seconds, CL-PPCRE: 0.0500 seconds) +1124: 0.5259 (100000 repetitions, Perl: 0.1711 seconds, CL-PPCRE: 0.0900 seconds) +1125: 0.3481 (100000 repetitions, Perl: 0.1723 seconds, CL-PPCRE: 0.0600 seconds) +1126: 0.5827 (100000 repetitions, Perl: 0.1716 seconds, CL-PPCRE: 0.1000 seconds) +1127: 0.5218 (1000000 repetitions, Perl: 0.8432 seconds, CL-PPCRE: 0.4400 seconds) +1128: 0.5541 (100000 repetitions, Perl: 0.1444 seconds, CL-PPCRE: 0.0800 seconds) +1129: 0.4897 (1000000 repetitions, Perl: 0.9190 seconds, CL-PPCRE: 0.4500 seconds) +1130: 0.6666 (1000000 repetitions, Perl: 0.9151 seconds, CL-PPCRE: 0.6100 seconds) +1131: 0.5408 (1000000 repetitions, Perl: 0.8506 seconds, CL-PPCRE: 0.4600 seconds) +1132: 0.7029 (1000000 repetitions, Perl: 0.9105 seconds, CL-PPCRE: 0.6400 seconds) +1133: 0.3426 (100000 repetitions, Perl: 0.1751 seconds, CL-PPCRE: 0.0600 seconds) +1134: 0.4030 (100000 repetitions, Perl: 0.1737 seconds, CL-PPCRE: 0.0700 seconds) +1135: 0.3455 (100000 repetitions, Perl: 0.1737 seconds, CL-PPCRE: 0.0600 seconds) +1136: 0.2454 (100000 repetitions, Perl: 0.1223 seconds, CL-PPCRE: 0.0300 seconds) +1137: 0.3244 (100000 repetitions, Perl: 0.1233 seconds, CL-PPCRE: 0.0400 seconds) +1138: 0.2405 (100000 repetitions, Perl: 0.1247 seconds, CL-PPCRE: 0.0300 seconds) +1139: 0.3148 (1000000 repetitions, Perl: 0.7941 seconds, CL-PPCRE: 0.2500 seconds) +1140: 0.3763 (100000 repetitions, Perl: 0.1595 seconds, CL-PPCRE: 0.0600 seconds) +1141: 0.3067 (100000 repetitions, Perl: 0.1630 seconds, CL-PPCRE: 0.0500 seconds) +1142: 0.3115 (100000 repetitions, Perl: 0.1605 seconds, CL-PPCRE: 0.0500 seconds) +1143: 0.3903 (100000 repetitions, Perl: 0.1281 seconds, CL-PPCRE: 0.0500 seconds) +1144: 0.2431 (100000 repetitions, Perl: 0.1234 seconds, CL-PPCRE: 0.0300 seconds) +1145: 0.2490 (100000 repetitions, Perl: 0.1205 seconds, CL-PPCRE: 0.0300 seconds) +1146: 0.2464 (100000 repetitions, Perl: 0.1218 seconds, CL-PPCRE: 0.0300 seconds) +1147: 0.3224 (1000000 repetitions, Perl: 0.7755 seconds, CL-PPCRE: 0.2500 seconds) +1148: 0.2474 (100000 repetitions, Perl: 0.1213 seconds, CL-PPCRE: 0.0300 seconds) +1149: 0.2453 (100000 repetitions, Perl: 0.1223 seconds, CL-PPCRE: 0.0300 seconds) +1150: 0.2402 (100000 repetitions, Perl: 0.1249 seconds, CL-PPCRE: 0.0300 seconds) +1151: 0.3149 (1000000 repetitions, Perl: 0.7939 seconds, CL-PPCRE: 0.2500 seconds) +1152: 0.3758 (100000 repetitions, Perl: 0.1596 seconds, CL-PPCRE: 0.0600 seconds) +1153: 0.5027 (100000 repetitions, Perl: 0.1591 seconds, CL-PPCRE: 0.0800 seconds) +1154: 0.4940 (100000 repetitions, Perl: 0.1619 seconds, CL-PPCRE: 0.0800 seconds) +1155: 0.5548 (100000 repetitions, Perl: 0.1262 seconds, CL-PPCRE: 0.0700 seconds) +1156: 0.2429 (100000 repetitions, Perl: 0.1235 seconds, CL-PPCRE: 0.0300 seconds) +1157: 0.2446 (100000 repetitions, Perl: 0.1227 seconds, CL-PPCRE: 0.0300 seconds) +1158: 0.2415 (100000 repetitions, Perl: 0.1242 seconds, CL-PPCRE: 0.0300 seconds) +1159: 0.3301 (1000000 repetitions, Perl: 0.7877 seconds, CL-PPCRE: 0.2600 seconds) +1160: 0.2993 (100000 repetitions, Perl: 0.1336 seconds, CL-PPCRE: 0.0400 seconds) +1161: 0.3004 (100000 repetitions, Perl: 0.1332 seconds, CL-PPCRE: 0.0400 seconds) +1162: 0.4877 (100000 repetitions, Perl: 0.1640 seconds, CL-PPCRE: 0.0800 seconds) +1163: 0.2980 (100000 repetitions, Perl: 0.1678 seconds, CL-PPCRE: 0.0500 seconds) +1164: 0.3522 (100000 repetitions, Perl: 0.1419 seconds, CL-PPCRE: 0.0500 seconds) +1165: 0.3501 (100000 repetitions, Perl: 0.1428 seconds, CL-PPCRE: 0.0500 seconds) +1166: 0.4903 (1000000 repetitions, Perl: 0.6119 seconds, CL-PPCRE: 0.3000 seconds) +1167: 0.5138 (100000 repetitions, Perl: 0.1752 seconds, CL-PPCRE: 0.0900 seconds) +1168: 0.4740 (100000 repetitions, Perl: 0.1899 seconds, CL-PPCRE: 0.0900 seconds) +1169: 0.7838 (100000 repetitions, Perl: 0.1786 seconds, CL-PPCRE: 0.1400 seconds) +1170: 0.5897 (100000 repetitions, Perl: 0.2374 seconds, CL-PPCRE: 0.1400 seconds) +1171: 0.4120 (100000 repetitions, Perl: 0.1456 seconds, CL-PPCRE: 0.0600 seconds) +1172: 0.3606 (100000 repetitions, Perl: 0.3050 seconds, CL-PPCRE: 0.1100 seconds) +1173: 0.3640 (100000 repetitions, Perl: 0.3022 seconds, CL-PPCRE: 0.1100 seconds) +1174: 0.3397 (100000 repetitions, Perl: 0.2943 seconds, CL-PPCRE: 0.1000 seconds) +1175: 0.3675 (100000 repetitions, Perl: 0.2993 seconds, CL-PPCRE: 0.1100 seconds) +1176: 0.3699 (100000 repetitions, Perl: 0.1892 seconds, CL-PPCRE: 0.0700 seconds) +1177: 0.3681 (100000 repetitions, Perl: 0.1902 seconds, CL-PPCRE: 0.0700 seconds) +1178: 0.2174 (100000 repetitions, Perl: 0.1380 seconds, CL-PPCRE: 0.0300 seconds) +1179: 0.4697 (1000000 repetitions, Perl: 0.6175 seconds, CL-PPCRE: 0.2900 seconds) +1180: 0.5686 (100000 repetitions, Perl: 0.1583 seconds, CL-PPCRE: 0.0900 seconds) +1181: 0.5004 (100000 repetitions, Perl: 0.1599 seconds, CL-PPCRE: 0.0800 seconds) +1182: 0.3159 (100000 repetitions, Perl: 0.1583 seconds, CL-PPCRE: 0.0500 seconds) +1183: 0.3580 (100000 repetitions, Perl: 0.2234 seconds, CL-PPCRE: 0.0800 seconds) +1184: 0.4515 (100000 repetitions, Perl: 0.1550 seconds, CL-PPCRE: 0.0700 seconds) +1185: 0.2848 (100000 repetitions, Perl: 0.1755 seconds, CL-PPCRE: 0.0500 seconds) +1186: 0.2827 (100000 repetitions, Perl: 0.1769 seconds, CL-PPCRE: 0.0500 seconds) +1187: 0.7259 (100000 repetitions, Perl: 0.2066 seconds, CL-PPCRE: 0.1500 seconds) +1188: 0.2363 (100000 repetitions, Perl: 0.1693 seconds, CL-PPCRE: 0.0400 seconds) +1189: 0.6586 (100000 repetitions, Perl: 0.3340 seconds, CL-PPCRE: 0.2200 seconds) +1190: 0.5050 (100000 repetitions, Perl: 0.2178 seconds, CL-PPCRE: 0.1100 seconds) +1191: 0.4693 (100000 repetitions, Perl: 0.1918 seconds, CL-PPCRE: 0.0900 seconds) +1192: 0.3908 (100000 repetitions, Perl: 0.2047 seconds, CL-PPCRE: 0.0800 seconds) +1193: 0.4733 (100000 repetitions, Perl: 0.2324 seconds, CL-PPCRE: 0.1100 seconds) +1194: 0.4724 (100000 repetitions, Perl: 0.2329 seconds, CL-PPCRE: 0.1100 seconds) +1195: 0.4342 (100000 repetitions, Perl: 0.2534 seconds, CL-PPCRE: 0.1100 seconds) +1196: 0.3314 (100000 repetitions, Perl: 0.1811 seconds, CL-PPCRE: 0.0600 seconds) +1197: 0.5206 (1000000 repetitions, Perl: 0.6147 seconds, CL-PPCRE: 0.3200 seconds) +1198: 0.7281 (1000000 repetitions, Perl: 0.6180 seconds, CL-PPCRE: 0.4500 seconds) +1199: 0.5142 (100000 repetitions, Perl: 0.1556 seconds, CL-PPCRE: 0.0800 seconds) +1200: 0.5652 (100000 repetitions, Perl: 0.2123 seconds, CL-PPCRE: 0.1200 seconds) +1201: 0.8035 (100000 repetitions, Perl: 0.1494 seconds, CL-PPCRE: 0.1200 seconds) +1202: 0.4921 (100000 repetitions, Perl: 0.2439 seconds, CL-PPCRE: 0.1200 seconds) +1203: 0.5212 (100000 repetitions, Perl: 0.1727 seconds, CL-PPCRE: 0.0900 seconds) +1204: 0.5820 (100000 repetitions, Perl: 0.1890 seconds, CL-PPCRE: 0.1100 seconds) +1205: 0.5753 (100000 repetitions, Perl: 0.2260 seconds, CL-PPCRE: 0.1300 seconds) +1206: 0.5358 (100000 repetitions, Perl: 0.2986 seconds, CL-PPCRE: 0.1600 seconds) +1207: 0.5399 (100000 repetitions, Perl: 0.2963 seconds, CL-PPCRE: 0.1600 seconds) +1208: 1.0716 (100000 repetitions, Perl: 0.2053 seconds, CL-PPCRE: 0.2200 seconds) +1209: 1.1409 (100000 repetitions, Perl: 0.2104 seconds, CL-PPCRE: 0.2400 seconds) +1210: 1.1050 (100000 repetitions, Perl: 0.1991 seconds, CL-PPCRE: 0.2200 seconds) +1211: 0.4698 (1000000 repetitions, Perl: 0.6173 seconds, CL-PPCRE: 0.2900 seconds) +1212: 0.4866 (1000000 repetitions, Perl: 0.6165 seconds, CL-PPCRE: 0.3000 seconds) +1213: 0.3107 (100000 repetitions, Perl: 0.1931 seconds, CL-PPCRE: 0.0600 seconds) +1214: 0.4636 (100000 repetitions, Perl: 0.2157 seconds, CL-PPCRE: 0.1000 seconds) +1215: 0.4719 (100000 repetitions, Perl: 0.2755 seconds, CL-PPCRE: 0.1300 seconds) +1216: 0.2852 (100000 repetitions, Perl: 0.1753 seconds, CL-PPCRE: 0.0500 seconds) +1217: 0.4211 (100000 repetitions, Perl: 0.1900 seconds, CL-PPCRE: 0.0800 seconds) +1218: 0.3272 (100000 repetitions, Perl: 0.1528 seconds, CL-PPCRE: 0.0500 seconds) +1219: 0.4935 (100000 repetitions, Perl: 0.1824 seconds, CL-PPCRE: 0.0900 seconds) +1220: 0.6097 (100000 repetitions, Perl: 0.1968 seconds, CL-PPCRE: 0.1200 seconds) +1221: 0.5091 (100000 repetitions, Perl: 0.1375 seconds, CL-PPCRE: 0.0700 seconds) +1222: 0.5014 (100000 repetitions, Perl: 0.1396 seconds, CL-PPCRE: 0.0700 seconds) +1223: 0.4948 (100000 repetitions, Perl: 0.1617 seconds, CL-PPCRE: 0.0800 seconds) +1224: 0.5640 (100000 repetitions, Perl: 0.3192 seconds, CL-PPCRE: 0.1800 seconds) +1225: 0.8114 (100000 repetitions, Perl: 0.3327 seconds, CL-PPCRE: 0.2700 seconds) +1226: 0.5465 (100000 repetitions, Perl: 0.9515 seconds, CL-PPCRE: 0.5200 seconds) +1227: 0.7252 (10000 repetitions, Perl: 0.1379 seconds, CL-PPCRE: 0.1000 seconds) +1228: 0.3727 (100000 repetitions, Perl: 0.1342 seconds, CL-PPCRE: 0.0500 seconds) +1229: 0.4447 (100000 repetitions, Perl: 0.1349 seconds, CL-PPCRE: 0.0600 seconds) +1230: 0.3507 (100000 repetitions, Perl: 0.1426 seconds, CL-PPCRE: 0.0500 seconds) +1231: 0.3976 (100000 repetitions, Perl: 0.1006 seconds, CL-PPCRE: 0.0400 seconds) +1232: 0.5323 (1000000 repetitions, Perl: 0.7890 seconds, CL-PPCRE: 0.4200 seconds) +1233: 0.4362 (1000000 repetitions, Perl: 0.8253 seconds, CL-PPCRE: 0.3600 seconds) +1234: 0.4144 (1000000 repetitions, Perl: 0.8204 seconds, CL-PPCRE: 0.3400 seconds) +1235: 0.3422 (100000 repetitions, Perl: 0.1461 seconds, CL-PPCRE: 0.0500 seconds) +1236: 0.3898 (100000 repetitions, Perl: 0.1539 seconds, CL-PPCRE: 0.0600 seconds) +1237: 0.3885 (100000 repetitions, Perl: 0.1545 seconds, CL-PPCRE: 0.0600 seconds) +1238: 0.5008 (100000 repetitions, Perl: 0.1997 seconds, CL-PPCRE: 0.1000 seconds) +1239: 0.5094 (100000 repetitions, Perl: 0.1963 seconds, CL-PPCRE: 0.1000 seconds) +1240: 0.4515 (100000 repetitions, Perl: 0.1550 seconds, CL-PPCRE: 0.0700 seconds) +1241: 0.6930 (1000000 repetitions, Perl: 0.6205 seconds, CL-PPCRE: 0.4300 seconds) +1242: 0.6343 (1000000 repetitions, Perl: 0.6148 seconds, CL-PPCRE: 0.3900 seconds) +1243: 0.5096 (100000 repetitions, Perl: 0.1570 seconds, CL-PPCRE: 0.0800 seconds) +1244: 0.5477 (100000 repetitions, Perl: 0.1826 seconds, CL-PPCRE: 0.1000 seconds) +1245: 0.5955 (100000 repetitions, Perl: 0.1847 seconds, CL-PPCRE: 0.1100 seconds) +1246: 0.5025 (100000 repetitions, Perl: 0.1592 seconds, CL-PPCRE: 0.0800 seconds) +1247: 0.6442 (1000000 repetitions, Perl: 0.6209 seconds, CL-PPCRE: 0.4000 seconds) +1248: 0.8571 (1000000 repetitions, Perl: 0.6183 seconds, CL-PPCRE: 0.5300 seconds) +1249: 0.4124 (100000 repetitions, Perl: 0.1697 seconds, CL-PPCRE: 0.0700 seconds) +1250: 0.4076 (100000 repetitions, Perl: 0.1472 seconds, CL-PPCRE: 0.0600 seconds) +1251: 0.4063 (100000 repetitions, Perl: 0.1477 seconds, CL-PPCRE: 0.0600 seconds) +1252: 0.4719 (100000 repetitions, Perl: 0.1483 seconds, CL-PPCRE: 0.0700 seconds) +1253: 0.4707 (100000 repetitions, Perl: 0.1487 seconds, CL-PPCRE: 0.0700 seconds) +1254: 0.4641 (100000 repetitions, Perl: 0.1293 seconds, CL-PPCRE: 0.0600 seconds) +1255: 0.4680 (1000000 repetitions, Perl: 0.9401 seconds, CL-PPCRE: 0.4400 seconds) +1256: 0.4910 (100000 repetitions, Perl: 0.1018 seconds, CL-PPCRE: 0.0500 seconds) +1257: 0.4802 (100000 repetitions, Perl: 0.1249 seconds, CL-PPCRE: 0.0600 seconds) +1258: 0.4269 (100000 repetitions, Perl: 0.1405 seconds, CL-PPCRE: 0.0600 seconds) +1259: 0.2609 (100000 repetitions, Perl: 0.1150 seconds, CL-PPCRE: 0.0300 seconds) +1260: 0.3090 (100000 repetitions, Perl: 0.1294 seconds, CL-PPCRE: 0.0400 seconds) +1261: 0.4528 (100000 repetitions, Perl: 0.1325 seconds, CL-PPCRE: 0.0600 seconds) +1262: 0.4556 (100000 repetitions, Perl: 0.1317 seconds, CL-PPCRE: 0.0600 seconds) +1263: 0.5502 (100000 repetitions, Perl: 0.1454 seconds, CL-PPCRE: 0.0800 seconds) +1264: 0.4150 (100000 repetitions, Perl: 0.1446 seconds, CL-PPCRE: 0.0600 seconds) +1265: 0.3445 (100000 repetitions, Perl: 0.1161 seconds, CL-PPCRE: 0.0400 seconds) +1266: 0.4460 (100000 repetitions, Perl: 0.1345 seconds, CL-PPCRE: 0.0600 seconds) +1267: 0.4512 (100000 repetitions, Perl: 0.1330 seconds, CL-PPCRE: 0.0600 seconds) +1268: 0.2792 (100000 repetitions, Perl: 0.1075 seconds, CL-PPCRE: 0.0300 seconds) +1269: 0.3707 (100000 repetitions, Perl: 0.1079 seconds, CL-PPCRE: 0.0400 seconds) +1270: 0.4187 (100000 repetitions, Perl: 0.1433 seconds, CL-PPCRE: 0.0600 seconds) +1271: 0.3944 (100000 repetitions, Perl: 0.1268 seconds, CL-PPCRE: 0.0500 seconds) +1272: 0.3111 (100000 repetitions, Perl: 0.1286 seconds, CL-PPCRE: 0.0400 seconds) +1273: 0.2980 (100000 repetitions, Perl: 0.1342 seconds, CL-PPCRE: 0.0400 seconds) +1274: 0.4554 (100000 repetitions, Perl: 0.1318 seconds, CL-PPCRE: 0.0600 seconds) +1275: 0.4558 (100000 repetitions, Perl: 0.1316 seconds, CL-PPCRE: 0.0600 seconds) +1276: 0.4516 (100000 repetitions, Perl: 0.1329 seconds, CL-PPCRE: 0.0600 seconds) +1277: 0.3876 (100000 repetitions, Perl: 0.1032 seconds, CL-PPCRE: 0.0400 seconds) +1278: 0.4804 (100000 repetitions, Perl: 0.1041 seconds, CL-PPCRE: 0.0500 seconds) +1279: 0.4588 (100000 repetitions, Perl: 0.1308 seconds, CL-PPCRE: 0.0600 seconds) +1280: 0.2754 (100000 repetitions, Perl: 0.1452 seconds, CL-PPCRE: 0.0400 seconds) +1281: 0.2799 (100000 repetitions, Perl: 0.1429 seconds, CL-PPCRE: 0.0400 seconds) +1282: 0.5499 (100000 repetitions, Perl: 0.1455 seconds, CL-PPCRE: 0.0800 seconds) +1283: 0.3526 (100000 repetitions, Perl: 0.1134 seconds, CL-PPCRE: 0.0400 seconds) +1284: 0.3570 (100000 repetitions, Perl: 0.1121 seconds, CL-PPCRE: 0.0400 seconds) +1285: 0.3734 (100000 repetitions, Perl: 0.1339 seconds, CL-PPCRE: 0.0500 seconds) +1286: 0.3545 (100000 repetitions, Perl: 0.1410 seconds, CL-PPCRE: 0.0500 seconds) +1287: 0.4091 (100000 repetitions, Perl: 0.1467 seconds, CL-PPCRE: 0.0600 seconds) +1288: 0.4858 (1000000 repetitions, Perl: 0.6176 seconds, CL-PPCRE: 0.3000 seconds) +1289: 0.6510 (100000 repetitions, Perl: 0.1382 seconds, CL-PPCRE: 0.0900 seconds) +1290: 0.6770 (100000 repetitions, Perl: 0.1477 seconds, CL-PPCRE: 0.1000 seconds) +1291: 0.6942 (100000 repetitions, Perl: 0.2305 seconds, CL-PPCRE: 0.1600 seconds) +1292: 0.6907 (100000 repetitions, Perl: 0.2316 seconds, CL-PPCRE: 0.1600 seconds) +1293: 0.4198 (100000 repetitions, Perl: 0.1429 seconds, CL-PPCRE: 0.0600 seconds) +1294: 0.4822 (100000 repetitions, Perl: 0.1452 seconds, CL-PPCRE: 0.0700 seconds) +1295: 0.4146 (100000 repetitions, Perl: 0.1447 seconds, CL-PPCRE: 0.0600 seconds) +1296: 0.3391 (100000 repetitions, Perl: 0.3244 seconds, CL-PPCRE: 0.1100 seconds) +1297: 0.3420 (100000 repetitions, Perl: 0.3217 seconds, CL-PPCRE: 0.1100 seconds) +1298: 0.3516 (100000 repetitions, Perl: 0.3128 seconds, CL-PPCRE: 0.1100 seconds) +1299: 0.3490 (100000 repetitions, Perl: 0.3152 seconds, CL-PPCRE: 0.1100 seconds) +1300: 0.3570 (100000 repetitions, Perl: 0.1961 seconds, CL-PPCRE: 0.0700 seconds) +1301: 0.3511 (100000 repetitions, Perl: 0.1994 seconds, CL-PPCRE: 0.0700 seconds) +1302: 0.3363 (100000 repetitions, Perl: 0.1487 seconds, CL-PPCRE: 0.0500 seconds) +1303: 0.2163 (100000 repetitions, Perl: 0.1387 seconds, CL-PPCRE: 0.0300 seconds) +1304: 0.5458 (100000 repetitions, Perl: 0.1649 seconds, CL-PPCRE: 0.0900 seconds) +1305: 0.5308 (100000 repetitions, Perl: 0.1696 seconds, CL-PPCRE: 0.0900 seconds) +1306: 0.2966 (100000 repetitions, Perl: 0.1686 seconds, CL-PPCRE: 0.0500 seconds) +1307: 0.4821 (100000 repetitions, Perl: 0.1867 seconds, CL-PPCRE: 0.0900 seconds) +1308: 0.4939 (100000 repetitions, Perl: 0.1620 seconds, CL-PPCRE: 0.0800 seconds) +1309: 0.3487 (100000 repetitions, Perl: 0.1434 seconds, CL-PPCRE: 0.0500 seconds) +1310: 0.3636 (100000 repetitions, Perl: 0.1375 seconds, CL-PPCRE: 0.0500 seconds) +1311: 0.6696 (100000 repetitions, Perl: 0.2539 seconds, CL-PPCRE: 0.1700 seconds) +1312: 0.3703 (100000 repetitions, Perl: 0.1350 seconds, CL-PPCRE: 0.0500 seconds) +1313: 0.4320 (100000 repetitions, Perl: 0.1389 seconds, CL-PPCRE: 0.0600 seconds) +1314: 0.6490 (100000 repetitions, Perl: 0.3544 seconds, CL-PPCRE: 0.2300 seconds) +1315: 0.5671 (100000 repetitions, Perl: 0.2292 seconds, CL-PPCRE: 0.1300 seconds) +1316: 0.5198 (100000 repetitions, Perl: 0.2116 seconds, CL-PPCRE: 0.1100 seconds) +1317: 0.4623 (100000 repetitions, Perl: 0.1730 seconds, CL-PPCRE: 0.0800 seconds) +1318: 0.6373 (100000 repetitions, Perl: 0.1883 seconds, CL-PPCRE: 0.1200 seconds) +1319: 0.6446 (100000 repetitions, Perl: 0.1862 seconds, CL-PPCRE: 0.1200 seconds) +1320: 0.6559 (100000 repetitions, Perl: 0.2135 seconds, CL-PPCRE: 0.1400 seconds) +1321: 0.4390 (100000 repetitions, Perl: 0.1822 seconds, CL-PPCRE: 0.0800 seconds) +1322: 0.5881 (100000 repetitions, Perl: 0.1700 seconds, CL-PPCRE: 0.1000 seconds) +1323: 0.7739 (100000 repetitions, Perl: 0.1680 seconds, CL-PPCRE: 0.1300 seconds) +1324: 0.3400 (100000 repetitions, Perl: 0.1471 seconds, CL-PPCRE: 0.0500 seconds) +1325: 0.5080 (100000 repetitions, Perl: 0.2559 seconds, CL-PPCRE: 0.1300 seconds) +1326: 0.5332 (100000 repetitions, Perl: 0.1875 seconds, CL-PPCRE: 0.1000 seconds) +1327: 0.5438 (100000 repetitions, Perl: 0.2023 seconds, CL-PPCRE: 0.1100 seconds) +1328: 0.5896 (100000 repetitions, Perl: 0.2374 seconds, CL-PPCRE: 0.1400 seconds) +1329: 0.6437 (100000 repetitions, Perl: 0.4194 seconds, CL-PPCRE: 0.2700 seconds) +1330: 0.5475 (100000 repetitions, Perl: 0.3105 seconds, CL-PPCRE: 0.1700 seconds) +1331: 0.5626 (100000 repetitions, Perl: 0.3022 seconds, CL-PPCRE: 0.1700 seconds) +1332: 1.2478 (100000 repetitions, Perl: 0.1763 seconds, CL-PPCRE: 0.2200 seconds) +1333: 1.3674 (100000 repetitions, Perl: 0.1828 seconds, CL-PPCRE: 0.2500 seconds) +1334: 1.2733 (100000 repetitions, Perl: 0.1728 seconds, CL-PPCRE: 0.2200 seconds) +1335: 0.5285 (100000 repetitions, Perl: 0.1325 seconds, CL-PPCRE: 0.0700 seconds) +1336: 0.4142 (100000 repetitions, Perl: 0.1690 seconds, CL-PPCRE: 0.0700 seconds) +1337: 0.4689 (1000000 repetitions, Perl: 0.6185 seconds, CL-PPCRE: 0.2900 seconds) +1338: 0.4705 (1000000 repetitions, Perl: 0.6164 seconds, CL-PPCRE: 0.2900 seconds) +1339: 0.5296 (100000 repetitions, Perl: 0.1511 seconds, CL-PPCRE: 0.0800 seconds) +1340: 0.5221 (100000 repetitions, Perl: 0.1915 seconds, CL-PPCRE: 0.1000 seconds) +1341: 0.5562 (100000 repetitions, Perl: 0.2337 seconds, CL-PPCRE: 0.1300 seconds) +1342: 0.4419 (100000 repetitions, Perl: 0.1358 seconds, CL-PPCRE: 0.0600 seconds) +1343: 0.6095 (100000 repetitions, Perl: 0.1477 seconds, CL-PPCRE: 0.0900 seconds) +1344: 0.3896 (100000 repetitions, Perl: 0.1540 seconds, CL-PPCRE: 0.0600 seconds) +1345: 0.5580 (100000 repetitions, Perl: 0.1613 seconds, CL-PPCRE: 0.0900 seconds) +1346: 0.5612 (100000 repetitions, Perl: 0.1960 seconds, CL-PPCRE: 0.1100 seconds) +1347: 0.3277 (100000 repetitions, Perl: 0.2136 seconds, CL-PPCRE: 0.0700 seconds) +1348: 0.2471 (100000 repetitions, Perl: 0.2428 seconds, CL-PPCRE: 0.0600 seconds) +1349: 0.2891 (100000 repetitions, Perl: 0.2767 seconds, CL-PPCRE: 0.0800 seconds) +1350: 0.3802 (100000 repetitions, Perl: 0.2104 seconds, CL-PPCRE: 0.0800 seconds) +1351: 0.3484 (100000 repetitions, Perl: 0.2583 seconds, CL-PPCRE: 0.0900 seconds) +1352: 0.3698 (100000 repetitions, Perl: 0.2433 seconds, CL-PPCRE: 0.0900 seconds) +1353: 0.3679 (100000 repetitions, Perl: 0.2447 seconds, CL-PPCRE: 0.0900 seconds) +1354: 0.3893 (100000 repetitions, Perl: 0.3853 seconds, CL-PPCRE: 0.1500 seconds) +1355: 0.3846 (100000 repetitions, Perl: 0.2600 seconds, CL-PPCRE: 0.1000 seconds) +1356: 0.4225 (100000 repetitions, Perl: 0.3313 seconds, CL-PPCRE: 0.1400 seconds) +1357: 0.4133 (100000 repetitions, Perl: 0.3145 seconds, CL-PPCRE: 0.1300 seconds) +1358: 0.4143 (100000 repetitions, Perl: 0.3379 seconds, CL-PPCRE: 0.1400 seconds) +1359: 0.3678 (100000 repetitions, Perl: 0.3806 seconds, CL-PPCRE: 0.1400 seconds) +1360: 0.4124 (100000 repetitions, Perl: 0.3637 seconds, CL-PPCRE: 0.1500 seconds) +1361: 0.4276 (100000 repetitions, Perl: 0.3508 seconds, CL-PPCRE: 0.1500 seconds) +1362: 0.4059 (100000 repetitions, Perl: 0.3449 seconds, CL-PPCRE: 0.1400 seconds) +1363: 0.3658 (100000 repetitions, Perl: 0.3827 seconds, CL-PPCRE: 0.1400 seconds) +1364: 0.4070 (100000 repetitions, Perl: 0.3440 seconds, CL-PPCRE: 0.1400 seconds) +1365: 0.4046 (100000 repetitions, Perl: 0.2966 seconds, CL-PPCRE: 0.1200 seconds) +1366: 0.3032 (100000 repetitions, Perl: 0.2639 seconds, CL-PPCRE: 0.0800 seconds) +1367: 0.5464 (100000 repetitions, Perl: 0.1464 seconds, CL-PPCRE: 0.0800 seconds) +1368: 0.2849 (100000 repetitions, Perl: 0.1404 seconds, CL-PPCRE: 0.0400 seconds) +1369: 0.4075 (100000 repetitions, Perl: 0.4172 seconds, CL-PPCRE: 0.1700 seconds) +1370: 0.9250 (1000000 repetitions, Perl: 0.6162 seconds, CL-PPCRE: 0.5700 seconds) +1371: 0.4216 (100000 repetitions, Perl: 0.7589 seconds, CL-PPCRE: 0.3200 seconds) +1372: 0.4316 (100000 repetitions, Perl: 0.7877 seconds, CL-PPCRE: 0.3400 seconds) +1373: 0.6365 (100000 repetitions, Perl: 0.2828 seconds, CL-PPCRE: 0.1800 seconds) +1374: 0.7316 (100000 repetitions, Perl: 0.2324 seconds, CL-PPCRE: 0.1700 seconds) +1375: 0.6991 (100000 repetitions, Perl: 0.2575 seconds, CL-PPCRE: 0.1800 seconds) +1376: 0.4090 (100000 repetitions, Perl: 0.3912 seconds, CL-PPCRE: 0.1600 seconds) +1377: 0.2652 (100000 repetitions, Perl: 0.1885 seconds, CL-PPCRE: 0.0500 seconds) +1378: 0.3020 (100000 repetitions, Perl: 0.1325 seconds, CL-PPCRE: 0.0400 seconds) +1379: 0.2309 (100000 repetitions, Perl: 0.1299 seconds, CL-PPCRE: 0.0300 seconds) +1380: 0.2177 (100000 repetitions, Perl: 0.1838 seconds, CL-PPCRE: 0.0400 seconds) +1381: 0.2384 (100000 repetitions, Perl: 0.1678 seconds, CL-PPCRE: 0.0400 seconds) +1382: 0.2337 (100000 repetitions, Perl: 0.1711 seconds, CL-PPCRE: 0.0400 seconds) +1383: 0.2700 (100000 repetitions, Perl: 0.1852 seconds, CL-PPCRE: 0.0500 seconds) +1384: 0.2408 (100000 repetitions, Perl: 0.1661 seconds, CL-PPCRE: 0.0400 seconds) +1385: 0.4655 (100000 repetitions, Perl: 0.3437 seconds, CL-PPCRE: 0.1600 seconds) +1386: 0.8942 (100000 repetitions, Perl: 0.1342 seconds, CL-PPCRE: 0.1200 seconds) +1387: 0.3001 (100000 repetitions, Perl: 0.3665 seconds, CL-PPCRE: 0.1100 seconds) +1388: 0.3030 (100000 repetitions, Perl: 0.5611 seconds, CL-PPCRE: 0.1700 seconds) +1389: 0.3822 (100000 repetitions, Perl: 0.6802 seconds, CL-PPCRE: 0.2600 seconds) +1390: 0.4852 (100000 repetitions, Perl: 0.2473 seconds, CL-PPCRE: 0.1200 seconds) +1391: 0.7024 (100000 repetitions, Perl: 0.1424 seconds, CL-PPCRE: 0.1000 seconds) +1392: 0.3041 (100000 repetitions, Perl: 0.1644 seconds, CL-PPCRE: 0.0500 seconds) +1393: 0.5266 (100000 repetitions, Perl: 0.1709 seconds, CL-PPCRE: 0.0900 seconds) +1394: 0.3038 (100000 repetitions, Perl: 0.1646 seconds, CL-PPCRE: 0.0500 seconds) +1395: 0.4551 (100000 repetitions, Perl: 0.1758 seconds, CL-PPCRE: 0.0800 seconds) +1396: 0.3618 (1000000 repetitions, Perl: 0.8845 seconds, CL-PPCRE: 0.3200 seconds) +1397: 0.4574 (1000000 repetitions, Perl: 0.7651 seconds, CL-PPCRE: 0.3500 seconds) +1398: 0.3032 (100000 repetitions, Perl: 0.1649 seconds, CL-PPCRE: 0.0500 seconds) +1399: 0.4585 (100000 repetitions, Perl: 0.1745 seconds, CL-PPCRE: 0.0800 seconds) +1400: 0.3029 (100000 repetitions, Perl: 0.1651 seconds, CL-PPCRE: 0.0500 seconds) +1401: 0.4451 (100000 repetitions, Perl: 0.1797 seconds, CL-PPCRE: 0.0800 seconds) +1402: 0.4356 (1000000 repetitions, Perl: 0.7805 seconds, CL-PPCRE: 0.3400 seconds) +1403: 0.4575 (1000000 repetitions, Perl: 0.7651 seconds, CL-PPCRE: 0.3500 seconds) +1404: 0.3098 (100000 repetitions, Perl: 0.1614 seconds, CL-PPCRE: 0.0500 seconds) +1405: 0.4778 (100000 repetitions, Perl: 0.1674 seconds, CL-PPCRE: 0.0800 seconds) +1406: 0.3176 (100000 repetitions, Perl: 0.1574 seconds, CL-PPCRE: 0.0500 seconds) +1407: 0.5297 (100000 repetitions, Perl: 0.1699 seconds, CL-PPCRE: 0.0900 seconds) +1408: 0.3185 (100000 repetitions, Perl: 0.1570 seconds, CL-PPCRE: 0.0500 seconds) +1409: 0.4814 (1000000 repetitions, Perl: 0.7686 seconds, CL-PPCRE: 0.3700 seconds) +1410: 0.3147 (100000 repetitions, Perl: 0.1589 seconds, CL-PPCRE: 0.0500 seconds) +1411: 0.5297 (100000 repetitions, Perl: 0.1699 seconds, CL-PPCRE: 0.0900 seconds) +1412: 0.4106 (1000000 repetitions, Perl: 0.7793 seconds, CL-PPCRE: 0.3200 seconds) +1413: 0.4384 (1000000 repetitions, Perl: 0.7756 seconds, CL-PPCRE: 0.3400 seconds) +1414: 0.3158 (100000 repetitions, Perl: 0.1583 seconds, CL-PPCRE: 0.0500 seconds) +1415: 0.4746 (100000 repetitions, Perl: 0.1686 seconds, CL-PPCRE: 0.0800 seconds) +1416: 0.3202 (100000 repetitions, Perl: 0.1561 seconds, CL-PPCRE: 0.0500 seconds) +1417: 0.5344 (100000 repetitions, Perl: 0.1684 seconds, CL-PPCRE: 0.0900 seconds) +1418: 0.4052 (1000000 repetitions, Perl: 0.7651 seconds, CL-PPCRE: 0.3100 seconds) +1419: 0.3992 (1000000 repetitions, Perl: 0.7765 seconds, CL-PPCRE: 0.3100 seconds) +1420: 0.3187 (100000 repetitions, Perl: 0.1569 seconds, CL-PPCRE: 0.0500 seconds) +1421: 0.4692 (100000 repetitions, Perl: 0.1705 seconds, CL-PPCRE: 0.0800 seconds) +1422: 0.4313 (1000000 repetitions, Perl: 0.7652 seconds, CL-PPCRE: 0.3300 seconds) +1423: 0.4179 (1000000 repetitions, Perl: 0.7656 seconds, CL-PPCRE: 0.3200 seconds) +1424: 0.9233 (1000000 repetitions, Perl: 0.6174 seconds, CL-PPCRE: 0.5700 seconds) +1425: 0.5082 (100000 repetitions, Perl: 0.1377 seconds, CL-PPCRE: 0.0700 seconds) +1426: 0.5301 (100000 repetitions, Perl: 0.1698 seconds, CL-PPCRE: 0.0900 seconds) +1427: 0.4377 (100000 repetitions, Perl: 0.1371 seconds, CL-PPCRE: 0.0600 seconds) +1428: 0.8477 (100000 repetitions, Perl: 0.1533 seconds, CL-PPCRE: 0.1300 seconds) +1429: 0.5569 (100000 repetitions, Perl: 0.1616 seconds, CL-PPCRE: 0.0900 seconds) +1430: 0.5470 (100000 repetitions, Perl: 0.1645 seconds, CL-PPCRE: 0.0900 seconds) +1431: 0.2694 (100000 repetitions, Perl: 0.3340 seconds, CL-PPCRE: 0.0900 seconds) +1432: 0.3398 (100000 repetitions, Perl: 0.2648 seconds, CL-PPCRE: 0.0900 seconds) +1433: 0.3196 (100000 repetitions, Perl: 0.1564 seconds, CL-PPCRE: 0.0500 seconds) +1434: 0.2563 (100000 repetitions, Perl: 0.1561 seconds, CL-PPCRE: 0.0400 seconds) +1435: 0.2549 (100000 repetitions, Perl: 0.1569 seconds, CL-PPCRE: 0.0400 seconds) +1436: 0.3966 (1000000 repetitions, Perl: 0.7817 seconds, CL-PPCRE: 0.3100 seconds) +1437: 0.3186 (100000 repetitions, Perl: 0.1569 seconds, CL-PPCRE: 0.0500 seconds) +1438: 0.2879 (100000 repetitions, Perl: 0.1737 seconds, CL-PPCRE: 0.0500 seconds) +1440: 0.4261 (100000 repetitions, Perl: 0.1877 seconds, CL-PPCRE: 0.0800 seconds) +1441: 0.2673 (100000 repetitions, Perl: 0.1871 seconds, CL-PPCRE: 0.0500 seconds) +1442: 0.3109 (100000 repetitions, Perl: 0.2573 seconds, CL-PPCRE: 0.0800 seconds) +1443: 0.8570 (100000 repetitions, Perl: 0.1750 seconds, CL-PPCRE: 0.1500 seconds) +1444: 0.4761 (100000 repetitions, Perl: 0.1470 seconds, CL-PPCRE: 0.0700 seconds) +1445: 0.2776 (100000 repetitions, Perl: 0.1441 seconds, CL-PPCRE: 0.0400 seconds) +1446: 0.4592 (100000 repetitions, Perl: 0.1525 seconds, CL-PPCRE: 0.0700 seconds) +1447: 0.4758 (100000 repetitions, Perl: 0.1471 seconds, CL-PPCRE: 0.0700 seconds) +1448: 0.5301 (100000 repetitions, Perl: 0.1698 seconds, CL-PPCRE: 0.0900 seconds) +1449: 0.6724 (100000 repetitions, Perl: 0.1933 seconds, CL-PPCRE: 0.1300 seconds) +1450: 0.6677 (100000 repetitions, Perl: 0.1947 seconds, CL-PPCRE: 0.1300 seconds) +1451: 0.4503 (100000 repetitions, Perl: 0.1999 seconds, CL-PPCRE: 0.0900 seconds) +1452: 0.4078 (100000 repetitions, Perl: 0.1962 seconds, CL-PPCRE: 0.0800 seconds) +1453: 0.5974 (100000 repetitions, Perl: 0.1339 seconds, CL-PPCRE: 0.0800 seconds) +1454: 0.6096 (100000 repetitions, Perl: 0.1312 seconds, CL-PPCRE: 0.0800 seconds) +1455: 0.4783 (100000 repetitions, Perl: 0.1464 seconds, CL-PPCRE: 0.0700 seconds) +1456: 0.2228 (100000 repetitions, Perl: 0.1347 seconds, CL-PPCRE: 0.0300 seconds) +1457: 0.3958 (100000 repetitions, Perl: 0.1516 seconds, CL-PPCRE: 0.0600 seconds) +1458: 0.4623 (100000 repetitions, Perl: 0.1514 seconds, CL-PPCRE: 0.0700 seconds) +1459: 0.4619 (100000 repetitions, Perl: 0.1515 seconds, CL-PPCRE: 0.0700 seconds) +1460: 0.4710 (100000 repetitions, Perl: 0.1699 seconds, CL-PPCRE: 0.0800 seconds) +1461: 0.4722 (100000 repetitions, Perl: 0.1482 seconds, CL-PPCRE: 0.0700 seconds) +1462: 0.5930 (100000 repetitions, Perl: 0.1686 seconds, CL-PPCRE: 0.1000 seconds) +1463: 0.5698 (100000 repetitions, Perl: 0.1579 seconds, CL-PPCRE: 0.0900 seconds) +1464: 0.8227 (1000000 repetitions, Perl: 0.6199 seconds, CL-PPCRE: 0.5100 seconds) +1465: 0.5918 (100000 repetitions, Perl: 0.1352 seconds, CL-PPCRE: 0.0800 seconds) +1466: 0.7302 (100000 repetitions, Perl: 0.1370 seconds, CL-PPCRE: 0.1000 seconds) +1467: 0.3578 (100000 repetitions, Perl: 0.2795 seconds, CL-PPCRE: 0.1000 seconds) +1468: 0.3107 (100000 repetitions, Perl: 0.2574 seconds, CL-PPCRE: 0.0800 seconds) +1469: 0.3741 (100000 repetitions, Perl: 0.2139 seconds, CL-PPCRE: 0.0800 seconds) +1470: 0.4383 (100000 repetitions, Perl: 0.2281 seconds, CL-PPCRE: 0.1000 seconds) +1471: 0.1875 (100000 repetitions, Perl: 0.1600 seconds, CL-PPCRE: 0.0300 seconds) +1472: 0.1889 (100000 repetitions, Perl: 0.1588 seconds, CL-PPCRE: 0.0300 seconds) +1473: 0.2495 (100000 repetitions, Perl: 0.1603 seconds, CL-PPCRE: 0.0400 seconds) +1474: 0.2374 (100000 repetitions, Perl: 0.1685 seconds, CL-PPCRE: 0.0400 seconds) +1475: 0.5786 (100000 repetitions, Perl: 0.2420 seconds, CL-PPCRE: 0.1400 seconds) +1476: 0.3304 (100000 repetitions, Perl: 0.2724 seconds, CL-PPCRE: 0.0900 seconds) +1477: 0.4475 (100000 repetitions, Perl: 0.1788 seconds, CL-PPCRE: 0.0800 seconds) +1478: 0.6218 (100000 repetitions, Perl: 0.2412 seconds, CL-PPCRE: 0.1500 seconds) +1479: 0.5484 (100000 repetitions, Perl: 0.1459 seconds, CL-PPCRE: 0.0800 seconds) +1480: 0.6176 (100000 repetitions, Perl: 0.1457 seconds, CL-PPCRE: 0.0900 seconds) +1481: 0.5064 (100000 repetitions, Perl: 0.2567 seconds, CL-PPCRE: 0.1300 seconds) +1482: 0.9923 (100000 repetitions, Perl: 0.3023 seconds, CL-PPCRE: 0.3000 seconds) +1483: 0.4191 (100000 repetitions, Perl: 0.1909 seconds, CL-PPCRE: 0.0800 seconds) +1484: 0.4962 (100000 repetitions, Perl: 0.1814 seconds, CL-PPCRE: 0.0900 seconds) +1485: 0.5508 (100000 repetitions, Perl: 0.2542 seconds, CL-PPCRE: 0.1400 seconds) +1486: 1.0588 (100000 repetitions, Perl: 0.3022 seconds, CL-PPCRE: 0.3200 seconds) +1487: 0.7284 (100000 repetitions, Perl: 0.6453 seconds, CL-PPCRE: 0.4700 seconds) +1488: 0.7429 (100000 repetitions, Perl: 0.6461 seconds, CL-PPCRE: 0.4800 seconds) +1489: 0.4189 (100000 repetitions, Perl: 0.1910 seconds, CL-PPCRE: 0.0800 seconds) +1490: 0.3235 (100000 repetitions, Perl: 0.1546 seconds, CL-PPCRE: 0.0500 seconds) +1491: 0.5143 (100000 repetitions, Perl: 0.1556 seconds, CL-PPCRE: 0.0800 seconds) +1492: 0.4563 (100000 repetitions, Perl: 0.1534 seconds, CL-PPCRE: 0.0700 seconds) +1493: 0.5185 (100000 repetitions, Perl: 0.1543 seconds, CL-PPCRE: 0.0800 seconds) +1494: 0.4955 (100000 repetitions, Perl: 0.1615 seconds, CL-PPCRE: 0.0800 seconds) +1495: 0.4944 (100000 repetitions, Perl: 0.1618 seconds, CL-PPCRE: 0.0800 seconds) +1496: 0.4331 (100000 repetitions, Perl: 0.8082 seconds, CL-PPCRE: 0.3500 seconds) +1497: 0.7886 (1000000 repetitions, Perl: 0.7608 seconds, CL-PPCRE: 0.6000 seconds) +1498: 0.5902 (1000000 repetitions, Perl: 0.7624 seconds, CL-PPCRE: 0.4500 seconds) +1499: 0.2554 (100000 repetitions, Perl: 0.1566 seconds, CL-PPCRE: 0.0400 seconds) +1500: 0.2541 (100000 repetitions, Perl: 0.1574 seconds, CL-PPCRE: 0.0400 seconds) +1501: 0.2524 (100000 repetitions, Perl: 0.1585 seconds, CL-PPCRE: 0.0400 seconds) +1502: 0.3265 (100000 repetitions, Perl: 0.3369 seconds, CL-PPCRE: 0.1100 seconds) +1503: 0.3811 (100000 repetitions, Perl: 0.3674 seconds, CL-PPCRE: 0.1400 seconds) +1504: 0.3815 (100000 repetitions, Perl: 0.3670 seconds, CL-PPCRE: 0.1400 seconds) +1505: 0.3818 (100000 repetitions, Perl: 0.3667 seconds, CL-PPCRE: 0.1400 seconds) +1506: 0.4213 (100000 repetitions, Perl: 0.4510 seconds, CL-PPCRE: 0.1900 seconds) +1507: 0.4781 (100000 repetitions, Perl: 0.5438 seconds, CL-PPCRE: 0.2600 seconds) +1508: 0.6455 (100000 repetitions, Perl: 0.6972 seconds, CL-PPCRE: 0.4500 seconds) +1509: 0.5764 (100000 repetitions, Perl: 0.5899 seconds, CL-PPCRE: 0.3400 seconds) +1510: 0.5361 (100000 repetitions, Perl: 0.4850 seconds, CL-PPCRE: 0.2600 seconds) +1511: 0.7082 (1000000 repetitions, Perl: 0.6495 seconds, CL-PPCRE: 0.4600 seconds) +1512: 0.5625 (100000 repetitions, Perl: 0.1600 seconds, CL-PPCRE: 0.0900 seconds) +1513: 0.5700 (100000 repetitions, Perl: 0.1579 seconds, CL-PPCRE: 0.0900 seconds) +1514: 0.5287 (100000 repetitions, Perl: 0.2837 seconds, CL-PPCRE: 0.1500 seconds) +1515: 0.5201 (100000 repetitions, Perl: 0.2884 seconds, CL-PPCRE: 0.1500 seconds) +1516: 0.5035 (100000 repetitions, Perl: 0.2780 seconds, CL-PPCRE: 0.1400 seconds) +1517: 0.5849 (100000 repetitions, Perl: 0.2906 seconds, CL-PPCRE: 0.1700 seconds) +1518: 0.6021 (100000 repetitions, Perl: 0.2824 seconds, CL-PPCRE: 0.1700 seconds) +1519: 0.6077 (100000 repetitions, Perl: 0.3127 seconds, CL-PPCRE: 0.1900 seconds) +1520: 0.7115 (100000 repetitions, Perl: 0.6746 seconds, CL-PPCRE: 0.4800 seconds) +1521: 0.7063 (100000 repetitions, Perl: 0.6796 seconds, CL-PPCRE: 0.4800 seconds) +1522: 0.7059 (100000 repetitions, Perl: 0.6658 seconds, CL-PPCRE: 0.4700 seconds) +1523: 0.7191 (100000 repetitions, Perl: 0.6675 seconds, CL-PPCRE: 0.4800 seconds) +1524: 0.4683 (100000 repetitions, Perl: 0.1922 seconds, CL-PPCRE: 0.0900 seconds) +1525: 0.4213 (100000 repetitions, Perl: 0.2136 seconds, CL-PPCRE: 0.0900 seconds) +1526: 0.0286 (10000 repetitions, Perl: 0.3498 seconds, CL-PPCRE: 0.0100 seconds) +1527: 0.6763 (100000 repetitions, Perl: 0.8429 seconds, CL-PPCRE: 0.5700 seconds) +1528: 0.8554 (1000000 repetitions, Perl: 0.8768 seconds, CL-PPCRE: 0.7500 seconds) +1529: 0.9597 (100000 repetitions, Perl: 0.1146 seconds, CL-PPCRE: 0.1100 seconds) +1530: 0.2910 (100000 repetitions, Perl: 0.2406 seconds, CL-PPCRE: 0.0700 seconds) +1531: 0.2867 (100000 repetitions, Perl: 0.2442 seconds, CL-PPCRE: 0.0700 seconds) +1532: 0.3131 (100000 repetitions, Perl: 0.1597 seconds, CL-PPCRE: 0.0500 seconds) +1533: 0.3589 (100000 repetitions, Perl: 0.2508 seconds, CL-PPCRE: 0.0900 seconds) +1534: 0.3536 (100000 repetitions, Perl: 0.2546 seconds, CL-PPCRE: 0.0900 seconds) +1535: 0.3596 (100000 repetitions, Perl: 0.1947 seconds, CL-PPCRE: 0.0700 seconds) +1536: 0.3210 (100000 repetitions, Perl: 0.2492 seconds, CL-PPCRE: 0.0800 seconds) +1537: 0.2765 (100000 repetitions, Perl: 0.2531 seconds, CL-PPCRE: 0.0700 seconds) +1538: 0.3216 (100000 repetitions, Perl: 0.1866 seconds, CL-PPCRE: 0.0600 seconds) +1539: 0.3169 (100000 repetitions, Perl: 0.2524 seconds, CL-PPCRE: 0.0800 seconds) +1540: 0.3192 (100000 repetitions, Perl: 0.2506 seconds, CL-PPCRE: 0.0800 seconds) +1541: 0.3373 (100000 repetitions, Perl: 0.2075 seconds, CL-PPCRE: 0.0700 seconds) +1542: 0.7186 (100000 repetitions, Perl: 0.2644 seconds, CL-PPCRE: 0.1900 seconds) +1543: 0.7809 (100000 repetitions, Perl: 0.4354 seconds, CL-PPCRE: 0.3400 seconds) +1544: 0.7975 (100000 repetitions, Perl: 0.4389 seconds, CL-PPCRE: 0.3500 seconds) +1545: 0.7251 (100000 repetitions, Perl: 0.2620 seconds, CL-PPCRE: 0.1900 seconds) +1546: 0.7521 (100000 repetitions, Perl: 0.4387 seconds, CL-PPCRE: 0.3300 seconds) +1547: 0.8778 (100000 repetitions, Perl: 0.4443 seconds, CL-PPCRE: 0.3900 seconds) +1548: 0.5969 (100000 repetitions, Perl: 0.3016 seconds, CL-PPCRE: 0.1800 seconds) +1549: 0.7601 (100000 repetitions, Perl: 0.4736 seconds, CL-PPCRE: 0.3600 seconds) +1550: 0.7864 (100000 repetitions, Perl: 0.4832 seconds, CL-PPCRE: 0.3800 seconds) +1551: 0.5106 (100000 repetitions, Perl: 0.3330 seconds, CL-PPCRE: 0.1700 seconds) +1552: 0.4608 (100000 repetitions, Perl: 0.3038 seconds, CL-PPCRE: 0.1400 seconds) +1553: 0.4988 (100000 repetitions, Perl: 0.3207 seconds, CL-PPCRE: 0.1600 seconds) +1554: 0.3418 (100000 repetitions, Perl: 0.3803 seconds, CL-PPCRE: 0.1300 seconds) +1555: 0.3461 (100000 repetitions, Perl: 0.2311 seconds, CL-PPCRE: 0.0800 seconds) +1556: 0.2425 (100000 repetitions, Perl: 0.1237 seconds, CL-PPCRE: 0.0300 seconds) +1557: 0.3378 (100000 repetitions, Perl: 0.1184 seconds, CL-PPCRE: 0.0400 seconds) +1558: 0.3310 (100000 repetitions, Perl: 0.1208 seconds, CL-PPCRE: 0.0400 seconds) +1559: 0.3415 (100000 repetitions, Perl: 0.1171 seconds, CL-PPCRE: 0.0400 seconds) +1560: 0.3131 (1000000 repetitions, Perl: 0.8943 seconds, CL-PPCRE: 0.2800 seconds) +1561: 0.3385 (100000 repetitions, Perl: 0.1182 seconds, CL-PPCRE: 0.0400 seconds) +1562: 0.2542 (100000 repetitions, Perl: 0.1180 seconds, CL-PPCRE: 0.0300 seconds) +1563: 0.2498 (100000 repetitions, Perl: 0.1201 seconds, CL-PPCRE: 0.0300 seconds) +1564: 0.3125 (1000000 repetitions, Perl: 0.8961 seconds, CL-PPCRE: 0.2800 seconds) \ No newline at end of file
Added: branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/doc/index.html =================================================================== --- branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/doc/index.html 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/doc/index.html 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,2510 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<html> + +<head> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <title>CL-PPCRE - Portable Perl-compatible regular expressions for Common Lisp</title> + <style type="text/css"> + pre { padding:5px; background-color:#e0e0e0 } + h3, h4 { text-decoration: underline; } + a { text-decoration: none; padding: 1px 2px 1px 2px; } + a:visited { text-decoration: none; padding: 1px 2px 1px 2px; } + a:hover { text-decoration: none; padding: 1px 1px 1px 1px; border: 1px solid #000000; } + a:focus { text-decoration: none; padding: 1px 2px 1px 2px; border: none; } + a.none { text-decoration: none; padding: 0; } + a.none:visited { text-decoration: none; padding: 0; } + a.none:hover { text-decoration: none; border: none; padding: 0; } + a.none:focus { text-decoration: none; border: none; padding: 0; } + a.noborder { text-decoration: none; padding: 0; } + a.noborder:visited { text-decoration: none; padding: 0; } + a.noborder:hover { text-decoration: none; border: none; padding: 0; } + a.noborder:focus { text-decoration: none; border: none; padding: 0; } + pre.none { padding:5px; background-color:#ffffff } + </style> +</head> + +<body bgcolor=white> + +<h2>CL-PPCRE - Portable Perl-compatible regular expressions for Common Lisp</h2> + +<blockquote> +<br> <br><h3>Abstract</h3> + +CL-PPCRE is a portable regular expression library for Common Lisp +which has the following features: + +<ul> + +<li>It is <b>compatible with Perl</b>. (Well - as far as you can be +compatible with a language defined by its ever-changing +implementation. As of December 2002 CL-PPCRE was <a href="#perl">more +compatible</a> with the regex semantics of Perl 5.8.0 than, say, +Perl 5.6.1 was...) It even correctly parses and +applies <a href="http://www.oreilly.com/catalog/regex2/">Jeffrey +Friedl's</a> famous 6600-byte long RFC822 address pattern. + +<li>It is <b>fast</b>. Used with a Lisp compiler which compiles to +native code it is <a href="#performance">on par</a> with Perl's highly +optimized regex engine (written in C) which to my knowledge is faster +than most other regex engines around. + +<li>It is <b>portable</b>, i.e. the code aims to be strictly <a +href="http://www.lispworks.com/documentation/HyperSpec/Front/index.htm%22%3EANSI-c...</a>. If +you encounter any deviations, this is an error and should be +reported to <a +href="#mail">the mailing list</a>. CL-PPCRE has been +successfully tested with the following Common Lisp implementations: + +<ul> + +<li><a href="http://www.franz.com/products/allegrocl/">Allegro Common Lisp</a> +<li><a href="http://armedbear.org/abcl.html">Armed Bear Common Lisp</a> +<li><a href="http://clisp.sourceforge.net/">CLISP</a> +<li><a href="http://www.cons.org/cmucl/">CMUCL</a> +<li><a href="http://www.cormanlisp.com/">Corman Lisp</a> +<li><a href="http://ecls.sourceforge.net/">ECL</a> +<li><a href="http://www.symbolics.com/">Genera</a> +<li><a href="http://www.digitool.com/">Macintosh Common Lisp</a> +<li><a href="http://openmcl.clozure.com/">OpenMCL</a> +<li><a href="http://sbcl.sourceforge.net/">SBCL</a> +<li><a href="http://www.scieneer.com/scl/">Scieneer Common Lisp</a> +<li><a href="http://www.lispworks.com/">LispWorks</a> + +</ul> + +If you succeed in using CL-PPCRE on other platforms, please <a +href="#mail">let us know</a>. + +<br> +Note that the tests mainly made sure that the package compiled +without errors and that the <a href="#test">test suite</a> - which +compiles about 1,500 regex strings into scanners and applies these to +target strings with the <a href="#scan"><code>SCAN</code></a> function +- yields the expected results. Other functions like <a +href="#split"><code>SPLIT</code></a>, <a +href="#all-matches"><code>ALL-MATCHES</code></a>, <a +href="#regex-replace"><code>REGEX-REPLACE</code></a>, <a +href="#regex-apropos"><code>REGEX-APROPOS</code></a>, or <a +href="#do-scans">the <code>DO</code>-macros</a> have only been tested +on CMUCL and LispWorks which were my main development platforms. + +<br>Also, I don't have the time to re-test any implementation with +every new release of CL-PPCRE. <a href="#mail">Let us +know</a> if your implementation is listed above and fails with a +recent version and I'll try to fix it. + +<li>It is <b>thread-safe</b>. Although the code uses closures +extensively, no state which dynamically changes during the scanning +process is stored in the lexical environments of the closures, so it +should be safe to use CL-PPCRE in a multi-threaded program. Tests with +LispWorks and Scieneer Common Lisp seem to confirm this. + +<li>It comes with <b>convenient features</b> like a <a +href="#split"><code>SPLIT</code></a> function, a couple of <a +href="#do-scans"><code>DO</code>-like loop constructs</a>, and a <a +href="#regex-apropos"><code>regex-based APROPOS feature</code></a> +similar to the one found in <a +href="http://www.gnu.org/software/emacs/emacs.html%22%3EEmacs</a>. + +<li>In addition to specifying regular expressions as strings like in +Perl you can also use <a +href="#create-scanner2"><b>S-expressions</b></a> which obviously is +more Lisp-y. + +<li>Is it is fully <b>documented</b> so I might have a chance to +understand my own code in about six months... :) + +<li>It comes with a <a +href="http://www.opensource.org/licenses/bsd-license.php%22%3E<b>BSD-style +license</b></a> so you can basically do with it whatever you want. + +</ul> + +CL-PPCRE has been used successfully in various applications like <a +href="http://nostoc.stanford.edu/Docs/%22%3EBioBike</a>, +<a href="http://clutu.com/">clutu</a>, +<a +href="http://www.hpc.unm.edu/~download/LoGS/%22%3ELoGS</a>, <a href="http://cafespot.net/">CafeSpot</a>, <a href="http://www.eboy.com/">Eboy</a>, or <a +href="http://weitz.de/regex-coach/%22%3EThe Regex Coach</a>. + +<p> +<font color=red>Download shortcut:</font> <a href="http://weitz.de/files/cl-ppcre.tar.gz">http://weitz.de/files/cl-ppcre.tar.gz</a>. + +</blockquote> + +<br> <br><h3><a class=none name="contents">Contents</a></h3> +<ol> + <li><a href="#install">Download and installation</a> + <li><a href="#mail">Support and mailing lists</a> + <li><a href="#dict">The CL-PPCRE dictionary</a> + <ol> + <li><a href="#create-scanner"><code>create-scanner</code></a> (for Perl regex strings) + <li><a href="#create-scanner2"><code>create-scanner</code></a> (for parse trees) + <li><a href="#parse-tree-synonym"><code>parse-tree-synonym</code></a> + <li><a href="#define-parse-tree-synonym"><code>define-parse-tree-synonym</code></a> + <li><a href="#scan"><code>scan</code></a> + <li><a href="#scan-to-strings"><code>scan-to-strings</code></a> + <li><a href="#register-groups-bind"><code>register-groups-bind</code></a> + <li><a href="#do-scans"><code>do-scans</code></a> + <li><a href="#do-matches"><code>do-matches</code></a> + <li><a href="#do-matches-as-strings"><code>do-matches-as-strings</code></a> + <li><a href="#do-register-groups"><code>do-register-groups</code></a> + <li><a href="#all-matches"><code>all-matches</code></a> + <li><a href="#all-matches-as-strings"><code>all-matches-as-strings</code></a> + <li><a href="#split"><code>split</code></a> + <li><a href="#regex-replace"><code>regex-replace</code></a> + <li><a href="#regex-replace-all"><code>regex-replace-all</code></a> + <li><a href="#regex-apropos"><code>regex-apropos</code></a> + <li><a href="#regex-apropos-list"><code>regex-apropos-list</code></a> + <li><a href="#regex-char-code-limit"><code>*regex-char-code-limit*</code></a> + <li><a href="#use-bmh-matchers"><code>*use-bmh-matchers*</code></a> + <li><a href="#*allow-quoting*"><code>*allow-quoting*</code></a> + <li><a href="#*allow-named-registers*"><code>*allow-named-registers*</code></a> + <li><a href="#quote-meta-chars"><code>quote-meta-chars</code></a> + <li><a href="#ppcre-error"><code>ppcre-error</code></a> + <li><a href="#ppcre-invocation-error"><code>ppcre-invocation-error</code></a> + <li><a href="#ppcre-syntax-error"><code>ppcre-syntax-error</code></a> + <li><a href="#ppcre-syntax-error-string"><code>ppcre-syntax-error-string</code></a> + <li><a href="#ppcre-syntax-error-pos"><code>ppcre-syntax-error-pos</code></a> + </ol> + <li><a href="#filters">Filters</a> + <li><a href="#test">Testing CL-PPCRE</a> + <li><a href="#perl">Compatibility with Perl</a> + <ol> + <li><a href="#empty">Empty strings instead of <code>undef</code> in <code>$1</code>, <code>$2</code>, etc.</a> + <li><a href="#scope">Strange scoping of embedded modifiers</a> + <li><a href="#inconsistent">Inconsistent capturing of <code>$1</code>, <code>$2</code>, etc.</a> + <li><a href="#lookaround">Captured groups not available outside of look-aheads and look-behinds</a> + <li><a href="#order">Alternations don't always work from left to right</a> + <li><a href="#mac"><code>"\r"</code> doesn't work with MCL</a> + <li><a href="#alpha">What about <code>"\w"</code>?</a> + </ol> + <li><a href="#performance">Performance</a> + <ol> + <li><a href="#bench">Benchmarking</a> + <li><a href="#other">Other performance issues</a> + </ol> + <li><a href="#bugs">Bugs and problems</a> + <ol> + <li><a href="#stack">Stack overflow</a> + <li><a href="#quote"><code>"\Q"</code> doesn't work, or does it?</a> + <li><a href="#backslash">Backslashes may confuse you...</a> + </ol> + <li><a href="#remarks">Remarks</a> + <li><a href="#allegro">AllegroCL compatibility mode</a> + <li><a href="#ack">Acknowledgements</a> +</ol> + +<br> <br><h3><a name="install" class=none>Download and installation</a></h3> + +CL-PPCRE together with this documentation can be downloaded from <a +href="http://weitz.de/files/cl-ppcre.tar.gz%22%3Ehttp://weitz.de/files/cl-ppcre.ta...</a>. The +current version is 1.3.2. +<p> +If you're on <a href="http://www.debian.org/">Debian</a>, you should +probably use the <a +href="http://packages.debian.org/cgi-bin/search_packages.pl?keywords=cl-ppcre&... +Debian package</a> which is available thanks to <a href="http://pvaneynd.mailworks.org/">Peter van Eynde</a> and <a href="http://b9.com/">Kevin +Rosenberg</a>. There's also a port +for <a href="http://www.gentoo.org/proj/en/common-lisp/index.xml">Gentoo Linux</a> thanks to Matthew Kennedy and a <a href="http://www.freebsd.org/cgi/url.cgi?ports/textproc/cl-ppcre/pkg-descr">FreeBSD port</a> thanks to Henrik Motakef. +Installation via <a +href="http://www.cliki.net/asdf-install%22%3Easdf-install</a> should as well +be possible. +<p> +CL-PPCRE comes with simple system definitions for <a +href="http://www.cliki.net/mk-defsystem%22%3EMK:DEFSYSTEM</a> and <a +href="http://www.cliki.net/asdf%22%3Easdf</a> so you can either adapt it +to your needs or just unpack the archive and from within the CL-PPCRE +directory start your Lisp image and evaluate the form +<code>(mk:compile-system "cl-ppcre")</code> (or the +equivalent one for asdf) which should compile and load the whole +system. +<p> +If for some reason you don't want to use MK:DEFSYSTEM or asdf, you +can just <code>LOAD</code> the file <code>load.lisp</code> or you +can also get away with something like this: + +<pre> +(loop for name in '("packages" "specials" "util" "errors" "lexer" + "parser" "regex-class" "convert" "optimize" + "closures" "repetition-closures" "scanner" "api") + do (compile-file (make-pathname :name name + :type "lisp")) + (load name)) +</pre> + +Note that on CL implementations which use the Python compiler +(i.e. CMUCL, SBCL, SCL) you can concatenate the compiled object files +to create one single object file which you can load afterwards: + +<pre> +cat {packages,specials,util,errors,lexer,parser,regex-class,convert,optimize,closures,repetition-closures,scanner,api}.x86f > cl-ppcre.x86f +</pre> + +(Replace ".<code>x86f</code>" with the correct suffix for +your platform.) +<p> +Note that there is <em>no</em> public CVS repository for CL-PPCRE - the repository at <a href="http://common-lisp.net/">common-lisp.net</a> is out of date and not in sync with the (current) version distributed from <a href="http://weitz.de/">weitz.de</a>. +<p> +Luís Oliveira maintains a <a href="http://darcs.net/">darcs</a> +repository of CL-PPCRE +at <a +href="http://common-lisp.net/~loliveira/ediware/%22%3Ehttp://common-lisp.net/~loli...</a>. + + +<br> <br><h3><a name="mail" class=none>Support and mailing lists</a></h3> + +For questions, bug reports, feature requests, improvements, or patches +please use the <a +href="http://common-lisp.net/mailman/listinfo/cl-ppcre-devel%22%3Ecl-ppcre-devel +mailing list</a>. If you want to be notified about future releases, +subscribe to the <a +href="http://common-lisp.net/mailman/listinfo/cl-ppcre-announce%22%3Ecl-ppcre-anno... +mailing list</a>. These mailing lists were made available thanks to +the services of <a href="http://common-lisp.net/">common-lisp.net</a>. +<p> +If you want to send patches, please <a href="http://weitz.de/patches.html">read this first</a>. + +<br> <br><h3><a class=none name="dict">The CL-PPCRE dictionary</a></h3> + +CL-PPCRE exports the following symbols: + +<p><br>[Method] +<br><a class=none name="create-scanner"><b>create-scanner</b> <i>(string string)<tt>&key</tt> case-insensitive-mode multi-line-mode single-line-mode extended-mode destructive</i> => <i>scanner, register-names</i></a> + +<blockquote><br> Accepts a string which is a regular expression in +Perl syntax and returns a closure which will scan strings for this +regular expression. The second value is only returned if <a href="#*allow-named-registers*"><code>*ALLOW-NAMED-REGISTERS*</code></a> is <i>true</i>. It represents a list of strings mapping registers to their respective names - the first element stands for first register, the second element for second register, etc. You have to store this value if you want to map a register number to its name later as <i>scanner</i> doesn't capture any information about register names. If a register isn't named, it has NIL as its name. +<p> +The mode keyword arguments are equivalent to the +<code>"imsx"</code> modifiers in Perl. The +<code>destructive</code> keyword will be ignored. +<p> +The function accepts most of the regex syntax of Perl 5 as described +in <a +href="http://perldoc.perl.org/perlre.html%22%3E<code>man +perlre</code></a> including extended features like non-greedy +repetitions, positive and negative look-ahead and look-behind +assertions, "standalone" subexpressions, and conditional +subpatterns. The following Perl features are (currently) <b>not</b> +supported: + +<ul> + +<li><code>(?{ code })</code> and <code>(??{ code })</code> because +they obviously don't make sense in Lisp. + +<li><code>\N{name}</code> (named characters), <code>\x{263a}</code> +(wide hex characters), <code>\l</code>, <code>\u</code>, +<code>\L</code>, and <code>\U</code> +because they're actually not part of Perl's regex syntax and +(honestly) because I was too lazy - but see <a href="http://weitz.de/cl-interpol/">CL-INTERPOL</a>. + +<li><code>\pP</code> and <code>\PP</code> (named properties), +<code>\X</code> (extended Unicode), and <code>\C</code> (single +character). But you can of course use all characters +supported by your CL implementation. + +<li>Posix character classes like <code>[[:alpha]]</code>. I +<em>might</em> add this in the future. + +<li><code>\G</code> for Perl's <code>pos()</code> because we don't have it. + +</ul> + +Note, however, that <code>\t</code>, <code>\n</code>, <code>\r</code>, +<code>\f</code>, <code>\a</code>, <code>\e</code>, <code>\033</code> +(octal character codes), <code>\x1B</code> (hexadecimal character +codes), <code>\c[</code> (control characters), <code>\w</code>, +<code>\W</code>, <code>\s</code>, <code>\S</code>, <code>\d</code>, +<code>\D</code>, <code>\b</code>, <code>\B</code>, <code>\A</code>, +<code>\Z</code>, and <code>\z</code> <b>are</b> supported. +<p> +Since version 0.6.0 CL-PPCRE also supports Perl's <code>\Q</code> and <code>\E</code> - see <a +href="#*allow-quoting*"><code>*ALLOW-QUOTING*</code></a> below. Make sure you also read <a href="#quote">the relevant section</a> in "<a href="#bugs">Bugs and problems</a>." +<p> +Since version 1.3.0 CL-PPCRE offers support for <a href="http://www.franz.com/support/documentation/7.0/doc/regexp.htm#regexp-new-capturing-2">AllegroCL's</a> <code>(?<name>"<regex>")</code> named registers and <code>\k<name></code> back-references syntax, have a look at <a href="#*allow-named-registers*"><code>*ALLOW-NAMED-REGISTERS*</code></a> for details. +<p> +The keyword arguments are just for your +convenience. You can always use embedded modifiers like +<code>"(?i-s)"</code> instead.</blockquote> + +<p><br>[Method] +<br><a class=none name="create-scanner"><b>create-scanner</b> <i>(function function)<tt>&key</tt> case-insensitive-mode multi-line-mode single-line-mode extended-mode destructive</i> => <i>scanner</i></a> +<blockquote><br> +In this case <code><i>function</i></code> should be a scanner returned by another invocation of <code>CREATE-SCANNER</code>. It will be returned as is. +</blockquote> + +<p><br>[Method] +<br><a class=none name="create-scanner2"><b>create-scanner</b> <i>(parse-tree t)<tt>&key</tt> case-insensitive-mode multi-line-mode single-line-mode extended-mode destructive</i> => <i>scanner, register-names</i></a> +<blockquote><br> +This is similar to <a +href="#create-scanner"><code>CREATE-SCANNER</code></a> for regex strings above but +accepts a <em>parse tree</em> as its first argument. A parse tree is an S-expression +conforming to the following syntax: + +<ul> + +<li>Every string and character is a parse tree and is treated +<em>literally</em> as a part of the regular expression, +i.e. parentheses, brackets, asterisks and such aren't special. + +<li>The symbol <code>:VOID</code> is equivalent to the empty string. + +<li>The symbol <code>:EVERYTHING</code> is equivalent to Perl's dot, +i.e it matches everything (except maybe a newline character depending +on the mode). + +<li>The symbols <code>:WORD-BOUNDARY</code> and +<code>:NON-WORD-BOUNDARY</code> are equivalent to Perl's +<code>"\b"</code> and <code>"\B"</code>. + +<li>The symbols <code>:DIGIT-CLASS</code>, +<code>:NON-DIGIT-CLASS</code>, <code>:WORD-CHAR-CLASS</code>, +<code>:NON-WORD-CHAR-CLASS</code>, +<code>:WHITESPACE-CHAR-CLASS</code>, and +<code>:NON-WHITESPACE-CHAR-CLASS</code> are equivalent to Perl's +<em>special character classes</em> <code>"\d"</code>, +<code>"\D"</code>, <code>"\w"</code>, +<code>"\W"</code>, <code>"\s"</code>, and +<code>"\S"</code> respectively. + +<li>The symbols <code>:START-ANCHOR</code>, <code>:END-ANCHOR</code>, +<code>:MODELESS-START-ANCHOR</code>, +<code>:MODELESS-END-ANCHOR</code>, and +<code>:MODELESS-END-ANCHOR-NO-NEWLINE</code> are equivalent to Perl's +<code>"^"</code>, <code>"$"</code>, +<code>"\A"</code>, <code>"\Z"</code>, and +<code>"\z"</code> respectively. + +<li>The symbols <code>:CASE-INSENSITIVE-P</code>, +<code>:CASE-SENSITIVE-P</code>, <code>:MULTI-LINE-MODE-P</code>, +<code>:NOT-MULTI-LINE-MODE-P</code>, <code>:SINGLE-LINE-MODE-P</code>, +and <code>:NOT-SINGLE-LINE-MODE-P</code> are equivalent to Perl's +<em>embedded modifiers</em> <code>"(?i)"</code>, +<code>"(?-i)"</code>, <code>"(?m)"</code>, +<code>"(?-m)"</code>, <code>"(?s)"</code>, and +<code>"(?-s)"</code>. As usual, changes applied to modes are +kept local to the innermost enclosing grouping or clustering +construct. + +</li><li>All other symbols will signal an error of type <a +href="#ppcre-syntax-error"><code>PPCRE-SYNTAX-ERROR</code></a> +<em>unless</em> they are defined to be <a +href="#parse-tree-synonym"><em>parse tree synonyms</em></a>. + +<li><code>(:FLAGS {<modifier>}*)</code> where +<code><modifier></code> is one of the modifier symbols from +above is used to group modifier symbols. The modifiers are applied +from left to right. (This construct is obviously redundant. It is only +there because it's used by the parser.) + +<li><code>(:SEQUENCE {<<i>parse-tree</i>>}*)</code> means a +sequence of parse trees, i.e. the parse trees must match one after +another. Example: <code>(:SEQUENCE #\f #\o #\o)</code> is equivalent +to the parse tree <code>"foo"</code>. + +<li><code>(:GROUP {<<i>parse-tree</i>>}*)</code> is like +<code>:SEQUENCE</code> but changes applied to modifier flags (see +above) are kept local to the parse trees enclosed by this +construct. Think of it as the S-expression variant of Perl's +<code>"(?:<<i>pattern</i>>)"</code> construct. + +<li><code>(:ALTERNATION {<<i>parse-tree</i>>}*)</code> means an +alternation of parse trees, i.e. one of the parse trees must +match. Example: <code>(:ALTERNATION #\b #\a #\z)</code> is equivalent +to the Perl regex string <code>"b|a|z"</code>. + +<li><code>(:BRANCH <<i>test</i>> +<<i>parse-tree</i>>)</code> is for conditional regular +expressions. <code><<i>test</i>></code> is either a number which +stands for a register or a parse tree which is a look-ahead or +look-behind assertion. See the entry for +<code>(?(<<i>condition</i>>)<<i>yes-pattern</i>>|<<i>no-pattern</i>>)</code> +in <a +href="http://perldoc.perl.org/perlre.html#Extended-Patterns%22%3E<code>man +perlre</code></a> for the semantics of this construct. If +<code><<i>parse-tree</i>></code> is an alternation is +<em>must</em> enclose exactly one or two parse trees where the second +one (if present) will be treated as the "no-pattern" - in +all other cases <code><<i>parse-tree</i>></code> will be treated +as the "yes-pattern". + +<li><code>(:POSITIVE-LOOKAHEAD|:NEGATIVE-LOOKAHEAD|:POSITIVE-LOOKBEHIND|:NEGATIVE-LOOKBEHIND +<<i>parse-tree</i>>)</code> should be pretty obvious... + +<li><code>(:GREEDY-REPETITION|:NON-GREEDY-REPETITION +<<i>min</i>> <<i>max</i>> +<<i>parse-tree</i>>)</code> where +<code><<i>min</i>></code> is a non-negative integer and +<code><<i>max</i>></code> is either a non-negative integer not +smaller than <code><<i>min</i>></code> or <code>NIL</code> will +result in a regular expression which tries to match +<code><<i>parse-tree</i>></code> at least +<code><<i>min</i>></code> times and at most +<code><<i>max</i>></code> times (or as often as possible if +<code><<i>max</i>></code> is <code>NIL</code>). So, e.g., +<code>(:NON-GREEDY-REPETITION 0 1 "ab")</code> is equivalent +to the Perl regex string <code>"(?:ab)??"</code>. + +<li><code>(:STANDALONE <<i>parse-tree</i>>)</code> is an +"independent" subexpression, i.e. <code>(:STANDALONE +"bar")</code> is equivalent to the Perl regex string +<code>"(?>bar)"</code>. + +<li><code>(:REGISTER <<i>parse-tree</i>>)</code> is a capturing +register group. As usual, registers are counted from left to right +beginning with 1. + +<li><code>(:NAMED-REGISTER <<i>name</i>> <<i>parse-tree</i>>)</code> is a named capturing +register group. Acts as <code>:REGISTER</code>, but assigns <code><<i>name</i>></code> to a register too. This <code><<i>name</i>></code> can be later referred to via <code>:BACK-REFERENCE</code>. Names are case-sensitive and don't need to be unique. See <a href="#*allow-named-registers*"><code>*ALLOW-NAMED-REGISTERS*</code></a> for details. + + +<li><code>(:BACK-REFERENCE <<i>ref</i>>)</code> is a +back-reference to a register group. <code><<i>ref</i>></code> is +a positive integer or a string denoting a register name. If there are +several registers with the same name, the regex engine tries to +successfully match at least of them, starting with the most recently +seen register continuing to the least recently seen one, until a match +is found. See <a +href="#*allow-named-registers*"><code>*ALLOW-NAMED-REGISTERS*</code></a> +for more information. + +<li><a class=none name="filterdef"><code>(:FILTER <<i>function</i>> <tt>&optional</tt> +<<i>length</i>>)</code></a> where +<code><<i>function</i>></code> is a <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_f.htm#function_... +designator</a> and <code><<i>length</i>></code> is a +non-negative integer or <code>NIL</code> is a user-defined <a +href="#filters">filter</a>. + +<li><code>(:REGEX <<i>string</i>>)</code> where +<code><<i>string</i>></code> is an +embedded <a href="#create-scanner">regular expression in Perl +syntax</a>. + +<li><code>(:CHAR-CLASS|:INVERTED-CHAR-CLASS +{<<i>item</i>>}*)</code> where <code><<i>item</i>></code> +is either a character, a <em>character range</em>, or a symbol for a +special character class (see above) will be translated into a (one +character wide) character class. A <em>character range</em> looks like +<code>(:RANGE <<i>char1</i>> <<i>char2</i>>)</code> where +<code><<i>char1</i>></code> and +<code><<i>char2</i>></code> are characters such that +<code>(CHAR<= <<i>char1</i>> <<i>char2</i>>)</code> is +true. Example: <code>(:INVERTED-CHAR-CLASS #\a (:RANGE #\D #\G) +:DIGIT-CLASS)</code> is equivalent to the Perl regex string +<code>"[^aD-G\d]"</code>. + +</ul> + +Because <code>CREATE-SCANNER</code> is defined as a generic function +which dispatches on its first argument there's a certain ambiguity: +Although strings are valid parse trees they will be interpreted as +Perl regex strings when given to <code>CREATE-SCANNER</code>. To +circumvent this you can always use the equivalent parse tree <code>(:GROUP +<<i>string</i>>)</code> instead. +<p> +Note that <code>CREATE-SCANNER</code> doesn't always check +for the well-formedness of its first argument, i.e. you are expected +to provide <em>correct</em> parse trees. + +<p> +The usage of the keyword argument <code>extended-mode</code> obviously +doesn't make sense if <code>CREATE-SCANNER</code> is applied to parse +trees and will signal an error. +<p> +If <code>destructive</code> is not <code>NIL</code> (the default is +<code>NIL</code>), the function is allowed to destructively modify +<code><i>parse-tree</i></code> while creating the scanner. +<p> +If you want to find out how parse trees are related to Perl regex +strings, you should play around with +<code>CL-PPCRE::PARSE-STRING</code> - a function which converts Perl +regex strings to parse trees. Here are some examples: + +<pre> +* (cl-ppcre::parse-string "(ab)*") +(:GREEDY-REPETITION 0 NIL (:REGISTER "ab")) + +* (cl-ppcre::parse-string "(a(b))") +(:REGISTER (:SEQUENCE #\a (:REGISTER #\b))) + +* (cl-ppcre::parse-string "(?:abc){3,5}") +(:GREEDY-REPETITION 3 5 (:GROUP "abc")) +<font color=orange>;; (:GREEDY-REPETITION 3 5 "abc") would also be OK</font> + +* (cl-ppcre::parse-string "a(?i)b(?-i)c") +(:SEQUENCE #\a + (:SEQUENCE (:FLAGS :CASE-INSENSITIVE-P) + (:SEQUENCE #\b (:SEQUENCE (:FLAGS :CASE-SENSITIVE-P) #\c)))) +<font color=orange>;; same as (:SEQUENCE #\a :CASE-INSENSITIVE-P #\b :CASE-SENSITIVE-P #\c)</font> + +* (cl-ppcre::parse-string "(?=a)b") +(:SEQUENCE (:POSITIVE-LOOKAHEAD #\a) #\b) +</pre></blockquote> + +<p><br>[Accessor] +<br><a class="none" name="parse-tree-synonym"><b>parse-tree-synonym</b> <i>symbol</i> => <i>parse-tree</i> +<br><tt>(setf (</tt><b>parse-tree-synonym</b> <i>symbol</i><tt>)</tt> <i>new-parse-tree</i><tt>)</tt></a> + +</p><blockquote><br> +Any symbol (unless it's a keyword with a special meaning in parse +trees) can be made a "synonym", i.e. an abbreviation, for another parse +tree by this accessor. <code>PARSE-TREE-SYNONYM</code> returns <code>NIL</code> if <code><i>symbol</i></code> isn't a synonym yet. +<p> +Here's an example: + +</p><pre>* (cl-ppcre::parse-string "a*b+") +(:SEQUENCE (:GREEDY-REPETITION 0 NIL #\a) (:GREEDY-REPETITION 1 NIL #\b)) + +* (defun my-repetition (char min) + `(:greedy-repetition ,min nil ,char)) +MY-REPETITION + +* (setf (parse-tree-synonym 'a*) (my-repetition #\a 0)) +(:GREEDY-REPETITION 0 NIL #\a) + +* (setf (parse-tree-synonym 'b+) (my-repetition #\b 1)) +(:GREEDY-REPETITION 1 NIL #\b) + +* (let ((scanner (create-scanner '(:sequence a* b+)))) + (dolist (string '("ab" "b" "aab" "a" "x")) + (print (scan scanner string))) + (values)) +0 +0 +0 +NIL +NIL + +* (parse-tree-synonym 'a*) +(:GREEDY-REPETITION 0 NIL #\a) + +* (parse-tree-synonym 'a+) +NIL +</pre></blockquote> + +<p><br>[Macro] +<br><a class="none" name="define-parse-tree-synonym"><b>define-parse-tree-synonym</b> <i>name parse-tree</i> => <i>parse-tree</i></a> + +</p><blockquote><br> +This is a convenience macro for parse tree synonyms defined as + +<pre>(defmacro define-parse-tree-synonym (name parse-tree) + `(eval-when (:compile-toplevel :load-toplevel :execute) + (setf (parse-tree-synonym ',name) ',parse-tree))) +</pre> + +so you can write code like this: + +<pre> +(define-parse-tree-synonym a-z + (:char-class (:range #\a #\z) (:range #\a #\z))) + +(define-parse-tree-synonym a-z* + (:greedy-repetition 0 nil a-z)) + +(defun ascii-char-tester (string) + (scan '(:sequence :start-anchor a-z* :end-anchor) + string)) +</pre></blockquote> + +<p><br> +<b>For the rest of this section </b><code><i>regex</i></code><b> can +always be a string (which is interpreted as a Perl regular +expression), a parse tree, or a scanner created by +</b><code>CREATE-SCANNER</code><b>. The +</b><code><i>start</i></code><b> and </b><code><i>end</i></code><b> +keyword parameters are always used as in </b><a +href="#scan"><code>SCAN</code></a><b>.</b> + + + + +<p><br>[Generic Function] +<br><a class=none name="scan"><b>scan</b> <i>regex target-string <tt>&key</tt> start end</i> => <i>match-start, match-end, reg-starts, reg-ends</i></a> + +<blockquote><br> +Searches the string <code><i>target-string</i></code> +from <code><i>start</i></code> (which defaults to 0) to +<code><i>end</i></code> (which default to the length of +<code><i>target-string</i></code>) and tries to match +<code><i>regex</i></code>. On success returns four values - the start +of the match, the end of the match, and two arrays denoting the +beginnings and ends of register matches. On failure returns +<code>NIL</code>. <code><i>target-string</i></code> will be coerced +to a simple string if it isn't one already. (There's another keyword +parameter <code><i>real-start-pos</i></code>. This one should +<em>never</em> be set from user code - it is only used internally.) +<p> +<code>SCAN</code> acts as if the part of +<code><i>target-string</i></code> between <code><i>start</i></code> +and <code><i>end</i></code> were a standalone string, i.e. look-aheads +and look-behinds can't look beyond these boundaries. +<p> +Examples: +<pre> +* (cl-ppcre:scan "(a)*b" "xaaabd") +1 +5 +#(3) +#(4) + +* (cl-ppcre:scan "(a)*b" "xaaabd" :start 1) +1 +5 +#(3) +#(4) + +* (cl-ppcre:scan "(a)*b" "xaaabd" :start 2) +2 +5 +#(3) +#(4) + +* (cl-ppcre:scan "(a)*b" "xaaabd" :end 4) +NIL + +* (cl-ppcre:scan '(:GREEDY-REPETITION 0 NIL #\b) "bbbc") +0 +3 +#() +#() + +* (cl-ppcre:scan '(:GREEDY-REPETITION 4 6 #\b) "bbbc") +NIL + +* (let ((s (cl-ppcre:create-scanner "(([a-c])+)x"))) + (cl-ppcre:scan s "abcxy")) +0 +4 +#(0 2) +#(3 3) +</pre></blockquote> + + + +<p><br>[Function] +<br><a class=none name="scan-to-strings"><b>scan-to-strings</b> <i>regex target-string <tt>&key</tt> start end sharedp</i> => <i>match, regs</i></a> + +<blockquote><br> +Like <a href="#scan"><code>SCAN</code></a> but returns substrings of +<code><i>target-string</i></code> instead of positions, i.e. this +function returns two values on success: the whole match as a string +plus an array of substrings (or <code>NIL</code>s) corresponding to +the matched registers. If <code><i>sharedp</i></code> is true, the substrings may share structure with +<code><i>target-string</i></code>. +<p> +Examples: +<pre> +* (cl-ppcre:scan-to-strings "[^b]*b" "aaabd") +"aaab" +#() + +* (cl-ppcre:scan-to-strings "([^b])*b" "aaabd") +"aaab" +#("a") + +* (cl-ppcre:scan-to-strings "(([^b])*)b" "aaabd") +"aaab" +#("aaa" "a") +</pre></blockquote> + + +<p><br>[Macro] +<br><a class=none name="register-groups-bind"><b>register-groups-bind</b> <i>var-list (regex target-string <tt>&key</tt> start end sharedp) declaration* statement*</i> => <i>result*</i></a> + +<blockquote><br> +Evaluates <code><i>statement*</i></code> with the variables in <code><i>var-list</i></code> bound to the +corresponding register groups after <code><i>target-string</i></code> has been matched +against <code><i>regex</i></code>, i.e. each variable is either +bound to a string or to <code>NIL</code>. +As a shortcut, the elements of <code><i>var-list</i></code> can also be lists of the form <code>(FN VAR)</code> where <code>VAR</code> is the variable symbol +and <code>FN</code> is a <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_f.htm#function_... +designator</a> (which is evaluated) denoting a function which is to be applied to the string before the result is bound to <code>VAR</code>. +To make this even more convenient the form <code>(FN VAR1 ...VARn)</code> can be used as an abbreviation for +<code>(FN VAR1) ... (FN VARn)</code>. +<p> +If there is no match, the <code><i>statement*</i></code> forms are <em>not</em> +executed. For each element of +<code><i>var-list</i></code> which is <code>NIL</code> there's no binding to the corresponding register +group. The number of variables in <code><i>var-list</i></code> must not be greater than +the number of register groups. If <code><i>sharedp</i></code> is true, the substrings may +share structure with <code><i>target-string</i></code>. +<p>Examples: +<pre> +* (register-groups-bind (first second third fourth) + ("((a)|(b)|(c))+" "abababc" :sharedp t) + (list first second third fourth)) +("c" "a" "b" "c") + +* (register-groups-bind (nil second third fourth) + <font color=orange>;; note that we don't bind the first and fifth register group</font> + ("((a)|(b)|(c))()+" "abababc" :start 6) + (list second third fourth)) +(NIL NIL "c") + +* (register-groups-bind (first) + ("(a|b)+" "accc" :start 1) + (format t "This will not be printed: ~A" first)) +NIL + +* (register-groups-bind (fname lname (#'parse-integer date month year)) + ("(\w+)\s+(\w+)\s+(\d{1,2})\.(\d{1,2})\.(\d{4})" "Frank Zappa 21.12.1940") + (list fname lname (encode-universal-time 0 0 0 date month year))) +("Frank" "Zappa" 1292882400) +</pre> +</blockquote> + +<p><br>[Macro] +<br><a class=none name="do-scans"><b>do-scans</b> <i>(match-start match-end reg-starts reg-ends regex target-string <tt>&optional</tt> result-form <tt>&key</tt> start end) declaration* statement*</i> => <i>result*</i></a> + +<blockquote><br> +A macro which iterates over <code><i>target-string</i></code> and +tries to match <code><i>regex</i></code> as often as possible +evaluating <code><i>statement*</i></code> with +<code><i>match-start</i></code>, <code><i>match-end</i></code>, +<code><i>reg-starts</i></code>, and <code><i>reg-ends</i></code> bound +to the four return values of each match (see <a +href="#scan"><code>SCAN</code></a>) in turn. After the last match, +returns <code><i>result-form</i></code> if provided or +<code>NIL</code> otherwise. An implicit block named <code>NIL</code> +surrounds <code>DO-SCANS</code>; <code>RETURN</code> may be used to +terminate the loop immediately. If <code><i>regex</i></code> matches +an empty string, the scan is continued one position behind this match. +<p> +This is the most general macro to iterate over all matches in a target +string. See the source code of <a +href="#do-matches"><code>DO-MATCHES</code></a>, <a +href="#all-matches"><code>ALL-MATCHES</code></a>, <a +href="#split"><code>SPLIT</code></a>, or <a +href="#regex-replace-all"><code>REGEX-REPLACE-ALL</code></a> for examples of its +usage.</blockquote> + + + + +<p><br>[Macro] +<br><a class=none name="do-matches"><b>do-matches</b> <i>(match-start match-end regex target-string <tt>&optional</tt> result-form <tt>&key</tt> start end) declaration* statement*</i> => <i>result*</i></a> + +<blockquote><br> +Like <a href="#do-scans"><code>DO-SCANS</code></a> but doesn't bind +variables to the register arrays. +<p>Example: +<pre> +* (defun foo (regex target-string &key (start 0) (end (length target-string))) + (let ((sum 0)) + (cl-ppcre:do-matches (s e regex target-string nil :start start :end end) + (incf sum (- e s))) + (format t "~,2F% of the string was inside of a match~%" + <font color=orange>;; note: doesn't check for division by zero</font> + (float (* 100 (/ sum (- end start))))))) + +FOO + +* (foo "a" "abcabcabc") +33.33% of the string was inside of a match +NIL +* (foo "aa|b" "aacabcbbc") +55.56% of the string was inside of a match +NIL +</pre></blockquote> + + + + +<p><br>[Macro] +<br><a class=none name="do-matches-as-strings"><b>do-matches-as-strings</b> <i>(match-var regex target-string <tt>&optional</tt> result-form <tt>&key</tt> start end sharedp) declaration* statement*</i> => <i>result*</i></a> + +<blockquote><br> +Like <a href="#do-matches"><code>DO-MATCHES</code></a> but binds +<code><i>match-var</i></code> to the substring of +<code><i>target-string</i></code> corresponding to each match in turn. If <code><i>sharedp</i></code> is true, the substrings may share structure with +<code><i>target-string</i></code>. +<p> +Example: +<pre> +* (defun crossfoot (target-string &key (start 0) (end (length target-string))) + (let ((sum 0)) + (cl-ppcre:do-matches-as-strings (m :digit-class + target-string nil + :start start :end end) + (incf sum (parse-integer m))) + (if (< sum 10) + sum + (crossfoot (format nil "~A" sum))))) + +CROSSFOOT + +* (crossfoot "bar") +0 + +* (crossfoot "a3x") +3 + +* (crossfoot "12345") +6 +</pre> + +Of course, in real life you would do this with <a href="#do-matches"><code>DO-MATCHES</code></a> and use the <code><i>start</i></code> and <code><i>end</i></code> keyword parameters of <a href="http://www.lispworks.com/documentation/HyperSpec/Body/f_parse_.htm"><code>PARSE-INTEGER</code></a>.</blockquote> + +<p><br>[Macro] +<br><a class=none name="do-register-groups"><b>do-register-groups</b> <i>var-list (regex target-string <tt>&optional</tt> result-form <tt>&key</tt> start end sharedp) declaration* statement*</i> => <i>result*</i></a> + +<blockquote><br> +Iterates over <code><i>target-string</i></code> and tries to match <code><i>regex</i></code> as often as +possible evaluating <code><i>statement*</i></code> with the variables in <code><i>var-list</i></code> bound to the +corresponding register groups for each match in turn, i.e. each +variable is either bound to a string or to <code>NIL</code>. You can use the same shortcuts and abbreviations as in <a href="#register-groups-bind"><code>REGISTER-GROUPS-BIND</code></a>. The number of +variables in <code><i>var-list</i></code> must not be greater than the number of register +groups. For each element of +<code><i>var-list</i></code> which is <code>NIL</code> there's no binding to the corresponding register +group. After the last match, returns <code><i>result-form</i></code> if provided or <code>NIL</code> +otherwise. An implicit block named <code>NIL</code> surrounds <code>DO-REGISTER-GROUPS</code>; +<code>RETURN</code> may be used to terminate the loop immediately. If <code><i>regex</i></code> matches +an empty string, the scan is continued one position behind this +match. If <code><i>sharedp</i></code> is true, the substrings may share structure with +<code><i>target-string</i></code>. +<p>Example: +<pre> +* (do-register-groups (first second third fourth) + ("((a)|(b)|(c))" "abababc" nil :start 2 :sharedp t) + (print (list first second third fourth))) +("a" "a" NIL NIL) +("b" NIL "b" NIL) +("a" "a" NIL NIL) +("b" NIL "b" NIL) +("c" NIL NIL "c") +NIL + +* (let (result) + (do-register-groups ((#'parse-integer n) (#'intern sign) whitespace) + ("(\d+)|(\+|-|\*|/)|(\s+)" "12*15 - 42/3") + (unless whitespace + (push (or n sign) result))) + (nreverse result)) +(12 * 15 - 42 / 3) +</pre> +</blockquote> + + +<p><br>[Function] +<br><a class=none name="all-matches"><b>all-matches</b> <i>regex target-string <tt>&key</tt> start end</i> => <i>list</i></a> + +<blockquote><br> +Returns a list containing the start and end positions of all matches +of <code><i>regex</i></code> against +<code><i>target-string</i></code>, i.e. if there are <code>N</code> +matches the list contains <code>(* 2 N)</code> elements. If +<code><i>regex</i></code> matches an empty string the scan is +continued one position behind this match. +<p> +Examples: +<pre> +* (cl-ppcre:all-matches "a" "foo bar baz") +(5 6 9 10) + +* (cl-ppcre:all-matches "\w*" "foo bar baz") +(0 3 3 3 4 7 7 7 8 11 11 11) +</pre></blockquote> + + + + +<p><br>[Function] +<br><a class=none name="all-matches-as-strings"><b>all-matches-as-strings</b> <i>regex target-string <tt>&key</tt> start end sharedp</i> => <i>list</i></a> + +<blockquote><br> +Like <a href="#all-matches"><code>ALL-MATCHES</code></a> but +returns a list of substrings instead. If <code><i>sharedp</i></code> is true, the substrings may share structure with +<code><i>target-string</i></code>. +<p> +Examples: +<pre> +* (cl-ppcre:all-matches-as-strings "a" "foo bar baz") +("a" "a") + +* (cl-ppcre:all-matches-as-strings "\w*" "foo bar baz") +("foo" "" "bar" "" "baz" "") +</pre></blockquote> + + + + + + +<p><br>[Function] +<br><a class=none name="split"><b>split</b> <i>regex target-string <tt>&key</tt> start end limit with-registers-p omit-unmatched-p sharedp</i> => <i>list</i></a> + +<blockquote><br> +Matches <code><i>regex</i></code> against +<code><i>target-string</i></code> as often as possible and returns a +list of the substrings between the matches. If +<code><i>with-registers-p</i></code> is true, substrings corresponding +to matched registers are inserted into the list as well. If +<code><i>omit-unmatched-p</i></code> is true, unmatched registers will +simply be left out, otherwise they will show up as +<code>NIL</code>. <code><i>limit</i></code> limits the number of +elements returned - registers aren't counted. If +<code><i>limit</i></code> is <code>NIL</code> (or 0 which is +equivalent), trailing empty strings are removed from the result list. +If <code><i>regex</i></code> matches an empty string, the scan is +continued one position behind this match. If <code><i>sharedp</i></code> is true, the substrings may share structure with +<code><i>target-string</i></code>. +<p> +Beginning with CL-PPCRE 0.2.0, this function also tries hard to be +Perl-compatible - thus the somewhat peculiar behaviour. But note that +it hasn't been as extensively tested as <a +href="#scan"><code>SCAN</code></a>. +<p> +Examples: +<pre> +* (cl-ppcre:split "\s+" "foo bar baz +frob") +("foo" "bar" "baz" "frob") + +* (cl-ppcre:split "\s*" "foo bar baz") +("f" "o" "o" "b" "a" "r" "b" "a" "z") + +* (cl-ppcre:split "(\s+)" "foo bar baz") +("foo" "bar" "baz") + +* (cl-ppcre:split "(\s+)" "foo bar baz" :with-registers-p t) +("foo" " " "bar" " " "baz") + +* (cl-ppcre:split "(\s)(\s*)" "foo bar baz" :with-registers-p t) +("foo" " " "" "bar" " " " " "baz") + +* (cl-ppcre:split "(,)|(;)" "foo,bar;baz" :with-registers-p t) +("foo" "," NIL "bar" NIL ";" "baz") + +* (cl-ppcre:split "(,)|(;)" "foo,bar;baz" :with-registers-p t :omit-unmatched-p t) +("foo" "," "bar" ";" "baz") + +* (cl-ppcre:split ":" "a:b:c:d:e:f:g::") +("a" "b" "c" "d" "e" "f" "g") + +* (cl-ppcre:split ":" "a:b:c:d:e:f:g::" :limit 1) +("a:b:c:d:e:f:g::") + +* (cl-ppcre:split ":" "a:b:c:d:e:f:g::" :limit 2) +("a" "b:c:d:e:f:g::") + +* (cl-ppcre:split ":" "a:b:c:d:e:f:g::" :limit 3) +("a" "b" "c:d:e:f:g::") + +* (cl-ppcre:split ":" "a:b:c:d:e:f:g::" :limit 1000) +("a" "b" "c" "d" "e" "f" "g" "" "") +</pre></blockquote> + + + + + +<p><br>[Function] +<br><a class=none name="regex-replace"><b>regex-replace</b> <i>regex target-string replacement <tt>&key</tt> start end preserve-case simple-calls element-type</i> => <i>string, matchp</i></a> + +<blockquote><br> Try to match <code><i>target-string</i></code> +between <code><i>start</i></code> and <code><i>end</i></code> against +<code><i>regex</i></code> and replace the first match with +<code><i>replacement</i></code>. Two values are returned; the modified +string, and <code>T</code> if <code><i>regex</i></code> matched or +<code>NIL</code> otherwise. +<p> +<code><i>replacement</i></code> can be a string which may contain the +special substrings <code>"&"</code> for the whole +match, <code>"`"</code> for the part of +<code><i>target-string</i></code> before the match, +<code>"'"</code> for the part of +<code><i>target-string</i></code> after the match, +<code>"\N"</code> or <code>"{N}"</code> for the +<code>N</code>th register where <code>N</code> is a positive integer. +<p> +<code><i>replacement</i></code> can also be a <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_f.htm#function_... +designator</a> in which case the match will be replaced with the +result of calling the function designated by +<code><i>replacement</i></code> with the arguments +<code><i>target-string</i></code>, <code><i>start</i></code>, +<code><i>end</i></code>, <code><i>match-start</i></code>, +<code><i>match-end</i></code>, <code><i>reg-starts</i></code>, and +<code><i>reg-ends</i></code>. (<code><i>reg-starts</i></code> and +<code><i>reg-ends</i></code> are arrays holding the start and end +positions of matched registers (or <code>NIL</code>) - the meaning of +the other arguments should be obvious.) +<p> +If <code><i>simple-calls</i></code> is true, a function designated by +<code><i>replacement</i></code> will instead be called with the +arguments <code><i>match</i></code>, <code><i>register-1</i></code>, +..., <code><i>register-n</i></code> where <code><i>match</i></code> is +the whole match as a string and <code><i>register-1</i></code> to +<code><i>register-n</i></code> are the matched registers, also as +strings (or <code>NIL</code>). Note that these strings share structure with +<code><i>target-string</i></code> so you must not modify them. +<p> +Finally, <code><i>replacement</i></code> can be a list where each +element is a string (which will be inserted verbatim), one of the +symbols <code>:match</code>, <code>:before-match</code>, or +<code>:after-match</code> (corresponding to +<code>"&"</code>, <code>"`"</code>, and +<code>"'"</code> above), an integer <code>N</code> +(representing register <code>(1+ N)</code>), or a function +designator. +<p> +If <code><i>preserve-case</i></code> is true (default is +<code>NIL</code>), the replacement will try to preserve the case (all +upper case, all lower case, or capitalized) of the match. The result +will always be a <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_f.htm#fresh%22%...</a> +string, even if <code><i>regex</i></code> doesn't match. +<p> +<code><i>element-type</i></code> specifies +the <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_a.htm#array_ele... +element type</a> of the string which is returned, the default +is <a +href="http://www.lispworks.com/documentation/lw50/LWRM/html/lwref-346.htm%22%3E<code>LW:SIMPLE-CHAR</code></a> +for LispWorks +and <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/t_ch.htm%22%3E<code>CHARACTER</code></a> +for other Lisps. +<p> +Examples: + +<pre> +* (cl-ppcre:regex-replace "fo+" "foo bar" "frob") +"frob bar" +T + +* (cl-ppcre:regex-replace "fo+" "FOO bar" "frob") +"FOO bar" +NIL + +* (cl-ppcre:regex-replace "(?i)fo+" "FOO bar" "frob") +"frob bar" +T + +* (cl-ppcre:regex-replace "(?i)fo+" "FOO bar" "frob" :preserve-case t) +"FROB bar" +T + +* (cl-ppcre:regex-replace "(?i)fo+" "Foo bar" "frob" :preserve-case t) +"Frob bar" +T + +* (cl-ppcre:regex-replace "bar" "foo bar baz" "[frob (was '\&' between '\`' and '\'')]") +"foo [frob (was 'bar' between 'foo ' and ' baz')] baz" +T + +* (cl-ppcre:regex-replace "bar" "foo bar baz" + '("[frob (was '" :match "' between '" :before-match "' and '" :after-match "')]")) +"foo [frob (was 'bar' between 'foo ' and ' baz')] baz" +T + +* (cl-ppcre:regex-replace "(be)(nev)(o)(lent)" + "benevolent: adj. generous, kind" + #'(lambda (match &rest registers) + (format nil "~A [~{~A~^.~}]" match registers)) + :simple-calls t) +"benevolent [be.nev.o.lent]: adj. generous, kind" +T +</pre></blockquote> + + +<p><br>[Function] +<br><a class=none name="regex-replace-all"><b>regex-replace-all</b> <i>regex target-string replacement <tt>&key</tt> start end preserve-case simple-calls element-type</i> => <i>string, matchp</i></a> + +<blockquote><br> +Like <a href="#regex-replace"><code>REGEX-REPLACE</code></a> but replaces all matches. +<p> +Examples: + +<pre> +* (cl-ppcre:regex-replace-all "(?i)fo+" "foo Fooo FOOOO bar" "frob" :preserve-case t) +"frob Frob FROB bar" +T + +* (cl-ppcre:regex-replace-all "(?i)f(o+)" "foo Fooo FOOOO bar" "fr\1b" :preserve-case t) +"froob Frooob FROOOOB bar" +T + +* (let ((qp-regex (cl-ppcre:create-scanner "[\x80-\xff]"))) + (defun encode-quoted-printable (string) + "Convert 8-bit string to quoted-printable representation." + <font color=orange>;; won't work for Corman Lisp because non-ASCII characters aren't 8-bit there</font> + (flet ((convert (target-string start end match-start match-end reg-starts reg-ends) + (declare (ignore start end match-end reg-starts reg-ends)) + (format nil "=~2,'0x" (char-code (char target-string match-start))))) + (cl-ppcre:regex-replace-all qp-regex string #'convert)))) +Converted ENCODE-QUOTED-PRINTABLE. +ENCODE-QUOTED-PRINTABLE + +* (encode-quoted-printable "Fête Sørensen naïve Hühner Straße") +"F=EAte S=F8rensen na=EFve H=FChner Stra=DFe" +T + +* (let ((url-regex (cl-ppcre:create-scanner "[^a-zA-Z0-9_\-.]"))) + (defun url-encode (string) + "URL-encode a string." + <font color=orange>;; won't work for Corman Lisp because non-ASCII characters aren't 8-bit there</font> + (flet ((convert (target-string start end match-start match-end reg-starts reg-ends) + (declare (ignore start end match-end reg-starts reg-ends)) + (format nil "%~2,'0x" (char-code (char target-string match-start))))) + (cl-ppcre:regex-replace-all url-regex string #'convert)))) +Converted URL-ENCODE. +URL-ENCODE + +* (url-encode "Fête Sørensen naïve Hühner Straße") +"F%EAte%20S%F8rensen%20na%EFve%20H%FChner%20Stra%DFe" +T + +* (defun how-many (target-string start end match-start match-end reg-starts reg-ends) + (declare (ignore start end match-start match-end)) + (format nil "~A" (- (svref reg-ends 0) + (svref reg-starts 0)))) +HOW-MANY + +* (cl-ppcre:regex-replace-all "{(.+?)}" + "foo{...}bar{.....}{..}baz{....}frob" + (list "[" 'how-many " dots]")) +"foo[3 dots]bar[5 dots][2 dots]baz[4 dots]frob" +T + +* (let ((qp-regex (cl-ppcre:create-scanner "[\x80-\xff]"))) + (defun encode-quoted-printable (string) + "Convert 8-bit string to quoted-printable representation. +Version using SIMPLE-CALLS keyword argument." + <font color=orange>;; ;; won't work for Corman Lisp because non-ASCII characters aren't 8-bit there</font> + (flet ((convert (match) + (format nil "=~2,'0x" (char-code (char match 0))))) + (cl-ppcre:regex-replace-all qp-regex string #'convert + :simple-calls t)))) + +Converted ENCODE-QUOTED-PRINTABLE. +ENCODE-QUOTED-PRINTABLE + +* (encode-quoted-printable "Fête Sørensen naïve Hühner Straße") +"F=EAte S=F8rensen na=EFve H=FChner Stra=DFe" +T + +* (defun how-many (match first-register) + (declare (ignore match)) + (format nil "~A" (length first-register))) +HOW-MANY + +* (cl-ppcre:regex-replace-all "{(.+?)}" + "foo{...}bar{.....}{..}baz{....}frob" + (list "[" 'how-many " dots]") + :simple-calls t) + +"foo[3 dots]bar[5 dots][2 dots]baz[4 dots]frob" +T +</pre></blockquote> + +<p><br>[Function] +<br><a class=none name="regex-apropos"><b>regex-apropos</b> <i>regex <tt>&optional</tt> packages <tt>&key</tt> case-insensitive</i> => <i>list</i></a> + +<blockquote><br> +Like <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/f_apropo.htm%22%3E<code>APROPOS</code></a> +but searches for interned symbols which match the regular expression +<code><i>regex</i></code>. The output is implementation-dependent. If +<code><i>case-insensitive</i></code> is true (which is the default) +and <code><i>regex</i></code> isn't already a scanner, a +case-insensitive scanner is used. +<p> +Here are examples for CMUCL: + +<pre> +* *package* +#<The COMMON-LISP-USER package, 16/21 internal, 0/9 external> + +* (defun foo (n &optional (k 0)) (+ 3 n k)) +FOO + +* (defparameter foo "bar") +FOO + +* (defparameter |foobar| 42) +|foobar| + +* (defparameter fooboo 43) +FOOBOO + +* (defclass frobar () ()) +#<STANDARD-CLASS FROBAR {4874E625}> + +* (cl-ppcre:regex-apropos "foo(?:bar)?") +FOO [variable] value: "bar" + [compiled function] (N &OPTIONAL (K 0)) +FOOBOO [variable] value: 43 +|foobar| [variable] value: 42 + +* (cl-ppcre:regex-apropos "(?:foo|fro)bar") +PCL::|COMMON-LISP-USER::FROBAR class predicate| [compiled closure] +FROBAR [class] #<STANDARD-CLASS FROBAR {4874E625}> +|foobar| [variable] value: 42 + +* (cl-ppcre:regex-apropos "(?:foo|fro)bar" 'cl-user) +FROBAR [class] #<STANDARD-CLASS FROBAR {4874E625}> +|foobar| [variable] value: 42 + +* (cl-ppcre:regex-apropos "(?:foo|fro)bar" '(pcl ext)) +PCL::|COMMON-LISP-USER::FROBAR class predicate| [compiled closure] + +* (cl-ppcre:regex-apropos "foo") +FOO [variable] value: "bar" + [compiled function] (N &OPTIONAL (K 0)) +FOOBOO [variable] value: 43 +|foobar| [variable] value: 42 + +* (cl-ppcre:regex-apropos "foo" nil :case-insensitive nil) +|foobar| [variable] value: 42 +</pre></blockquote> + + + + +<p><br>[Function] +<br><a class=none name="regex-apropos-list"><b>regex-apropos-list</b> <i>regex <tt>&optional</tt> packages <tt>&key</tt> upcase</i> => <i>list</i></a> + +<blockquote><br> +Like <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/f_apropo.htm%22%3E<code>APROPOS-LIST</code></a> +but searches for interned symbols which match the regular expression +<code><i>regex</i></code>. If <code><i>case-insensitive</i></code> is +true (which is the default) and <code><i>regex</i></code> isn't +already a scanner, a case-insensitive scanner is used. +<p> +Example (continued from above): + +<pre> +* (cl-ppcre:regex-apropos-list "foo(?:bar)?") +(|foobar| FOOBOO FOO) +</pre></blockquote> + +<p><br>[Special variable] +<br><a class=none name="regex-char-code-limit"><b>*regex-char-code-limit*</b></a> + +<blockquote><br>This variable controls whether scanners take into +account all characters of your CL implementation or only those +the <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/f_char_c.htm#char-code...<code>CHAR-CODE</code></a> +of which is not larger than its value. The default is +<a +href="http://www.lispworks.com/documentation/HyperSpec/Body/v_char_c.htm%22%3E<code>CHAR-CODE-LIMIT</code></a>, +and you might see significant speed and space improvements during +scanner <em>creation</em> if, say, your target strings only contain <a +href="http://czyborra.com/charsets/iso8859.html%22%3EISO-8859-1</a> +characters and you're using an implementation like AllegroCL, +CLISP, LispWorks, or SBCL where <code>CHAR-CODE-LIMIT</code> has a value +much higher than 256. The <a href="#test">test suite</a> will +automatically set <code>*REGEX-CHAR-CODE-LIMIT*</code> to 256 while +you're running the default test. +<p> +Here's an example with LispWorks: + +<pre> +CL-USER 23 > (time (cl-ppcre:create-scanner "[3\D]")) +Timing the evaluation of (CL-PPCRE:CREATE-SCANNER "[3\D]") + +user time = 0.443 +system time = 0.001 +Elapsed time = 0:00:01 +Allocation = 546600 bytes standard / 2162611 bytes fixlen +0 Page faults +#<closure 20654AF2> + +CL-USER 24 > (time (let ((cl-ppcre:*regex-char-code-limit* 256)) (cl-ppcre:create-scanner "[3\D]"))) +Timing the evaluation of (LET ((CL-PPCRE:*REGEX-CHAR-CODE-LIMIT* 256)) (CL-PPCRE:CREATE-SCANNER "[3\D]")) + +user time = 0.000 +system time = 0.000 +Elapsed time = 0:00:00 +Allocation = 3336 bytes standard / 8338 bytes fixlen +0 Page faults +#<closure 206569DA> +</pre> +<p> +Note: Due to the nature of <a href="http://www.lispworks.com/documentation/HyperSpec/Body/s_ld_tim.htm"><code>LOAD-TIME-VALUE</code></a> and the <a +href="#compiler-macro">compiler macro for <code>SCAN</code> and other functions</a>, some +scanners might be created in a <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_n.htm#null_lexi... +lexical environment</a> at load time or at compile time so be careful +to which value <code>*REGEX-CHAR-CODE-LIMIT*</code> is bound at that +time. The default value should always yield correct results unless you +play dirty tricks with implementation-dependent behaviour, though.</blockquote> + +<p><br>[Special variable] +<br><a class=none name="use-bmh-matchers"><b>*use-bmh-matchers*</b></a> + +<blockquote><br>Usually, the scanners created by <a +href="#create-scanner"><code>CREATE-SCANNER</code></a> (or +implicitly by other functions and macros) will use fast <a +href="http://www-igm.univ-mlv.fr/~lecroq/string/node18.html%22%3EBoyer-Moore-Horsp... +matchers</a> to check for constant strings at the start or end of the +regular expression. If <code>*USE-BMH-MATCHERS*</code> is +<code>NIL</code> (the default is <code>T</code>), the standard +function <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/f_search.htm%22%3E<code>SEARCH</code></a> +will be used instead. This will usually be a bit slower but can save +lots of space if you're storing many scanners. The <a +href="#test">test suite</a> will automatically set +<code>*USE-BMH-MATCHERS*</code> to <code>NIL</code> while you're running +the default test. +<p> +Note: Due to the nature of <a href="http://www.lispworks.com/documentation/HyperSpec/Body/s_ld_tim.htm"><code>LOAD-TIME-VALUE</code></a> and the <a +href="#compiler-macro">compiler macro for <code>SCAN</code> and other functions</a>, some +scanners might be created in a <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_n.htm#null_lexi... +lexical environment</a> at load time or at compile time so be careful +to which value <code>*USE-BMH-MATCHERS*</code> is bound at that +time.</blockquote> + +<p><br>[Special variable] +<br><a class=none name="*allow-quoting*"><b>*allow-quoting*</b></a> + +<blockquote><br> +If this value is <em>true</em> (the default is <code>NIL</code>), +CL-PPCRE will support <code>\Q</code> and <code>\E</code> in regex +strings to quote (disable) metacharacters. Note that this entails a +slight performance penalty when creating scanners because (a copy of) the regex +string is modified (probably more than once) before it +is fed to the parser. Also, the parser's <a +href="#ppcre-syntax-error">syntax error messages</a> will complain +about the converted string and not about the original regex string. + +<pre> +* (cl-ppcre:scan "^a+$" "a+") +NIL + +* (let ((cl-ppcre:*allow-quoting* t)) + <font color=orange>;;we use CREATE-SCANNER because of Lisps like SBCL that don't have an interpreter</font> + (cl-ppcre:scan (cl-ppcre:create-scanner "^\Qa+\E$") "a+")) +0 +2 +#() +#() + +* (let ((cl-ppcre:*allow-quoting* t)) + (cl-ppcre:scan (cl-ppcre:create-scanner "\Qa()\E(?#comment\Q)a**b") "()ab")) + +Quantifier '*' not allowed at position 19 in string "a\(\)(?#commentQ)a**b" +</pre> + +Note how in the last example the regex string in the error message is +different from the first argument to the <code>SCAN</code> +function. Also note that the second example might be easier to +understand (and Lisp-ier) if you write it like this: + +<pre> +* (cl-ppcre:scan '(:sequence :start-anchor + "a+" <font color=orange>;; no quoting necessary</font> + :end-anchor) + "a+") +0 +2 +#() +#() +</pre> + +Make sure you also read <a href="#quote">the relevant section</a> in "<a href="#bugs">Bugs and problems</a>." +<p> +Note: Due to the nature of <a href="http://www.lispworks.com/documentation/HyperSpec/Body/s_ld_tim.htm"><code>LOAD-TIME-VALUE</code></a> and the <a +href="#compiler-macro">compiler macro for <code>SCAN</code> and other functions</a>, some +scanners might be created in a <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_n.htm#null_lexi... +lexical environment</a> at load time or at compile time so be careful +to which value <code>*ALLOW-QUOTING*</code> is bound at that +time.</blockquote> + +</blockquote> + +<p><br>[Special variable] +<br><a class=none name="*allow-named-registers*"><b>*allow-named-registers*</b></a> + +<blockquote><br> +If this value is <em>true</em> (the default is <code>NIL</code>), +CL-PPCRE will support <code>(?<i><name>"<regex>"</i>)</code> and <code>\k<i><name></i></code> in regex +strings to provide named registers and back-references as in <a href="http://www.franz.com/support/documentation/7.0/doc/regexp.htm#regexp-new-capturing-2">AllegroCL</a>. <code><i>name</i></code> is has to start with a letter and can contain only alphanumeric characters or minus sign. Names of registers are matched case-sensitively. +The <a href="#create-scanner2">parse tree syntax</a> is not affected by the <code>*ALLOW-NAMED-REGISTERS*</code> switch, <code>:NAMED-REGISTER</code> and <code>:BACK-REFERENCE</code> forms are always resolved as expected. There are also no restrictions on register names in this syntax except that they have to be strings. + +<p> +Examples: + +<pre> +<font color=orange>;; Perl compatible mode (*ALLOW-NAMED-REGISTERS* is NIL)</font> +* (cl-ppcre:create-scanner "(?<reg>.*)") +Character 'r' may not follow '(?<' at position 3 in string "(?<reg>)" + +<font color=orange>;; just unescapes "\k"</font> +* (cl-ppcre::parse-string "\k<reg>") +"k<reg>" +</pre> + +<pre> +* (setq cl-ppcre:*allow-named-registers* t) +T + +* (cl-ppcre:create-scanner "((?<small>[a-z]*)(?<big>[A-Z]*))") +#<CLOSURE (LAMBDA (STRING CL-PPCRE::START CL-PPCRE::END)) {AD75BFD}> +(NIL "small" "big") + +<font color=orange>;; the scanner doesn't capture any information about named groups - +;; you have to store the second value returned from CREATE-SCANNER yourself</font> +* (cl-ppcre:scan * "aaaBBB") +0 +6 +#(0 0 3) +#(6 3 6) +</pre> + +<pre> +<font color=orange>;; parse tree syntax</font> +* (cl-ppcre::parse-string "((?<small>[a-z]*)(?<big>[A-Z]*))") +(:REGISTER + (:SEQUENCE + (:NAMED-REGISTER "small" + (:GREEDY-REPETITION 0 NIL (:CHAR-CLASS (:RANGE #\a #\z)))) + (:NAMED-REGISTER "big" + (:GREEDY-REPETITION 0 NIL (:CHAR-CLASS (:RANGE #\A #\Z)))))) + +* (cl-ppcre:create-scanner *) +#<CLOSURE (LAMBDA (STRING CL-PPCRE::START CL-PPCRE::END)) {B158E3D}> +(NIL "small" "big") +</pre> + +<pre> +<font color=orange>;; multiple-choice back-reference</font> +* (cl-ppcre:scan "^(?<reg>[ab])(?<reg>[12])\k<reg>\k<reg>$" "a1aa") +0 +4 +#(0 1) +#(1 2) + +* (cl-ppcre:scan "^(?<reg>[ab])(?<reg>[12])\k<reg>\k<reg>$" "a22a") +0 +4 +#(0 1) +#(1 2) +</pre> + + +<pre> +<font color=orange>;; demonstrating most-recently-seen-register-first property of back-reference; +;; "greedy" regex (analogous to "aa?")</font> +* (cl-ppcre:scan "^(?<reg>)(?<reg>a)(\k<reg>)" "a") +0 +1 +#(0 0 1) +#(0 1 1) + +* (cl-ppcre:scan "^(?<reg>)(?<reg>a)(\k<reg>)" "aa") +0 +2 +#(0 0 1) +#(0 1 2) +</pre> + +<pre> +<font color=orange>;; switched groups +;; "lazy" regex (analogous to "aa??")</font> +* (cl-ppcre:scan "^(?<reg>a)(?<reg>)(\k<reg>)" "a") +0 +1 +#(0 1 1) +#(1 1 1) + +<font color=orange>;; scanner ignores the second "a"</font> +* (cl-ppcre:scan "^(?<reg>a)(?<reg>)(\k<reg>)" "aa") +0 +1 +#(0 1 1) +#(1 1 1) + +<font color=orange>;; "aa" will be matched only when forced by adding "$" at the end</font> +* (cl-ppcre:scan "^(?<reg>a)(?<reg>)(\k<reg>)$" "aa") +0 +2 +#(0 1 1) +#(1 1 2) +</pre> +Note: Due to the nature of <a href="http://www.lispworks.com/documentation/HyperSpec/Body/s_ld_tim.htm"><code>LOAD-TIME-VALUE</code></a> and the <a +href="#compiler-macro">compiler macro for <code>SCAN</code> and other functions</a>, some +scanners might be created in a <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_n.htm#null_lexi... +lexical environment</a> at load time or at compile time so be careful +to which value <code>*ALLOW-NAMED-REGISTERS*</code> is bound at that +time.</blockquote> +</blockquote> + +<p><br>[Function] +<br><a class=none name="quote-meta-chars"><b>quote-meta-chars</b> <i>string</i> => <i>string'</i></a> + +<blockquote><br> +This is a simple utility function used when <a +href="#*allow-quoting*"><code>*ALLOW-QUOTING*</code></a> is +<em>true</em>. It returns a string <code>STRING'</code> where all +non-word characters (everything except ASCII characters, digits and +underline) of <code>STRING</code> are quoted by prepending a +backslash similar to Perl's <code>quotemeta</code> function. It always returns a <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_f.htm#fresh%22%...</a> +string. +<pre> +* (cl-ppcre:quote-meta-chars "[a-z]*") +"\[a\-z\]\*" +</pre></blockquote> + +<p><br>[Condition type] +<br><a class=none name="ppcre-error"><b>ppcre-error</b></a> + +<blockquote><br> +Every error signaled by CL-PPCRE is of type +<code>PPCRE-ERROR</code>. This is a direct subtype of <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/e_smp_er.htm%22%3E<code>SIMPLE-ERROR</code></a> +without any additional slots or options. +</blockquote> + +<p><br>[Condition type] +<br><a class=none name="ppcre-invocation-error"><b>ppcre-invocation-error</b></a> + +<blockquote><br> +Errors of type <code>PPCRE-INVOCATION-ERROR</code> +are signaled if one of the exported functions of CL-PPCRE is called with wrong or +inconsistent arguments. This is a direct subtype of <a +href="#ppcre-error"><code>PPCRE-ERROR</code></a> without any +additional slots or options. +</blockquote> + +<p><br>[Condition type] +<br><a class=none name="ppcre-syntax-error"><b>ppcre-syntax-error</b></a> + +<blockquote><br> +An error of type <code>PPCRE-SYNTAX-ERROR</code> is signaled if +CL-PPCRE's parser encounters an error when trying to parse a regex +string or to convert a parse tree into its internal representation. +This is a direct subtype of <a +href="#ppcre-error"><code>PPCRE-ERROR</code></a> with two additional +slots. These denote the regex string which HTML-PPCRE was parsing and +the position within the string where the error occured. If the error +happens while CL-PPCRE is converting a parse tree, both of these slots +contain <code>NIL</code>. (See the next two entries on how to access +these slots.) +<p> +As many syntax errors can't be detected before the parser is at the +end of the stream, the row and column usually denote the last position +where the parser was happy and not the position where it gave up. + +<pre> +* (handler-case + (cl-ppcre:scan "foo**x" "fooox") + (cl-ppcre:ppcre-syntax-error (condition) + (format t "Houston, we've got a problem with the string ~S:~%~ + Looks like something went wrong at position ~A.~%~ + The last message we received was "~?"." + (cl-ppcre:ppcre-syntax-error-string condition) + (cl-ppcre:ppcre-syntax-error-pos condition) + (simple-condition-format-control condition) + (simple-condition-format-arguments condition)) + (values))) +Houston, we've got a problem with the string "foo**x": +Looks like something went wrong at position 4. +The last message we received was "Quantifier '*' not allowed". +</pre> +</blockquote> + +<p><br>[Function] +<br><a class=none name="ppcre-syntax-error-string"><b>ppcre-syntax-error-string</b></a> <i>condition</i> => <i>string</i> + +<blockquote><br> +If <code><i>condition</i></code> is a condition of type <a +href="#ppcre-syntax-error"><code>PPCRE-SYNTAX-ERROR</code></a>, this +function will return the string the parser was parsing when the error was +encountered (or <code>NIL</code> if the error happened while trying to +convert a parse tree). This might be particularly useful when <a +href="#*allow-quoting*"><code>*ALLOW-QUOTING*</code></a> is +<em>true</em> because in this case the offending string might not be the one you gave to the <a +href="#create-scanner"><code>CREATE-SCANNER</code></a> function. +</blockquote> + +<p><br>[Function] +<br><a class=none name="ppcre-syntax-error-pos"><b>ppcre-syntax-error-pos</b></a> <i>condition</i> => <i>number</i> + +<blockquote><br> +If <code><i>condition</i></code> is a condition of type <a +href="#ppcre-syntax-error"><code>PPCRE-SYNTAX-ERROR</code></a>, this +function will return the position within the string where the error +occured (or <code>NIL</code> if the error happened while trying to +convert a parse tree). +</blockquote> + + +<br> <br><h3><a name="filters" class=none>Filters</a></h3> + +Because several users have asked for it, CL-PPCRE now offers +"filters" (see <a href="#filterdef">above</a> for syntax) +which are basically arbitrary, user-defined functions that can act as +regex building blocks. Filters can only be used within <a +href="#create-scanner2">parse trees</a>, not within Perl regex +strings. +<p> +A filter is defined by its <em>filter function</em> which must be a +function of one argument. During the parsing process this function +might be called once or several times or it might not be called at +all. If it's called, its argument is an integer <code><i>pos</i></code> +which is the current position within the target string. The filter can +either return <code>NIL</code> (which means that the subexpression +represented by this filter didn't match) or an integer not smaller +than <code><i>pos</i></code> for success. A zero-length assertion +should return <code><i>pos</i></code> itself while a filter which +wants to consume <code>N</code> characters should return +<code>(+ POS N)</code>. +<p> +If you supply the optional value <code><i>length</i></code> and it is +not <code>NIL</code>, then this is a promise to the regex engine that +your filter will <em>always</em> consume <em>exactly</em> +<code><i>length</i></code> characters. The regex engine might use this +information for optimization purposes but it is otherwise irrelevant +to the outcome of the matching process. +<p> +The filter function can access the following special variables from +its code body: +<ul> + +<li><code>CL-PPCRE::*STRING*</code>: The target (a string) of the +current matching process. + +<li><code>CL-PPCRE::*START-POS*</code> and +<code>CL-PPCRE::*END-POS*</code>: The start and end (integers) indices +of the current matching process. These correspond to the +<code>START</code> and <code>END</code> keyword parameters of <a +href="#scan"><code>SCAN</code></a>. + +<li><code>CL-PPCRE::*REAL-START-POS*</code>: The initial starting +position. This is only relevant for repeated scans (as in <a +href="#do-scans"><code>DO-SCANS</code></a>) where +<code>CL-PPCRE::*START-POS*</code> will be moved forward while +<code>CL-PPCRE::*REAL-START-POS*</code> won't. For normal scans the +value of this variable is <code>NIL</code>. + +<li><CODE>CL-PPCRE::*REG-STARTS*</CODE> and +<CODE>CL-PPCRE::*REG-ENDS*</CODE>: Two simple vectors which denote the +start and end indices of registers within the regular expression. The +first register is indexed by 0. If a register hasn't matched yet, +then its corresponding entry in <CODE>CL-PPCRE::*REG-STARTS*</CODE> is +<code>NIL</code>. + +</ul> + +These variables should be considered read-only. Do <em>not</em> change +these values unless you really know what you're doing! +<p> +Note that the names of the variables are not exported from the +<code>CL-PPCRE</code> package because there's currently no guarantee +that they will be available in future releases. +<p> +Here are some filter examples: +<pre> +* (defun my-info-filter (pos) + "Show some info about the matching process." + (format t "Called at position ~A~%" pos) + (loop with dim = (array-dimension cl-ppcre::*reg-starts* 0) + for i below dim + for reg-start = (aref cl-ppcre::*reg-starts* i) + for reg-end = (aref cl-ppcre::*reg-ends* i) + do (format t "Register ~A is currently " (1+ i)) + when reg-start + (write-string cl-ppcre::*string* nil + do (write-char #') + (write-string cl-ppcre::*string* nil + :start reg-start :end reg-end) + (write-char #') + else + do (write-string "unbound") + do (terpri)) + (terpri) + pos) +MY-INFO-FILTER + +* (scan '(:sequence + (:register + (:greedy-repetition 0 nil + (:char-class (:range #\a #\z)))) + (:filter my-info-filter 0) "X") + "bYcdeX") +Called at position 1 +Register 1 is currently 'b' + +Called at position 0 +Register 1 is currently '' + +Called at position 1 +Register 1 is currently '' + +Called at position 5 +Register 1 is currently 'cde' + +2 +6 +#(2) +#(5) + +* (scan '(:sequence + (:register + (:greedy-repetition 0 nil + (:char-class (:range #\a #\z)))) + (:filter my-info-filter 0) "X") + "bYcdeZ") +NIL + +* (defun my-weird-filter (pos) + "Only match at this point if either pos is odd and the character + we're looking at is lowerrcase or if pos is even and the next two + characters we're looking at are uppercase. Consume these characters if + there's a match." + (format t "Trying at position ~A~%" pos) + (cond ((and (oddp pos) + (< pos cl-ppcre::*end-pos*) + (lower-case-p (char cl-ppcre::*string* pos))) + (1+ pos)) + ((and (evenp pos) + (< (1+ pos) cl-ppcre::*end-pos*) + (upper-case-p (char cl-ppcre::*string* pos)) + (upper-case-p (char cl-ppcre::*string* (1+ pos)))) + (+ pos 2)) + (t nil))) +MY-WEIRD-FILTER + +* (defparameter *weird-regex* + `(:sequence "+" (:filter ,#'my-weird-filter) "+")) +*WEIRD-REGEX* + +* (scan *weird-regex* "+A++a+AA+") +Trying at position 1 +Trying at position 3 +Trying at position 4 +Trying at position 6 +5 +9 +#() +#() + +* (fmakunbound 'my-weird-filter) +MY-WEIRD-FILTER + +* (scan *weird-regex* "+A++a+AA+") +Trying at position 1 +Trying at position 3 +Trying at position 4 +Trying at position 6 +5 +9 +#() +#() +</pre> + +Note that in the second call to <code>SCAN</code> our filter wasn't +invoked at all - it was optimized away by the regex engine because it +knew that it couldn't match. Also note that <code>*WEIRD-REGEX*</code> +still worked after we removed the global function definition of +<code>MY-WEIRD-FILTER</code> because the regular expression had +captured the original definition. + +<p> + +For more ideas about what you can do with filters see <a +href="http://common-lisp.net/pipermail/cl-ppcre-devel/2004-October/000069.html%22%... +thread</a> on the <a href="#mail">mailing list</a>. + +<br> <br><h3><a name="test" class=none>Testing CL-PPCRE</a></h3> + +CL-PPCRE comes with a comprehensive test suite most of which is stolen +from the <a href="http://www.pcre.org/">PCRE</a> library. You can use +it like this: + +<pre> +* (mk:compile-system "cl-ppcre-test") +<font color=orange>; Loading #p"/home/edi/cl-ppcre/cl-ppcre.system". +; Loading #p"/home/edi/cl-ppcre/packages.x86f". +; Loading #p"/home/edi/cl-ppcre/specials.x86f". +; Loading #p"/home/edi/cl-ppcre/util.x86f". +; Loading #p"/home/edi/cl-ppcre/errors.x86f". +; Loading #p"/home/edi/cl-ppcre/lexer.x86f". +; Loading #p"/home/edi/cl-ppcre/parser.x86f". +; Loading #p"/home/edi/cl-ppcre/regex-class.x86f". +; Loading #p"/home/edi/cl-ppcre/convert.x86f". +; Loading #p"/home/edi/cl-ppcre/optimize.x86f". +; Loading #p"/home/edi/cl-ppcre/closures.x86f". +; Loading #p"/home/edi/cl-ppcre/repetition-closures.x86f". +; Loading #p"/home/edi/cl-ppcre/scanner.x86f". +; Loading #p"/home/edi/cl-ppcre/api.x86f". +; Loading #p"/home/edi/cl-ppcre/ppcre-tests.x86f".</font> +NIL + +* (cl-ppcre-test:test) + +<font color=orange>;; .... +;; (a list of <a class=noborder href="#perl">incompatibilities with Perl</a>)</font> +</pre> + +(If you're not using MK:DEFSYSTEM or asdf, it suffices to build +CL-PPCRE and then compile and load the file +<code>ppcre-tests.lisp</code>.) +<p> +With LispWorks, SCL, and SBCL (starting from version 0.8.4.8) you can also call +<code>CL-PPCRE-TEST:TEST</code> with a keyword argument argument +<code>THREADED</code> which - in addition to the usual tests - will +also check whether the scanners created by CL-PPCRE are thread-safe. +<p> +Note that the file <code>testdata</code> provided with CL-PPCRE +was created on a Linux system with Perl 5.8.0. You can (and you +<em>should</em> if you're on Mac OS or Windows) create your own +<code>testdata</code> with the Perl script +<code>perltest.pl</code>: + +<pre> +edi@bird:~/cl-ppcre > perl perltest.pl < testinput > testdata +</pre> + +Of course you can also create your own tests - the format accepted by +<code>perltest.pl</code> should be rather clear from looking at the +file <code>testinput</code>. Note that the target strings are wrapped +in double quotes and then fed to Perl's <code>eval</code> so you can +use ugly Perl constructs like, say, <code>a@{['b' x 10]}c</code> which +will result in the target string +<code>"abbbbbbbbbbc"</code>. + +<br> <br><h3><a name="perl" class=none>Compatibility with Perl</a></h3> + +Depending on your Perl version you might encounter a couple of small +incompatibilities with Perl most of which aren't due to CL-PPCRE: + +<h4><a name="empty" class=none>Empty strings instead of <code>undef</code> in <code>$1</code>, <code>$2</code>, etc.</a></h4> + +(Cf. case #629 of <a href="#test"><code>testdata</code></a>.) +This is <a +href="http://groups.google.com/groups?threadm=87u1kw8hfr.fsf%40dyn164.dbdmedia.de%... +bug</a> in Perl 5.6.1 and earlier which has been fixed in 5.8.0. + +<h4><a name="scope" class=none>Strange scoping of embedded modifiers</a></h4> + +(Cf. case #430 of <a href="#test"><code>testdata</code></a>.) +This is <a +href="http://groups.google.com/groups?threadm=871y80dpqh.fsf%40bird.agharta.de%22%... +bug</a> in Perl 5.6.1 and earlier which has been fixed in 5.8.0. + +<h4><a name="inconsistent" class=none>Inconsistent capturing of <code>$1</code>, <code>$2</code>, etc.</a></h4> + +(Cf. case #662 of <a href="#test"><code>testdata</code></a>.) +This is <a +href="http://bugs6.perl.org/rt2/Ticket/Display.html?id=18708%22%3Ea +bug</a> in Perl which hasn't been fixed yet. + +<h4><a name="lookaround" class=none>Captured groups not available outside of look-aheads and look-behinds</a></h4> + +(Cf. case #1439 of <a href="#test"><code>testdata</code></a>.) +Well, OK, this ain't a Perl bug. I just can't quite understand why +captured groups should only be seen within the scope of a look-ahead +or look-behind. For the moment, CL-PPCRE and Perl agree to +disagree... :) + +<h4><a name="order" class=none>Alternations don't always work from left to right</a></h4> + +(Cf. case #790 of <a href="#test"><code>testdata</code></a>.) I +also think this a Perl bug but I currently have lost the drive to +report it. + +<h4><a name="mac" class=none><code>"\r"</code> doesn't work with MCL</a></h4> + +(Cf. case #9 of <a href="#test"><code>testdata</code></a>.) For +some strange reason that I don't understand MCL translates +<code>#\Return</code> to <code>(CODE-CHAR 10)</code> while MacPerl +translates <code>"\r"</code> to <code>(CODE-CHAR +13)</code>. Hmmm... + +<h4><a name="alpha" class=none>What about <code>"\w"</code>?</a></h4> + +CL-PPCRE uses <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/f_alphan.htm%22%3E<code>ALPHANUMERICP</code></a> +to decide whether a character matches Perl's +<code>"\w"</code>, so depending on your CL implementation +you might encounter differences between Perl and CL-PPCRE when +matching non-ASCII characters. + +<br> <br><h3><a name="performance" class=none>Performance</a></h3> + +<h4><a name="bench" class=none>Benchmarking</a></h4> + +The <a href="">CL-PPCRE test suite</a> can also be used for +benchmarking purposes: If you call <code>perltest.pl</code> with a +command line argument, it will be interpreted as the minimum number of seconds +each test should run. Perl will time its tests accordingly and create +output which, when fed to <code>CL-PPCRE-TEST:TEST</code>, will result +in a benchmark. Here's an example: + +<pre> +edi@bird:~/cl-ppcre > echo "/((a{0,5}){0,5})*[c]/ +aaaaaaaaaaaac + +/((a{0,5})*)*[c]/ +aaaaaaaaaaaac" | perl perltest.pl .5 > timedata +1 +2 + +edi@bird:~/cl-ppcre > cmucl -quiet +<font color=orange>; Loading #p"/home/edi/.cmucl-init".</font> + +* (mk:compile-system "cl-ppcre-test") +<font color=orange>; Loading #p"/home/edi/cl-ppcre/cl-ppcre.system". +; Loading #p"/home/edi/cl-ppcre/packages.x86f". +; Loading #p"/home/edi/cl-ppcre/specials.x86f". +; Loading #p"/home/edi/cl-ppcre/util.x86f". +; Loading #p"/home/edi/cl-ppcre/errors.x86f". +; Loading #p"/home/edi/cl-ppcre/lexer.x86f". +; Loading #p"/home/edi/cl-ppcre/parser.x86f". +; Loading #p"/home/edi/cl-ppcre/regex-class.x86f". +; Loading #p"/home/edi/cl-ppcre/convert.x86f". +; Loading #p"/home/edi/cl-ppcre/optimize.x86f". +; Loading #p"/home/edi/cl-ppcre/closures.x86f". +; Loading #p"/home/edi/cl-ppcre/repetition-closures.x86f". +; Loading #p"/home/edi/cl-ppcre/scanner.x86f". +; Loading #p"/home/edi/cl-ppcre/api.x86f". +; Loading #p"/home/edi/cl-ppcre/ppcre-tests.x86f".</font> +NIL + +* (cl-ppcre-test:test :file-name "/home/edi/cl-ppcre/timedata") + 1: 0.5559 (1000000 repetitions, Perl: 4.5330 seconds, CL-PPCRE: 2.5200 seconds) + 2: 0.4573 (1000000 repetitions, Perl: 4.5922 seconds, CL-PPCRE: 2.1000 seconds) +NIL +</pre> + +We gave two test cases to <code>perltest.pl</code> and asked it to repeat those tests often enough so that it takes at least 0.5 seconds to run each of them. In both cases, CMUCL was about twice as fast as Perl. +<p> +Here are some more benchmarks (done with Perl 5.6.1 and CMUCL 18d+ in 2002): +<p> + +<table border=1> +<tr><td><b>Test case</b></td><td><b>Repetitions</b></td><td><b>Perl (sec)</b></td><td><b>CL-PPCRE (sec)</b></td><td><b>Ratio CL-PPCRE/Perl</b></td></tr> +<tr><td><code>"@{['x' x 100]}" =~ /(.)*/s</code></td><td align=right>100000</td><td align=right>0.1394</td><td align=right>0.0700</td><td align=right>0.5022</td></tr> +<tr><td><code>"@{['x' x 1000]}" =~ /(.)*/s</code></td><td align=right>100000</td><td align=right>0.1628</td><td align=right>0.0600</td><td align=right>0.3685</td></tr> +<tr><td><code>"@{['x' x 10000]}" =~ /(.)*/s</code></td><td align=right>100000</td><td align=right>0.5071</td><td align=right>0.0600</td><td align=right>0.1183</td></tr> +<tr><td><code>"@{['x' x 100000]}" =~ /(.)*/s</code></td><td align=right>10000</td><td align=right>0.3902</td><td align=right>0.0000</td><td align=right>0.0000</td></tr> +<tr><td><code>"@{['x' x 100]}" =~ /.*/</code></td><td align=right>100000</td><td align=right>0.1520</td><td align=right>0.0800</td><td align=right>0.5262</td></tr> +<tr><td><code>"@{['x' x 1000]}" =~ /.*/</code></td><td align=right>100000</td><td align=right>0.3786</td><td align=right>0.5400</td><td align=right>1.4263</td></tr> +<tr><td><code>"@{['x' x 10000]}" =~ /.*/</code></td><td align=right>10000</td><td align=right>0.2709</td><td align=right>0.5100</td><td align=right>1.8826</td></tr> +<tr><td><code>"@{['x' x 100000]}" =~ /.*/</code></td><td align=right>1000</td><td align=right>0.2734</td><td align=right>0.5100</td><td align=right>1.8656</td></tr> +<tr><td><code>"@{['x' x 100]}" =~ /.*/s</code></td><td align=right>100000</td><td align=right>0.1320</td><td align=right>0.0300</td><td align=right>0.2274</td></tr> +<tr><td><code>"@{['x' x 1000]}" =~ /.*/s</code></td><td align=right>100000</td><td align=right>0.1634</td><td align=right>0.0300</td><td align=right>0.1836</td></tr> +<tr><td><code>"@{['x' x 10000]}" =~ /.*/s</code></td><td align=right>100000</td><td align=right>0.5304</td><td align=right>0.0300</td><td align=right>0.0566</td></tr> +<tr><td><code>"@{['x' x 100000]}" =~ /.*/s</code></td><td align=right>10000</td><td align=right>0.3966</td><td align=right>0.0000</td><td align=right>0.0000</td></tr> +<tr><td><code>"@{['x' x 100]}" =~ /x*/</code></td><td align=right>100000</td><td align=right>0.1507</td><td align=right>0.0900</td><td align=right>0.5970</td></tr> +<tr><td><code>"@{['x' x 1000]}" =~ /x*/</code></td><td align=right>100000</td><td align=right>0.3782</td><td align=right>0.6300</td><td align=right>1.6658</td></tr> +<tr><td><code>"@{['x' x 10000]}" =~ /x*/</code></td><td align=right>10000</td><td align=right>0.2730</td><td align=right>0.6000</td><td align=right>2.1981</td></tr> +<tr><td><code>"@{['x' x 100000]}" =~ /x*/</code></td><td align=right>1000</td><td align=right>0.2708</td><td align=right>0.5900</td><td align=right>2.1790</td></tr> +<tr><td><code>"@{['x' x 100]}" =~ /[xy]*/</code></td><td align=right>100000</td><td align=right>0.2637</td><td align=right>0.1500</td><td align=right>0.5688</td></tr> +<tr><td><code>"@{['x' x 1000]}" =~ /[xy]*/</code></td><td align=right>10000</td><td align=right>0.1449</td><td align=right>0.1200</td><td align=right>0.8282</td></tr> +<tr><td><code>"@{['x' x 10000]}" =~ /[xy]*/</code></td><td align=right>1000</td><td align=right>0.1344</td><td align=right>0.1100</td><td align=right>0.8185</td></tr> +<tr><td><code>"@{['x' x 100000]}" =~ /[xy]*/</code></td><td align=right>100</td><td align=right>0.1355</td><td align=right>0.1200</td><td align=right>0.8857</td></tr> +<tr><td><code>"@{['x' x 100]}" =~ /(.)*/</code></td><td align=right>100000</td><td align=right>0.1523</td><td align=right>0.1100</td><td align=right>0.7220</td></tr> +<tr><td><code>"@{['x' x 1000]}" =~ /(.)*/</code></td><td align=right>100000</td><td align=right>0.3735</td><td align=right>0.5700</td><td align=right>1.5262</td></tr> +<tr><td><code>"@{['x' x 10000]}" =~ /(.)*/</code></td><td align=right>10000</td><td align=right>0.2735</td><td align=right>0.5100</td><td align=right>1.8647</td></tr> +<tr><td><code>"@{['x' x 100000]}" =~ /(.)*/</code></td><td align=right>1000</td><td align=right>0.2598</td><td align=right>0.5000</td><td align=right>1.9242</td></tr> +<tr><td><code>"@{['x' x 100]}" =~ /(x)*/</code></td><td align=right>100000</td><td align=right>0.1565</td><td align=right>0.1300</td><td align=right>0.8307</td></tr> +<tr><td><code>"@{['x' x 1000]}" =~ /(x)*/</code></td><td align=right>100000</td><td align=right>0.3783</td><td align=right>0.6600</td><td align=right>1.7446</td></tr> +<tr><td><code>"@{['x' x 10000]}" =~ /(x)*/</code></td><td align=right>10000</td><td align=right>0.2720</td><td align=right>0.6000</td><td align=right>2.2055</td></tr> +<tr><td><code>"@{['x' x 100000]}" =~ /(x)*/</code></td><td align=right>1000</td><td align=right>0.2725</td><td align=right>0.6000</td><td align=right>2.2020</td></tr> +<tr><td><code>"@{['x' x 100]}" =~ /(y|x)*/</code></td><td align=right>10000</td><td align=right>0.2411</td><td align=right>0.1000</td><td align=right>0.4147</td></tr> +<tr><td><code>"@{['x' x 1000]}" =~ /(y|x)*/</code></td><td align=right>1000</td><td align=right>0.2313</td><td align=right>0.0900</td><td align=right>0.3891</td></tr> +<tr><td><code>"@{['x' x 10000]}" =~ /(y|x)*/</code></td><td align=right>100</td><td align=right>0.2336</td><td align=right>0.0900</td><td align=right>0.3852</td></tr> +<tr><td><code>"@{['x' x 100000]}" =~ /(y|x)*/</code></td><td align=right>10</td><td align=right>0.4165</td><td align=right>0.0900</td><td align=right>0.2161</td></tr> +<tr><td><code>"@{['x' x 100]}" =~ /([xy])*/</code></td><td align=right>100000</td><td align=right>0.2678</td><td align=right>0.1800</td><td align=right>0.6721</td></tr> +<tr><td><code>"@{['x' x 1000]}" =~ /([xy])*/</code></td><td align=right>10000</td><td align=right>0.1459</td><td align=right>0.1200</td><td align=right>0.8227</td></tr> +<tr><td><code>"@{['x' x 10000]}" =~ /([xy])*/</code></td><td align=right>1000</td><td align=right>0.1372</td><td align=right>0.1100</td><td align=right>0.8017</td></tr> +<tr><td><code>"@{['x' x 100000]}" =~ /([xy])*/</code></td><td align=right>100</td><td align=right>0.1358</td><td align=right>0.1100</td><td align=right>0.8098</td></tr> +<tr><td><code>"@{['x' x 100]}" =~ /((x){2})*/</code></td><td align=right>10000</td><td align=right>0.1073</td><td align=right>0.0400</td><td align=right>0.3727</td></tr> +<tr><td><code>"@{['x' x 1000]}" =~ /((x){2})*/</code></td><td align=right>10000</td><td align=right>0.9146</td><td align=right>0.2400</td><td align=right>0.2624</td></tr> +<tr><td><code>"@{['x' x 10000]}" =~ /((x){2})*/</code></td><td align=right>1000</td><td align=right>0.9020</td><td align=right>0.2300</td><td align=right>0.2550</td></tr> +<tr><td><code>"@{['x' x 100000]}" =~ /((x){2})*/</code></td><td align=right>100</td><td align=right>0.8983</td><td align=right>0.2300</td><td align=right>0.2560</td></tr> +<tr><td><code>"@{[join undef, map { chr(ord('a') + rand 26) } (1..100)]}FOOBARBAZ" =~ /[a-z]*FOOBARBAZ/</code></td><td align=right>100000</td><td align=right>0.2829</td><td align=right>0.2300</td><td align=right>0.8129</td></tr> +<tr><td><code>"@{[join undef, map { chr(ord('a') + rand 26) } (1..1000)]}FOOBARBAZ" =~ /[a-z]*FOOBARBAZ/</code></td><td align=right>10000</td><td align=right>0.1859</td><td align=right>0.1700</td><td align=right>0.9143</td></tr> +<tr><td><code>"@{[join undef, map { chr(ord('a') + rand 26) } (1..10000)]}FOOBARBAZ" =~ /[a-z]*FOOBARBAZ/</code></td><td align=right>1000</td><td align=right>0.1420</td><td align=right>0.1700</td><td align=right>1.1968</td></tr> +<tr><td><code>"@{[join undef, map { chr(ord('a') + rand 26) } (1..100)]}NOPE" =~ /[a-z]*FOOBARBAZ/</code></td><td align=right>1000000</td><td align=right>0.9196</td><td align=right>0.4600</td><td align=right>0.5002</td></tr> +<tr><td><code>"@{[join undef, map { chr(ord('a') + rand 26) } (1..1000)]}NOPE" =~ /[a-z]*FOOBARBAZ/</code></td><td align=right>100000</td><td align=right>0.2166</td><td align=right>0.2500</td><td align=right>1.1542</td></tr> +<tr><td><code>"@{[join undef, map { chr(ord('a') + rand 26) } (1..10000)]}NOPE" =~ /[a-z]*FOOBARBAZ/</code></td><td align=right>10000</td><td align=right>0.1465</td><td align=right>0.2300</td><td align=right>1.5696</td></tr> +<tr><td><code>"@{[join undef, map { chr(ord('a') + rand 26) } (1..100)]}FOOBARBAZ" =~ /([a-z])*FOOBARBAZ/</code></td><td align=right>100000</td><td align=right>0.2917</td><td align=right>0.2600</td><td align=right>0.8915</td></tr> +<tr><td><code>"@{[join undef, map { chr(ord('a') + rand 26) } (1..1000)]}FOOBARBAZ" =~ /([a-z])*FOOBARBAZ/</code></td><td align=right>10000</td><td align=right>0.1811</td><td align=right>0.1800</td><td align=right>0.9942</td></tr> +<tr><td><code>"@{[join undef, map { chr(ord('a') + rand 26) } (1..10000)]}FOOBARBAZ" =~ /([a-z])*FOOBARBAZ/</code></td><td align=right>1000</td><td align=right>0.1424</td><td align=right>0.1600</td><td align=right>1.1233</td></tr> +<tr><td><code>"@{[join undef, map { chr(ord('a') + rand 26) } (1..100)]}NOPE" =~ /([a-z])*FOOBARBAZ/</code></td><td align=right>1000000</td><td align=right>0.9154</td><td align=right>0.7400</td><td align=right>0.8083</td></tr> +<tr><td><code>"@{[join undef, map { chr(ord('a') + rand 26) } (1..1000)]}NOPE" =~ /([a-z])*FOOBARBAZ/</code></td><td align=right>100000</td><td align=right>0.2170</td><td align=right>0.2800</td><td align=right>1.2901</td></tr> +<tr><td><code>"@{[join undef, map { chr(ord('a') + rand 26) } (1..10000)]}NOPE" =~ /([a-z])*FOOBARBAZ/</code></td><td align=right>10000</td><td align=right>0.1497</td><td align=right>0.2300</td><td align=right>1.5360</td></tr> +<tr><td><code>"@{[join undef, map { chr(ord('a') + rand 26) } (1..100)]}FOOBARBAZ" =~ /([a-z]|ab)*FOOBARBAZ/</code></td><td align=right>10000</td><td align=right>0.4359</td><td align=right>0.1500</td><td align=right>0.3441</td></tr> +<tr><td><code>"@{[join undef, map { chr(ord('a') + rand 26) } (1..1000)]}FOOBARBAZ" =~ /([a-z]|ab)*FOOBARBAZ/</code></td><td align=right>1000</td><td align=right>0.5456</td><td align=right>0.1500</td><td align=right>0.2749</td></tr> +<tr><td><code>"@{[join undef, map { chr(ord('a') + rand 26) } (1..10000)]}FOOBARBAZ" =~ /([a-z]|ab)*FOOBARBAZ/</code></td><td align=right>10</td><td align=right>0.2039</td><td align=right>0.0600</td><td align=right>0.2943</td></tr> +<tr><td><code>"@{[join undef, map { chr(ord('a') + rand 26) } (1..100)]}NOPE" =~ /([a-z]|ab)*FOOBARBAZ/</code></td><td align=right>1000000</td><td align=right>0.9311</td><td align=right>0.7400</td><td align=right>0.7947</td></tr> +<tr><td><code>"@{[join undef, map { chr(ord('a') + rand 26) } (1..1000)]}NOPE" =~ /([a-z]|ab)*FOOBARBAZ/</code></td><td align=right>100000</td><td align=right>0.2162</td><td align=right>0.2700</td><td align=right>1.2489</td></tr> +<tr><td><code>"@{[join undef, map { chr(ord('a') + rand 26) } (1..10000)]}NOPE" =~ /([a-z]|ab)*FOOBARBAZ/</code></td><td align=right>10000</td><td align=right>0.1488</td><td align=right>0.2300</td><td align=right>1.5455</td></tr> +<tr><td><code>"@{[join undef, map { chr(ord('a') + rand 26) } (1..100)]}NOPE" =~ /[a-z]*FOOBARBAZ/i</code></td><td align=right>1000</td><td align=right>0.1555</td><td align=right>0.0000</td><td align=right>0.0000</td></tr> +<tr><td><code>"@{[join undef, map { chr(ord('a') + rand 26) } (1..1000)]}NOPE" =~ /[a-z]*FOOBARBAZ/i</code></td><td align=right>10</td><td align=right>0.1441</td><td align=right>0.0000</td><td align=right>0.0000</td></tr> +<tr><td><code>"@{[join undef, map { chr(ord('a') + rand 26) } (1..10000)]}NOPE" =~ /[a-z]*FOOBARBAZ/i</code></td><td align=right>10</td><td align=right>13.7150</td><td align=right>0.0100</td><td align=right>0.0007</td></tr> + +</table> + +<p> +As you might have noticed, Perl shines if it can reduce significant +parts of the matching process to cases where it can advance through +the target string one character at a time. This leads to C code where +you can very efficiently test and increment a pointer into a string in +a tight loop and can hardly be beaten with CL. In almost all other +cases, the CMUCL/CL-PPCRE combination is usually faster than Perl - +sometimes a lot faster. +<p> +As most of the examples above were chosen to make Perl look good +here's <a href="benchmarks.2002-12-22.txt">another benchmark</a> - the +result of running <a href="#test"><code>perltest.pl</code></a> against the +full <a href="#test"><code>testdata</code></a> file with a time +limit of 0.1 seconds, CL-PPCRE 0.1.2 on CMUCL 18e-pre +vs. Perl 5.6.1. CL-PPCRE is faster than Perl in 1511 of 1545 +cases - in 1045 cases it's more than twice as fast. +<p> +Note that Perl as well as CL-PPCRE keep the rightmost matches in +registers - keep that in mind if you benchmark against other regex +implementations. Also note that <code>CL-PPCRE-TEST:TEST</code> +automatically skips test cases where Perl and CL-PPCRE don't agree. + +<h4><a name="other" class=none>Other performance issues</a></h4> + +While the scanners created by CL-PPCRE are pretty fast, the process +which creates scanners from Perl regex strings and parse trees isn't +that speedy and conses a lot. It is recommended that you store and +re-use scanners if possible. The <code>DO-</code>macros will do this +for you automatically. +<p> +However, beginning with version 0.5.2, CL-PPCRE uses a <a +name="compiler-macro" +href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_c.htm#compiler_... +macro</a> and <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/s_ld_tim.htm%22%3E<code>LOAD-TIME-VALUE</code></a> +to make sure that the scanner is only built once if the first argument +to <a href="#scan"><code>SCAN</code></a>, <a href="#scan-to-strings"><code>SCAN-TO-STRINGS</code></a>, <a href="#split"><code>SPLIT</code></a>, +<a href="#regex-replace"><code>REGEX-REPLACE</code></a>, or <a href="#regex-replace-all"><code>REGEX-REPLACE-ALL</code></a> is a <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_c.htm#constant_... +form</a>. (But see the notes for <a +href="#regex-char-code-limit"><code>*REGEX-CHAR-CODE-LIMIT*</code></a> and +<a href="#use-bmh-matchers"><code>*USE-BMH-MATCHERS*</code></a>.) +<p> +Here's an example of its effect + +<pre> +* (trace cl-ppcre::convert) +(CL-PPCRE::CONVERT) +* (defun foo (string) (cl-ppcre:scan "(?s).*" string)) +FOO +* (time (foo "The quick brown fox")) +Compiling LAMBDA NIL: +Compiling Top-Level Form: + + 0: (CL-PPCRE::CONVERT #<lambda-list-unavailable>) + 0: CL-PPCRE::CONVERT returned + #<CL-PPCRE::SEQ {48B033C5}> + 0 + #<CL-PPCRE::EVERYTHING {48B031D5}> +Evaluation took: + 0.0 seconds of real time + 0.00293 seconds of user run time + 9.77e-4 seconds of system run time + 0 page faults and + 11,408 bytes consed. +0 +19 +#() +#() +* (time (foo "The quick brown fox")) +Compiling LAMBDA NIL: +Compiling Top-Level Form: + + 0: (CL-PPCRE::CONVERT #<lambda-list-unavailable>) + 0: CL-PPCRE::CONVERT returned + #<CL-PPCRE::SEQ {48B14C4D}> + 0 + #<CL-PPCRE::EVERYTHING {48B14B65}> +Evaluation took: + 0.0 seconds of real time + 0.00293 seconds of user run time + 0.0 seconds of system run time + 0 page faults and + 10,960 bytes consed. +0 +19 +#() +#() +* (compile 'foo) + 0: (CL-PPCRE::CONVERT #<lambda-list-unavailable>) + 0: CL-PPCRE::CONVERT returned + #<CL-PPCRE::SEQ {48B1FEC5}> + 0 + #<CL-PPCRE::EVERYTHING {48B1FDDD}> +Compiling LAMBDA (STRING): +Compiling Top-Level Form: +FOO +NIL +NIL +* (time (foo "The quick brown fox")) +Compiling LAMBDA NIL: +Compiling Top-Level Form: + +Evaluation took: + 0.0 seconds of real time + 0.0 seconds of user run time + 0.0 seconds of system run time + 0 page faults and + 0 bytes consed. +0 +19 +#() +#() +* (time (foo "The quick brown fox")) +Compiling LAMBDA NIL: +Compiling Top-Level Form: + +Evaluation took: + 0.0 seconds of real time + 0.0 seconds of user run time + 0.0 seconds of system run time + 0 page faults and + 0 bytes consed. +0 +19 +#() +#() +* +</pre> + +<p> +Of course, the usual rules for creating efficient regular expressions +apply to CL-PPCRE as well although it can optimize a couple of cases +itself. The most important rule is probably that you shouldn't use +capturing groups if you don't need the captured information, i.e. use +<code>"(?:a|b)*"</code> instead of +<code>"(a|b)*"</code> if you don't need to refer to the +register. (In fact, in this particular case CL-PPCRE will be able to +optimize away the register group, but it won't if you replace +<code>"a|b"</code> with, say, +<code>"a|bc"</code>.) +<p> +Another point worth mentioning is that you definitely should use +single-line mode if you have long strings without +<code>#\Newline</code> (or where you don't care about the line breaks) +and plan to use regular expressions like +<code>".*"</code>. See the <a href="#bench">benchmarks</a> +for comparisons between single-line mode and normal mode with such +target strings. +<p> +Another thing to consider is that, for performance reasons, CL-PPCRE +assumes that most of the target strings you're trying to match are <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/t_smp_st.htm%22%3Esimp... +strings</a> and coerces non-simple strings to simple strings before +scanning them. If you plan on working with non-simple strings mostly, +you might consider modifying the CL-PPCRE source code. This is easy: +Change all occurences of <code>SCHAR</code> to <code>CHAR</code> and +redefine the macro in <code>util.lisp</code> where the coercion takes +place - that's all. + +<br> <br><h3><a name="bugs" class=none>Bugs and problems</a></h3> + +<h4><a name="stack" class=none>Stack overflow</a></h4> + +CL-PPCRE can optimize away a lot of unnecessary backtracking but +sometimes this simply isn't possible. With complicated regular +expressions and long strings this might lead to stack overflows +depending on your machine and your CL implementation. +<p> +Here's one example with CLISP: + +<pre> +[1]> (defun target (n) (concatenate 'string (make-string n :initial-element #\a) "b")) +TARGET + +[2]> (cl-ppcre:scan "a*" (target 1000)) +0 ; +1000 ; +#() ; +#() + +[3]> (cl-ppcre:scan "(?:a|b)*" (target 1000)) +0 ; +1001 ; +#() ; +#() + +[4]> (cl-ppcre:scan "(a|b)*" (target 1000)) +0 ; +1001 ; +#(1000) ; +#(1001) + +[5]> (cl-ppcre:scan "(a|b)*" (target 10000)) +0 ; +10001 ; +#(10000) ; +#(10001) + +[6]> (cl-ppcre:scan "(a|b)*" (target 100000)) +0 ; +100001 ; +#(100000) ; +#(100001) + +[7]> (cl-ppcre:scan "(a|b)*" (target 1000000)) +0 ; +1000001 ; +#(1000000) ; +#(1000001) + +<font color=orange>;; No problem until now - but...</font> + +[8]> (cl-ppcre:scan "(a|)*" (target 100000)) +*** - Lisp stack overflow. RESET + +[9]> (cl-ppcre:scan "(a|)*" (target 3200)) +*** - Lisp stack overflow. RESET +</pre> + +<p> +With CMUCL the situation is better and worse at the same time. It will +take a lot longer until CMUCL gives up but if it gives up the whole +Lisp image will silently die (at least on my machine): +<p> +[Note: This was true for CMUCL 18e - CMUCL 19a behaves in a much nicer way and gives you a chance to recover.] + +<pre> +* (defun target (n) (concatenate 'string (make-string n :initial-element #\a) "b")) +TARGET + +* (cl-ppcre:scan "(a|)*" (target 3200)) +0 +3200 +#(3200) +#(3200) + +* (cl-ppcre:scan "(a|)*" (target 10000)) +0 +10000 +#(10000) +#(10000) + +* (cl-ppcre:scan "(a|)*" (target 100000)) +0 +100000 +#(100000) +#(100000) + +* (cl-ppcre:scan "(a|)*" (target 1000000)) +0 +1000000 +#(1000000) +#(1000000) + +<font color=orange>;; No problem until now - but...</font> + +* (cl-ppcre:scan "(a|)*" (target 10000000)) +edi@bird:~ > +</pre> + +This behaviour can be changed with <em>very</em> conservative optimization settings but that'll make CL-PPCRE crawl compared to Perl. + +<p> +You might want to compare this to the way Perl handles the same situation. It might lie to you: + +<pre> +edi@bird:~ > perl -le '$_="a" x 32766 . "b"; /(a|)*/; print $1' + +edi@bird:~ > perl -le '$_="a" x 32767 . "b"; /(a|)*/; print $1' +a +</pre> + +Or it might warn you before it's lying to you: +<pre> +edi@bird:~ > perl -lwe '$_="a" x 32767 . "b"; /(a|)*/; print $1' +Complex regular subexpression recursion limit (32766) exceeded at -e line 1. +a +</pre> + +Or it might simply die: +<pre> +edi@bird:~ > /opt/perl-5.8/bin/perl -lwe '$_="a" x 32767 . "b"; /(a|)*/; print $1' +Segmentation fault +</pre> + +Your mileage may vary, of course... + +<h4><a name="quote" class=none><code>"\Q"</code> doesn't work, or does it?</a></h4> + +In Perl the following code works as expected, i.e. it prints <code>1</code>. +<pre> +#!/usr/bin/perl -l + +$a = '\E*'; +print 1 + if '\E*\E*' =~ /(?:\Q$a\E){2}/; +</pre> + +If you try to do something similar in CL-PPCRE, you get an error: + +<pre> +* (let ((cl-ppcre:*allow-quoting* t) + (a "\E*")) + (cl-ppcre:scan (concatenate 'string "(?:\Q" a "\E){2}") "\E*\E*")) +Quantifier '*' not allowed at position 3 in string "(?:*\E){2}" +</pre> + +The error message might give you a hint as to why this happens: +Because <a href="#*allow-quoting*"><code>*ALLOW-QUOTING*</code></a> +was <em>true</em> the concatenated string was pre-processed before it +was fed to CL-PPCRE's parser - the result of this pre-processing is +<code>"(?:*\E){2}"</code> because the +<code>"\E"</code> in the string <code>A</code> was taken to +be the end of the quoted section started by +<code>"\Q"</code>. This cannot happen in Perl due to its +complicated interpolation rules - see <code>man perlop</code> for +the scary details. It <em>can</em> happen in CL-PPCRE, though. +Bummer! +<p> +What gives? <code>"\Q...\E"</code> in CL-PPCRE should only +be used in literal strings. If you want to quote arbitrary strings, +try <a href="http://weitz.de/cl-interpol/">CL-INTERPOL</a> or use <a +href="#quote-meta-chars"><code>QUOTE-META-CHARS</code></a>: +<pre> +* (let ((a "\E*")) + (cl-ppcre:scan (concatenate 'string + "(?:" (cl-ppcre:quote-meta-chars a) "){2}") + "\E*\E*")) +0 +6 +#() +#() +</pre> +Or, even better and Lisp-ier, use the <a href="#create-scanner2">S-expression syntax</a> instead - no need for quoting in this case: +<pre> +* (let ((a "\E*")) + (cl-ppcre:scan `(:greedy-repetition 2 2 ,a) + "\E*\E*")) +0 +6 +#() +#() +</pre> + +<h4><a name="backslash" class=none>Backslashes may confuse you...</a></h4> + +<pre> +* (let ((a "y\y")) + (cl-ppcre:scan a a)) +NIL +</pre> + +You didn't expect this to yield <code>NIL</code>, did you? Shouldn't something like <code>(CL-PPCRE:SCAN A A)</code> always return a true value? No, because the first and the second argument to <code>SCAN</code> are handled differently: The first argument is fed to CL-PPCRE's parser and is treated like a Perl regular expression. In particular, the parser "sees" <code>\y</code> and converts it to <code>y</code> because <code>\y</code> has no special meaning in regular expressions. So, the regular expression is the constant string <code>"yy"</code>. But the second argument isn't converted - it is left as is, i.e. it's equivalent to Perl's <code>'y\y'</code>. In other words, this example would be equivalent to the Perl code + +<pre> +'y\y' =~ /y\y/; +</pre> + +or to + +<pre> +$a = 'y\y'; +$a =~ /$a/; +</pre> + +which should explain why it doesn't match. +<p> +Still confused? You might want to try <a href="http://weitz.de/cl-interpol/">CL-INTERPOL</a>. + +<br> <br><h3><a class=none name="remarks">Remarks</a></h3> + +The sample output from CMUCL and CLISP has been slightly edited to +increase readability. +<p> +All test cases and benchmarks in this document where performed on an +IBM Thinkpad T23 laptop (Pentium III 1.2 GHz, +768 MB RAM) running <a href="http://www.gentoo.org/">Gentoo +Linux</a> 1.1a. + +<br> <br><h3><a class=none name="allegro">AllegroCL compatibility mode</a></h3> + +Since autumn 2004 <a +href="http://www.franz.com/products/allegrocl/%22%3EAllegroCL</a> offers +<a +href="http://www.franz.com/support/documentation/7.0/doc/regexp.htm%22%3Ea +new regular expression API</a> with a syntax very similar to +CL-PPCRE. Although CL-PPCRE is quite fast already, AllegroCL's engine will +most likely be even faster (but only on AllegroCL, of course). However, you might want to +stick to CL-PPCRE because you have a "legacy" application or because +you want your code to be portable to other Lisp implementations. +Therefore, beginning from version 1.2.0, CL-PPCRE offers a +"compatibility mode" where you can continue using the CL-PPCRE API as +described <a href="#dict">above</a> but deploy the AllegroCL regex +engine under the hood. (The details are: Calls to <a +href="#create-scanner"><code>CREATE-SCANNER</code></a> and <a +href="#scan"><code>SCAN</code></a> are dispatched to their AllegroCL +counterparts <a +href="http://www.franz.com/support/documentation/7.0/doc/operators/excl/compile-re...<code>EXCL:COMPILE-RE</code></a> +and <a +href="http://www.franz.com/support/documentation/7.0/doc/operators/excl/match-re.h...<code>EXCL:MATCH-RE</code></a> +while everything else is left as is.) +<p> +The advantage of this mode is that you'll get a much smaller image and +most likely faster code. (But note that CL-PPCRE needs to do a small amount of work to massage AllegroCL's output into the format expected by CL-PPCRE.) The downside is that your code won't be +fully compatible with CL-PPCRE anymore. Here are some of the +differences (most of which probably don't matter very often): +<ul> +<li>The AllegroCL engine doesn't offer <a +href="#parse-tree-synonym">parse tree synonyms</a> and <a href="#filters">filters</a>. +<li>The AllegroCL engine <a href="http://www.franz.com/support/documentation/7.0/doc/regexp.htm#regexp-new-compatibility-2">will choke on some regular expressions involving curly braces</a> that are accepted by Perl and CL-PPCRE's native engine. +<li>The AllegroCL engine's case-folding mode switch (which is used instead of CL-PPCRE's <a href="#create-scanner"><code>:CASE-INSENSITIVE</code> keyword parameter</a>) <a href="http://www.franz.com/support/documentation/7.0/doc/regexp.htm#regexp-new-matching-2">is currently only effective for ASCII characters</a>. +<li>The AllegroCL engine <a href="http://www.franz.com/support/documentation/7.0/doc/regexp.htm#regexp-new-compatibility-2">doesn't support</a> <a href="#*allow-quoting*">quoting of metacharacters</a>. +<li>In AllegroCL compatibility mode compiled regular expressions (as returned by <a href="#create-scanner"><code>CREATE-SCANNER</code></a>) aren't functions but structures. +</ul> +For more details about the AllegroCL engine and possible deviations from CL-PPCRE see the <a href="http://www.franz.com/support/documentation/7.0/doc/regexp.htm">documentation</a> at the <a href="http://www.franz.com/">Franz Inc. website</a>. +<p> +To use the AllegroCL compatibility mode you have to +<pre> +(push :use-acl-regexp2-engine *features*) +</pre> +<em>before</em> you compile CL-PPCRE. + +<br> <br><h3><a class=none name="ack">Acknowledgements</a></h3> + +Although I didn't use their code I was heavily inspired by looking at +the Scheme/CL regex implementations of <a +href="http://www.ccs.neu.edu/home/dorai/pregexp/pregexp.html%22%3EDorai +Sitaram</a> and <a +href="http://www.geocities.com/mparker762/clawk#regex%22%3EMichael +Parker</a>. Also, the nice folks from CMUCL's <a +href="http://www.cons.org/cmucl/support.html%22%3Emailing list</a> as well +as the output of Perl's <code>use re "debug"</code> pragma +have been very helpful in optimizing the scanners created by CL-PPCRE. + +<p> +The asdf system definitions were kindly provided by Marco +Baringer. Hannu Koivisto provided patches to make the +<code>.system</code> files more usable. Thanks to Kevin Rosenberg and +Douglas Crosher for pointing out how to be friendly to case-sensitive +ACL images. Thanks to Karsten Poeck and JP Massar for their help in +making CL-PPCRE work with Corman Lisp. JP Massar and Kent M. Pitman +also helped to improve/fix the test suite and the compiler macro. See +the <a href="http://weitz.de/cl-ppcre/CHANGELOG">ChangeLog</a> for several other people who helped with bug +reports or patches. + +<p> +Thanks to the guys at "<a href="http://www.weinhandel-ottensen.de/">Café Olé</a>" in Hamburg +where I wrote most of the code and thanks to my wife for lending me +her PowerBook to test CL-PPCRE with MCL and OpenMCL. + +<p> +$Header: /usr/local/cvsrep/cl-ppcre/doc/index.html,v 1.162 2007/09/13 07:52:15 edi Exp $ +<p><a href="http://weitz.de/index.html">BACK TO MY HOMEPAGE</a> + +</body> +</html>
Added: branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/errors.lisp =================================================================== --- branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/errors.lisp 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/errors.lisp 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,84 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-PPCRE; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/cl-ppcre/errors.lisp,v 1.16 2007/01/01 23:43:10 edi Exp $ + +;;; Copyright (c) 2002-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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-package #:cl-ppcre) + +(defvar *syntax-error-string* nil + "The string which caused the syntax error.") + +(define-condition ppcre-error (simple-error) + () + (:documentation "All errors signaled by CL-PPCRE are of +this type.")) + +(define-condition ppcre-syntax-error (ppcre-error) + ((string :initarg :string + :reader ppcre-syntax-error-string) + (pos :initarg :pos + :reader ppcre-syntax-error-pos)) + (:default-initargs + :pos nil + :string *syntax-error-string*) + (:report (lambda (condition stream) + (format stream "~?~@[ at position ~A~]~@[ in string ~S~]" + (simple-condition-format-control condition) + (simple-condition-format-arguments condition) + (ppcre-syntax-error-pos condition) + (ppcre-syntax-error-string condition)))) + (:documentation "Signaled if CL-PPCRE's parser encounters an error +when trying to parse a regex string or to convert a parse tree into +its internal representation.")) + +(setf (documentation 'ppcre-syntax-error-string 'function) + "Returns the string the parser was parsing when the error was +encountered (or NIL if the error happened while trying to convert a +parse tree).") + +(setf (documentation 'ppcre-syntax-error-pos 'function) + "Returns the position within the string where the error occured +(or NIL if the error happened while trying to convert a parse tree") + +(define-condition ppcre-invocation-error (ppcre-error) + () + (:documentation "Signaled when CL-PPCRE functions are +invoked with wrong arguments.")) + +(defmacro signal-ppcre-syntax-error* (pos format-control &rest format-arguments) + `(error 'ppcre-syntax-error + :pos ,pos + :format-control ,format-control + :format-arguments (list ,@format-arguments))) + +(defmacro signal-ppcre-syntax-error (format-control &rest format-arguments) + `(signal-ppcre-syntax-error* nil ,format-control ,@format-arguments)) + +(defmacro signal-ppcre-invocation-error (format-control &rest format-arguments) + `(error 'ppcre-invocation-error + :format-control ,format-control + :format-arguments (list ,@format-arguments)))
Added: branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/lexer.lisp =================================================================== --- branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/lexer.lisp 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/lexer.lisp 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,736 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-PPCRE; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/cl-ppcre/lexer.lisp,v 1.27 2007/03/24 23:52:44 edi Exp $ + +;;; The lexer's responsibility is to convert the regex string into a +;;; sequence of tokens which are in turn consumed by the parser. +;;; +;;; The lexer is aware of Perl's 'extended mode' and it also 'knows' +;;; (with a little help from the parser) how many register groups it +;;; has opened so far. (The latter is necessary for interpreting +;;; strings like "\10" correctly.) + +;;; Copyright (c) 2002-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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-package #:cl-ppcre) + +(declaim (inline map-char-to-special-class)) +(defun map-char-to-special-char-class (chr) + (declare #.*standard-optimize-settings*) + "Maps escaped characters like "\d" to the tokens which represent +their associated character classes." + (case chr + ((#\d) + :digit-class) + ((#\D) + :non-digit-class) + ((#\w) + :word-char-class) + ((#\W) + :non-word-char-class) + ((#\s) + :whitespace-char-class) + ((#\S) + :non-whitespace-char-class))) + +(locally + (declare #.*standard-optimize-settings*) + (defstruct (lexer (:constructor make-lexer-internal)) + "LEXER structures are used to hold the regex string which is +currently lexed and to keep track of the lexer's state." + (str "" + :type string + :read-only t) + (len 0 + :type fixnum + :read-only t) + (reg 0 + :type fixnum) + (pos 0 + :type fixnum) + (last-pos nil + :type list))) + +(defun make-lexer (string) + (declare (inline make-lexer-internal) + #-genera (type string string)) + (make-lexer-internal :str (maybe-coerce-to-simple-string string) + :len (length string))) + +(declaim (inline end-of-string-p)) +(defun end-of-string-p (lexer) + (declare #.*standard-optimize-settings*) + "Tests whether we're at the end of the regex string." + (<= (lexer-len lexer) + (lexer-pos lexer))) + +(declaim (inline looking-at-p)) +(defun looking-at-p (lexer chr) + (declare #.*standard-optimize-settings*) + "Tests whether the next character the lexer would see is CHR. +Does not respect extended mode." + (and (not (end-of-string-p lexer)) + (char= (schar (lexer-str lexer) (lexer-pos lexer)) + chr))) + +(declaim (inline next-char-non-extended)) +(defun next-char-non-extended (lexer) + (declare #.*standard-optimize-settings*) + "Returns the next character which is to be examined and updates the +POS slot. Does not respect extended mode." + (cond ((end-of-string-p lexer) + nil) + (t + (prog1 + (schar (lexer-str lexer) (lexer-pos lexer)) + (incf (lexer-pos lexer)))))) + +(defun next-char (lexer) + (declare #.*standard-optimize-settings*) + "Returns the next character which is to be examined and updates the +POS slot. Respects extended mode, i.e. whitespace, comments, and also +nested comments are skipped if applicable." + (let ((next-char (next-char-non-extended lexer)) + last-loop-pos) + (loop + ;; remember where we started + (setq last-loop-pos (lexer-pos lexer)) + ;; first we look for nested comments like (?#foo) + (when (and next-char + (char= next-char #() + (looking-at-p lexer #?)) + (incf (lexer-pos lexer)) + (cond ((looking-at-p lexer ##) + ;; must be a nested comment - so we have to search for + ;; the closing parenthesis + (let ((error-pos (- (lexer-pos lexer) 2))) + (unless + ;; loop 'til ')' or end of regex string and + ;; return NIL if ')' wasn't encountered + (loop for skip-char = next-char + then (next-char-non-extended lexer) + while (and skip-char + (char/= skip-char #))) + finally (return skip-char)) + (signal-ppcre-syntax-error* + error-pos + "Comment group not closed"))) + (setq next-char (next-char-non-extended lexer))) + (t + ;; undo effect of previous INCF if we didn't see a # + (decf (lexer-pos lexer))))) + (when *extended-mode-p* + ;; now - if we're in extended mode - we skip whitespace and + ;; comments; repeat the following loop while we look at + ;; whitespace or ## + (loop while (and next-char + (or (char= next-char ##) + (whitespacep next-char))) + do (setq next-char + (if (char= next-char ##) + ;; if we saw a comment marker skip until + ;; we're behind #\Newline... + (loop for skip-char = next-char + then (next-char-non-extended lexer) + while (and skip-char + (char/= skip-char #\Newline)) + finally (return (next-char-non-extended lexer))) + ;; ...otherwise (whitespace) skip until we + ;; see the next non-whitespace character + (loop for skip-char = next-char + then (next-char-non-extended lexer) + while (and skip-char + (whitespacep skip-char)) + finally (return skip-char)))))) + ;; if the position has moved we have to repeat our tests + ;; because of cases like /^a (?#xxx) (?#yyy) {3}c/x which + ;; would be equivalent to /^a{3}c/ in Perl + (unless (> (lexer-pos lexer) last-loop-pos) + (return next-char))))) + +(declaim (inline fail)) +(defun fail (lexer) + (declare #.*standard-optimize-settings*) + "Moves (LEXER-POS LEXER) back to the last position stored in +(LEXER-LAST-POS LEXER) and pops the LAST-POS stack." + (unless (lexer-last-pos lexer) + (signal-ppcre-syntax-error "LAST-POS stack of LEXER ~A is empty" lexer)) + (setf (lexer-pos lexer) (pop (lexer-last-pos lexer))) + nil) + +(defun get-number (lexer &key (radix 10) max-length no-whitespace-p) + (declare #.*standard-optimize-settings*) + "Read and consume the number the lexer is currently looking at and +return it. Returns NIL if no number could be identified. +RADIX is used as in PARSE-INTEGER. If MAX-LENGTH is not NIL we'll read +at most the next MAX-LENGTH characters. If NO-WHITESPACE-P is not NIL +we don't tolerate whitespace in front of the number." + (when (or (end-of-string-p lexer) + (and no-whitespace-p + (whitespacep (schar (lexer-str lexer) (lexer-pos lexer))))) + (return-from get-number nil)) + (multiple-value-bind (integer new-pos) + (parse-integer (lexer-str lexer) + :start (lexer-pos lexer) + :end (if max-length + (let ((end-pos (+ (lexer-pos lexer) + (the fixnum max-length))) + (lexer-len (lexer-len lexer))) + (if (< end-pos lexer-len) + end-pos + lexer-len)) + (lexer-len lexer)) + :radix radix + :junk-allowed t) + (cond ((and integer (>= (the fixnum integer) 0)) + (setf (lexer-pos lexer) new-pos) + integer) + (t nil)))) + +(declaim (inline try-number)) +(defun try-number (lexer &key (radix 10) max-length no-whitespace-p) + (declare #.*standard-optimize-settings*) + "Like GET-NUMBER but won't consume anything if no number is seen." + ;; remember current position + (push (lexer-pos lexer) (lexer-last-pos lexer)) + (let ((number (get-number lexer + :radix radix + :max-length max-length + :no-whitespace-p no-whitespace-p))) + (or number (fail lexer)))) + +(declaim (inline make-char-from-code)) +(defun make-char-from-code (number error-pos) + (declare #.*standard-optimize-settings*) + "Create character from char-code NUMBER. NUMBER can be NIL +which is interpreted as 0. ERROR-POS is the position where +the corresponding number started within the regex string." + ;; only look at rightmost eight bits in compliance with Perl + (let ((code (logand #o377 (the fixnum (or number 0))))) + (or (and (< code char-code-limit) + (code-char code)) + (signal-ppcre-syntax-error* + error-pos + "No character for hex-code ~X" + number)))) + +(defun unescape-char (lexer) + (declare #.*standard-optimize-settings*) + "Convert the characters(s) following a backslash into a token +which is returned. This function is to be called when the backslash +has already been consumed. Special character classes like \W are +handled elsewhere." + (when (end-of-string-p lexer) + (signal-ppcre-syntax-error "String ends with backslash")) + (let ((chr (next-char-non-extended lexer))) + (case chr + ((#\E) + ;; if \Q quoting is on this is ignored, otherwise it's just an + ;; #\E + (if *allow-quoting* + :void + #\E)) + ((#\c) + ;; \cx means control-x in Perl + (let ((next-char (next-char-non-extended lexer))) + (unless next-char + (signal-ppcre-syntax-error* + (lexer-pos lexer) + "Character missing after '\c' at position ~A")) + (code-char (logxor #x40 (char-code (char-upcase next-char)))))) + ((#\x) + ;; \x should be followed by a hexadecimal char code, + ;; two digits or less + (let* ((error-pos (lexer-pos lexer)) + (number (get-number lexer :radix 16 :max-length 2 :no-whitespace-p t))) + ;; note that it is OK if \x is followed by zero digits + (make-char-from-code number error-pos))) + ((#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9) + ;; \x should be followed by an octal char code, + ;; three digits or less + (let* ((error-pos (decf (lexer-pos lexer))) + (number (get-number lexer :radix 8 :max-length 3))) + (make-char-from-code number error-pos))) + ;; the following five character names are 'semi-standard' + ;; according to the CLHS but I'm not aware of any implementation + ;; that doesn't implement them + ((#\t) + #\Tab) + ((#\n) + #\Newline) + ((#\r) + #\Return) + ((#\f) + #\Page) + ((#\b) + #\Backspace) + ((#\a) + (code-char 7)) ; ASCII bell + ((#\e) + (code-char 27)) ; ASCII escape + (otherwise + ;; all other characters aren't affected by a backslash + chr)))) + +(defun collect-char-class (lexer) + (declare #.*standard-optimize-settings*) + "Reads and consumes characters from regex string until a right +bracket is seen. Assembles them into a list (which is returned) of +characters, character ranges, like (:RANGE #\A #\E) for a-e, and +tokens representing special character classes." + (let ((start-pos (lexer-pos lexer)) ; remember start for error message + hyphen-seen + last-char + list) + (flet ((handle-char (c) + "Do the right thing with character C depending on whether +we're inside a range or not." + (cond ((and hyphen-seen last-char) + (setf (car list) (list :range last-char c) + last-char nil)) + (t + (push c list) + (setq last-char c))) + (setq hyphen-seen nil))) + (loop for first = t then nil + for c = (next-char-non-extended lexer) + ;; leave loop if at end of string + while c + do (cond + ((char= c #\) + ;; we've seen a backslash + (let ((next-char (next-char-non-extended lexer))) + (case next-char + ((#\d #\D #\w #\W #\s #\S) + ;; a special character class + (push (map-char-to-special-char-class next-char) list) + ;; if the last character was a hyphen + ;; just collect it literally + (when hyphen-seen + (push #- list)) + ;; if the next character is a hyphen do the same + (when (looking-at-p lexer #-) + (push #- list) + (incf (lexer-pos lexer))) + (setq hyphen-seen nil)) + ((#\E) + ;; if \Q quoting is on we ignore \E, + ;; otherwise it's just a plain #\E + (unless *allow-quoting* + (handle-char #\E))) + (otherwise + ;; otherwise unescape the following character(s) + (decf (lexer-pos lexer)) + (handle-char (unescape-char lexer)))))) + (first + ;; the first character must not be a right bracket + ;; and isn't treated specially if it's a hyphen + (handle-char c)) + ((char= c #]) + ;; end of character class + ;; make sure we collect a pending hyphen + (when hyphen-seen + (setq hyphen-seen nil) + (handle-char #-)) + ;; reverse the list to preserve the order intended + ;; by the author of the regex string + (return-from collect-char-class (nreverse list))) + ((and (char= c #-) + last-char + (not hyphen-seen)) + ;; if the last character was 'just a character' + ;; we expect to be in the middle of a range + (setq hyphen-seen t)) + ((char= c #-) + ;; otherwise this is just an ordinary hyphen + (handle-char #-)) + (t + ;; default case - just collect the character + (handle-char c)))) + ;; we can only exit the loop normally if we've reached the end + ;; of the regex string without seeing a right bracket + (signal-ppcre-syntax-error* + start-pos + "Missing right bracket to close character class")))) + +(defun maybe-parse-flags (lexer) + (declare #.*standard-optimize-settings*) + "Reads a sequence of modifiers (including #\- to reverse their +meaning) and returns a corresponding list of "flag" tokens. The +"x" modifier is treated specially in that it dynamically modifies +the behaviour of the lexer itself via the special variable +*EXTENDED-MODE-P*." + (prog1 + (loop with set = t + for chr = (next-char-non-extended lexer) + unless chr + do (signal-ppcre-syntax-error "Unexpected end of string") + while (find chr "-imsx" :test #'char=) + ;; the first #- will invert the meaning of all modifiers + ;; following it + if (char= chr #-) + do (setq set nil) + else if (char= chr #\x) + do (setq *extended-mode-p* set) + else collect (if set + (case chr + ((#\i) + :case-insensitive-p) + ((#\m) + :multi-line-mode-p) + ((#\s) + :single-line-mode-p)) + (case chr + ((#\i) + :case-sensitive-p) + ((#\m) + :not-multi-line-mode-p) + ((#\s) + :not-single-line-mode-p)))) + (decf (lexer-pos lexer)))) + +(defun get-quantifier (lexer) + (declare #.*standard-optimize-settings*) + "Returns a list of two values (min max) if what the lexer is looking +at can be interpreted as a quantifier. Otherwise returns NIL and +resets the lexer to its old position." + ;; remember starting position for FAIL and UNGET-TOKEN functions + (push (lexer-pos lexer) (lexer-last-pos lexer)) + (let ((next-char (next-char lexer))) + (case next-char + ((#*) + ;; * (Kleene star): match 0 or more times + '(0 nil)) + ((#+) + ;; +: match 1 or more times + '(1 nil)) + ((#?) + ;; ?: match 0 or 1 times + '(0 1)) + ((#{) + ;; one of + ;; {n}: match exactly n times + ;; {n,}: match at least n times + ;; {n,m}: match at least n but not more than m times + ;; note that anything not matching one of these patterns will + ;; be interpreted literally - even whitespace isn't allowed + (let ((num1 (get-number lexer :no-whitespace-p t))) + (if num1 + (let ((next-char (next-char-non-extended lexer))) + (case next-char + ((#,) + (let* ((num2 (get-number lexer :no-whitespace-p t)) + (next-char (next-char-non-extended lexer))) + (case next-char + ((#}) + ;; this is the case {n,} (NUM2 is NIL) or {n,m} + (list num1 num2)) + (otherwise + (fail lexer))))) + ((#}) + ;; this is the case {n} + (list num1 num1)) + (otherwise + (fail lexer)))) + ;; no number following left curly brace, so we treat it + ;; like a normal character + (fail lexer)))) + ;; cannot be a quantifier + (otherwise + (fail lexer))))) + +(defun parse-register-name-aux (lexer) + "Reads and returns the name in a named register group. It is +assumed that the starting #< character has already been read. The +closing #> will also be consumed." + ;; we have to look for an ending > character now + (let ((end-name (position #> + (lexer-str lexer) + :start (lexer-pos lexer) + :test #'char=))) + (unless end-name + ;; there has to be > somewhere, syntax error otherwise + (signal-ppcre-syntax-error* + (1- (lexer-pos lexer)) + "Opening #< in named group has no closing #>")) + (let ((name (subseq (lexer-str lexer) + (lexer-pos lexer) + end-name))) + (unless (every #'(lambda (char) + (or (alphanumericp char) + (char= #- char))) + name) + ;; register name can contain only alphanumeric characters or #- + (signal-ppcre-syntax-error* + (lexer-pos lexer) + "Invalid character in named register group")) + ;; advance lexer beyond "<name>" part + (setf (lexer-pos lexer) (1+ end-name)) + name))) + +(defun get-token (lexer) + (declare #.*standard-optimize-settings*) + "Returns and consumes the next token from the regex string (or NIL)." + ;; remember starting position for UNGET-TOKEN function + (push (lexer-pos lexer) + (lexer-last-pos lexer)) + (let ((next-char (next-char lexer))) + (cond (next-char + (case next-char + ;; the easy cases first - the following six characters + ;; always have a special meaning and get translated + ;; into tokens immediately + ((#)) + :close-paren) + ((#|) + :vertical-bar) + ((#?) + :question-mark) + ((#.) + :everything) + ((#^) + :start-anchor) + ((#$) + :end-anchor) + ((#+ #*) + ;; quantifiers will always be consumend by + ;; GET-QUANTIFIER, they must not appear here + (signal-ppcre-syntax-error* + (1- (lexer-pos lexer)) + "Quantifier '~A' not allowed" + next-char)) + ((#{) + ;; left brace isn't a special character in it's own + ;; right but we must check if what follows might + ;; look like a quantifier + (let ((this-pos (lexer-pos lexer)) + (this-last-pos (lexer-last-pos lexer))) + (unget-token lexer) + (when (get-quantifier lexer) + (signal-ppcre-syntax-error* + (car this-last-pos) + "Quantifier '~A' not allowed" + (subseq (lexer-str lexer) + (car this-last-pos) + (lexer-pos lexer)))) + (setf (lexer-pos lexer) this-pos + (lexer-last-pos lexer) this-last-pos) + next-char)) + ((#[) + ;; left bracket always starts a character class + (cons (cond ((looking-at-p lexer #^) + (incf (lexer-pos lexer)) + :inverted-char-class) + (t + :char-class)) + (collect-char-class lexer))) + ((#\) + ;; backslash might mean different things so we have + ;; to peek one char ahead: + (let ((next-char (next-char-non-extended lexer))) + (case next-char + ((#\A) + :modeless-start-anchor) + ((#\Z) + :modeless-end-anchor) + ((#\z) + :modeless-end-anchor-no-newline) + ((#\b) + :word-boundary) + ((#\B) + :non-word-boundary) + ((#\k) + (cond ((and *allow-named-registers* + (looking-at-p lexer #<)) + ;; back-referencing a named register + (incf (lexer-pos lexer)) + (list :back-reference + (nreverse (parse-register-name-aux lexer)))) + (t + ;; false alarm, just unescape \k + #\k))) + ((#\d #\D #\w #\W #\s #\S) + ;; these will be treated like character classes + (map-char-to-special-char-class next-char)) + ((#\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9) + ;; uh, a digit... + (let* ((old-pos (decf (lexer-pos lexer))) + ;; ...so let's get the whole number first + (backref-number (get-number lexer))) + (declare (type fixnum backref-number)) + (cond ((and (> backref-number (lexer-reg lexer)) + (<= 10 backref-number)) + ;; \10 and higher are treated as octal + ;; character codes if we haven't + ;; opened that much register groups + ;; yet + (setf (lexer-pos lexer) old-pos) + ;; re-read the number from the old + ;; position and convert it to its + ;; corresponding character + (make-char-from-code (get-number lexer :radix 8 :max-length 3) + old-pos)) + (t + ;; otherwise this must refer to a + ;; backreference + (list :back-reference backref-number))))) + ((#\0) + ;; this always means an octal character code + ;; (at most three digits) + (let ((old-pos (decf (lexer-pos lexer)))) + (make-char-from-code (get-number lexer :radix 8 :max-length 3) + old-pos))) + (otherwise + ;; in all other cases just unescape the + ;; character + (decf (lexer-pos lexer)) + (unescape-char lexer))))) + ((#() + ;; an open parenthesis might mean different things + ;; depending on what follows... + (cond ((looking-at-p lexer #?) + ;; this is the case '(?' (and probably more behind) + (incf (lexer-pos lexer)) + ;; we have to check for modifiers first + ;; because a colon might follow + (let* ((flags (maybe-parse-flags lexer)) + (next-char (next-char-non-extended lexer))) + ;; modifiers are only allowed if a colon + ;; or a closing parenthesis are following + (when (and flags + (not (find next-char ":)" :test #'char=))) + (signal-ppcre-syntax-error* + (car (lexer-last-pos lexer)) + "Sequence '~A' not recognized" + (subseq (lexer-str lexer) + (car (lexer-last-pos lexer)) + (lexer-pos lexer)))) + (case next-char + ((nil) + ;; syntax error + (signal-ppcre-syntax-error + "End of string following '(?'")) + ((#)) + ;; an empty group except for the flags + ;; (if there are any) + (or (and flags + (cons :flags flags)) + :void)) + ((#() + ;; branch + :open-paren-paren) + ((#>) + ;; standalone + :open-paren-greater) + ((#=) + ;; positive look-ahead + :open-paren-equal) + ((#!) + ;; negative look-ahead + :open-paren-exclamation) + ((#:) + ;; non-capturing group - return flags as + ;; second value + (values :open-paren-colon flags)) + ((#<) + ;; might be a look-behind assertion or a named group, so + ;; check next character + (let ((next-char (next-char-non-extended lexer))) + (if (alpha-char-p next-char) + (progn + ;; we have encountered a named group + ;; are we supporting register naming? + (unless *allow-named-registers* + (signal-ppcre-syntax-error* + (1- (lexer-pos lexer)) + "Character '~A' may not follow '(?<'" + next-char)) + ;; put the letter back + (decf (lexer-pos lexer)) + ;; named group + :open-paren-less-letter) + (case next-char + ((#=) + ;; positive look-behind + :open-paren-less-equal) + ((#!) + ;; negative look-behind + :open-paren-less-exclamation) + ((#)) + ;; Perl allows "(?<)" and treats + ;; it like a null string + :void) + ((nil) + ;; syntax error + (signal-ppcre-syntax-error + "End of string following '(?<'")) + (t + ;; also syntax error + (signal-ppcre-syntax-error* + (1- (lexer-pos lexer)) + "Character '~A' may not follow '(?<'" + next-char )))))) + (otherwise + (signal-ppcre-syntax-error* + (1- (lexer-pos lexer)) + "Character '~A' may not follow '(?'" + next-char))))) + (t + ;; if next-char was not #? (this is within + ;; the first COND), we've just seen an opening + ;; parenthesis and leave it like that + :open-paren))) + (otherwise + ;; all other characters are their own tokens + next-char))) + ;; we didn't get a character (this if the "else" branch from + ;; the first IF), so we don't return a token but NIL + (t + (pop (lexer-last-pos lexer)) + nil)))) + +(declaim (inline unget-token)) +(defun unget-token (lexer) + (declare #.*standard-optimize-settings*) + "Moves the lexer back to the last position stored in the LAST-POS stack." + (if (lexer-last-pos lexer) + (setf (lexer-pos lexer) + (pop (lexer-last-pos lexer))) + (error "No token to unget (this should not happen)"))) + +(declaim (inline start-of-subexpr-p)) +(defun start-of-subexpr-p (lexer) + (declare #.*standard-optimize-settings*) + "Tests whether the next token can start a valid sub-expression, i.e. +a stand-alone regex." + (let* ((pos (lexer-pos lexer)) + (next-char (next-char lexer))) + (not (or (null next-char) + (prog1 + (member (the character next-char) + '(#) #|) + :test #'char=) + (setf (lexer-pos lexer) pos))))))
Added: branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/lispworks-defsystem.lisp =================================================================== --- branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/lispworks-defsystem.lisp 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/lispworks-defsystem.lisp 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,57 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-USER; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/cl-ppcre/lispworks-defsystem.lisp,v 1.3 2007/01/01 23:43:10 edi Exp $ + +;;; This system definition for LispWorks was kindly provided by Wade Humeniuk + +;;; Copyright (c) 2002-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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-package #:cl-user) + +(defparameter *cl-ppcre-base-directory* + (make-pathname :name nil :type nil :version nil + :defaults (parse-namestring *load-truename*))) + +(defsystem cl-ppcre + (:default-pathname *cl-ppcre-base-directory* + :default-type :lisp-file) + :members ("packages" + "specials" + "util" + "errors" + "lexer" + "parser" + "regex-class" + "convert" + "optimize" + "closures" + "repetition-closures" + "scanner" + "api") + :rules ((:in-order-to :compile :all + (:requires (:load :previous))) + (:in-order-to :load :all + (:requires (:load :previous))))) \ No newline at end of file
Added: branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/load.lisp =================================================================== --- branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/load.lisp 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/load.lisp 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,67 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-USER; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/cl-ppcre/load.lisp,v 1.15 2007/01/01 23:43:10 edi Exp $ + +;;; Copyright (c) 2002-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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-package :cl-user) + +(let ((cl-ppcre-base-directory + (make-pathname :name nil :type nil :version nil + :defaults (parse-namestring *load-truename*))) + must-compile) + (with-compilation-unit () + (dolist (file '("packages" + "specials" + "util" + "errors" + #-:use-acl-regexp2-engine "lexer" + #-:use-acl-regexp2-engine "parser" + #-:use-acl-regexp2-engine "regex-class" + #-:use-acl-regexp2-engine "convert" + #-:use-acl-regexp2-engine "optimize" + #-:use-acl-regexp2-engine "closures" + #-:use-acl-regexp2-engine "repetition-closures" + #-:use-acl-regexp2-engine "scanner" + "api" + "ppcre-tests")) + (let ((pathname (make-pathname :name file :type "lisp" :version nil + :defaults cl-ppcre-base-directory))) + ;; don't use COMPILE-FILE in Corman Lisp, it's broken - LOAD + ;; will yield compiled functions anyway + #-:cormanlisp + (let ((compiled-pathname (compile-file-pathname pathname))) + (unless (and (not must-compile) + (probe-file compiled-pathname) + (< (file-write-date pathname) + (file-write-date compiled-pathname))) + (setq must-compile t) + (compile-file pathname)) + (setq pathname compiled-pathname)) + (load pathname))))) + + +
Added: branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/optimize.lisp =================================================================== --- branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/optimize.lisp 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/optimize.lisp 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,579 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-PPCRE; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/cl-ppcre/optimize.lisp,v 1.30 2007/01/01 23:43:10 edi Exp $ + +;;; This file contains optimizations which can be applied to converted +;;; parse trees. + +;;; Copyright (c) 2002-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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-package #:cl-ppcre) + +(defgeneric flatten (regex) + (declare #.*standard-optimize-settings*) + (:documentation "Merges adjacent sequences and alternations, i.e. it +transforms #<SEQ #<STR "a"> #<SEQ #<STR "b"> #<STR "c">>> to +#<SEQ #<STR "a"> #<STR "b"> #<STR "c">>. This is a destructive +operation on REGEX.")) + +(defmethod flatten ((seq seq)) + (declare #.*standard-optimize-settings*) + ;; this looks more complicated than it is because we modify SEQ in + ;; place to avoid unnecessary consing + (let ((elements-rest (elements seq))) + (loop + (unless elements-rest + (return)) + (let ((flattened-element (flatten (car elements-rest))) + (next-elements-rest (cdr elements-rest))) + (cond ((typep flattened-element 'seq) + ;; FLATTENED-ELEMENT is a SEQ object, so we "splice" + ;; it into out list of elements + (let ((flattened-element-elements + (elements flattened-element))) + (setf (car elements-rest) + (car flattened-element-elements) + (cdr elements-rest) + (nconc (cdr flattened-element-elements) + (cdr elements-rest))))) + (t + ;; otherwise we just replace the current element with + ;; its flattened counterpart + (setf (car elements-rest) flattened-element))) + (setq elements-rest next-elements-rest)))) + (let ((elements (elements seq))) + (cond ((cadr elements) + seq) + ((cdr elements) + (first elements)) + (t (make-instance 'void))))) + +(defmethod flatten ((alternation alternation)) + (declare #.*standard-optimize-settings*) + ;; same algorithm as above + (let ((choices-rest (choices alternation))) + (loop + (unless choices-rest + (return)) + (let ((flattened-choice (flatten (car choices-rest))) + (next-choices-rest (cdr choices-rest))) + (cond ((typep flattened-choice 'alternation) + (let ((flattened-choice-choices + (choices flattened-choice))) + (setf (car choices-rest) + (car flattened-choice-choices) + (cdr choices-rest) + (nconc (cdr flattened-choice-choices) + (cdr choices-rest))))) + (t + (setf (car choices-rest) flattened-choice))) + (setq choices-rest next-choices-rest)))) + (let ((choices (choices alternation))) + (cond ((cadr choices) + alternation) + ((cdr choices) + (first choices)) + (t (signal-ppcre-syntax-error + "Encountered alternation without choices."))))) + +(defmethod flatten ((branch branch)) + (declare #.*standard-optimize-settings*) + (with-slots (test then-regex else-regex) + branch + (setq test + (if (numberp test) + test + (flatten test)) + then-regex (flatten then-regex) + else-regex (flatten else-regex)) + branch)) + +(defmethod flatten ((regex regex)) + (declare #.*standard-optimize-settings*) + (typecase regex + ((or repetition register lookahead lookbehind standalone) + ;; if REGEX contains exactly one inner REGEX object flatten it + (setf (regex regex) + (flatten (regex regex))) + regex) + (t + ;; otherwise (ANCHOR, BACK-REFERENCE, CHAR-CLASS, EVERYTHING, + ;; LOOKAHEAD, LOOKBEHIND, STR, VOID, FILTER, and WORD-BOUNDARY) + ;; do nothing + regex))) + +(defgeneric gather-strings (regex) + (declare #.*standard-optimize-settings*) + (:documentation "Collects adjacent strings or characters into one +string provided they have the same case mode. This is a destructive +operation on REGEX.")) + +(defmethod gather-strings ((seq seq)) + (declare #.*standard-optimize-settings*) + ;; note that GATHER-STRINGS is to be applied after FLATTEN, i.e. it + ;; expects SEQ to be flattened already; in particular, SEQ cannot be + ;; empty and cannot contain embedded SEQ objects + (let* ((start-point (cons nil (elements seq))) + (curr-point start-point) + old-case-mode + collector + collector-start + (collector-length 0) + skip) + (declare (type fixnum collector-length)) + (loop + (let ((elements-rest (cdr curr-point))) + (unless elements-rest + (return)) + (let* ((element (car elements-rest)) + (case-mode (case-mode element old-case-mode))) + (cond ((and case-mode + (eq case-mode old-case-mode)) + ;; if ELEMENT is a STR and we have collected a STR of + ;; the same case mode in the last iteration we + ;; concatenate ELEMENT onto COLLECTOR and remember the + ;; value of its SKIP slot + (let ((old-collector-length collector-length)) + (unless (and (adjustable-array-p collector) + (array-has-fill-pointer-p collector)) + (setq collector + (make-array collector-length + :initial-contents collector + :element-type 'character + :fill-pointer t + :adjustable t) + collector-start nil)) + (adjust-array collector + (incf collector-length (len element)) + :fill-pointer t) + (setf (subseq collector + old-collector-length) + (str element) + ;; it suffices to remember the last SKIP slot + ;; because due to the way MAYBE-ACCUMULATE + ;; works adjacent STR objects have the same + ;; SKIP value + skip (skip element))) + (setf (cdr curr-point) (cdr elements-rest))) + (t + (let ((collected-string + (cond (collector-start + collector-start) + (collector + ;; if we have collected something already + ;; we convert it into a STR + (make-instance 'str + :skip skip + :str collector + :case-insensitive-p + (eq old-case-mode + :case-insensitive))) + (t nil)))) + (cond (case-mode + ;; if ELEMENT is a string with a different case + ;; mode than the last one we have either just + ;; converted COLLECTOR into a STR or COLLECTOR + ;; is still empty; in both cases we can now + ;; begin to fill it anew + (setq collector (str element) + collector-start element + ;; and we remember the SKIP value as above + skip (skip element) + collector-length (len element)) + (cond (collected-string + (setf (car elements-rest) + collected-string + curr-point + (cdr curr-point))) + (t + (setf (cdr curr-point) + (cdr elements-rest))))) + (t + ;; otherwise this is not a STR so we apply + ;; GATHER-STRINGS to it and collect it directly + ;; into RESULT + (cond (collected-string + (setf (car elements-rest) + collected-string + curr-point + (cdr curr-point) + (cdr curr-point) + (cons (gather-strings element) + (cdr curr-point)) + curr-point + (cdr curr-point))) + (t + (setf (car elements-rest) + (gather-strings element) + curr-point + (cdr curr-point)))) + ;; we also have to empty COLLECTOR here in case + ;; it was still filled from the last iteration + (setq collector nil + collector-start nil)))))) + (setq old-case-mode case-mode)))) + (when collector + (setf (cdr curr-point) + (cons + (make-instance 'str + :skip skip + :str collector + :case-insensitive-p + (eq old-case-mode + :case-insensitive)) + nil))) + (setf (elements seq) (cdr start-point)) + seq)) + +(defmethod gather-strings ((alternation alternation)) + (declare #.*standard-optimize-settings*) + ;; loop ON the choices of ALTERNATION so we can modify them directly + (loop for choices-rest on (choices alternation) + while choices-rest + do (setf (car choices-rest) + (gather-strings (car choices-rest)))) + alternation) + +(defmethod gather-strings ((branch branch)) + (declare #.*standard-optimize-settings*) + (with-slots (test then-regex else-regex) + branch + (setq test + (if (numberp test) + test + (gather-strings test)) + then-regex (gather-strings then-regex) + else-regex (gather-strings else-regex)) + branch)) + +(defmethod gather-strings ((regex regex)) + (declare #.*standard-optimize-settings*) + (typecase regex + ((or repetition register lookahead lookbehind standalone) + ;; if REGEX contains exactly one inner REGEX object apply + ;; GATHER-STRINGS to it + (setf (regex regex) + (gather-strings (regex regex))) + regex) + (t + ;; otherwise (ANCHOR, BACK-REFERENCE, CHAR-CLASS, EVERYTHING, + ;; LOOKAHEAD, LOOKBEHIND, STR, VOID, FILTER, and WORD-BOUNDARY) + ;; do nothing + regex))) + +;; Note that START-ANCHORED-P will be called after FLATTEN and GATHER-STRINGS. + +(defgeneric start-anchored-p (regex &optional in-seq-p) + (declare #.*standard-optimize-settings*) + (:documentation "Returns T if REGEX starts with a "real" start +anchor, i.e. one that's not in multi-line mode, NIL otherwise. If +IN-SEQ-P is true the function will return :ZERO-LENGTH if REGEX is a +zero-length assertion.")) + +(defmethod start-anchored-p ((seq seq) &optional in-seq-p) + (declare (ignore in-seq-p)) + ;; note that START-ANCHORED-P is to be applied after FLATTEN and + ;; GATHER-STRINGS, i.e. SEQ cannot be empty and cannot contain + ;; embedded SEQ objects + (loop for element in (elements seq) + for anchored-p = (start-anchored-p element t) + ;; skip zero-length elements because they won't affect the + ;; "anchoredness" of the sequence + while (eq anchored-p :zero-length) + finally (return (and anchored-p (not (eq anchored-p :zero-length)))))) + +(defmethod start-anchored-p ((alternation alternation) &optional in-seq-p) + (declare #.*standard-optimize-settings*) + (declare (ignore in-seq-p)) + ;; clearly an alternation can only be start-anchored if all of its + ;; choices are start-anchored + (loop for choice in (choices alternation) + always (start-anchored-p choice))) + +(defmethod start-anchored-p ((branch branch) &optional in-seq-p) + (declare #.*standard-optimize-settings*) + (declare (ignore in-seq-p)) + (and (start-anchored-p (then-regex branch)) + (start-anchored-p (else-regex branch)))) + +(defmethod start-anchored-p ((repetition repetition) &optional in-seq-p) + (declare #.*standard-optimize-settings*) + (declare (ignore in-seq-p)) + ;; well, this wouldn't make much sense, but anyway... + (and (plusp (minimum repetition)) + (start-anchored-p (regex repetition)))) + +(defmethod start-anchored-p ((register register) &optional in-seq-p) + (declare #.*standard-optimize-settings*) + (declare (ignore in-seq-p)) + (start-anchored-p (regex register))) + +(defmethod start-anchored-p ((standalone standalone) &optional in-seq-p) + (declare #.*standard-optimize-settings*) + (declare (ignore in-seq-p)) + (start-anchored-p (regex standalone))) + +(defmethod start-anchored-p ((anchor anchor) &optional in-seq-p) + (declare #.*standard-optimize-settings*) + (declare (ignore in-seq-p)) + (and (startp anchor) + (not (multi-line-p anchor)))) + +(defmethod start-anchored-p ((regex regex) &optional in-seq-p) + (declare #.*standard-optimize-settings*) + (typecase regex + ((or lookahead lookbehind word-boundary void) + ;; zero-length assertions + (if in-seq-p + :zero-length + nil)) + (filter + (if (and in-seq-p + (len regex) + (zerop (len regex))) + :zero-length + nil)) + (t + ;; BACK-REFERENCE, CHAR-CLASS, EVERYTHING, and STR + nil))) + +;; Note that END-STRING-AUX will be called after FLATTEN and GATHER-STRINGS. + +(defgeneric end-string-aux (regex &optional old-case-insensitive-p) + (declare #.*standard-optimize-settings*) + (:documentation "Returns the constant string (if it exists) REGEX +ends with wrapped into a STR object, otherwise NIL. +OLD-CASE-INSENSITIVE-P is the CASE-INSENSITIVE-P slot of the last STR +collected or :VOID if no STR has been collected yet. (This is a helper +function called by END-STRIN.)")) + +(defmethod end-string-aux ((str str) + &optional (old-case-insensitive-p :void)) + (declare #.*standard-optimize-settings*) + (declare (special last-str)) + (cond ((and (not (skip str)) ; avoid constituents of STARTS-WITH + ;; only use STR if nothing has been collected yet or if + ;; the collected string has the same value for + ;; CASE-INSENSITIVE-P + (or (eq old-case-insensitive-p :void) + (eq (case-insensitive-p str) old-case-insensitive-p))) + (setf last-str str + ;; set the SKIP property of this STR + (skip str) t) + str) + (t nil))) + +(defmethod end-string-aux ((seq seq) + &optional (old-case-insensitive-p :void)) + (declare #.*standard-optimize-settings*) + (declare (special continuep)) + (let (case-insensitive-p + concatenated-string + concatenated-start + (concatenated-length 0)) + (declare (type fixnum concatenated-length)) + (loop for element in (reverse (elements seq)) + ;; remember the case-(in)sensitivity of the last relevant + ;; STR object + for loop-old-case-insensitive-p = old-case-insensitive-p + then (if skip + loop-old-case-insensitive-p + (case-insensitive-p element-end)) + ;; the end-string of the current element + for element-end = (end-string-aux element + loop-old-case-insensitive-p) + ;; whether we encountered a zero-length element + for skip = (if element-end + (zerop (len element-end)) + nil) + ;; set CONTINUEP to NIL if we have to stop collecting to + ;; alert END-STRING-AUX methods on enclosing SEQ objects + unless element-end + do (setq continuep nil) + ;; end loop if we neither got a STR nor a zero-length + ;; element + while element-end + ;; only collect if not zero-length + unless skip + do (cond (concatenated-string + (when concatenated-start + (setf concatenated-string + (make-array concatenated-length + :initial-contents (reverse (str concatenated-start)) + :element-type 'character + :fill-pointer t + :adjustable t) + concatenated-start nil)) + (let ((len (len element-end)) + (str (str element-end))) + (declare (type fixnum len)) + (incf concatenated-length len) + (loop for i of-type fixnum downfrom (1- len) to 0 + do (vector-push-extend (char str i) + concatenated-string)))) + (t + (setf concatenated-string + t + concatenated-start + element-end + concatenated-length + (len element-end) + case-insensitive-p + (case-insensitive-p element-end)))) + ;; stop collecting if END-STRING-AUX on inner SEQ has said so + while continuep) + (cond ((zerop concatenated-length) + ;; don't bother to return zero-length strings + nil) + (concatenated-start + concatenated-start) + (t + (make-instance 'str + :str (nreverse concatenated-string) + :case-insensitive-p case-insensitive-p))))) + +(defmethod end-string-aux ((register register) + &optional (old-case-insensitive-p :void)) + (declare #.*standard-optimize-settings*) + (end-string-aux (regex register) old-case-insensitive-p)) + +(defmethod end-string-aux ((standalone standalone) + &optional (old-case-insensitive-p :void)) + (declare #.*standard-optimize-settings*) + (end-string-aux (regex standalone) old-case-insensitive-p)) + +(defmethod end-string-aux ((regex regex) + &optional (old-case-insensitive-p :void)) + (declare #.*standard-optimize-settings*) + (declare (special last-str end-anchored-p continuep)) + (typecase regex + ((or anchor lookahead lookbehind word-boundary void) + ;; a zero-length REGEX object - for the sake of END-STRING-AUX + ;; this is a zero-length string + (when (and (typep regex 'anchor) + (not (startp regex)) + (or (no-newline-p regex) + (not (multi-line-p regex))) + (eq old-case-insensitive-p :void)) + ;; if this is a "real" end-anchor and we haven't collected + ;; anything so far we can set END-ANCHORED-P (where 1 or 0 + ;; indicate whether we accept a #\Newline at the end or not) + (setq end-anchored-p (if (no-newline-p regex) 0 1))) + (make-instance 'str + :str "" + :case-insensitive-p :void)) + (t + ;; (ALTERNATION, BACK-REFERENCE, BRANCH, CHAR-CLASS, EVERYTHING, + ;; REPETITION, FILTER) + nil))) + +(defun end-string (regex) + (declare (special end-string-offset)) + (declare #.*standard-optimize-settings*) + "Returns the constant string (if it exists) REGEX ends with wrapped +into a STR object, otherwise NIL." + ;; LAST-STR points to the last STR object (seen from the end) that's + ;; part of END-STRING; CONTINUEP is set to T if we stop collecting + ;; in the middle of a SEQ + (let ((continuep t) + last-str) + (declare (special continuep last-str)) + (prog1 + (end-string-aux regex) + (when last-str + ;; if we've found something set the START-OF-END-STRING-P of + ;; the leftmost STR collected accordingly and remember the + ;; OFFSET of this STR (in a special variable provided by the + ;; caller of this function) + (setf (start-of-end-string-p last-str) t + end-string-offset (offset last-str)))))) + +(defgeneric compute-min-rest (regex current-min-rest) + (declare #.*standard-optimize-settings*) + (:documentation "Returns the minimal length of REGEX plus +CURRENT-MIN-REST. This is similar to REGEX-MIN-LENGTH except that it +recurses down into REGEX and sets the MIN-REST slots of REPETITION +objects.")) + +(defmethod compute-min-rest ((seq seq) current-min-rest) + (declare #.*standard-optimize-settings*) + (loop for element in (reverse (elements seq)) + for last-min-rest = current-min-rest then this-min-rest + for this-min-rest = (compute-min-rest element last-min-rest) + finally (return this-min-rest))) + +(defmethod compute-min-rest ((alternation alternation) current-min-rest) + (declare #.*standard-optimize-settings*) + (loop for choice in (choices alternation) + minimize (compute-min-rest choice current-min-rest))) + +(defmethod compute-min-rest ((branch branch) current-min-rest) + (declare #.*standard-optimize-settings*) + (min (compute-min-rest (then-regex branch) current-min-rest) + (compute-min-rest (else-regex branch) current-min-rest))) + +(defmethod compute-min-rest ((str str) current-min-rest) + (declare #.*standard-optimize-settings*) + (+ current-min-rest (len str))) + +(defmethod compute-min-rest ((filter filter) current-min-rest) + (declare #.*standard-optimize-settings*) + (+ current-min-rest (or (len filter) 0))) + +(defmethod compute-min-rest ((repetition repetition) current-min-rest) + (declare #.*standard-optimize-settings*) + (setf (min-rest repetition) current-min-rest) + (compute-min-rest (regex repetition) current-min-rest) + (+ current-min-rest (* (minimum repetition) (min-len repetition)))) + +(defmethod compute-min-rest ((register register) current-min-rest) + (declare #.*standard-optimize-settings*) + (compute-min-rest (regex register) current-min-rest)) + +(defmethod compute-min-rest ((standalone standalone) current-min-rest) + (declare #.*standard-optimize-settings*) + (declare (ignore current-min-rest)) + (compute-min-rest (regex standalone) 0)) + +(defmethod compute-min-rest ((lookahead lookahead) current-min-rest) + (declare #.*standard-optimize-settings*) + (compute-min-rest (regex lookahead) 0) + current-min-rest) + +(defmethod compute-min-rest ((lookbehind lookbehind) current-min-rest) + (declare #.*standard-optimize-settings*) + (compute-min-rest (regex lookbehind) (+ current-min-rest (len lookbehind))) + current-min-rest) + +(defmethod compute-min-rest ((regex regex) current-min-rest) + (declare #.*standard-optimize-settings*) + (typecase regex + ((or char-class everything) + (1+ current-min-rest)) + (t + ;; zero min-len and no embedded regexes (ANCHOR, + ;; BACK-REFERENCE, VOID, and WORD-BOUNDARY) + current-min-rest)))
Added: branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/packages.lisp =================================================================== --- branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/packages.lisp 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/packages.lisp 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,106 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-USER; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/cl-ppcre/packages.lisp,v 1.23 2007/03/24 23:52:44 edi Exp $ + +;;; Copyright (c) 2002-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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-package :cl-user) + +#-:cormanlisp +(defpackage #:cl-ppcre + (:nicknames #:ppcre) + #+genera (:shadowing-import-from #:common-lisp #:lambda #:simple-string #:string) + (:use #-genera #:cl #+genera #:future-common-lisp) + (:export #:create-scanner + #:parse-tree-synonym + #:define-parse-tree-synonym + #:scan + #:scan-to-strings + #:do-scans + #:do-matches + #:do-matches-as-strings + #:all-matches + #:all-matches-as-strings + #:split + #:regex-replace + #:regex-replace-all + #:regex-apropos + #:regex-apropos-list + #:quote-meta-chars + #:*regex-char-code-limit* + #:*use-bmh-matchers* + #:*allow-quoting* + #:*allow-named-registers* + #:ppcre-error + #:ppcre-invocation-error + #:ppcre-syntax-error + #:ppcre-syntax-error-string + #:ppcre-syntax-error-pos + #:register-groups-bind + #:do-register-groups)) + +#+:cormanlisp +(defpackage "CL-PPCRE" + (:nicknames "PPCRE") + (:use "CL") + (:export "CREATE-SCANNER" + "PARSE-TREE-SYNONYM" + "DEFINE-PARSE-TREE-SYNONYM" + "SCAN" + "SCAN-TO-STRINGS" + "DO-SCANS" + "DO-MATCHES" + "DO-MATCHES-AS-STRINGS" + "ALL-MATCHES" + "ALL-MATCHES-AS-STRINGS" + "SPLIT" + "REGEX-REPLACE" + "REGEX-REPLACE-ALL" + "REGEX-APROPOS" + "REGEX-APROPOS-LIST" + "QUOTE-META-CHARS" + "*REGEX-CHAR-CODE-LIMIT*" + "*USE-BMH-MATCHERS*" + "*ALLOW-QUOTING*" + "*ALLOW-NAMED-REGISTERS*" + "PPCRE-ERROR" + "PPCRE-INVOCATION-ERROR" + "PPCRE-SYNTAX-ERROR" + "PPCRE-SYNTAX-ERROR-STRING" + "PPCRE-SYNTAX-ERROR-POS" + "REGISTER-GROUPS-BIND" + "DO-REGISTER-GROUPS")) + +#-:cormanlisp +(defpackage #:cl-ppcre-test + #+genera (:shadowing-import-from #:common-lisp #:lambda) + (:use #-genera #:cl #+genera #:future-common-lisp #:cl-ppcre) + (:export #:test)) + +#+:cormanlisp +(defpackage "CL-PPCRE-TEST" + (:use "CL" "CL-PPCRE") + (:export "TEST"))
Added: branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/parser.lisp =================================================================== --- branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/parser.lisp 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/parser.lisp 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,323 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-PPCRE; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/cl-ppcre/parser.lisp,v 1.24 2007/03/24 23:52:44 edi Exp $ + +;;; The parser will - with the help of the lexer - parse a regex +;;; string and convert it into a "parse tree" (see docs for details +;;; about the syntax of these trees). Note that the lexer might return +;;; illegal parse trees. It is assumed that the conversion process +;;; later on will track them down. + +;;; Copyright (c) 2002-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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-package #:cl-ppcre) + +(defun group (lexer) + (declare #.*standard-optimize-settings*) + "Parses and consumes a <group>. +The productions are: <group> -> "("<regex>")" + "(?:"<regex>")" + "(?>"<regex>")" + "(?<flags>:"<regex>")" + "(?="<regex>")" + "(?!"<regex>")" + "(?<="<regex>")" + "(?<!"<regex>")" + "(?("<num>")"<regex>")" + "(?("<regex>")"<regex>")" + "(?<name>"<regex>")" (when *ALLOW-NAMED-REGISTERS* is T) + <legal-token> +where <flags> is parsed by the lexer function MAYBE-PARSE-FLAGS. +Will return <parse-tree> or (<grouping-type> <parse-tree>) where +<grouping-type> is one of six keywords - see source for details." + (multiple-value-bind (open-token flags) + (get-token lexer) + (cond ((eq open-token :open-paren-paren) + ;; special case for conditional regular expressions; note + ;; that at this point we accept a couple of illegal + ;; combinations which'll be sorted out later by the + ;; converter + (let* ((open-paren-pos (car (lexer-last-pos lexer))) + ;; check if what follows "(?(" is a number + (number (try-number lexer :no-whitespace-p t)) + ;; make changes to extended-mode-p local + (*extended-mode-p* *extended-mode-p*)) + (declare (type fixnum open-paren-pos)) + (cond (number + ;; condition is a number (i.e. refers to a + ;; back-reference) + (let* ((inner-close-token (get-token lexer)) + (reg-expr (reg-expr lexer)) + (close-token (get-token lexer))) + (unless (eq inner-close-token :close-paren) + (signal-ppcre-syntax-error* + (+ open-paren-pos 2) + "Opening paren has no matching closing paren")) + (unless (eq close-token :close-paren) + (signal-ppcre-syntax-error* + open-paren-pos + "Opening paren has no matching closing paren")) + (list :branch number reg-expr))) + (t + ;; condition must be a full regex (actually a + ;; look-behind or look-ahead); and here comes a + ;; terrible kludge: instead of being cleanly + ;; separated from the lexer, the parser pushes + ;; back the lexer by one position, thereby + ;; landing in the middle of the 'token' "(?(" - + ;; yuck!! + (decf (lexer-pos lexer)) + (let* ((inner-reg-expr (group lexer)) + (reg-expr (reg-expr lexer)) + (close-token (get-token lexer))) + (unless (eq close-token :close-paren) + (signal-ppcre-syntax-error* + open-paren-pos + "Opening paren has no matching closing paren")) + (list :branch inner-reg-expr reg-expr)))))) + ((member open-token '(:open-paren + :open-paren-colon + :open-paren-greater + :open-paren-equal + :open-paren-exclamation + :open-paren-less-equal + :open-paren-less-exclamation + :open-paren-less-letter) + :test #'eq) + ;; make changes to extended-mode-p local + (let ((*extended-mode-p* *extended-mode-p*)) + ;; we saw one of the six token representing opening + ;; parentheses + (let* ((open-paren-pos (car (lexer-last-pos lexer))) + (register-name (when (eq open-token :open-paren-less-letter) + (parse-register-name-aux lexer))) + (reg-expr (reg-expr lexer)) + (close-token (get-token lexer))) + (when (or (eq open-token :open-paren) + (eq open-token :open-paren-less-letter)) + ;; if this is the "("<regex>")" or "(?"<name>""<regex>")" production we have to + ;; increment the register counter of the lexer + (incf (lexer-reg lexer))) + (unless (eq close-token :close-paren) + ;; the token following <regex> must be the closing + ;; parenthesis or this is a syntax error + (signal-ppcre-syntax-error* + open-paren-pos + "Opening paren has no matching closing paren")) + (if flags + ;; if the lexer has returned a list of flags this must + ;; have been the "(?:"<regex>")" production + (cons :group (nconc flags (list reg-expr))) + (if (eq open-token :open-paren-less-letter) + (list :named-register + ;; every string was reversed, so we have to + ;; reverse it back to get the name + (nreverse register-name) + reg-expr) + (list (case open-token + ((:open-paren) + :register) + ((:open-paren-colon) + :group) + ((:open-paren-greater) + :standalone) + ((:open-paren-equal) + :positive-lookahead) + ((:open-paren-exclamation) + :negative-lookahead) + ((:open-paren-less-equal) + :positive-lookbehind) + ((:open-paren-less-exclamation) + :negative-lookbehind)) + reg-expr)))))) + (t + ;; this is the <legal-token> production; <legal-token> is + ;; any token which passes START-OF-SUBEXPR-P (otherwise + ;; parsing had already stopped in the SEQ method) + open-token)))) + +(defun greedy-quant (lexer) + (declare #.*standard-optimize-settings*) + "Parses and consumes a <greedy-quant>. +The productions are: <greedy-quant> -> <group> | <group><quantifier> +where <quantifier> is parsed by the lexer function GET-QUANTIFIER. +Will return <parse-tree> or (:GREEDY-REPETITION <min> <max> <parse-tree>)." + (let* ((group (group lexer)) + (token (get-quantifier lexer))) + (if token + ;; if GET-QUANTIFIER returned a non-NIL value it's the + ;; two-element list (<min> <max>) + (list :greedy-repetition (first token) (second token) group) + group))) + +(defun quant (lexer) + (declare #.*standard-optimize-settings*) + "Parses and consumes a <quant>. +The productions are: <quant> -> <greedy-quant> | <greedy-quant>"?". +Will return the <parse-tree> returned by GREEDY-QUANT and optionally +change :GREEDY-REPETITION to :NON-GREEDY-REPETITION." + (let* ((greedy-quant (greedy-quant lexer)) + (pos (lexer-pos lexer)) + (next-char (next-char lexer))) + (when next-char + (if (char= next-char #?) + (setf (car greedy-quant) :non-greedy-repetition) + (setf (lexer-pos lexer) pos))) + greedy-quant)) + +(defun seq (lexer) + (declare #.*standard-optimize-settings*) + "Parses and consumes a <seq>. +The productions are: <seq> -> <quant> | <quant><seq>. +Will return <parse-tree> or (:SEQUENCE <parse-tree> <parse-tree>)." + (flet ((make-array-from-two-chars (char1 char2) + (let ((string (make-array 2 + :element-type 'character + :fill-pointer t + :adjustable t))) + (setf (aref string 0) char1) + (setf (aref string 1) char2) + string))) + ;; Note that we're calling START-OF-SUBEXPR-P before we actually try + ;; to parse a <seq> or <quant> in order to catch empty regular + ;; expressions + (if (start-of-subexpr-p lexer) + (let ((quant (quant lexer))) + (if (start-of-subexpr-p lexer) + (let* ((seq (seq lexer)) + (quant-is-char-p (characterp quant)) + (seq-is-sequence-p (and (consp seq) + (eq (first seq) :sequence)))) + (cond ((and quant-is-char-p + (characterp seq)) + (make-array-from-two-chars seq quant)) + ((and quant-is-char-p + (stringp seq)) + (vector-push-extend quant seq) + seq) + ((and quant-is-char-p + seq-is-sequence-p + (characterp (second seq))) + (cond ((cddr seq) + (setf (cdr seq) + (cons + (make-array-from-two-chars (second seq) + quant) + (cddr seq))) + seq) + (t (make-array-from-two-chars (second seq) quant)))) + ((and quant-is-char-p + seq-is-sequence-p + (stringp (second seq))) + (cond ((cddr seq) + (setf (cdr seq) + (cons + (progn + (vector-push-extend quant (second seq)) + (second seq)) + (cddr seq))) + seq) + (t + (vector-push-extend quant (second seq)) + (second seq)))) + (seq-is-sequence-p + ;; if <seq> is also a :SEQUENCE parse tree we merge + ;; both lists into one to avoid unnecessary consing + (setf (cdr seq) + (cons quant (cdr seq))) + seq) + (t (list :sequence quant seq)))) + quant)) + :void))) + +(defun reg-expr (lexer) + (declare #.*standard-optimize-settings*) + "Parses and consumes a <regex>, a complete regular expression. +The productions are: <regex> -> <seq> | <seq>"|"<regex>. +Will return <parse-tree> or (:ALTERNATION <parse-tree> <parse-tree>)." + (let ((pos (lexer-pos lexer))) + (case (next-char lexer) + ((nil) + ;; if we didn't get any token we return :VOID which stands for + ;; "empty regular expression" + :void) + ((#|) + ;; now check whether the expression started with a vertical + ;; bar, i.e. <seq> - the left alternation - is empty + (list :alternation :void (reg-expr lexer))) + (otherwise + ;; otherwise un-read the character we just saw and parse a + ;; <seq> plus the character following it + (setf (lexer-pos lexer) pos) + (let* ((seq (seq lexer)) + (pos (lexer-pos lexer))) + (case (next-char lexer) + ((nil) + ;; no further character, just a <seq> + seq) + ((#|) + ;; if the character was a vertical bar, this is an + ;; alternation and we have the second production + (let ((reg-expr (reg-expr lexer))) + (cond ((and (consp reg-expr) + (eq (first reg-expr) :alternation)) + ;; again we try to merge as above in SEQ + (setf (cdr reg-expr) + (cons seq (cdr reg-expr))) + reg-expr) + (t (list :alternation seq reg-expr))))) + (otherwise + ;; a character which is not a vertical bar - this is + ;; either a syntax error or we're inside of a group and + ;; the next character is a closing parenthesis; so we + ;; just un-read the character and let another function + ;; take care of it + (setf (lexer-pos lexer) pos) + seq))))))) + +(defun reverse-strings (parse-tree) + (declare #.*standard-optimize-settings*) + (cond ((stringp parse-tree) + (nreverse parse-tree)) + ((consp parse-tree) + (loop for parse-tree-rest on parse-tree + while parse-tree-rest + do (setf (car parse-tree-rest) + (reverse-strings (car parse-tree-rest)))) + parse-tree) + (t parse-tree))) + +(defun parse-string (string) + (declare #.*standard-optimize-settings*) + "Translate the regex string STRING into a parse tree." + (let* ((lexer (make-lexer string)) + (parse-tree (reverse-strings (reg-expr lexer)))) + ;; check whether we've consumed the whole regex string + (if (end-of-string-p lexer) + parse-tree + (signal-ppcre-syntax-error* + (lexer-pos lexer) + "Expected end of string"))))
Added: branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/perltest.pl =================================================================== --- branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/perltest.pl 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/perltest.pl 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,174 @@ +#!/usr/bin/perl + +# This is a heavily modified version of the file 'perltest' which +# comes with the PCRE library package, which is open source software, +# written by Philip Hazel, and copyright by the University of +# Cambridge, England. + +# The PCRE library package is available from +# ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/ + +use Time::HiRes qw(time); + +sub string_for_lisp { + my(@a, $t, $in_string, $switch); + + my $string = shift; + $string =~ s/\/\\/g; + $string =~ s/"/\"/g; + + return ""$string"" + if $string =~ /^[\n\x20-\x7f]*$/; + + $in_string = 1; + foreach $c (split(//, $string)) { + if (ord $c >= 32 and ord $c < 127) { + if ($in_string) { + $t .= $c; + } else { + $in_string = 1; + $t = $c; + } + } else { + if ($in_string) { + push @a, ""$t""; + $in_string = 0; + $switch = 1; + } + push @a, ord $c; + } + } + if ($switch) { + if ($in_string) { + push @a, ""$t""; + } + '(' . (join ' ', @a) . ')'; + } else { + ""$t""; + } +} + +$min_time = shift; + +NEXT_RE: while (1) { + last + if !($_ = <>); + next + if $_ eq ""; + + $pattern = $_; + + while ($pattern !~ /^\s*(.).*\1/s) { + last + if !($_ = <>); + $pattern .= $_; + } + + chomp($pattern); + $pattern =~ s/\s+$//; + $pattern =~ s/+(?=[a-z]*$)//; + + $multi_line_mode = ($pattern =~ /m[a-z]*$/) ? 't' : 'nil'; + $single_line_mode = ($pattern =~ /s[a-z]*$/) ? 't' : 'nil'; + $extended_mode = ($pattern =~ /x[a-z]*$/) ? 't' : 'nil'; + $case_insensitive_mode = ($pattern =~ /i[a-z]*$/) ? 't' : 'nil'; + $pattern =~ s/^(.*)g([a-z]*)$/\1\2/; + + $pattern_for_lisp = $pattern; + $pattern_for_lisp =~ s/[a-z]*$//; + $pattern_for_lisp =~ s/^\s*(.)(.*)\1/$2/s; + $pattern_for_lisp =~ s/\/\\/g; + $pattern_for_lisp =~ s/"/\"/g; + + $pattern = "/(?#)/$2" + if ($pattern =~ /^(.)\1(.*)$/); + + while (1) { + last NEXT_RE + if !($_ = <>); + + chomp; + + s/\s+$//; + s/^\s+//; + + last + if ($_ eq ""); + + $info_string = string_for_lisp ""$_" =~ $pattern"; + $x = eval ""$_""; + + @subs = (); + + eval <<"END"; +if ($x =~ ${pattern}) { + push @subs,$&; + push @subs,$1; + push @subs,$2; + push @subs,$3; + push @subs,$4; + push @subs,$5; + push @subs,$6; + push @subs,$7; + push @subs,$8; + push @subs,$9; + push @subs,$10; + push @subs,$11; + push @subs,$12; + push @subs,$13; + push @subs,$14; + push @subs,$15; + push @subs,$16; +} + +$test = sub { + my $times = shift; + + my $start = time; + for (my $i = 0; $i < $times; $i++) { + $x =~ ${pattern}; + } + return time - $start; +}; +END + + $times = 1; + $used = 0; + $counter++; + print STDERR "$counter\n"; + + if ($@) { + $error = 't'; + } else { + $error = 'nil'; + if ($min_time) { + $times = 10; + while (1) { + $used = &$test($times); + last + if $used > $min_time; + $times *= 10; + } + } + } + + print "($counter $info_string "$pattern_for_lisp" $case_insensitive_mode $multi_line_mode $single_line_mode $extended_mode " . string_for_lisp($x) . " $error $times $used "; + if (!@subs) { + print 'nil nil'; + } else { + print string_for_lisp($subs[0]) . ' ('; + undef $not_first; + for ($i = 1; $i <= 16; $i++) { + print ' ' + unless $i == 1; + if (defined $subs[$i]) { + print string_for_lisp $subs[$i]; + } else { + print 'nil'; + } + } + print ')'; + } + print ")\n"; + } +}
Property changes on: branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/perltest.pl ___________________________________________________________________ Name: svn:executable + *
Added: branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/ppcre-tests.lisp =================================================================== --- branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/ppcre-tests.lisp 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/ppcre-tests.lisp 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,268 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-PPCRE-TEST; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/cl-ppcre/ppcre-tests.lisp,v 1.34 2007/01/01 23:43:10 edi Exp $ + +;;; Copyright (c) 2002-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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-package #:cl-ppcre-test) + +(defparameter *cl-ppcre-test-base-directory* + (make-pathname :name nil :type nil :version nil + :defaults (parse-namestring *load-truename*))) + +(defun full-gc () + "Start a full garbage collection." + ;; what are the corresponding values for MCL and OpenMCL? + #+:allegro (excl:gc t) + #+(or :cmu :scl) (ext:gc :full t) + #+:ecl (si:gc t) + #+:clisp (ext:gc) + #+:cormanlisp (loop for i from 0 to 3 do (cormanlisp:gc i)) + #+:lispworks (hcl:mark-and-sweep 3) + #+:sbcl (sb-ext:gc :full t)) + +;; warning: ugly code ahead!! +;; this is just a quick hack for testing purposes + +(defun time-regex (factor regex string + &key case-insensitive-mode + multi-line-mode + single-line-mode + extended-mode) + (declare #.ppcre::*standard-optimize-settings*) + "Auxiliary function used by TEST to benchmark a regex scanner +against Perl timings." + (declare (type string string)) + (let* ((scanner (create-scanner regex + :case-insensitive-mode case-insensitive-mode + :multi-line-mode multi-line-mode + :single-line-mode single-line-mode + :extended-mode extended-mode)) + ;; make sure GC doesn't invalidate our benchmarking + (dummy (full-gc)) + (start (get-internal-real-time))) + (declare (ignore dummy)) + (dotimes (i factor) + (funcall scanner string 0 (length string))) + (float (/ (- (get-internal-real-time) start) internal-time-units-per-second)))) + +#+(or scl + lispworks + (and sbcl sb-thread)) +(defun threaded-scan (scanner target-string &key (threads 10) (repetitions 5000)) + (declare #.ppcre::*standard-optimize-settings*) + "Auxiliary function used by TEST to check whether SCANNER is thread-safe." + (full-gc) + (let ((collector (make-array threads)) + (counter 0)) + (loop for i below threads + do (let* ((j i) + (fn + (lambda () + (let ((r (random repetitions))) + (loop for k below repetitions + if (= k r) + do (setf (aref collector j) + (let ((result + (multiple-value-list + (cl-ppcre:scan scanner target-string)))) + (unless (cdr result) + (setq result '(nil nil #() #()))) + result)) + else + do (cl-ppcre:scan scanner target-string)) + (incf counter))))) + #+scl (thread:thread-create fn) + #+lispworks (mp:process-run-function "" nil fn) + #+(and sbcl sb-thread) (sb-thread:make-thread fn))) + (loop while (< counter threads) + do (sleep .1)) + (destructuring-bind (first-start first-end first-reg-starts first-reg-ends) + (aref collector 0) + (loop for (start end reg-starts reg-ends) across collector + if (or (not (eql first-start start)) + (not (eql first-end end)) + (/= (length first-reg-starts) (length reg-starts)) + (/= (length first-reg-ends) (length reg-ends)) + (loop for first-reg-start across first-reg-starts + for reg-start across reg-starts + thereis (not (eql first-reg-start reg-start))) + (loop for first-reg-end across first-reg-ends + for reg-end across reg-ends + thereis (not (eql first-reg-end reg-end)))) + do (return (format nil "~&Inconsistent results during multi-threading")))))) + +(defun create-string-from-input (input) + (cond ((or (null input) + (stringp input)) + input) + (t + (cl-ppcre::string-list-to-simple-string + (loop for element in input + if (stringp element) + collect element + else + collect (string (code-char element))))))) + +(defun test (&key (file-name + (make-pathname :name "testdata" + :type nil :version nil + :defaults *cl-ppcre-test-base-directory*) + file-name-provided-p) + threaded) + (declare #.ppcre::*standard-optimize-settings*) + (declare (ignorable threaded)) + "Loop through all test cases in FILE-NAME and print report. Only in +LispWorks and SCL: If THREADED is true, also test whether the scanners +work multi-threaded." + (with-open-file (stream file-name + #+(or :allegro :clisp :scl :sbcl) + :external-format + #+(or :allegro :clisp :scl :sbcl) + (if file-name-provided-p + :default + #+(or :allegro :scl :sbcl) :iso-8859-1 + #+:clisp charset:iso-8859-1)) + (loop with testcount of-type fixnum = 0 + with *regex-char-code-limit* = (if file-name-provided-p + *regex-char-code-limit* + ;; the standard test suite + ;; doesn't need Unicode + ;; support + 256) + with *allow-quoting* = (if file-name-provided-p + *allow-quoting* + t) + for input-line = (read stream nil nil) + for (counter info-string regex + case-insensitive-mode multi-line-mode + single-line-mode extended-mode + string perl-error factor + perl-time ex-result ex-subs) = input-line + while input-line + do (let ((info-string (create-string-from-input info-string)) + (regex (create-string-from-input regex)) + (string (create-string-from-input string)) + (ex-result (create-string-from-input ex-result)) + (ex-subs (mapcar #'create-string-from-input ex-subs)) + (errors '())) + ;; provide some visual feedback for slow CL + ;; implementations; suggested by JP Massar + (incf testcount) + #+(or scl + lispworks + (and sbcl sb-thread)) + (when threaded + (format t "Test #~A (ID ~A)~%" testcount counter) + (force-output)) + (unless #-(or scl + lispworks + (and sbcl sb-thread)) + nil + #+(or scl + lispworks + (and sbcl sb-thread)) + threaded + (when (zerop (mod testcount 10)) + (format t ".") + (force-output)) + (when (zerop (mod testcount 100)) + (terpri))) + (handler-case + (let* ((*use-bmh-matchers* (if (and (> factor 1) (plusp perl-time)) + *use-bmh-matchers* + ;; if we only check for + ;; correctness we don't + ;; care about speed that + ;; match (but rather + ;; about space + ;; constraints of the + ;; trial versions) + nil)) + (scanner (create-scanner regex + :case-insensitive-mode case-insensitive-mode + :multi-line-mode multi-line-mode + :single-line-mode single-line-mode + :extended-mode extended-mode))) + (multiple-value-bind (result1 result2 sub-starts sub-ends) + (scan scanner string) + (cond (perl-error + (push (format nil + "~&expected an error but got a result") + errors)) + (t + (when (not (eq result1 ex-result)) + (if result1 + (let ((result (subseq string result1 result2))) + (unless (string= result ex-result) + (push (format nil + "~&expected ~S but got ~S" + ex-result result) + errors)) + (setq sub-starts (coerce sub-starts 'list) + sub-ends (coerce sub-ends 'list)) + (loop for i from 0 + for ex-sub in ex-subs + for sub-start = (nth i sub-starts) + for sub-end = (nth i sub-ends) + for sub = (if (and sub-start sub-end) + (subseq string sub-start sub-end) + nil) + unless (string= ex-sub sub) + do (push (format nil + "~&\~A: expected ~S but got ~S" + (1+ i) ex-sub sub) errors))) + (push (format nil + "~&expected ~S but got ~S" + ex-result result1) + errors))))) + #+(or scl + lispworks + (and sbcl sb-thread)) + (when threaded + (let ((thread-result (threaded-scan scanner string))) + (when thread-result + (push thread-result errors)))))) + (condition (msg) + (unless perl-error + (push (format nil "~&got an unexpected error: '~A'" msg) + errors)))) + (setq errors (nreverse errors)) + (cond (errors + (when (or (<= factor 1) (zerop perl-time)) + (format t "~&~4@A (~A):~{~& ~A~}~%" + counter info-string errors))) + ((and (> factor 1) (plusp perl-time)) + (let ((result (time-regex factor regex string + :case-insensitive-mode case-insensitive-mode + :multi-line-mode multi-line-mode + :single-line-mode single-line-mode + :extended-mode extended-mode))) + (format t "~&~4@A: ~,4F (~A repetitions, Perl: ~,4F seconds, CL-PPCRE: ~,4F seconds)" counter + (float (/ result perl-time)) factor perl-time result) + #+:cormanlisp (force-output *standard-output*))) + (t nil)))) + (values)))
Added: branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/regex-class.lisp =================================================================== --- branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/regex-class.lisp 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/regex-class.lisp 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,807 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-PPCRE; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/cl-ppcre/regex-class.lisp,v 1.32 2007/03/24 23:52:44 edi Exp $ + +;;; This file defines the REGEX class and some utility methods for +;;; this class. REGEX objects are used to represent the (transformed) +;;; parse trees internally + +;;; Copyright (c) 2002-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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-package #:cl-ppcre) + +;; Genera need the eval-when, here, or the types created by the class +;; definitions aren't seen by the typep calls later in the file. +(eval-when (:compile-toplevel :load-toplevel :execute) + (locally + (declare #.*standard-optimize-settings*) + (defclass regex () + () + (:documentation "The REGEX base class. All other classes inherit +from this one.")) + + + (defclass seq (regex) + ((elements :initarg :elements + :accessor elements + :type cons + :documentation "A list of REGEX objects.")) + (:documentation "SEQ objects represents sequences of +regexes. (Like "ab" is the sequence of "a" and "b".)")) + + (defclass alternation (regex) + ((choices :initarg :choices + :accessor choices + :type cons + :documentation "A list of REGEX objects")) + (:documentation "ALTERNATION objects represent alternations of +regexes. (Like "a|b" ist the alternation of "a" or "b".)")) + + (defclass lookahead (regex) + ((regex :initarg :regex + :accessor regex + :documentation "The REGEX object we're checking.") + (positivep :initarg :positivep + :reader positivep + :documentation "Whether this assertion is positive.")) + (:documentation "LOOKAHEAD objects represent look-ahead assertions.")) + + (defclass lookbehind (regex) + ((regex :initarg :regex + :accessor regex + :documentation "The REGEX object we're checking.") + (positivep :initarg :positivep + :reader positivep + :documentation "Whether this assertion is positive.") + (len :initarg :len + :accessor len + :type fixnum + :documentation "The (fixed) length of the enclosed regex.")) + (:documentation "LOOKBEHIND objects represent look-behind assertions.")) + + (defclass repetition (regex) + ((regex :initarg :regex + :accessor regex + :documentation "The REGEX that's repeated.") + (greedyp :initarg :greedyp + :reader greedyp + :documentation "Whether the repetition is greedy.") + (minimum :initarg :minimum + :accessor minimum + :type fixnum + :documentation "The minimal number of repetitions.") + (maximum :initarg :maximum + :accessor maximum + :documentation "The maximal number of repetitions. +Can be NIL for unbounded.") + (min-len :initarg :min-len + :reader min-len + :documentation "The minimal length of the enclosed regex.") + (len :initarg :len + :reader len + :documentation "The length of the enclosed regex. NIL +if unknown.") + (min-rest :initform 0 + :accessor min-rest + :type fixnum + :documentation "The minimal number of characters which must +appear after this repetition.") + (contains-register-p :initarg :contains-register-p + :reader contains-register-p + :documentation "If the regex contains a register.")) + (:documentation "REPETITION objects represent repetitions of regexes.")) + + (defclass register (regex) + ((regex :initarg :regex + :accessor regex + :documentation "The inner regex.") + (num :initarg :num + :reader num + :type fixnum + :documentation "The number of this register, starting from 0. +This is the index into *REGS-START* and *REGS-END*.") + (name :initarg :name + :reader name + :documentation "Name of this register or NIL.")) + (:documentation "REGISTER objects represent register groups.")) + + (defclass standalone (regex) + ((regex :initarg :regex + :accessor regex + :documentation "The inner regex.")) + (:documentation "A standalone regular expression.")) + + (defclass back-reference (regex) + ((num :initarg :num + :accessor num + :type fixnum + :documentation "The number of the register this +reference refers to.") + (name :initarg :name + :accessor name + :documentation "The name of the register this +reference refers to or NIL.") + (case-insensitive-p :initarg :case-insensitive-p + :reader case-insensitive-p + :documentation "Whether we check +case-insensitively.")) + (:documentation "BACK-REFERENCE objects represent backreferences.")) + (defclass char-class (regex) + ((hash :initarg :hash + :reader hash + :type (or hash-table null) + :documentation "A hash table the keys of which are the +characters; the values are always T.") + (case-insensitive-p :initarg :case-insensitive-p + :reader case-insensitive-p + :documentation "If the char class +case-insensitive.") + (invertedp :initarg :invertedp + :reader invertedp + :documentation "Whether we mean the inverse of +the char class.") + (word-char-class-p :initarg :word-char-class-p + :reader word-char-class-p + :documentation "Whether this CHAR CLASS +represents the special class WORD-CHAR-CLASS.")) + (:documentation "CHAR-CLASS objects represent character classes.")) + + (defclass str (regex) + ((str :initarg :str + :accessor str + :type string + :documentation "The actual string.") + (len :initform 0 + :accessor len + :type fixnum + :documentation "The length of the string.") + (case-insensitive-p :initarg :case-insensitive-p + :reader case-insensitive-p + :documentation "If we match case-insensitively.") + (offset :initform nil + :accessor offset + :documentation "Offset from the left of the whole +parse tree. The first regex has offset 0. NIL if unknown, i.e. behind +a variable-length regex.") + (skip :initform nil + :initarg :skip + :accessor skip + :documentation "If we can avoid testing for this +string because the SCAN function has done this already.") + (start-of-end-string-p :initform nil + :accessor start-of-end-string-p + :documentation "If this is the unique +STR which starts END-STRING (a slot of MATCHER).")) + (:documentation "STR objects represent string.")) + + (defclass anchor (regex) + ((startp :initarg :startp + :reader startp + :documentation "Whether this is a "start anchor".") + (multi-line-p :initarg :multi-line-p + :reader multi-line-p + :documentation "Whether we're in multi-line mode, +i.e. whether each #\Newline is surrounded by anchors.") + (no-newline-p :initarg :no-newline-p + :reader no-newline-p + :documentation "Whether we ignore #\Newline at the end.")) + (:documentation "ANCHOR objects represent anchors like "^" or "$".")) + + (defclass everything (regex) + ((single-line-p :initarg :single-line-p + :reader single-line-p + :documentation "Whether we're in single-line mode, +i.e. whether we also match #\Newline.")) + (:documentation "EVERYTHING objects represent regexes matching +"everything", i.e. dots.")) + + (defclass word-boundary (regex) + ((negatedp :initarg :negatedp + :reader negatedp + :documentation "Whether we mean the opposite, +i.e. no word-boundary.")) + (:documentation "WORD-BOUNDARY objects represent word-boundary assertions.")) + + (defclass branch (regex) + ((test :initarg :test + :accessor test + :documentation "The test of this branch, one of +LOOKAHEAD, LOOKBEHIND, or a number.") + (then-regex :initarg :then-regex + :accessor then-regex + :documentation "The regex that's to be matched if the +test succeeds.") + (else-regex :initarg :else-regex + :initform (make-instance 'void) + :accessor else-regex + :documentation "The regex that's to be matched if the +test fails.")) + (:documentation "BRANCH objects represent Perl's conditional regular +expressions.")) + + (defclass filter (regex) + ((fn :initarg :fn + :accessor fn + :type (or function symbol) + :documentation "The user-defined function.") + (len :initarg :len + :reader len + :documentation "The fixed length of this filter or NIL.")) + (:documentation "FILTER objects represent arbitrary functions +defined by the user.")) + + (defclass void (regex) + () + (:documentation "VOID objects represent empty regular expressions.")))) + +(defmethod initialize-instance :after ((char-class char-class) &rest init-args) + (declare #.*standard-optimize-settings*) + "Make large hash tables smaller, if possible." + (let ((hash (getf init-args :hash))) + (when (and hash + (> *regex-char-code-limit* 256) + (> (hash-table-count hash) + (/ *regex-char-code-limit* 2))) + (setf (slot-value char-class 'hash) + (merge-inverted-hash (make-hash-table) + hash) + (slot-value char-class 'invertedp) + (not (slot-value char-class 'invertedp)))))) + +(defmethod initialize-instance :after ((str str) &rest init-args) + (declare #.*standard-optimize-settings*) + (declare (ignore init-args)) + "Automatically computes the length of a STR after initialization." + (let ((str-slot (slot-value str 'str))) + (unless (typep str-slot 'simple-string) + (setf (slot-value str 'str) (coerce str-slot 'simple-string)))) + (setf (len str) (length (str str)))) + +;;; The following four methods allow a VOID object to behave like a +;;; zero-length STR object (only readers needed) + +(defmethod len ((void void)) + (declare #.*standard-optimize-settings*) + 0) + +(defmethod str ((void void)) + (declare #.*standard-optimize-settings*) + "") + +(defmethod skip ((void void)) + (declare #.*standard-optimize-settings*) + nil) + +(defmethod start-of-end-string-p ((void void)) + (declare #.*standard-optimize-settings*) + nil) + +(defgeneric case-mode (regex old-case-mode) + (declare #.*standard-optimize-settings*) + (:documentation "Utility function used by the optimizer (see GATHER-STRINGS). +Returns a keyword denoting the case-(in)sensitivity of a STR or its +second argument if the STR has length 0. Returns NIL for REGEX objects +which are not of type STR.")) + +(defmethod case-mode ((str str) old-case-mode) + (declare #.*standard-optimize-settings*) + (cond ((zerop (len str)) + old-case-mode) + ((case-insensitive-p str) + :case-insensitive) + (t + :case-sensitive))) + +(defmethod case-mode ((regex regex) old-case-mode) + (declare #.*standard-optimize-settings*) + (declare (ignore old-case-mode)) + nil) + +(defgeneric copy-regex (regex) + (declare #.*standard-optimize-settings*) + (:documentation "Implements a deep copy of a REGEX object.")) + +(defmethod copy-regex ((anchor anchor)) + (declare #.*standard-optimize-settings*) + (make-instance 'anchor + :startp (startp anchor) + :multi-line-p (multi-line-p anchor) + :no-newline-p (no-newline-p anchor))) + +(defmethod copy-regex ((everything everything)) + (declare #.*standard-optimize-settings*) + (make-instance 'everything + :single-line-p (single-line-p everything))) + +(defmethod copy-regex ((word-boundary word-boundary)) + (declare #.*standard-optimize-settings*) + (make-instance 'word-boundary + :negatedp (negatedp word-boundary))) + +(defmethod copy-regex ((void void)) + (declare #.*standard-optimize-settings*) + (make-instance 'void)) + +(defmethod copy-regex ((lookahead lookahead)) + (declare #.*standard-optimize-settings*) + (make-instance 'lookahead + :regex (copy-regex (regex lookahead)) + :positivep (positivep lookahead))) + +(defmethod copy-regex ((seq seq)) + (declare #.*standard-optimize-settings*) + (make-instance 'seq + :elements (mapcar #'copy-regex (elements seq)))) + +(defmethod copy-regex ((alternation alternation)) + (declare #.*standard-optimize-settings*) + (make-instance 'alternation + :choices (mapcar #'copy-regex (choices alternation)))) + +(defmethod copy-regex ((branch branch)) + (declare #.*standard-optimize-settings*) + (with-slots (test) + branch + (make-instance 'branch + :test (if (typep test 'regex) + (copy-regex test) + test) + :then-regex (copy-regex (then-regex branch)) + :else-regex (copy-regex (else-regex branch))))) + +(defmethod copy-regex ((lookbehind lookbehind)) + (declare #.*standard-optimize-settings*) + (make-instance 'lookbehind + :regex (copy-regex (regex lookbehind)) + :positivep (positivep lookbehind) + :len (len lookbehind))) + +(defmethod copy-regex ((repetition repetition)) + (declare #.*standard-optimize-settings*) + (make-instance 'repetition + :regex (copy-regex (regex repetition)) + :greedyp (greedyp repetition) + :minimum (minimum repetition) + :maximum (maximum repetition) + :min-len (min-len repetition) + :len (len repetition) + :contains-register-p (contains-register-p repetition))) + +(defmethod copy-regex ((register register)) + (declare #.*standard-optimize-settings*) + (make-instance 'register + :regex (copy-regex (regex register)) + :num (num register) + :name (name register))) + +(defmethod copy-regex ((standalone standalone)) + (declare #.*standard-optimize-settings*) + (make-instance 'standalone + :regex (copy-regex (regex standalone)))) + +(defmethod copy-regex ((back-reference back-reference)) + (declare #.*standard-optimize-settings*) + (make-instance 'back-reference + :num (num back-reference) + :case-insensitive-p (case-insensitive-p back-reference))) + +(defmethod copy-regex ((char-class char-class)) + (declare #.*standard-optimize-settings*) + (make-instance 'char-class + :hash (hash char-class) + :case-insensitive-p (case-insensitive-p char-class) + :invertedp (invertedp char-class) + :word-char-class-p (word-char-class-p char-class))) + +(defmethod copy-regex ((str str)) + (declare #.*standard-optimize-settings*) + (make-instance 'str + :str (str str) + :case-insensitive-p (case-insensitive-p str))) + +(defmethod copy-regex ((filter filter)) + (declare #.*standard-optimize-settings*) + (make-instance 'filter + :fn (fn filter) + :len (len filter))) + +;;; Note that COPY-REGEX and REMOVE-REGISTERS could have easily been +;;; wrapped into one function. Maybe in the next release... + +;;; Further note that this function is used by CONVERT to factor out +;;; complicated repetitions, i.e. cases like +;;; (a)* -> (?:a*(a))? +;;; This won't work for, say, +;;; ((a)|(b))* -> (?:(?:a|b)*((a)|(b)))? +;;; and therefore we stop REGISTER removal once we see an ALTERNATION. + +(defgeneric remove-registers (regex) + (declare #.*standard-optimize-settings*) + (:documentation "Returns a deep copy of a REGEX (see COPY-REGEX) and +optionally removes embedded REGISTER objects if possible and if the +special variable REMOVE-REGISTERS-P is true.")) + +(defmethod remove-registers ((register register)) + (declare #.*standard-optimize-settings*) + (declare (special remove-registers-p reg-seen)) + (cond (remove-registers-p + (remove-registers (regex register))) + (t + ;; mark REG-SEEN as true so enclosing REPETITION objects + ;; (see method below) know if they contain a register or not + (setq reg-seen t) + (copy-regex register)))) + +(defmethod remove-registers ((repetition repetition)) + (declare #.*standard-optimize-settings*) + (let* (reg-seen + (inner-regex (remove-registers (regex repetition)))) + ;; REMOVE-REGISTERS will set REG-SEEN (see method above) if + ;; (REGEX REPETITION) contains a REGISTER + (declare (special reg-seen)) + (make-instance 'repetition + :regex inner-regex + :greedyp (greedyp repetition) + :minimum (minimum repetition) + :maximum (maximum repetition) + :min-len (min-len repetition) + :len (len repetition) + :contains-register-p reg-seen))) + +(defmethod remove-registers ((standalone standalone)) + (declare #.*standard-optimize-settings*) + (make-instance 'standalone + :regex (remove-registers (regex standalone)))) + +(defmethod remove-registers ((lookahead lookahead)) + (declare #.*standard-optimize-settings*) + (make-instance 'lookahead + :regex (remove-registers (regex lookahead)) + :positivep (positivep lookahead))) + +(defmethod remove-registers ((lookbehind lookbehind)) + (declare #.*standard-optimize-settings*) + (make-instance 'lookbehind + :regex (remove-registers (regex lookbehind)) + :positivep (positivep lookbehind) + :len (len lookbehind))) + +(defmethod remove-registers ((branch branch)) + (declare #.*standard-optimize-settings*) + (with-slots (test) + branch + (make-instance 'branch + :test (if (typep test 'regex) + (remove-registers test) + test) + :then-regex (remove-registers (then-regex branch)) + :else-regex (remove-registers (else-regex branch))))) + +(defmethod remove-registers ((alternation alternation)) + (declare #.*standard-optimize-settings*) + (declare (special remove-registers-p)) + ;; an ALTERNATION, so we can't remove REGISTER objects further down + (setq remove-registers-p nil) + (copy-regex alternation)) + +(defmethod remove-registers ((regex regex)) + (declare #.*standard-optimize-settings*) + (copy-regex regex)) + +(defmethod remove-registers ((seq seq)) + (declare #.*standard-optimize-settings*) + (make-instance 'seq + :elements (mapcar #'remove-registers (elements seq)))) + +(defgeneric everythingp (regex) + (declare #.*standard-optimize-settings*) + (:documentation "Returns an EVERYTHING object if REGEX is equivalent +to this object, otherwise NIL. So, "(.){1}" would return true +(i.e. the object corresponding to ".", for example.")) + +(defmethod everythingp ((seq seq)) + (declare #.*standard-optimize-settings*) + ;; we might have degenerate cases like (:SEQUENCE :VOID ...) + ;; due to the parsing process + (let ((cleaned-elements (remove-if #'(lambda (element) + (typep element 'void)) + (elements seq)))) + (and (= 1 (length cleaned-elements)) + (everythingp (first cleaned-elements))))) + +(defmethod everythingp ((alternation alternation)) + (declare #.*standard-optimize-settings*) + (with-slots (choices) + alternation + (and (= 1 (length choices)) + ;; this is unlikely to happen for human-generated regexes, + ;; but machine-generated ones might look like this + (everythingp (first choices))))) + +(defmethod everythingp ((repetition repetition)) + (declare #.*standard-optimize-settings*) + (with-slots (maximum minimum regex) + repetition + (and maximum + (= 1 minimum maximum) + ;; treat "<regex>{1,1}" like "<regex>" + (everythingp regex)))) + +(defmethod everythingp ((register register)) + (declare #.*standard-optimize-settings*) + (everythingp (regex register))) + +(defmethod everythingp ((standalone standalone)) + (declare #.*standard-optimize-settings*) + (everythingp (regex standalone))) + +(defmethod everythingp ((everything everything)) + (declare #.*standard-optimize-settings*) + everything) + +(defmethod everythingp ((regex regex)) + (declare #.*standard-optimize-settings*) + ;; the general case for ANCHOR, BACK-REFERENCE, BRANCH, CHAR-CLASS, + ;; LOOKAHEAD, LOOKBEHIND, STR, VOID, FILTER, and WORD-BOUNDARY + nil) + +(defgeneric regex-length (regex) + (declare #.*standard-optimize-settings*) + (:documentation "Return the length of REGEX if it is fixed, NIL otherwise.")) + +(defmethod regex-length ((seq seq)) + (declare #.*standard-optimize-settings*) + ;; simply add all inner lengths unless one of them is NIL + (loop for sub-regex in (elements seq) + for len = (regex-length sub-regex) + if (not len) do (return nil) + sum len)) + +(defmethod regex-length ((alternation alternation)) + (declare #.*standard-optimize-settings*) + ;; only return a true value if all inner lengths are non-NIL and + ;; mutually equal + (loop for sub-regex in (choices alternation) + for old-len = nil then len + for len = (regex-length sub-regex) + if (or (not len) + (and old-len (/= len old-len))) do (return nil) + finally (return len))) + +(defmethod regex-length ((branch branch)) + (declare #.*standard-optimize-settings*) + ;; only return a true value if both alternations have a length and + ;; if they're equal + (let ((then-length (regex-length (then-regex branch)))) + (and then-length + (eql then-length (regex-length (else-regex branch))) + then-length))) + +(defmethod regex-length ((repetition repetition)) + (declare #.*standard-optimize-settings*) + ;; we can only compute the length of a REPETITION object if the + ;; number of repetitions is fixed; note that we don't call + ;; REGEX-LENGTH for the inner regex, we assume that the LEN slot is + ;; always set correctly + (with-slots (len minimum maximum) + repetition + (if (and len + (eql minimum maximum)) + (* minimum len) + nil))) + +(defmethod regex-length ((register register)) + (declare #.*standard-optimize-settings*) + (regex-length (regex register))) + +(defmethod regex-length ((standalone standalone)) + (declare #.*standard-optimize-settings*) + (regex-length (regex standalone))) + +(defmethod regex-length ((back-reference back-reference)) + (declare #.*standard-optimize-settings*) + ;; with enough effort we could possibly do better here, but + ;; currently we just give up and return NIL + nil) + +(defmethod regex-length ((char-class char-class)) + (declare #.*standard-optimize-settings*) + 1) + +(defmethod regex-length ((everything everything)) + (declare #.*standard-optimize-settings*) + 1) + +(defmethod regex-length ((str str)) + (declare #.*standard-optimize-settings*) + (len str)) + +(defmethod regex-length ((filter filter)) + (declare #.*standard-optimize-settings*) + (len filter)) + +(defmethod regex-length ((regex regex)) + (declare #.*standard-optimize-settings*) + ;; the general case for ANCHOR, LOOKAHEAD, LOOKBEHIND, VOID, and + ;; WORD-BOUNDARY (which all have zero-length) + 0) + +(defgeneric regex-min-length (regex) + (declare #.*standard-optimize-settings*) + (:documentation "Returns the minimal length of REGEX.")) + +(defmethod regex-min-length ((seq seq)) + (declare #.*standard-optimize-settings*) + ;; simply add all inner minimal lengths + (loop for sub-regex in (elements seq) + for len = (regex-min-length sub-regex) + sum len)) + +(defmethod regex-min-length ((alternation alternation)) + (declare #.*standard-optimize-settings*) + ;; minimal length of an alternation is the minimal length of the + ;; "shortest" element + (loop for sub-regex in (choices alternation) + for len = (regex-min-length sub-regex) + minimize len)) + +(defmethod regex-min-length ((branch branch)) + (declare #.*standard-optimize-settings*) + ;; minimal length of both alternations + (min (regex-min-length (then-regex branch)) + (regex-min-length (else-regex branch)))) + +(defmethod regex-min-length ((repetition repetition)) + (declare #.*standard-optimize-settings*) + ;; obviously the product of the inner minimal length and the minimal + ;; number of repetitions + (* (minimum repetition) (min-len repetition))) + +(defmethod regex-min-length ((register register)) + (declare #.*standard-optimize-settings*) + (regex-min-length (regex register))) + +(defmethod regex-min-length ((standalone standalone)) + (declare #.*standard-optimize-settings*) + (regex-min-length (regex standalone))) + +(defmethod regex-min-length ((char-class char-class)) + (declare #.*standard-optimize-settings*) + 1) + +(defmethod regex-min-length ((everything everything)) + (declare #.*standard-optimize-settings*) + 1) + +(defmethod regex-min-length ((str str)) + (declare #.*standard-optimize-settings*) + (len str)) + +(defmethod regex-min-length ((filter filter)) + (declare #.*standard-optimize-settings*) + (or (len filter) + 0)) + +(defmethod regex-min-length ((regex regex)) + (declare #.*standard-optimize-settings*) + ;; the general case for ANCHOR, BACK-REFERENCE, LOOKAHEAD, + ;; LOOKBEHIND, VOID, and WORD-BOUNDARY + 0) + +(defgeneric compute-offsets (regex start-pos) + (declare #.*standard-optimize-settings*) + (:documentation "Returns the offset the following regex would have +relative to START-POS or NIL if we can't compute it. Sets the OFFSET +slot of REGEX to START-POS if REGEX is a STR. May also affect OFFSET +slots of STR objects further down the tree.")) + +;; note that we're actually only interested in the offset of +;; "top-level" STR objects (see ADVANCE-FN in the SCAN function) so we +;; can stop at variable-length alternations and don't need to descend +;; into repetitions + +(defmethod compute-offsets ((seq seq) start-pos) + (declare #.*standard-optimize-settings*) + (loop for element in (elements seq) + ;; advance offset argument for next call while looping through + ;; the elements + for pos = start-pos then curr-offset + for curr-offset = (compute-offsets element pos) + while curr-offset + finally (return curr-offset))) + +(defmethod compute-offsets ((alternation alternation) start-pos) + (declare #.*standard-optimize-settings*) + (loop for choice in (choices alternation) + for old-offset = nil then curr-offset + for curr-offset = (compute-offsets choice start-pos) + ;; we stop immediately if two alternations don't result in the + ;; same offset + if (or (not curr-offset) + (and old-offset (/= curr-offset old-offset))) + do (return nil) + finally (return curr-offset))) + +(defmethod compute-offsets ((branch branch) start-pos) + (declare #.*standard-optimize-settings*) + ;; only return offset if both alternations have equal value + (let ((then-offset (compute-offsets (then-regex branch) start-pos))) + (and then-offset + (eql then-offset (compute-offsets (else-regex branch) start-pos)) + then-offset))) + +(defmethod compute-offsets ((repetition repetition) start-pos) + (declare #.*standard-optimize-settings*) + ;; no need to descend into the inner regex + (with-slots (len minimum maximum) + repetition + (if (and len + (eq minimum maximum)) + ;; fixed number of repetitions, so we know how to proceed + (+ start-pos (* minimum len)) + ;; otherwise return NIL + nil))) + +(defmethod compute-offsets ((register register) start-pos) + (declare #.*standard-optimize-settings*) + (compute-offsets (regex register) start-pos)) + +(defmethod compute-offsets ((standalone standalone) start-pos) + (declare #.*standard-optimize-settings*) + (compute-offsets (regex standalone) start-pos)) + +(defmethod compute-offsets ((char-class char-class) start-pos) + (declare #.*standard-optimize-settings*) + (1+ start-pos)) + +(defmethod compute-offsets ((everything everything) start-pos) + (declare #.*standard-optimize-settings*) + (1+ start-pos)) + +(defmethod compute-offsets ((str str) start-pos) + (declare #.*standard-optimize-settings*) + (setf (offset str) start-pos) + (+ start-pos (len str))) + +(defmethod compute-offsets ((back-reference back-reference) start-pos) + (declare #.*standard-optimize-settings*) + ;; with enough effort we could possibly do better here, but + ;; currently we just give up and return NIL + (declare (ignore start-pos)) + nil) + +(defmethod compute-offsets ((filter filter) start-pos) + (declare #.*standard-optimize-settings*) + (let ((len (len filter))) + (if len + (+ start-pos len) + nil))) + +(defmethod compute-offsets ((regex regex) start-pos) + (declare #.*standard-optimize-settings*) + ;; the general case for ANCHOR, LOOKAHEAD, LOOKBEHIND, VOID, and + ;; WORD-BOUNDARY (which all have zero-length) + start-pos)
Added: branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/repetition-closures.lisp =================================================================== --- branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/repetition-closures.lisp 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/repetition-closures.lisp 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,844 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-PPCRE; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/cl-ppcre/repetition-closures.lisp,v 1.28 2007/01/01 23:43:10 edi Exp $ + +;;; This is actually a part of closures.lisp which we put into a +;;; separate file because it is rather complex. We only deal with +;;; REPETITIONs here. Note that this part of the code contains some +;;; rather crazy micro-optimizations which were introduced to be as +;;; competitive with Perl as possible in tight loops. + +;;; Copyright (c) 2002-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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-package #:cl-ppcre) + +(defmacro incf-after (place &optional (delta 1) &environment env) + "Utility macro inspired by C's "place++", i.e. first return the +value of PLACE and afterwards increment it by DELTA." + (with-unique-names (%temp) + (multiple-value-bind (vars vals store-vars writer-form reader-form) + (get-setf-expansion place env) + `(let* (,@(mapcar #'list vars vals) + (,%temp ,reader-form) + (,(car store-vars) (+ ,%temp ,delta))) + ,writer-form + ,%temp)))) + +;; code for greedy repetitions with minimum zero + +(defmacro greedy-constant-length-closure (check-curr-pos) + "This is the template for simple greedy repetitions (where simple +means that the minimum number of repetitions is zero, that the inner +regex to be checked is of fixed length LEN, and that it doesn't +contain registers, i.e. there's no need for backtracking). +CHECK-CURR-POS is a form which checks whether the inner regex of the +repetition matches at CURR-POS." + `(if maximum + (lambda (start-pos) + (declare (type fixnum start-pos maximum)) + ;; because we know LEN we know in advance where to stop at the + ;; latest; we also take into consideration MIN-REST, i.e. the + ;; minimal length of the part behind the repetition + (let ((target-end-pos (min (1+ (- *end-pos* len min-rest)) + ;; don't go further than MAXIMUM + ;; repetitions, of course + (+ start-pos + (the fixnum (* len maximum))))) + (curr-pos start-pos)) + (declare (type fixnum target-end-pos curr-pos)) + (block greedy-constant-length-matcher + ;; we use an ugly TAGBODY construct because this might be a + ;; tight loop and this version is a bit faster than our LOOP + ;; version (at least in CMUCL) + (tagbody + forward-loop + ;; first go forward as far as possible, i.e. while + ;; the inner regex matches + (when (>= curr-pos target-end-pos) + (go backward-loop)) + (when ,check-curr-pos + (incf curr-pos len) + (go forward-loop)) + backward-loop + ;; now go back LEN steps each until we're able to match + ;; the rest of the regex + (when (< curr-pos start-pos) + (return-from greedy-constant-length-matcher nil)) + (let ((result (funcall next-fn curr-pos))) + (when result + (return-from greedy-constant-length-matcher result))) + (decf curr-pos len) + (go backward-loop))))) + ;; basically the same code; it's just a bit easier because we're + ;; not bounded by MAXIMUM + (lambda (start-pos) + (declare (type fixnum start-pos)) + (let ((target-end-pos (1+ (- *end-pos* len min-rest))) + (curr-pos start-pos)) + (declare (type fixnum target-end-pos curr-pos)) + (block greedy-constant-length-matcher + (tagbody + forward-loop + (when (>= curr-pos target-end-pos) + (go backward-loop)) + (when ,check-curr-pos + (incf curr-pos len) + (go forward-loop)) + backward-loop + (when (< curr-pos start-pos) + (return-from greedy-constant-length-matcher nil)) + (let ((result (funcall next-fn curr-pos))) + (when result + (return-from greedy-constant-length-matcher result))) + (decf curr-pos len) + (go backward-loop))))))) + +(defun create-greedy-everything-matcher (maximum min-rest next-fn) + (declare #.*standard-optimize-settings*) + (declare (type fixnum min-rest) + (type function next-fn)) + "Creates a closure which just matches as far ahead as possible, +i.e. a closure for a dot in single-line mode." + (if maximum + (lambda (start-pos) + (declare (type fixnum start-pos maximum)) + ;; because we know LEN we know in advance where to stop at the + ;; latest; we also take into consideration MIN-REST, i.e. the + ;; minimal length of the part behind the repetition + (let ((target-end-pos (min (+ start-pos maximum) + (- *end-pos* min-rest)))) + (declare (type fixnum target-end-pos)) + ;; start from the highest possible position and go backward + ;; until we're able to match the rest of the regex + (loop for curr-pos of-type fixnum from target-end-pos downto start-pos + thereis (funcall next-fn curr-pos)))) + ;; basically the same code; it's just a bit easier because we're + ;; not bounded by MAXIMUM + (lambda (start-pos) + (declare (type fixnum start-pos)) + (let ((target-end-pos (- *end-pos* min-rest))) + (declare (type fixnum target-end-pos)) + (loop for curr-pos of-type fixnum from target-end-pos downto start-pos + thereis (funcall next-fn curr-pos)))))) + +(defgeneric create-greedy-constant-length-matcher (repetition next-fn) + (declare #.*standard-optimize-settings*) + (:documentation "Creates a closure which tries to match REPETITION. It is assumed +that REPETITION is greedy and the minimal number of repetitions is +zero. It is furthermore assumed that the inner regex of REPETITION is +of fixed length and doesn't contain registers.")) + +(defmethod create-greedy-constant-length-matcher ((repetition repetition) + next-fn) + (declare #.*standard-optimize-settings*) + (let ((len (len repetition)) + (maximum (maximum repetition)) + (regex (regex repetition)) + (min-rest (min-rest repetition))) + (declare (type fixnum len min-rest) + (type function next-fn)) + (cond ((zerop len) + ;; inner regex has zero-length, so we can discard it + ;; completely + next-fn) + (t + ;; now first try to optimize for a couple of common cases + (typecase regex + (str + (let ((str (str regex))) + (if (= 1 len) + ;; a single character + (let ((chr (schar str 0))) + (if (case-insensitive-p regex) + (greedy-constant-length-closure + (char-equal chr (schar *string* curr-pos))) + (greedy-constant-length-closure + (char= chr (schar *string* curr-pos))))) + ;; a string + (if (case-insensitive-p regex) + (greedy-constant-length-closure + (*string*-equal str curr-pos (+ curr-pos len) 0 len)) + (greedy-constant-length-closure + (*string*= str curr-pos (+ curr-pos len) 0 len)))))) + (char-class + ;; a character class + (insert-char-class-tester (regex (schar *string* curr-pos)) + (if (invertedp regex) + (greedy-constant-length-closure + (not (char-class-test))) + (greedy-constant-length-closure + (char-class-test))))) + (everything + ;; an EVERYTHING object, i.e. a dot + (if (single-line-p regex) + (create-greedy-everything-matcher maximum min-rest next-fn) + (greedy-constant-length-closure + (char/= #\Newline (schar *string* curr-pos))))) + (t + ;; the general case - we build an inner matcher which + ;; just checks for immediate success, i.e. NEXT-FN is + ;; #'IDENTITY + (let ((inner-matcher (create-matcher-aux regex #'identity))) + (declare (type function inner-matcher)) + (greedy-constant-length-closure + (funcall inner-matcher curr-pos))))))))) + +(defgeneric create-greedy-no-zero-matcher (repetition next-fn) + (declare #.*standard-optimize-settings*) + (:documentation "Creates a closure which tries to match REPETITION. It is assumed +that REPETITION is greedy and the minimal number of repetitions is +zero. It is furthermore assumed that the inner regex of REPETITION can +never match a zero-length string (or instead the maximal number of +repetitions is 1).")) + +(defmethod create-greedy-no-zero-matcher ((repetition repetition) next-fn) + (declare #.*standard-optimize-settings*) + (let ((maximum (maximum repetition)) + ;; REPEAT-MATCHER is part of the closure's environment but it + ;; can only be defined after GREEDY-AUX is defined + repeat-matcher) + (declare (type function next-fn)) + (cond + ((eql maximum 1) + ;; this is essentially like the next case but with a known + ;; MAXIMUM of 1 we can get away without a counter; note that + ;; we always arrive here if CONVERT optimizes <regex>* to + ;; (?:<regex'>*<regex>)? + (setq repeat-matcher + (create-matcher-aux (regex repetition) next-fn)) + (lambda (start-pos) + (declare (type function repeat-matcher)) + (or (funcall repeat-matcher start-pos) + (funcall next-fn start-pos)))) + (maximum + ;; we make a reservation for our slot in *REPEAT-COUNTERS* + ;; because we need to keep track whether we've reached MAXIMUM + ;; repetitions + (let ((rep-num (incf-after *rep-num*))) + (flet ((greedy-aux (start-pos) + (declare (type fixnum start-pos maximum rep-num) + (type function repeat-matcher)) + ;; the actual matcher which first tries to match the + ;; inner regex of REPETITION (if we haven't done so + ;; too often) and on failure calls NEXT-FN + (or (and (< (aref *repeat-counters* rep-num) maximum) + (incf (aref *repeat-counters* rep-num)) + ;; note that REPEAT-MATCHER will call + ;; GREEDY-AUX again recursively + (prog1 + (funcall repeat-matcher start-pos) + (decf (aref *repeat-counters* rep-num)))) + (funcall next-fn start-pos)))) + ;; create a closure to match the inner regex and to + ;; implement backtracking via GREEDY-AUX + (setq repeat-matcher + (create-matcher-aux (regex repetition) #'greedy-aux)) + ;; the closure we return is just a thin wrapper around + ;; GREEDY-AUX to initialize the repetition counter + (lambda (start-pos) + (declare (type fixnum start-pos)) + (setf (aref *repeat-counters* rep-num) 0) + (greedy-aux start-pos))))) + (t + ;; easier code because we're not bounded by MAXIMUM, but + ;; basically the same + (flet ((greedy-aux (start-pos) + (declare (type fixnum start-pos) + (type function repeat-matcher)) + (or (funcall repeat-matcher start-pos) + (funcall next-fn start-pos)))) + (setq repeat-matcher + (create-matcher-aux (regex repetition) #'greedy-aux)) + #'greedy-aux))))) + +(defgeneric create-greedy-matcher (repetition next-fn) + (declare #.*standard-optimize-settings*) + (:documentation "Creates a closure which tries to match REPETITION. It is assumed +that REPETITION is greedy and the minimal number of repetitions is +zero.")) + +(defmethod create-greedy-matcher ((repetition repetition) next-fn) + (declare #.*standard-optimize-settings*) + (let ((maximum (maximum repetition)) + ;; we make a reservation for our slot in *LAST-POS-STORES* because + ;; we have to watch out for endless loops as the inner regex might + ;; match zero-length strings + (zero-length-num (incf-after *zero-length-num*)) + ;; REPEAT-MATCHER is part of the closure's environment but it + ;; can only be defined after GREEDY-AUX is defined + repeat-matcher) + (declare (type fixnum zero-length-num) + (type function next-fn)) + (cond + (maximum + ;; we make a reservation for our slot in *REPEAT-COUNTERS* + ;; because we need to keep track whether we've reached MAXIMUM + ;; repetitions + (let ((rep-num (incf-after *rep-num*))) + (flet ((greedy-aux (start-pos) + ;; the actual matcher which first tries to match the + ;; inner regex of REPETITION (if we haven't done so + ;; too often) and on failure calls NEXT-FN + (declare (type fixnum start-pos maximum rep-num) + (type function repeat-matcher)) + (let ((old-last-pos + (svref *last-pos-stores* zero-length-num))) + (when (and old-last-pos + (= (the fixnum old-last-pos) start-pos)) + ;; stop immediately if we've been here before, + ;; i.e. if the last attempt matched a zero-length + ;; string + (return-from greedy-aux (funcall next-fn start-pos))) + ;; otherwise remember this position for the next + ;; repetition + (setf (svref *last-pos-stores* zero-length-num) start-pos) + (or (and (< (aref *repeat-counters* rep-num) maximum) + (incf (aref *repeat-counters* rep-num)) + ;; note that REPEAT-MATCHER will call + ;; GREEDY-AUX again recursively + (prog1 + (funcall repeat-matcher start-pos) + (decf (aref *repeat-counters* rep-num)) + (setf (svref *last-pos-stores* zero-length-num) + old-last-pos))) + (funcall next-fn start-pos))))) + ;; create a closure to match the inner regex and to + ;; implement backtracking via GREEDY-AUX + (setq repeat-matcher + (create-matcher-aux (regex repetition) #'greedy-aux)) + ;; the closure we return is just a thin wrapper around + ;; GREEDY-AUX to initialize the repetition counter and our + ;; slot in *LAST-POS-STORES* + (lambda (start-pos) + (declare (type fixnum start-pos)) + (setf (aref *repeat-counters* rep-num) 0 + (svref *last-pos-stores* zero-length-num) nil) + (greedy-aux start-pos))))) + (t + ;; easier code because we're not bounded by MAXIMUM, but + ;; basically the same + (flet ((greedy-aux (start-pos) + (declare (type fixnum start-pos) + (type function repeat-matcher)) + (let ((old-last-pos + (svref *last-pos-stores* zero-length-num))) + (when (and old-last-pos + (= (the fixnum old-last-pos) start-pos)) + (return-from greedy-aux (funcall next-fn start-pos))) + (setf (svref *last-pos-stores* zero-length-num) start-pos) + (or (prog1 + (funcall repeat-matcher start-pos) + (setf (svref *last-pos-stores* zero-length-num) old-last-pos)) + (funcall next-fn start-pos))))) + (setq repeat-matcher + (create-matcher-aux (regex repetition) #'greedy-aux)) + (lambda (start-pos) + (declare (type fixnum start-pos)) + (setf (svref *last-pos-stores* zero-length-num) nil) + (greedy-aux start-pos))))))) + +;; code for non-greedy repetitions with minimum zero + +(defmacro non-greedy-constant-length-closure (check-curr-pos) + "This is the template for simple non-greedy repetitions (where +simple means that the minimum number of repetitions is zero, that the +inner regex to be checked is of fixed length LEN, and that it doesn't +contain registers, i.e. there's no need for backtracking). +CHECK-CURR-POS is a form which checks whether the inner regex of the +repetition matches at CURR-POS." + `(if maximum + (lambda (start-pos) + (declare (type fixnum start-pos maximum)) + ;; because we know LEN we know in advance where to stop at the + ;; latest; we also take into consideration MIN-REST, i.e. the + ;; minimal length of the part behind the repetition + (let ((target-end-pos (min (1+ (- *end-pos* len min-rest)) + (+ start-pos + (the fixnum (* len maximum)))))) + ;; move forward by LEN and always try NEXT-FN first, then + ;; CHECK-CUR-POS + (loop for curr-pos of-type fixnum from start-pos + below target-end-pos + by len + thereis (funcall next-fn curr-pos) + while ,check-curr-pos + finally (return (funcall next-fn curr-pos))))) + ;; basically the same code; it's just a bit easier because we're + ;; not bounded by MAXIMUM + (lambda (start-pos) + (declare (type fixnum start-pos)) + (let ((target-end-pos (1+ (- *end-pos* len min-rest)))) + (loop for curr-pos of-type fixnum from start-pos + below target-end-pos + by len + thereis (funcall next-fn curr-pos) + while ,check-curr-pos + finally (return (funcall next-fn curr-pos))))))) + +(defgeneric create-non-greedy-constant-length-matcher (repetition next-fn) + (declare #.*standard-optimize-settings*) + (:documentation "Creates a closure which tries to match REPETITION. It is assumed +that REPETITION is non-greedy and the minimal number of repetitions is +zero. It is furthermore assumed that the inner regex of REPETITION is +of fixed length and doesn't contain registers.")) + +(defmethod create-non-greedy-constant-length-matcher ((repetition repetition) next-fn) + (declare #.*standard-optimize-settings*) + (let ((len (len repetition)) + (maximum (maximum repetition)) + (regex (regex repetition)) + (min-rest (min-rest repetition))) + (declare (type fixnum len min-rest) + (type function next-fn)) + (cond ((zerop len) + ;; inner regex has zero-length, so we can discard it + ;; completely + next-fn) + (t + ;; now first try to optimize for a couple of common cases + (typecase regex + (str + (let ((str (str regex))) + (if (= 1 len) + ;; a single character + (let ((chr (schar str 0))) + (if (case-insensitive-p regex) + (non-greedy-constant-length-closure + (char-equal chr (schar *string* curr-pos))) + (non-greedy-constant-length-closure + (char= chr (schar *string* curr-pos))))) + ;; a string + (if (case-insensitive-p regex) + (non-greedy-constant-length-closure + (*string*-equal str curr-pos (+ curr-pos len) 0 len)) + (non-greedy-constant-length-closure + (*string*= str curr-pos (+ curr-pos len) 0 len)))))) + (char-class + ;; a character class + (insert-char-class-tester (regex (schar *string* curr-pos)) + (if (invertedp regex) + (non-greedy-constant-length-closure + (not (char-class-test))) + (non-greedy-constant-length-closure + (char-class-test))))) + (everything + (if (single-line-p regex) + ;; a dot which really can match everything; we rely + ;; on the compiler to optimize this away + (non-greedy-constant-length-closure + t) + ;; a dot which has to watch out for #\Newline + (non-greedy-constant-length-closure + (char/= #\Newline (schar *string* curr-pos))))) + (t + ;; the general case - we build an inner matcher which + ;; just checks for immediate success, i.e. NEXT-FN is + ;; #'IDENTITY + (let ((inner-matcher (create-matcher-aux regex #'identity))) + (declare (type function inner-matcher)) + (non-greedy-constant-length-closure + (funcall inner-matcher curr-pos))))))))) + +(defgeneric create-non-greedy-no-zero-matcher (repetition next-fn) + (declare #.*standard-optimize-settings*) + (:documentation "Creates a closure which tries to match REPETITION. It is assumed +that REPETITION is non-greedy and the minimal number of repetitions is +zero. It is furthermore assumed that the inner regex of REPETITION can +never match a zero-length string (or instead the maximal number of +repetitions is 1).")) + +(defmethod create-non-greedy-no-zero-matcher ((repetition repetition) next-fn) + (declare #.*standard-optimize-settings*) + (let ((maximum (maximum repetition)) + ;; REPEAT-MATCHER is part of the closure's environment but it + ;; can only be defined after NON-GREEDY-AUX is defined + repeat-matcher) + (declare (type function next-fn)) + (cond + ((eql maximum 1) + ;; this is essentially like the next case but with a known + ;; MAXIMUM of 1 we can get away without a counter + (setq repeat-matcher + (create-matcher-aux (regex repetition) next-fn)) + (lambda (start-pos) + (declare (type function repeat-matcher)) + (or (funcall next-fn start-pos) + (funcall repeat-matcher start-pos)))) + (maximum + ;; we make a reservation for our slot in *REPEAT-COUNTERS* + ;; because we need to keep track whether we've reached MAXIMUM + ;; repetitions + (let ((rep-num (incf-after *rep-num*))) + (flet ((non-greedy-aux (start-pos) + ;; the actual matcher which first calls NEXT-FN and + ;; on failure tries to match the inner regex of + ;; REPETITION (if we haven't done so too often) + (declare (type fixnum start-pos maximum rep-num) + (type function repeat-matcher)) + (or (funcall next-fn start-pos) + (and (< (aref *repeat-counters* rep-num) maximum) + (incf (aref *repeat-counters* rep-num)) + ;; note that REPEAT-MATCHER will call + ;; NON-GREEDY-AUX again recursively + (prog1 + (funcall repeat-matcher start-pos) + (decf (aref *repeat-counters* rep-num))))))) + ;; create a closure to match the inner regex and to + ;; implement backtracking via NON-GREEDY-AUX + (setq repeat-matcher + (create-matcher-aux (regex repetition) #'non-greedy-aux)) + ;; the closure we return is just a thin wrapper around + ;; NON-GREEDY-AUX to initialize the repetition counter + (lambda (start-pos) + (declare (type fixnum start-pos)) + (setf (aref *repeat-counters* rep-num) 0) + (non-greedy-aux start-pos))))) + (t + ;; easier code because we're not bounded by MAXIMUM, but + ;; basically the same + (flet ((non-greedy-aux (start-pos) + (declare (type fixnum start-pos) + (type function repeat-matcher)) + (or (funcall next-fn start-pos) + (funcall repeat-matcher start-pos)))) + (setq repeat-matcher + (create-matcher-aux (regex repetition) #'non-greedy-aux)) + #'non-greedy-aux))))) + +(defgeneric create-non-greedy-matcher (repetition next-fn) + (declare #.*standard-optimize-settings*) + (:documentation "Creates a closure which tries to match REPETITION. It is assumed +that REPETITION is non-greedy and the minimal number of repetitions is +zero.")) + +(defmethod create-non-greedy-matcher ((repetition repetition) next-fn) + (declare #.*standard-optimize-settings*) + ;; we make a reservation for our slot in *LAST-POS-STORES* because + ;; we have to watch out for endless loops as the inner regex might + ;; match zero-length strings + (let ((zero-length-num (incf-after *zero-length-num*)) + (maximum (maximum repetition)) + ;; REPEAT-MATCHER is part of the closure's environment but it + ;; can only be defined after NON-GREEDY-AUX is defined + repeat-matcher) + (declare (type fixnum zero-length-num) + (type function next-fn)) + (cond + (maximum + ;; we make a reservation for our slot in *REPEAT-COUNTERS* + ;; because we need to keep track whether we've reached MAXIMUM + ;; repetitions + (let ((rep-num (incf-after *rep-num*))) + (flet ((non-greedy-aux (start-pos) + ;; the actual matcher which first calls NEXT-FN and + ;; on failure tries to match the inner regex of + ;; REPETITION (if we haven't done so too often) + (declare (type fixnum start-pos maximum rep-num) + (type function repeat-matcher)) + (let ((old-last-pos + (svref *last-pos-stores* zero-length-num))) + (when (and old-last-pos + (= (the fixnum old-last-pos) start-pos)) + ;; stop immediately if we've been here before, + ;; i.e. if the last attempt matched a zero-length + ;; string + (return-from non-greedy-aux (funcall next-fn start-pos))) + ;; otherwise remember this position for the next + ;; repetition + (setf (svref *last-pos-stores* zero-length-num) start-pos) + (or (funcall next-fn start-pos) + (and (< (aref *repeat-counters* rep-num) maximum) + (incf (aref *repeat-counters* rep-num)) + ;; note that REPEAT-MATCHER will call + ;; NON-GREEDY-AUX again recursively + (prog1 + (funcall repeat-matcher start-pos) + (decf (aref *repeat-counters* rep-num)) + (setf (svref *last-pos-stores* zero-length-num) + old-last-pos))))))) + ;; create a closure to match the inner regex and to + ;; implement backtracking via NON-GREEDY-AUX + (setq repeat-matcher + (create-matcher-aux (regex repetition) #'non-greedy-aux)) + ;; the closure we return is just a thin wrapper around + ;; NON-GREEDY-AUX to initialize the repetition counter and our + ;; slot in *LAST-POS-STORES* + (lambda (start-pos) + (declare (type fixnum start-pos)) + (setf (aref *repeat-counters* rep-num) 0 + (svref *last-pos-stores* zero-length-num) nil) + (non-greedy-aux start-pos))))) + (t + ;; easier code because we're not bounded by MAXIMUM, but + ;; basically the same + (flet ((non-greedy-aux (start-pos) + (declare (type fixnum start-pos) + (type function repeat-matcher)) + (let ((old-last-pos + (svref *last-pos-stores* zero-length-num))) + (when (and old-last-pos + (= (the fixnum old-last-pos) start-pos)) + (return-from non-greedy-aux (funcall next-fn start-pos))) + (setf (svref *last-pos-stores* zero-length-num) start-pos) + (or (funcall next-fn start-pos) + (prog1 + (funcall repeat-matcher start-pos) + (setf (svref *last-pos-stores* zero-length-num) + old-last-pos)))))) + (setq repeat-matcher + (create-matcher-aux (regex repetition) #'non-greedy-aux)) + (lambda (start-pos) + (declare (type fixnum start-pos)) + (setf (svref *last-pos-stores* zero-length-num) nil) + (non-greedy-aux start-pos))))))) + +;; code for constant repetitions, i.e. those with a fixed number of repetitions + +(defmacro constant-repetition-constant-length-closure (check-curr-pos) + "This is the template for simple constant repetitions (where simple +means that the inner regex to be checked is of fixed length LEN, and +that it doesn't contain registers, i.e. there's no need for +backtracking) and where constant means that MINIMUM is equal to +MAXIMUM. CHECK-CURR-POS is a form which checks whether the inner regex +of the repetition matches at CURR-POS." + `(lambda (start-pos) + (declare (type fixnum start-pos)) + (let ((target-end-pos (+ start-pos + (the fixnum (* len repetitions))))) + (declare (type fixnum target-end-pos)) + ;; first check if we won't go beyond the end of the string + (and (>= *end-pos* target-end-pos) + ;; then loop through all repetitions step by step + (loop for curr-pos of-type fixnum from start-pos + below target-end-pos + by len + always ,check-curr-pos) + ;; finally call NEXT-FN if we made it that far + (funcall next-fn target-end-pos))))) + +(defgeneric create-constant-repetition-constant-length-matcher + (repetition next-fn) + (declare #.*standard-optimize-settings*) + (:documentation "Creates a closure which tries to match REPETITION. It is assumed +that REPETITION has a constant number of repetitions. It is +furthermore assumed that the inner regex of REPETITION is of fixed +length and doesn't contain registers.")) + +(defmethod create-constant-repetition-constant-length-matcher + ((repetition repetition) next-fn) + (declare #.*standard-optimize-settings*) + (let ((len (len repetition)) + (repetitions (minimum repetition)) + (regex (regex repetition))) + (declare (type fixnum len repetitions) + (type function next-fn)) + (if (zerop len) + ;; if the length is zero it suffices to try once + (create-matcher-aux regex next-fn) + ;; otherwise try to optimize for a couple of common cases + (typecase regex + (str + (let ((str (str regex))) + (if (= 1 len) + ;; a single character + (let ((chr (schar str 0))) + (if (case-insensitive-p regex) + (constant-repetition-constant-length-closure + (and (char-equal chr (schar *string* curr-pos)) + (1+ curr-pos))) + (constant-repetition-constant-length-closure + (and (char= chr (schar *string* curr-pos)) + (1+ curr-pos))))) + ;; a string + (if (case-insensitive-p regex) + (constant-repetition-constant-length-closure + (let ((next-pos (+ curr-pos len))) + (declare (type fixnum next-pos)) + (and (*string*-equal str curr-pos next-pos 0 len) + next-pos))) + (constant-repetition-constant-length-closure + (let ((next-pos (+ curr-pos len))) + (declare (type fixnum next-pos)) + (and (*string*= str curr-pos next-pos 0 len) + next-pos))))))) + (char-class + ;; a character class + (insert-char-class-tester (regex (schar *string* curr-pos)) + (if (invertedp regex) + (constant-repetition-constant-length-closure + (and (not (char-class-test)) + (1+ curr-pos))) + (constant-repetition-constant-length-closure + (and (char-class-test) + (1+ curr-pos)))))) + (everything + (if (single-line-p regex) + ;; a dot which really matches everything - we just have to + ;; advance the index into *STRING* accordingly and check + ;; if we didn't go past the end + (lambda (start-pos) + (declare (type fixnum start-pos)) + (let ((next-pos (+ start-pos repetitions))) + (declare (type fixnum next-pos)) + (and (<= next-pos *end-pos*) + (funcall next-fn next-pos)))) + ;; a dot which is not in single-line-mode - make sure we + ;; don't match #\Newline + (constant-repetition-constant-length-closure + (and (char/= #\Newline (schar *string* curr-pos)) + (1+ curr-pos))))) + (t + ;; the general case - we build an inner matcher which just + ;; checks for immediate success, i.e. NEXT-FN is #'IDENTITY + (let ((inner-matcher (create-matcher-aux regex #'identity))) + (declare (type function inner-matcher)) + (constant-repetition-constant-length-closure + (funcall inner-matcher curr-pos)))))))) + +(defgeneric create-constant-repetition-matcher (repetition next-fn) + (declare #.*standard-optimize-settings*) + (:documentation "Creates a closure which tries to match REPETITION. It is assumed +that REPETITION has a constant number of repetitions.")) + +(defmethod create-constant-repetition-matcher ((repetition repetition) next-fn) + (declare #.*standard-optimize-settings*) + (let ((repetitions (minimum repetition)) + ;; we make a reservation for our slot in *REPEAT-COUNTERS* + ;; because we need to keep track of the number of repetitions + (rep-num (incf-after *rep-num*)) + ;; REPEAT-MATCHER is part of the closure's environment but it + ;; can only be defined after NON-GREEDY-AUX is defined + repeat-matcher) + (declare (type fixnum repetitions rep-num) + (type function next-fn)) + (if (zerop (min-len repetition)) + ;; we make a reservation for our slot in *LAST-POS-STORES* + ;; because we have to watch out for needless loops as the inner + ;; regex might match zero-length strings + (let ((zero-length-num (incf-after *zero-length-num*))) + (declare (type fixnum zero-length-num)) + (flet ((constant-aux (start-pos) + ;; the actual matcher which first calls NEXT-FN and + ;; on failure tries to match the inner regex of + ;; REPETITION (if we haven't done so too often) + (declare (type fixnum start-pos) + (type function repeat-matcher)) + (let ((old-last-pos + (svref *last-pos-stores* zero-length-num))) + (when (and old-last-pos + (= (the fixnum old-last-pos) start-pos)) + ;; if we've been here before we matched a + ;; zero-length string the last time, so we can + ;; just carry on because we will definitely be + ;; able to do this again often enough + (return-from constant-aux (funcall next-fn start-pos))) + ;; otherwise remember this position for the next + ;; repetition + (setf (svref *last-pos-stores* zero-length-num) start-pos) + (cond ((< (aref *repeat-counters* rep-num) repetitions) + ;; not enough repetitions yet, try it again + (incf (aref *repeat-counters* rep-num)) + ;; note that REPEAT-MATCHER will call + ;; CONSTANT-AUX again recursively + (prog1 + (funcall repeat-matcher start-pos) + (decf (aref *repeat-counters* rep-num)) + (setf (svref *last-pos-stores* zero-length-num) + old-last-pos))) + (t + ;; we're done - call NEXT-FN + (funcall next-fn start-pos)))))) + ;; create a closure to match the inner regex and to + ;; implement backtracking via CONSTANT-AUX + (setq repeat-matcher + (create-matcher-aux (regex repetition) #'constant-aux)) + ;; the closure we return is just a thin wrapper around + ;; CONSTANT-AUX to initialize the repetition counter + (lambda (start-pos) + (declare (type fixnum start-pos)) + (setf (aref *repeat-counters* rep-num) 0 + (aref *last-pos-stores* zero-length-num) nil) + (constant-aux start-pos)))) + ;; easier code because we don't have to care about zero-length + ;; matches but basically the same + (flet ((constant-aux (start-pos) + (declare (type fixnum start-pos) + (type function repeat-matcher)) + (cond ((< (aref *repeat-counters* rep-num) repetitions) + (incf (aref *repeat-counters* rep-num)) + (prog1 + (funcall repeat-matcher start-pos) + (decf (aref *repeat-counters* rep-num)))) + (t (funcall next-fn start-pos))))) + (setq repeat-matcher + (create-matcher-aux (regex repetition) #'constant-aux)) + (lambda (start-pos) + (declare (type fixnum start-pos)) + (setf (aref *repeat-counters* rep-num) 0) + (constant-aux start-pos)))))) + +;; the actual CREATE-MATCHER-AUX method for REPETITION objects which +;; utilizes all the functions and macros defined above + +(defmethod create-matcher-aux ((repetition repetition) next-fn) + (declare #.*standard-optimize-settings*) + (with-slots (minimum maximum len min-len greedyp contains-register-p) + repetition + (cond ((and maximum + (zerop maximum)) + ;; this should have been optimized away by CONVERT but just + ;; in case... + (error "Got REPETITION with MAXIMUM 0 (should not happen)")) + ((and maximum + (= minimum maximum 1)) + ;; this should have been optimized away by CONVERT but just + ;; in case... + (error "Got REPETITION with MAXIMUM 1 and MINIMUM 1 (should not happen)")) + ((and (eql minimum maximum) + len + (not contains-register-p)) + (create-constant-repetition-constant-length-matcher repetition next-fn)) + ((eql minimum maximum) + (create-constant-repetition-matcher repetition next-fn)) + ((and greedyp + len + (not contains-register-p)) + (create-greedy-constant-length-matcher repetition next-fn)) + ((and greedyp + (or (plusp min-len) + (eql maximum 1))) + (create-greedy-no-zero-matcher repetition next-fn)) + (greedyp + (create-greedy-matcher repetition next-fn)) + ((and len + (plusp len) + (not contains-register-p)) + (create-non-greedy-constant-length-matcher repetition next-fn)) + ((or (plusp min-len) + (eql maximum 1)) + (create-non-greedy-no-zero-matcher repetition next-fn)) + (t + (create-non-greedy-matcher repetition next-fn)))))
Added: branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/scanner.lisp =================================================================== --- branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/scanner.lisp 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/scanner.lisp 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,507 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-PPCRE; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/cl-ppcre/scanner.lisp,v 1.28 2007/01/01 23:43:11 edi Exp $ + +;;; Here the scanner for the actual regex as well as utility scanners +;;; for the constant start and end strings are created. + +;;; Copyright (c) 2002-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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-package #:cl-ppcre) + +(defmacro bmh-matcher-aux (&key case-insensitive-p) + "Auxiliary macro used by CREATE-BMH-MATCHER." + (let ((char-compare (if case-insensitive-p 'char-equal 'char=))) + `(lambda (start-pos) + (declare (type fixnum start-pos)) + (if (or (minusp start-pos) + (> (the fixnum (+ start-pos m)) *end-pos*)) + nil + (loop named bmh-matcher + for k of-type fixnum = (+ start-pos m -1) + then (+ k (max 1 (aref skip (char-code (schar *string* k))))) + while (< k *end-pos*) + do (loop for j of-type fixnum downfrom (1- m) + for i of-type fixnum downfrom k + while (and (>= j 0) + (,char-compare (schar *string* i) + (schar pattern j))) + finally (if (minusp j) + (return-from bmh-matcher (1+ i))))))))) + +(defun create-bmh-matcher (pattern case-insensitive-p) + (declare #.*standard-optimize-settings*) + "Returns a Boyer-Moore-Horspool matcher which searches the (special) +simple-string *STRING* for the first occurence of the substring +PATTERN. The search starts at the position START-POS within *STRING* +and stops before *END-POS* is reached. Depending on the second +argument the search is case-insensitive or not. If the special +variable *USE-BMH-MATCHERS* is NIL, use the standard SEARCH function +instead. (BMH matchers are faster but need much more space.)" + ;; see http://www-igm.univ-mlv.fr/~lecroq/string/node18.html for + ;; details + (unless *use-bmh-matchers* + (let ((test (if case-insensitive-p #'char-equal #'char=))) + (return-from create-bmh-matcher + (lambda (start-pos) + (declare (type fixnum start-pos)) + (and (not (minusp start-pos)) + (search pattern + *string* + :start2 start-pos + :end2 *end-pos* + :test test)))))) + (let* ((m (length pattern)) + (skip (make-array *regex-char-code-limit* + :element-type 'fixnum + :initial-element m))) + (declare (type fixnum m)) + (loop for k of-type fixnum below m + if case-insensitive-p + do (setf (aref skip (char-code (char-upcase (schar pattern k)))) (- m k 1) + (aref skip (char-code (char-downcase (schar pattern k)))) (- m k 1)) + else + do (setf (aref skip (char-code (schar pattern k))) (- m k 1))) + (if case-insensitive-p + (bmh-matcher-aux :case-insensitive-p t) + (bmh-matcher-aux)))) + +(defmacro char-searcher-aux (&key case-insensitive-p) + "Auxiliary macro used by CREATE-CHAR-SEARCHER." + (let ((char-compare (if case-insensitive-p 'char-equal 'char=))) + `(lambda (start-pos) + (declare (type fixnum start-pos)) + (and (not (minusp start-pos)) + (loop for i of-type fixnum from start-pos below *end-pos* + thereis (and (,char-compare (schar *string* i) chr) i)))))) + +(defun create-char-searcher (chr case-insensitive-p) + (declare #.*standard-optimize-settings*) + "Returns a function which searches the (special) simple-string +*STRING* for the first occurence of the character CHR. The search +starts at the position START-POS within *STRING* and stops before +*END-POS* is reached. Depending on the second argument the search is +case-insensitive or not." + (if case-insensitive-p + (char-searcher-aux :case-insensitive-p t) + (char-searcher-aux))) + +(declaim (inline newline-skipper)) + +(defun newline-skipper (start-pos) + (declare #.*standard-optimize-settings*) + (declare (type fixnum start-pos)) + "Find the next occurence of a character in *STRING* which is behind +a #\Newline." + ;; we can start with (1- START-POS) without testing for (PLUSP + ;; START-POS) because we know we'll never call NEWLINE-SKIPPER on + ;; the first iteration + (loop for i of-type fixnum from (1- start-pos) below *end-pos* + thereis (and (char= (schar *string* i) + #\Newline) + (1+ i)))) + +(defmacro insert-advance-fn (advance-fn) + "Creates the actual closure returned by CREATE-SCANNER-AUX by +replacing '(ADVANCE-FN-DEFINITION) with a suitable definition for +ADVANCE-FN. This is a utility macro used by CREATE-SCANNER-AUX." + (subst + advance-fn '(advance-fn-definition) + '(lambda (string start end) + (block scan + ;; initialize a couple of special variables used by the + ;; matchers (see file specials.lisp) + (let* ((*string* string) + (*start-pos* start) + (*end-pos* end) + ;; we will search forward for END-STRING if this value + ;; isn't at least as big as POS (see ADVANCE-FN), so it + ;; is safe to start to the left of *START-POS*; note + ;; that this value will _never_ be decremented - this + ;; is crucial to the scanning process + (*end-string-pos* (1- *start-pos*)) + ;; the next five will shadow the variables defined by + ;; DEFPARAMETER; at this point, we don't know if we'll + ;; actually use them, though + (*repeat-counters* *repeat-counters*) + (*last-pos-stores* *last-pos-stores*) + (*reg-starts* *reg-starts*) + (*regs-maybe-start* *regs-maybe-start*) + (*reg-ends* *reg-ends*) + ;; we might be able to optimize the scanning process by + ;; (virtually) shifting *START-POS* to the right + (scan-start-pos *start-pos*) + (starts-with-str (if start-string-test + (str starts-with) + nil)) + ;; we don't need to try further than MAX-END-POS + (max-end-pos (- *end-pos* min-len))) + (declare (type fixnum scan-start-pos) + (type function match-fn)) + ;; definition of ADVANCE-FN will be inserted here by macrology + (labels ((advance-fn-definition)) + (declare (inline advance-fn)) + (when (plusp rep-num) + ;; we have at least one REPETITION which needs to count + ;; the number of repetitions + (setq *repeat-counters* (make-array rep-num + :initial-element 0 + :element-type 'fixnum))) + (when (plusp zero-length-num) + ;; we have at least one REPETITION which needs to watch + ;; out for zero-length repetitions + (setq *last-pos-stores* (make-array zero-length-num + :initial-element nil))) + (when (plusp reg-num) + ;; we have registers in our regular expression + (setq *reg-starts* (make-array reg-num :initial-element nil) + *regs-maybe-start* (make-array reg-num :initial-element nil) + *reg-ends* (make-array reg-num :initial-element nil))) + (when end-anchored-p + ;; the regular expression has a constant end string which + ;; is anchored at the very end of the target string + ;; (perhaps modulo a #\Newline) + (let ((end-test-pos (- *end-pos* (the fixnum end-string-len)))) + (declare (type fixnum end-test-pos) + (type function end-string-test)) + (unless (setq *end-string-pos* (funcall end-string-test + end-test-pos)) + (when (and (= 1 (the fixnum end-anchored-p)) + (> *end-pos* scan-start-pos) + (char= #\Newline (schar *string* (1- *end-pos*)))) + ;; if we didn't find an end string candidate from + ;; END-TEST-POS and if a #\Newline at the end is + ;; allowed we try it again from one position to the + ;; left + (setq *end-string-pos* (funcall end-string-test + (1- end-test-pos)))))) + (unless (and *end-string-pos* + (<= *start-pos* *end-string-pos*)) + ;; no end string candidate found, so give up + (return-from scan nil)) + (when end-string-offset + ;; if the offset of the constant end string from the + ;; left of the regular expression is known we can start + ;; scanning further to the right; this is similar to + ;; what we might do in ADVANCE-FN + (setq scan-start-pos (max scan-start-pos + (- (the fixnum *end-string-pos*) + (the fixnum end-string-offset)))))) + (cond + (start-anchored-p + ;; we're anchored at the start of the target string, + ;; so no need to try again after first failure + (when (or (/= *start-pos* scan-start-pos) + (< max-end-pos *start-pos*)) + ;; if END-STRING-OFFSET has proven that we don't + ;; need to bother to scan from *START-POS* or if the + ;; minimal length of the regular expression is + ;; longer than the target string we give up + (return-from scan nil)) + (when starts-with-str + (locally + (declare (type fixnum starts-with-len)) + (cond ((and (case-insensitive-p starts-with) + (not (*string*-equal starts-with-str + *start-pos* + (+ *start-pos* + starts-with-len) + 0 starts-with-len))) + ;; the regular expression has a + ;; case-insensitive constant start string + ;; and we didn't find it + (return-from scan nil)) + ((and (not (case-insensitive-p starts-with)) + (not (*string*= starts-with-str + *start-pos* + (+ *start-pos* starts-with-len) + 0 starts-with-len))) + ;; the regular expression has a + ;; case-sensitive constant start string + ;; and we didn't find it + (return-from scan nil)) + (t nil)))) + (when (and end-string-test + (not end-anchored-p)) + ;; the regular expression has a constant end string + ;; which isn't anchored so we didn't check for it + ;; already + (block end-string-loop + ;; we temporarily use *END-STRING-POS* as our + ;; starting position to look for end string + ;; candidates + (setq *end-string-pos* *start-pos*) + (loop + (unless (setq *end-string-pos* + (funcall (the function end-string-test) + *end-string-pos*)) + ;; no end string candidate found, so give up + (return-from scan nil)) + (unless end-string-offset + ;; end string doesn't have an offset so we + ;; can start scanning now + (return-from end-string-loop)) + (let ((maybe-start-pos (- (the fixnum *end-string-pos*) + (the fixnum end-string-offset)))) + (cond ((= maybe-start-pos *start-pos*) + ;; offset of end string into regular + ;; expression matches start anchor - + ;; fine... + (return-from end-string-loop)) + ((and (< maybe-start-pos *start-pos*) + (< (+ *end-string-pos* end-string-len) *end-pos*)) + ;; no match but maybe we find another + ;; one to the right - try again + (incf *end-string-pos*)) + (t + ;; otherwise give up + (return-from scan nil))))))) + ;; if we got here we scan exactly once + (let ((next-pos (funcall match-fn *start-pos*))) + (when next-pos + (values (if next-pos *start-pos* nil) + next-pos + *reg-starts* + *reg-ends*)))) + (t + (loop for pos = (if starts-with-everything + ;; don't jump to the next + ;; #\Newline on the first + ;; iteration + scan-start-pos + (advance-fn scan-start-pos)) + then (advance-fn pos) + ;; give up if the regular expression can't fit + ;; into the rest of the target string + while (and pos + (<= (the fixnum pos) max-end-pos)) + do (let ((next-pos (funcall match-fn pos))) + (when next-pos + (return-from scan (values pos + next-pos + *reg-starts* + *reg-ends*))) + ;; not yet found, increment POS + #-cormanlisp (incf (the fixnum pos)) + #+cormanlisp (incf pos))))))))) + :test #'equalp)) + +(defun create-scanner-aux (match-fn + min-len + start-anchored-p + starts-with + start-string-test + end-anchored-p + end-string-test + end-string-len + end-string-offset + rep-num + zero-length-num + reg-num) + (declare #.*standard-optimize-settings*) + (declare (type fixnum min-len zero-length-num rep-num reg-num)) + "Auxiliary function to create and return a scanner (which is +actually a closure). Used by CREATE-SCANNER." + (let ((starts-with-len (if (typep starts-with 'str) + (len starts-with))) + (starts-with-everything (typep starts-with 'everything))) + (cond + ;; this COND statement dispatches on the different versions we + ;; have for ADVANCE-FN and creates different closures for each; + ;; note that you see only the bodies of ADVANCE-FN below - the + ;; actual scanner is defined in INSERT-ADVANCE-FN above; (we + ;; could have done this with closures instead of macrology but + ;; would have consed a lot more) + ((and start-string-test end-string-test end-string-offset) + ;; we know that the regular expression has constant start and + ;; end strings and we know the end string's offset (from the + ;; left) + (insert-advance-fn + (advance-fn (pos) + (declare (type fixnum end-string-offset starts-with-len) + (type function start-string-test end-string-test)) + (loop + (unless (setq pos (funcall start-string-test pos)) + ;; give up completely if we can't find a start string + ;; candidate + (return-from scan nil)) + (locally + ;; from here we know that POS is a FIXNUM + (declare (type fixnum pos)) + (when (= pos (- (the fixnum *end-string-pos*) end-string-offset)) + ;; if we already found an end string candidate the + ;; position of which matches the start string + ;; candidate we're done + (return-from advance-fn pos)) + (let ((try-pos (+ pos starts-with-len))) + ;; otherwise try (again) to find an end string + ;; candidate which starts behind the start string + ;; candidate + (loop + (unless (setq *end-string-pos* + (funcall end-string-test try-pos)) + ;; no end string candidate found, so give up + (return-from scan nil)) + ;; NEW-POS is where we should start scanning + ;; according to the end string candidate + (let ((new-pos (- (the fixnum *end-string-pos*) + end-string-offset))) + (declare (type fixnum new-pos *end-string-pos*)) + (cond ((= new-pos pos) + ;; if POS and NEW-POS are equal then the + ;; two candidates agree so we're fine + (return-from advance-fn pos)) + ((> new-pos pos) + ;; if NEW-POS is further to the right we + ;; advance POS and try again, i.e. we go + ;; back to the start of the outer LOOP + (setq pos new-pos) + ;; this means "return from inner LOOP" + (return)) + (t + ;; otherwise NEW-POS is smaller than POS, + ;; so we have to redo the inner LOOP to + ;; find another end string candidate + ;; further to the right + (setq try-pos (1+ *end-string-pos*)))))))))))) + ((and starts-with-everything end-string-test end-string-offset) + ;; we know that the regular expression starts with ".*" (which + ;; is not in single-line-mode, see CREATE-SCANNER-AUX) and ends + ;; with a constant end string and we know the end string's + ;; offset (from the left) + (insert-advance-fn + (advance-fn (pos) + (declare (type fixnum end-string-offset) + (type function end-string-test)) + (loop + (unless (setq pos (newline-skipper pos)) + ;; if we can't find a #\Newline we give up immediately + (return-from scan nil)) + (locally + ;; from here we know that POS is a FIXNUM + (declare (type fixnum pos)) + (when (= pos (- (the fixnum *end-string-pos*) end-string-offset)) + ;; if we already found an end string candidate the + ;; position of which matches the place behind the + ;; #\Newline we're done + (return-from advance-fn pos)) + (let ((try-pos pos)) + ;; otherwise try (again) to find an end string + ;; candidate which starts behind the #\Newline + (loop + (unless (setq *end-string-pos* + (funcall end-string-test try-pos)) + ;; no end string candidate found, so we give up + (return-from scan nil)) + ;; NEW-POS is where we should start scanning + ;; according to the end string candidate + (let ((new-pos (- (the fixnum *end-string-pos*) + end-string-offset))) + (declare (type fixnum new-pos *end-string-pos*)) + (cond ((= new-pos pos) + ;; if POS and NEW-POS are equal then the + ;; the end string candidate agrees with + ;; the #\Newline so we're fine + (return-from advance-fn pos)) + ((> new-pos pos) + ;; if NEW-POS is further to the right we + ;; advance POS and try again, i.e. we go + ;; back to the start of the outer LOOP + (setq pos new-pos) + ;; this means "return from inner LOOP" + (return)) + (t + ;; otherwise NEW-POS is smaller than POS, + ;; so we have to redo the inner LOOP to + ;; find another end string candidate + ;; further to the right + (setq try-pos (1+ *end-string-pos*)))))))))))) + ((and start-string-test end-string-test) + ;; we know that the regular expression has constant start and + ;; end strings; similar to the first case but we only need to + ;; check for the end string, it doesn't provide enough + ;; information to advance POS + (insert-advance-fn + (advance-fn (pos) + (declare (type function start-string-test end-string-test)) + (unless (setq pos (funcall start-string-test pos)) + (return-from scan nil)) + (if (<= (the fixnum pos) + (the fixnum *end-string-pos*)) + (return-from advance-fn pos)) + (unless (setq *end-string-pos* (funcall end-string-test pos)) + (return-from scan nil)) + pos))) + ((and starts-with-everything end-string-test) + ;; we know that the regular expression starts with ".*" (which + ;; is not in single-line-mode, see CREATE-SCANNER-AUX) and ends + ;; with a constant end string; similar to the second case but we + ;; only need to check for the end string, it doesn't provide + ;; enough information to advance POS + (insert-advance-fn + (advance-fn (pos) + (declare (type function end-string-test)) + (unless (setq pos (newline-skipper pos)) + (return-from scan nil)) + (if (<= (the fixnum pos) + (the fixnum *end-string-pos*)) + (return-from advance-fn pos)) + (unless (setq *end-string-pos* (funcall end-string-test pos)) + (return-from scan nil)) + pos))) + (start-string-test + ;; just check for constant start string candidate + (insert-advance-fn + (advance-fn (pos) + (declare (type function start-string-test)) + (unless (setq pos (funcall start-string-test pos)) + (return-from scan nil)) + pos))) + (starts-with-everything + ;; just advance POS with NEWLINE-SKIPPER + (insert-advance-fn + (advance-fn (pos) + (unless (setq pos (newline-skipper pos)) + (return-from scan nil)) + pos))) + (end-string-test + ;; just check for the next end string candidate if POS has + ;; advanced beyond the last one + (insert-advance-fn + (advance-fn (pos) + (declare (type function end-string-test)) + (if (<= (the fixnum pos) + (the fixnum *end-string-pos*)) + (return-from advance-fn pos)) + (unless (setq *end-string-pos* (funcall end-string-test pos)) + (return-from scan nil)) + pos))) + (t + ;; not enough optimization information about the regular + ;; expression to optimize so we just return POS + (insert-advance-fn + (advance-fn (pos) + pos))))))
Added: branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/specials.lisp =================================================================== --- branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/specials.lisp 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/specials.lisp 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,147 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-PPCRE; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/cl-ppcre/specials.lisp,v 1.25 2007/03/24 23:52:45 edi Exp $ + +;;; globally declared special variables + +;;; Copyright (c) 2002-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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-package #:cl-ppcre) + +;;; special variables used to effect declarations + +(defvar *standard-optimize-settings* + '(optimize + speed + (safety 0) + (space 0) + (debug 1) + (compilation-speed 0) + #+:lispworks (hcl:fixnum-safety 0)) + "The standard optimize settings used by most declaration expressions.") + +(defvar *special-optimize-settings* + '(optimize speed space) + "Special optimize settings used only by a few declaration expressions.") + +;;; special variables used by the lexer/parser combo + +(defvar *extended-mode-p* nil + "Whether the parser will start in extended mode.") +(declaim (type boolean *extended-mode-p*)) + +;;; special variables used by the SCAN function and the matchers + +(defvar *string* "" + "The string which is currently scanned by SCAN. +Will always be coerced to a SIMPLE-STRING.") +(declaim (type simple-string *string*)) + +(defvar *start-pos* 0 + "Where to start scanning within *STRING*.") +(declaim (type fixnum *start-pos*)) + +(defvar *real-start-pos* nil + "The real start of *STRING*. This is for repeated scans and is only used internally.") +(declaim (type (or null fixnum) *real-start-pos*)) + +(defvar *end-pos* 0 + "Where to stop scanning within *STRING*.") +(declaim (type fixnum *end-pos*)) + +(defvar *reg-starts* (make-array 0) + "An array which holds the start positions +of the current register candidates.") +(declaim (type simple-vector *reg-starts*)) + +(defvar *regs-maybe-start* (make-array 0) + "An array which holds the next start positions +of the current register candidates.") +(declaim (type simple-vector *regs-maybe-start*)) + +(defvar *reg-ends* (make-array 0) + "An array which holds the end positions +of the current register candidates.") +(declaim (type simple-vector *reg-ends*)) + +(defvar *end-string-pos* nil + "Start of the next possible end-string candidate.") + +(defvar *rep-num* 0 + "Counts the number of "complicated" repetitions while the matchers +are built.") +(declaim (type fixnum *rep-num*)) + +(defvar *zero-length-num* 0 + "Counts the number of repetitions the inner regexes of which may +have zero-length while the matchers are built.") +(declaim (type fixnum *zero-length-num*)) + +(defvar *repeat-counters* (make-array 0 + :initial-element 0 + :element-type 'fixnum) + "An array to keep track of how often +repetitive patterns have been tested already.") +(declaim (type (array fixnum (*)) *repeat-counters*)) + +(defvar *last-pos-stores* (make-array 0) + "An array to keep track of the last positions +where we saw repetitive patterns. +Only used for patterns which might have zero length.") +(declaim (type simple-vector *last-pos-stores*)) + +(defvar *use-bmh-matchers* t + "Whether the scanners created by CREATE-SCANNER should use the (fast +but large) Boyer-Moore-Horspool matchers.") + +(defvar *allow-quoting* nil + "Whether the parser should support Perl's \Q and \E.") + +(defvar *allow-named-registers* nil + "Whether the parser should support AllegroCL's named registers +(?<name>"<regex>") and back-reference \k<name> syntax.") + +(pushnew :cl-ppcre *features*) + +;; stuff for Nikodemus Siivola's HYPERDOC +;; see http://common-lisp.net/project/hyperdoc/ +;; and http://www.cliki.net/hyperdoc +;; also used by LW-ADD-ONS + +(defvar *hyperdoc-base-uri* "http://weitz.de/cl-ppcre/") + +(let ((exported-symbols-alist + (loop for symbol being the external-symbols of :cl-ppcre + collect (cons symbol + (concatenate 'string + "#" + (string-downcase symbol)))))) + (defun hyperdoc-lookup (symbol type) + (declare (ignore type)) + (cdr (assoc symbol + exported-symbols-alist + :test #'eq)))) +
Added: branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/testdata =================================================================== --- branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/testdata 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/testdata 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,14288 @@ +(1 ""the quick brown fox" =~ /the quick brown fox/" "the quick brown fox" nil nil nil nil "the quick brown fox" nil 1 0 "the quick brown fox" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(2 ""The quick brown FOX" =~ /the quick brown fox/" "the quick brown fox" nil nil nil nil "The quick brown FOX" nil 1 0 nil nil) +(3 ""What do you know about the quick brown fox?" =~ /the quick brown fox/" "the quick brown fox" nil nil nil nil "What do you know about the quick brown fox?" nil 1 0 "the quick brown fox" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(4 ""What do you know about THE QUICK BROWN FOX?" =~ /the quick brown fox/" "the quick brown fox" nil nil nil nil "What do you know about THE QUICK BROWN FOX?" nil 1 0 nil nil) +(5 ""the quick brown fox" =~ /The quick brown fox/i" "The quick brown fox" t nil nil nil "the quick brown fox" nil 1 0 "the quick brown fox" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(6 ""The quick brown FOX" =~ /The quick brown fox/i" "The quick brown fox" t nil nil nil "The quick brown FOX" nil 1 0 "The quick brown FOX" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(7 ""What do you know about the quick brown fox?" =~ /The quick brown fox/i" "The quick brown fox" t nil nil nil "What do you know about the quick brown fox?" nil 1 0 "the quick brown fox" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(8 ""What do you know about THE QUICK BROWN FOX?" =~ /The quick brown fox/i" "The quick brown fox" t nil nil nil "What do you know about THE QUICK BROWN FOX?" nil 1 0 "THE QUICK BROWN FOX" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(9 ""abcd\t\n\r\f\a\e9;\$\\?caxyz" =~ /abcd\t\n\r\f\a\e\071\x3b\$\\\?caxyz/" "abcd\t\n\r\f\a\e\071\x3b\$\\\?caxyz" nil nil nil nil ("abcd" 9 10 13 12 7 27 "9;$\?caxyz") nil 1 0 ("abcd" 9 10 13 12 7 27 "9;$\?caxyz") (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(10 ""abxyzpqrrrabbxyyyypqAzz" =~ /a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/" "a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz" nil nil nil nil "abxyzpqrrrabbxyyyypqAzz" nil 1 0 "abxyzpqrrrabbxyyyypqAzz" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(11 ""abxyzpqrrrabbxyyyypqAzz" =~ /a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/" "a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz" nil nil nil nil "abxyzpqrrrabbxyyyypqAzz" nil 1 0 "abxyzpqrrrabbxyyyypqAzz" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(12 ""aabxyzpqrrrabbxyyyypqAzz" =~ /a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/" "a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz" nil nil nil nil "aabxyzpqrrrabbxyyyypqAzz" nil 1 0 "aabxyzpqrrrabbxyyyypqAzz" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(13 ""aaabxyzpqrrrabbxyyyypqAzz" =~ /a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/" "a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz" nil nil nil nil "aaabxyzpqrrrabbxyyyypqAzz" nil 1 0 "aaabxyzpqrrrabbxyyyypqAzz" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(14 ""aaaabxyzpqrrrabbxyyyypqAzz" =~ /a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/" "a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz" nil nil nil nil "aaaabxyzpqrrrabbxyyyypqAzz" nil 1 0 "aaaabxyzpqrrrabbxyyyypqAzz" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(15 ""abcxyzpqrrrabbxyyyypqAzz" =~ /a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/" "a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz" nil nil nil nil "abcxyzpqrrrabbxyyyypqAzz" nil 1 0 "abcxyzpqrrrabbxyyyypqAzz" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(16 ""aabcxyzpqrrrabbxyyyypqAzz" =~ /a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/" "a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz" nil nil nil nil "aabcxyzpqrrrabbxyyyypqAzz" nil 1 0 "aabcxyzpqrrrabbxyyyypqAzz" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(17 ""aaabcxyzpqrrrabbxyyyypAzz" =~ /a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/" "a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz" nil nil nil nil "aaabcxyzpqrrrabbxyyyypAzz" nil 1 0 "aaabcxyzpqrrrabbxyyyypAzz" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(18 ""aaabcxyzpqrrrabbxyyyypqAzz" =~ /a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/" "a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz" nil nil nil nil "aaabcxyzpqrrrabbxyyyypqAzz" nil 1 0 "aaabcxyzpqrrrabbxyyyypqAzz" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(19 ""aaabcxyzpqrrrabbxyyyypqqAzz" =~ /a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/" "a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz" nil nil nil nil "aaabcxyzpqrrrabbxyyyypqqAzz" nil 1 0 "aaabcxyzpqrrrabbxyyyypqqAzz" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(20 ""aaabcxyzpqrrrabbxyyyypqqqAzz" =~ /a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/" "a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz" nil nil nil nil "aaabcxyzpqrrrabbxyyyypqqqAzz" nil 1 0 "aaabcxyzpqrrrabbxyyyypqqqAzz" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(21 ""aaabcxyzpqrrrabbxyyyypqqqqAzz" =~ /a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/" "a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz" nil nil nil nil "aaabcxyzpqrrrabbxyyyypqqqqAzz" nil 1 0 "aaabcxyzpqrrrabbxyyyypqqqqAzz" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(22 ""aaabcxyzpqrrrabbxyyyypqqqqqAzz" =~ /a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/" "a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz" nil nil nil nil "aaabcxyzpqrrrabbxyyyypqqqqqAzz" nil 1 0 "aaabcxyzpqrrrabbxyyyypqqqqqAzz" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(23 ""aaabcxyzpqrrrabbxyyyypqqqqqqAzz" =~ /a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/" "a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz" nil nil nil nil "aaabcxyzpqrrrabbxyyyypqqqqqqAzz" nil 1 0 "aaabcxyzpqrrrabbxyyyypqqqqqqAzz" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(24 ""aaaabcxyzpqrrrabbxyyyypqAzz" =~ /a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/" "a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz" nil nil nil nil "aaaabcxyzpqrrrabbxyyyypqAzz" nil 1 0 "aaaabcxyzpqrrrabbxyyyypqAzz" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(25 ""abxyzzpqrrrabbxyyyypqAzz" =~ /a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/" "a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz" nil nil nil nil "abxyzzpqrrrabbxyyyypqAzz" nil 1 0 "abxyzzpqrrrabbxyyyypqAzz" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(26 ""aabxyzzzpqrrrabbxyyyypqAzz" =~ /a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/" "a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz" nil nil nil nil "aabxyzzzpqrrrabbxyyyypqAzz" nil 1 0 "aabxyzzzpqrrrabbxyyyypqAzz" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(27 ""aaabxyzzzzpqrrrabbxyyyypqAzz" =~ /a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/" "a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz" nil nil nil nil "aaabxyzzzzpqrrrabbxyyyypqAzz" nil 1 0 "aaabxyzzzzpqrrrabbxyyyypqAzz" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(28 ""aaaabxyzzzzpqrrrabbxyyyypqAzz" =~ /a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/" "a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz" nil nil nil nil "aaaabxyzzzzpqrrrabbxyyyypqAzz" nil 1 0 "aaaabxyzzzzpqrrrabbxyyyypqAzz" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(29 ""abcxyzzpqrrrabbxyyyypqAzz" =~ /a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/" "a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz" nil nil nil nil "abcxyzzpqrrrabbxyyyypqAzz" nil 1 0 "abcxyzzpqrrrabbxyyyypqAzz" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(30 ""aabcxyzzzpqrrrabbxyyyypqAzz" =~ /a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/" "a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz" nil nil nil nil "aabcxyzzzpqrrrabbxyyyypqAzz" nil 1 0 "aabcxyzzzpqrrrabbxyyyypqAzz" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(31 ""aaabcxyzzzzpqrrrabbxyyyypqAzz" =~ /a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/" "a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz" nil nil nil nil "aaabcxyzzzzpqrrrabbxyyyypqAzz" nil 1 0 "aaabcxyzzzzpqrrrabbxyyyypqAzz" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(32 ""aaaabcxyzzzzpqrrrabbxyyyypqAzz" =~ /a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/" "a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz" nil nil nil nil "aaaabcxyzzzzpqrrrabbxyyyypqAzz" nil 1 0 "aaaabcxyzzzzpqrrrabbxyyyypqAzz" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(33 ""aaaabcxyzzzzpqrrrabbbxyyyypqAzz" =~ /a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/" "a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz" nil nil nil nil "aaaabcxyzzzzpqrrrabbbxyyyypqAzz" nil 1 0 "aaaabcxyzzzzpqrrrabbbxyyyypqAzz" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(34 ""aaaabcxyzzzzpqrrrabbbxyyyyypqAzz" =~ /a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/" "a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz" nil nil nil nil "aaaabcxyzzzzpqrrrabbbxyyyyypqAzz" nil 1 0 "aaaabcxyzzzzpqrrrabbbxyyyyypqAzz" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(35 ""aaabcxyzpqrrrabbxyyyypABzz" =~ /a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/" "a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz" nil nil nil nil "aaabcxyzpqrrrabbxyyyypABzz" nil 1 0 "aaabcxyzpqrrrabbxyyyypABzz" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(36 ""aaabcxyzpqrrrabbxyyyypABBzz" =~ /a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/" "a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz" nil nil nil nil "aaabcxyzpqrrrabbxyyyypABBzz" nil 1 0 "aaabcxyzpqrrrabbxyyyypABBzz" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(37 "">>>aaabxyzpqrrrabbxyyyypqAzz" =~ /a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/" "a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz" nil nil nil nil ">>>aaabxyzpqrrrabbxyyyypqAzz" nil 1 0 "aaabxyzpqrrrabbxyyyypqAzz" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(38 "">aaaabxyzpqrrrabbxyyyypqAzz" =~ /a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/" "a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz" nil nil nil nil ">aaaabxyzpqrrrabbxyyyypqAzz" nil 1 0 "aaaabxyzpqrrrabbxyyyypqAzz" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(39 "">>>>abcxyzpqrrrabbxyyyypqAzz" =~ /a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/" "a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz" nil nil nil nil ">>>>abcxyzpqrrrabbxyyyypqAzz" nil 1 0 "abcxyzpqrrrabbxyyyypqAzz" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(40 ""abxyzpqrrabbxyyyypqAzz" =~ /a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/" "a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz" nil nil nil nil "abxyzpqrrabbxyyyypqAzz" nil 1 0 nil nil) +(41 ""abxyzpqrrrrabbxyyyypqAzz" =~ /a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/" "a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz" nil nil nil nil "abxyzpqrrrrabbxyyyypqAzz" nil 1 0 nil nil) +(42 ""abxyzpqrrrabxyyyypqAzz" =~ /a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/" "a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz" nil nil nil nil "abxyzpqrrrabxyyyypqAzz" nil 1 0 nil nil) +(43 ""aaaabcxyzzzzpqrrrabbbxyyyyyypqAzz" =~ /a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/" "a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz" nil nil nil nil "aaaabcxyzzzzpqrrrabbbxyyyyyypqAzz" nil 1 0 nil nil) +(44 ""aaaabcxyzzzzpqrrrabbbxyyypqAzz" =~ /a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/" "a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz" nil nil nil nil "aaaabcxyzzzzpqrrrabbbxyyypqAzz" nil 1 0 nil nil) +(45 ""aaabcxyzpqrrrabbxyyyypqqqqqqqAzz" =~ /a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/" "a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz" nil nil nil nil "aaabcxyzpqrrrabbxyyyypqqqqqqqAzz" nil 1 0 nil nil) +(46 ""abczz" =~ /^(abc){1,2}zz/" "^(abc){1,2}zz" nil nil nil nil "abczz" nil 1 0 "abczz" ("abc" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(47 ""abcabczz" =~ /^(abc){1,2}zz/" "^(abc){1,2}zz" nil nil nil nil "abcabczz" nil 1 0 "abcabczz" ("abc" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(48 ""zz" =~ /^(abc){1,2}zz/" "^(abc){1,2}zz" nil nil nil nil "zz" nil 1 0 nil nil) +(49 ""abcabcabczz" =~ /^(abc){1,2}zz/" "^(abc){1,2}zz" nil nil nil nil "abcabcabczz" nil 1 0 nil nil) +(50 "">>abczz" =~ /^(abc){1,2}zz/" "^(abc){1,2}zz" nil nil nil nil ">>abczz" nil 1 0 nil nil) +(51 ""bc" =~ /^(b+?|a){1,2}?c/" "^(b+?|a){1,2}?c" nil nil nil nil "bc" nil 1 0 "bc" ("b" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(52 ""bbc" =~ /^(b+?|a){1,2}?c/" "^(b+?|a){1,2}?c" nil nil nil nil "bbc" nil 1 0 "bbc" ("b" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(53 ""bbbc" =~ /^(b+?|a){1,2}?c/" "^(b+?|a){1,2}?c" nil nil nil nil "bbbc" nil 1 0 "bbbc" ("bb" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(54 ""bac" =~ /^(b+?|a){1,2}?c/" "^(b+?|a){1,2}?c" nil nil nil nil "bac" nil 1 0 "bac" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(55 ""bbac" =~ /^(b+?|a){1,2}?c/" "^(b+?|a){1,2}?c" nil nil nil nil "bbac" nil 1 0 "bbac" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(56 ""aac" =~ /^(b+?|a){1,2}?c/" "^(b+?|a){1,2}?c" nil nil nil nil "aac" nil 1 0 "aac" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(57 ""abbbbbbbbbbbc" =~ /^(b+?|a){1,2}?c/" "^(b+?|a){1,2}?c" nil nil nil nil "abbbbbbbbbbbc" nil 1 0 "abbbbbbbbbbbc" ("bbbbbbbbbbb" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(58 ""bbbbbbbbbbbac" =~ /^(b+?|a){1,2}?c/" "^(b+?|a){1,2}?c" nil nil nil nil "bbbbbbbbbbbac" nil 1 0 "bbbbbbbbbbbac" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(59 ""aaac" =~ /^(b+?|a){1,2}?c/" "^(b+?|a){1,2}?c" nil nil nil nil "aaac" nil 1 0 nil nil) +(60 ""abbbbbbbbbbbac" =~ /^(b+?|a){1,2}?c/" "^(b+?|a){1,2}?c" nil nil nil nil "abbbbbbbbbbbac" nil 1 0 nil nil) +(61 ""bc" =~ /^(b+|a){1,2}c/" "^(b+|a){1,2}c" nil nil nil nil "bc" nil 1 0 "bc" ("b" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(62 ""bbc" =~ /^(b+|a){1,2}c/" "^(b+|a){1,2}c" nil nil nil nil "bbc" nil 1 0 "bbc" ("bb" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(63 ""bbbc" =~ /^(b+|a){1,2}c/" "^(b+|a){1,2}c" nil nil nil nil "bbbc" nil 1 0 "bbbc" ("bbb" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(64 ""bac" =~ /^(b+|a){1,2}c/" "^(b+|a){1,2}c" nil nil nil nil "bac" nil 1 0 "bac" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(65 ""bbac" =~ /^(b+|a){1,2}c/" "^(b+|a){1,2}c" nil nil nil nil "bbac" nil 1 0 "bbac" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(66 ""aac" =~ /^(b+|a){1,2}c/" "^(b+|a){1,2}c" nil nil nil nil "aac" nil 1 0 "aac" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(67 ""abbbbbbbbbbbc" =~ /^(b+|a){1,2}c/" "^(b+|a){1,2}c" nil nil nil nil "abbbbbbbbbbbc" nil 1 0 "abbbbbbbbbbbc" ("bbbbbbbbbbb" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(68 ""bbbbbbbbbbbac" =~ /^(b+|a){1,2}c/" "^(b+|a){1,2}c" nil nil nil nil "bbbbbbbbbbbac" nil 1 0 "bbbbbbbbbbbac" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(69 ""aaac" =~ /^(b+|a){1,2}c/" "^(b+|a){1,2}c" nil nil nil nil "aaac" nil 1 0 nil nil) +(70 ""abbbbbbbbbbbac" =~ /^(b+|a){1,2}c/" "^(b+|a){1,2}c" nil nil nil nil "abbbbbbbbbbbac" nil 1 0 nil nil) +(71 ""bbc" =~ /^(b+|a){1,2}?bc/" "^(b+|a){1,2}?bc" nil nil nil nil "bbc" nil 1 0 "bbc" ("b" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(72 ""babc" =~ /^(b*|ba){1,2}?bc/" "^(b*|ba){1,2}?bc" nil nil nil nil "babc" nil 1 0 "babc" ("ba" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(73 ""bbabc" =~ /^(b*|ba){1,2}?bc/" "^(b*|ba){1,2}?bc" nil nil nil nil "bbabc" nil 1 0 "bbabc" ("ba" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(74 ""bababc" =~ /^(b*|ba){1,2}?bc/" "^(b*|ba){1,2}?bc" nil nil nil nil "bababc" nil 1 0 "bababc" ("ba" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(75 ""bababbc" =~ /^(b*|ba){1,2}?bc/" "^(b*|ba){1,2}?bc" nil nil nil nil "bababbc" nil 1 0 nil nil) +(76 ""babababc" =~ /^(b*|ba){1,2}?bc/" "^(b*|ba){1,2}?bc" nil nil nil nil "babababc" nil 1 0 nil nil) +(77 ""babc" =~ /^(ba|b*){1,2}?bc/" "^(ba|b*){1,2}?bc" nil nil nil nil "babc" nil 1 0 "babc" ("ba" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(78 ""bbabc" =~ /^(ba|b*){1,2}?bc/" "^(ba|b*){1,2}?bc" nil nil nil nil "bbabc" nil 1 0 "bbabc" ("ba" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(79 ""bababc" =~ /^(ba|b*){1,2}?bc/" "^(ba|b*){1,2}?bc" nil nil nil nil "bababc" nil 1 0 "bababc" ("ba" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(80 ""bababbc" =~ /^(ba|b*){1,2}?bc/" "^(ba|b*){1,2}?bc" nil nil nil nil "bababbc" nil 1 0 nil nil) +(81 ""babababc" =~ /^(ba|b*){1,2}?bc/" "^(ba|b*){1,2}?bc" nil nil nil nil "babababc" nil 1 0 nil nil) +(82 ""\x01\x01\e;z" =~ /^\ca\cA\c[\c{\c:/" "^\ca\cA\c[\c{\c:" nil nil nil nil ("" 1 1 27 ";z") nil 1 0 ("" 1 1 27 ";z") (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(83 ""athing" =~ /^[ab\]cde]/" "^[ab\]cde]" nil nil nil nil "athing" nil 1 0 "a" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(84 ""bthing" =~ /^[ab\]cde]/" "^[ab\]cde]" nil nil nil nil "bthing" nil 1 0 "b" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(85 ""]thing" =~ /^[ab\]cde]/" "^[ab\]cde]" nil nil nil nil "]thing" nil 1 0 "]" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(86 ""cthing" =~ /^[ab\]cde]/" "^[ab\]cde]" nil nil nil nil "cthing" nil 1 0 "c" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(87 ""dthing" =~ /^[ab\]cde]/" "^[ab\]cde]" nil nil nil nil "dthing" nil 1 0 "d" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(88 ""ething" =~ /^[ab\]cde]/" "^[ab\]cde]" nil nil nil nil "ething" nil 1 0 "e" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(89 ""fthing" =~ /^[ab\]cde]/" "^[ab\]cde]" nil nil nil nil "fthing" nil 1 0 nil nil) +(90 ""[thing" =~ /^[ab\]cde]/" "^[ab\]cde]" nil nil nil nil "[thing" nil 1 0 nil nil) +(91 ""\\thing" =~ /^[ab\]cde]/" "^[ab\]cde]" nil nil nil nil "\thing" nil 1 0 nil nil) +(92 ""]thing" =~ /^[]cde]/" "^[]cde]" nil nil nil nil "]thing" nil 1 0 "]" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(93 ""cthing" =~ /^[]cde]/" "^[]cde]" nil nil nil nil "cthing" nil 1 0 "c" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(94 ""dthing" =~ /^[]cde]/" "^[]cde]" nil nil nil nil "dthing" nil 1 0 "d" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(95 ""ething" =~ /^[]cde]/" "^[]cde]" nil nil nil nil "ething" nil 1 0 "e" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(96 ""athing" =~ /^[]cde]/" "^[]cde]" nil nil nil nil "athing" nil 1 0 nil nil) +(97 ""fthing" =~ /^[]cde]/" "^[]cde]" nil nil nil nil "fthing" nil 1 0 nil nil) +(98 ""fthing" =~ /^[^ab\]cde]/" "^[^ab\]cde]" nil nil nil nil "fthing" nil 1 0 "f" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(99 ""[thing" =~ /^[^ab\]cde]/" "^[^ab\]cde]" nil nil nil nil "[thing" nil 1 0 "[" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(100 ""\\thing" =~ /^[^ab\]cde]/" "^[^ab\]cde]" nil nil nil nil "\thing" nil 1 0 "\" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(101 ""athing" =~ /^[^ab\]cde]/" "^[^ab\]cde]" nil nil nil nil "athing" nil 1 0 nil nil) +(102 ""bthing" =~ /^[^ab\]cde]/" "^[^ab\]cde]" nil nil nil nil "bthing" nil 1 0 nil nil) +(103 ""]thing" =~ /^[^ab\]cde]/" "^[^ab\]cde]" nil nil nil nil "]thing" nil 1 0 nil nil) +(104 ""cthing" =~ /^[^ab\]cde]/" "^[^ab\]cde]" nil nil nil nil "cthing" nil 1 0 nil nil) +(105 ""dthing" =~ /^[^ab\]cde]/" "^[^ab\]cde]" nil nil nil nil "dthing" nil 1 0 nil nil) +(106 ""ething" =~ /^[^ab\]cde]/" "^[^ab\]cde]" nil nil nil nil "ething" nil 1 0 nil nil) +(107 ""athing" =~ /^[^]cde]/" "^[^]cde]" nil nil nil nil "athing" nil 1 0 "a" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(108 ""fthing" =~ /^[^]cde]/" "^[^]cde]" nil nil nil nil "fthing" nil 1 0 "f" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(109 ""]thing" =~ /^[^]cde]/" "^[^]cde]" nil nil nil nil "]thing" nil 1 0 nil nil) +(110 ""cthing" =~ /^[^]cde]/" "^[^]cde]" nil nil nil nil "cthing" nil 1 0 nil nil) +(111 ""dthing" =~ /^[^]cde]/" "^[^]cde]" nil nil nil nil "dthing" nil 1 0 nil nil) +(112 ""ething" =~ /^[^]cde]/" "^[^]cde]" nil nil nil nil "ething" nil 1 0 nil nil) +(113 (""" 129 "" =~ /^\" 129 "/") "^\�" nil nil nil nil ("" 129) nil 1 0 ("" 129) (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(114 (""" 255 "" =~ /^" 255 "/") "^�" nil nil nil nil ("" 255) nil 1 0 ("" 255) (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(115 ""0" =~ /^[0-9]+$/" "^[0-9]+$" nil nil nil nil "0" nil 1 0 "0" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(116 ""1" =~ /^[0-9]+$/" "^[0-9]+$" nil nil nil nil "1" nil 1 0 "1" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(117 ""2" =~ /^[0-9]+$/" "^[0-9]+$" nil nil nil nil "2" nil 1 0 "2" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(118 ""3" =~ /^[0-9]+$/" "^[0-9]+$" nil nil nil nil "3" nil 1 0 "3" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(119 ""4" =~ /^[0-9]+$/" "^[0-9]+$" nil nil nil nil "4" nil 1 0 "4" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(120 ""5" =~ /^[0-9]+$/" "^[0-9]+$" nil nil nil nil "5" nil 1 0 "5" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(121 ""6" =~ /^[0-9]+$/" "^[0-9]+$" nil nil nil nil "6" nil 1 0 "6" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(122 ""7" =~ /^[0-9]+$/" "^[0-9]+$" nil nil nil nil "7" nil 1 0 "7" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(123 ""8" =~ /^[0-9]+$/" "^[0-9]+$" nil nil nil nil "8" nil 1 0 "8" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(124 ""9" =~ /^[0-9]+$/" "^[0-9]+$" nil nil nil nil "9" nil 1 0 "9" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(125 ""10" =~ /^[0-9]+$/" "^[0-9]+$" nil nil nil nil "10" nil 1 0 "10" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(126 ""100" =~ /^[0-9]+$/" "^[0-9]+$" nil nil nil nil "100" nil 1 0 "100" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(127 ""abc" =~ /^[0-9]+$/" "^[0-9]+$" nil nil nil nil "abc" nil 1 0 nil nil) +(128 ""enter" =~ /^.*nter/" "^.*nter" nil nil nil nil "enter" nil 1 0 "enter" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(129 ""inter" =~ /^.*nter/" "^.*nter" nil nil nil nil "inter" nil 1 0 "inter" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(130 ""uponter" =~ /^.*nter/" "^.*nter" nil nil nil nil "uponter" nil 1 0 "uponter" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(131 ""xxx0" =~ /^xxx[0-9]+$/" "^xxx[0-9]+$" nil nil nil nil "xxx0" nil 1 0 "xxx0" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(132 ""xxx1234" =~ /^xxx[0-9]+$/" "^xxx[0-9]+$" nil nil nil nil "xxx1234" nil 1 0 "xxx1234" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(133 ""xxx" =~ /^xxx[0-9]+$/" "^xxx[0-9]+$" nil nil nil nil "xxx" nil 1 0 nil nil) +(134 ""x123" =~ /^.+[0-9][0-9][0-9]$/" "^.+[0-9][0-9][0-9]$" nil nil nil nil "x123" nil 1 0 "x123" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(135 ""xx123" =~ /^.+[0-9][0-9][0-9]$/" "^.+[0-9][0-9][0-9]$" nil nil nil nil "xx123" nil 1 0 "xx123" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(136 ""123456" =~ /^.+[0-9][0-9][0-9]$/" "^.+[0-9][0-9][0-9]$" nil nil nil nil "123456" nil 1 0 "123456" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(137 ""123" =~ /^.+[0-9][0-9][0-9]$/" "^.+[0-9][0-9][0-9]$" nil nil nil nil "123" nil 1 0 nil nil) +(138 ""x1234" =~ /^.+[0-9][0-9][0-9]$/" "^.+[0-9][0-9][0-9]$" nil nil nil nil "x1234" nil 1 0 "x1234" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(139 ""x123" =~ /^.+?[0-9][0-9][0-9]$/" "^.+?[0-9][0-9][0-9]$" nil nil nil nil "x123" nil 1 0 "x123" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(140 ""xx123" =~ /^.+?[0-9][0-9][0-9]$/" "^.+?[0-9][0-9][0-9]$" nil nil nil nil "xx123" nil 1 0 "xx123" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(141 ""123456" =~ /^.+?[0-9][0-9][0-9]$/" "^.+?[0-9][0-9][0-9]$" nil nil nil nil "123456" nil 1 0 "123456" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(142 ""123" =~ /^.+?[0-9][0-9][0-9]$/" "^.+?[0-9][0-9][0-9]$" nil nil nil nil "123" nil 1 0 nil nil) +(143 ""x1234" =~ /^.+?[0-9][0-9][0-9]$/" "^.+?[0-9][0-9][0-9]$" nil nil nil nil "x1234" nil 1 0 "x1234" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(144 ""abc!pqr=apquxz.ixr.zzz.ac.uk" =~ /^([^!]+)!(.+)=apquxz\.ixr\.zzz\.ac\.uk$/" "^([^!]+)!(.+)=apquxz\.ixr\.zzz\.ac\.uk$" nil nil nil nil "abc!pqr=apquxz.ixr.zzz.ac.uk" nil 1 0 "abc!pqr=apquxz.ixr.zzz.ac.uk" ("abc" "pqr" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(145 ""!pqr=apquxz.ixr.zzz.ac.uk" =~ /^([^!]+)!(.+)=apquxz\.ixr\.zzz\.ac\.uk$/" "^([^!]+)!(.+)=apquxz\.ixr\.zzz\.ac\.uk$" nil nil nil nil "!pqr=apquxz.ixr.zzz.ac.uk" nil 1 0 nil nil) +(146 ""abc!=apquxz.ixr.zzz.ac.uk" =~ /^([^!]+)!(.+)=apquxz\.ixr\.zzz\.ac\.uk$/" "^([^!]+)!(.+)=apquxz\.ixr\.zzz\.ac\.uk$" nil nil nil nil "abc!=apquxz.ixr.zzz.ac.uk" nil 1 0 nil nil) +(147 ""abc!pqr=apquxz:ixr.zzz.ac.uk" =~ /^([^!]+)!(.+)=apquxz\.ixr\.zzz\.ac\.uk$/" "^([^!]+)!(.+)=apquxz\.ixr\.zzz\.ac\.uk$" nil nil nil nil "abc!pqr=apquxz:ixr.zzz.ac.uk" nil 1 0 nil nil) +(148 ""abc!pqr=apquxz.ixr.zzz.ac.ukk" =~ /^([^!]+)!(.+)=apquxz\.ixr\.zzz\.ac\.uk$/" "^([^!]+)!(.+)=apquxz\.ixr\.zzz\.ac\.uk$" nil nil nil nil "abc!pqr=apquxz.ixr.zzz.ac.ukk" nil 1 0 nil nil) +(149 ""Well, we need a colon: somewhere" =~ /:/" ":" nil nil nil nil "Well, we need a colon: somewhere" nil 1 0 ":" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(150 ""Fail if we don't" =~ /:/" ":" nil nil nil nil "Fail if we don't" nil 1 0 nil nil) +(151 ""0abc" =~ /([\da-f:]+)$/i" "([\da-f:]+)$" t nil nil nil "0abc" nil 1 0 "0abc" ("0abc" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(152 ""abc" =~ /([\da-f:]+)$/i" "([\da-f:]+)$" t nil nil nil "abc" nil 1 0 "abc" ("abc" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(153 ""fed" =~ /([\da-f:]+)$/i" "([\da-f:]+)$" t nil nil nil "fed" nil 1 0 "fed" ("fed" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(154 ""E" =~ /([\da-f:]+)$/i" "([\da-f:]+)$" t nil nil nil "E" nil 1 0 "E" ("E" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(155 ""::" =~ /([\da-f:]+)$/i" "([\da-f:]+)$" t nil nil nil "::" nil 1 0 "::" ("::" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(156 ""5f03:12C0::932e" =~ /([\da-f:]+)$/i" "([\da-f:]+)$" t nil nil nil "5f03:12C0::932e" nil 1 0 "5f03:12C0::932e" ("5f03:12C0::932e" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(157 ""fed def" =~ /([\da-f:]+)$/i" "([\da-f:]+)$" t nil nil nil "fed def" nil 1 0 "def" ("def" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(158 ""Any old stuff" =~ /([\da-f:]+)$/i" "([\da-f:]+)$" t nil nil nil "Any old stuff" nil 1 0 "ff" ("ff" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(159 ""0zzz" =~ /([\da-f:]+)$/i" "([\da-f:]+)$" t nil nil nil "0zzz" nil 1 0 nil nil) +(160 ""gzzz" =~ /([\da-f:]+)$/i" "([\da-f:]+)$" t nil nil nil "gzzz" nil 1 0 nil nil) +(161 ""fed\x20" =~ /([\da-f:]+)$/i" "([\da-f:]+)$" t nil nil nil "fed " nil 1 0 nil nil) +(162 ""Any old rubbish" =~ /([\da-f:]+)$/i" "([\da-f:]+)$" t nil nil nil "Any old rubbish" nil 1 0 nil nil) +(163 "".1.2.3" =~ /^.*\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/" "^.*\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$" nil nil nil nil ".1.2.3" nil 1 0 ".1.2.3" ("1" "2" "3" nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(164 ""A.12.123.0" =~ /^.*\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/" "^.*\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$" nil nil nil nil "A.12.123.0" nil 1 0 "A.12.123.0" ("12" "123" "0" nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(165 "".1.2.3333" =~ /^.*\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/" "^.*\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$" nil nil nil nil ".1.2.3333" nil 1 0 nil nil) +(166 ""1.2.3" =~ /^.*\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/" "^.*\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$" nil nil nil nil "1.2.3" nil 1 0 nil nil) +(167 ""1234.2.3" =~ /^.*\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/" "^.*\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$" nil nil nil nil "1234.2.3" nil 1 0 nil nil) +(168 ""1 IN SOA non-sp1 non-sp2(" =~ /^(\d+)\s+IN\s+SOA\s+(\S+)\s+(\S+)\s*\(\s*$/" "^(\d+)\s+IN\s+SOA\s+(\S+)\s+(\S+)\s*\(\s*$" nil nil nil nil "1 IN SOA non-sp1 non-sp2(" nil 1 0 "1 IN SOA non-sp1 non-sp2(" ("1" "non-sp1" "non-sp2" nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(169 ""1 IN SOA non-sp1 non-sp2 (" =~ /^(\d+)\s+IN\s+SOA\s+(\S+)\s+(\S+)\s*\(\s*$/" "^(\d+)\s+IN\s+SOA\s+(\S+)\s+(\S+)\s*\(\s*$" nil nil nil nil "1 IN SOA non-sp1 non-sp2 (" nil 1 0 "1 IN SOA non-sp1 non-sp2 (" ("1" "non-sp1" "non-sp2" nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(170 ""1IN SOA non-sp1 non-sp2(" =~ /^(\d+)\s+IN\s+SOA\s+(\S+)\s+(\S+)\s*\(\s*$/" "^(\d+)\s+IN\s+SOA\s+(\S+)\s+(\S+)\s*\(\s*$" nil nil nil nil "1IN SOA non-sp1 non-sp2(" nil 1 0 nil nil) +(171 ""a." =~ /^[a-zA-Z\d][a-zA-Z\d\-]*(\.[a-zA-Z\d][a-zA-z\d\-]*)*\.$/" "^[a-zA-Z\d][a-zA-Z\d\-]*(\.[a-zA-Z\d][a-zA-z\d\-]*)*\.$" nil nil nil nil "a." nil 1 0 "a." (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(172 ""Z." =~ /^[a-zA-Z\d][a-zA-Z\d\-]*(\.[a-zA-Z\d][a-zA-z\d\-]*)*\.$/" "^[a-zA-Z\d][a-zA-Z\d\-]*(\.[a-zA-Z\d][a-zA-z\d\-]*)*\.$" nil nil nil nil "Z." nil 1 0 "Z." (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(173 ""2." =~ /^[a-zA-Z\d][a-zA-Z\d\-]*(\.[a-zA-Z\d][a-zA-z\d\-]*)*\.$/" "^[a-zA-Z\d][a-zA-Z\d\-]*(\.[a-zA-Z\d][a-zA-z\d\-]*)*\.$" nil nil nil nil "2." nil 1 0 "2." (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(174 ""ab-c.pq-r." =~ /^[a-zA-Z\d][a-zA-Z\d\-]*(\.[a-zA-Z\d][a-zA-z\d\-]*)*\.$/" "^[a-zA-Z\d][a-zA-Z\d\-]*(\.[a-zA-Z\d][a-zA-z\d\-]*)*\.$" nil nil nil nil "ab-c.pq-r." nil 1 0 "ab-c.pq-r." (".pq-r" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(175 ""sxk.zzz.ac.uk." =~ /^[a-zA-Z\d][a-zA-Z\d\-]*(\.[a-zA-Z\d][a-zA-z\d\-]*)*\.$/" "^[a-zA-Z\d][a-zA-Z\d\-]*(\.[a-zA-Z\d][a-zA-z\d\-]*)*\.$" nil nil nil nil "sxk.zzz.ac.uk." nil 1 0 "sxk.zzz.ac.uk." (".uk" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(176 ""x-.y-." =~ /^[a-zA-Z\d][a-zA-Z\d\-]*(\.[a-zA-Z\d][a-zA-z\d\-]*)*\.$/" "^[a-zA-Z\d][a-zA-Z\d\-]*(\.[a-zA-Z\d][a-zA-z\d\-]*)*\.$" nil nil nil nil "x-.y-." nil 1 0 "x-.y-." (".y-" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(177 ""-abc.peq." =~ /^[a-zA-Z\d][a-zA-Z\d\-]*(\.[a-zA-Z\d][a-zA-z\d\-]*)*\.$/" "^[a-zA-Z\d][a-zA-Z\d\-]*(\.[a-zA-Z\d][a-zA-z\d\-]*)*\.$" nil nil nil nil "-abc.peq." nil 1 0 nil nil) +(178 ""*.a" =~ /^\*\.[a-z]([a-z\-\d]*[a-z\d]+)?(\.[a-z]([a-z\-\d]*[a-z\d]+)?)*$/" "^\*\.[a-z]([a-z\-\d]*[a-z\d]+)?(\.[a-z]([a-z\-\d]*[a-z\d]+)?)*$" nil nil nil nil "*.a" nil 1 0 "*.a" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(179 ""*.b0-a" =~ /^\*\.[a-z]([a-z\-\d]*[a-z\d]+)?(\.[a-z]([a-z\-\d]*[a-z\d]+)?)*$/" "^\*\.[a-z]([a-z\-\d]*[a-z\d]+)?(\.[a-z]([a-z\-\d]*[a-z\d]+)?)*$" nil nil nil nil "*.b0-a" nil 1 0 "*.b0-a" ("0-a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(180 ""*.c3-b.c" =~ /^\*\.[a-z]([a-z\-\d]*[a-z\d]+)?(\.[a-z]([a-z\-\d]*[a-z\d]+)?)*$/" "^\*\.[a-z]([a-z\-\d]*[a-z\d]+)?(\.[a-z]([a-z\-\d]*[a-z\d]+)?)*$" nil nil nil nil "*.c3-b.c" nil 1 0 "*.c3-b.c" ("3-b" ".c" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(181 ""*.c-a.b-c" =~ /^\*\.[a-z]([a-z\-\d]*[a-z\d]+)?(\.[a-z]([a-z\-\d]*[a-z\d]+)?)*$/" "^\*\.[a-z]([a-z\-\d]*[a-z\d]+)?(\.[a-z]([a-z\-\d]*[a-z\d]+)?)*$" nil nil nil nil "*.c-a.b-c" nil 1 0 "*.c-a.b-c" ("-a" ".b-c" "-c" nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(182 ""*.0" =~ /^\*\.[a-z]([a-z\-\d]*[a-z\d]+)?(\.[a-z]([a-z\-\d]*[a-z\d]+)?)*$/" "^\*\.[a-z]([a-z\-\d]*[a-z\d]+)?(\.[a-z]([a-z\-\d]*[a-z\d]+)?)*$" nil nil nil nil "*.0" nil 1 0 nil nil) +(183 ""*.a-" =~ /^\*\.[a-z]([a-z\-\d]*[a-z\d]+)?(\.[a-z]([a-z\-\d]*[a-z\d]+)?)*$/" "^\*\.[a-z]([a-z\-\d]*[a-z\d]+)?(\.[a-z]([a-z\-\d]*[a-z\d]+)?)*$" nil nil nil nil "*.a-" nil 1 0 nil nil) +(184 ""*.a-b.c-" =~ /^\*\.[a-z]([a-z\-\d]*[a-z\d]+)?(\.[a-z]([a-z\-\d]*[a-z\d]+)?)*$/" "^\*\.[a-z]([a-z\-\d]*[a-z\d]+)?(\.[a-z]([a-z\-\d]*[a-z\d]+)?)*$" nil nil nil nil "*.a-b.c-" nil 1 0 nil nil) +(185 ""*.c-a.0-c" =~ /^\*\.[a-z]([a-z\-\d]*[a-z\d]+)?(\.[a-z]([a-z\-\d]*[a-z\d]+)?)*$/" "^\*\.[a-z]([a-z\-\d]*[a-z\d]+)?(\.[a-z]([a-z\-\d]*[a-z\d]+)?)*$" nil nil nil nil "*.c-a.0-c" nil 1 0 nil nil) +(186 ""abde" =~ /^(?=ab(de))(abd)(e)/" "^(?=ab(de))(abd)(e)" nil nil nil nil "abde" nil 1 0 "abde" ("de" "abd" "e" nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(187 ""abdf" =~ /^(?!(ab)de|x)(abd)(f)/" "^(?!(ab)de|x)(abd)(f)" nil nil nil nil "abdf" nil 1 0 "abdf" (nil "abd" "f" nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(188 ""abcd" =~ /^(?=(ab(cd)))(ab)/" "^(?=(ab(cd)))(ab)" nil nil nil nil "abcd" nil 1 0 "ab" ("abcd" "cd" "ab" nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(189 ""a.b.c.d" =~ /^[\da-f](\.[\da-f])*$/i" "^[\da-f](\.[\da-f])*$" t nil nil nil "a.b.c.d" nil 1 0 "a.b.c.d" (".d" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(190 ""A.B.C.D" =~ /^[\da-f](\.[\da-f])*$/i" "^[\da-f](\.[\da-f])*$" t nil nil nil "A.B.C.D" nil 1 0 "A.B.C.D" (".D" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(191 ""a.b.c.1.2.3.C" =~ /^[\da-f](\.[\da-f])*$/i" "^[\da-f](\.[\da-f])*$" t nil nil nil "a.b.c.1.2.3.C" nil 1 0 "a.b.c.1.2.3.C" (".C" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(192 ""\"1234\"" =~ /^\".*\"\s*(;.*)?$/" "^\".*\"\s*(;.*)?$" nil nil nil nil ""1234"" nil 1 0 ""1234"" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(193 ""\"abcd\" ;" =~ /^\".*\"\s*(;.*)?$/" "^\".*\"\s*(;.*)?$" nil nil nil nil ""abcd" ;" nil 1 0 ""abcd" ;" (";" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(194 ""\"\" ; rhubarb" =~ /^\".*\"\s*(;.*)?$/" "^\".*\"\s*(;.*)?$" nil nil nil nil """ ; rhubarb" nil 1 0 """ ; rhubarb" ("; rhubarb" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(195 ""\"1234\" : things" =~ /^\".*\"\s*(;.*)?$/" "^\".*\"\s*(;.*)?$" nil nil nil nil ""1234" : things" nil 1 0 nil nil) +(196 ""\" =~ /^$/" "^$" nil nil nil nil "" nil 1 0 "" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(197 ""ab c" =~ / ^ a (?# begins with a) b\sc (?# then b c) $ (?# then end)/x" " ^ a (?# begins with a) b\sc (?# then b c) $ (?# then end)" nil nil nil t "ab c" nil 1 0 "ab c" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(198 ""abc" =~ / ^ a (?# begins with a) b\sc (?# then b c) $ (?# then end)/x" " ^ a (?# begins with a) b\sc (?# then b c) $ (?# then end)" nil nil nil t "abc" nil 1 0 nil nil) +(199 ""ab cde" =~ / ^ a (?# begins with a) b\sc (?# then b c) $ (?# then end)/x" " ^ a (?# begins with a) b\sc (?# then b c) $ (?# then end)" nil nil nil t "ab cde" nil 1 0 nil nil) +(200 ""ab c" =~ /(?x) ^ a (?# begins with a) b\sc (?# then b c) $ (?# then end)/" "(?x) ^ a (?# begins with a) b\sc (?# then b c) $ (?# then end)" nil nil nil nil "ab c" nil 1 0 "ab c" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(201 ""abc" =~ /(?x) ^ a (?# begins with a) b\sc (?# then b c) $ (?# then end)/" "(?x) ^ a (?# begins with a) b\sc (?# then b c) $ (?# then end)" nil nil nil nil "abc" nil 1 0 nil nil) +(202 ""ab cde" =~ /(?x) ^ a (?# begins with a) b\sc (?# then b c) $ (?# then end)/" "(?x) ^ a (?# begins with a) b\sc (?# then b c) $ (?# then end)" nil nil nil nil "ab cde" nil 1 0 nil nil) +(203 ""a bcd" =~ /^ a\ b[c ]d $/x" "^ a\ b[c ]d $" nil nil nil t "a bcd" nil 1 0 "a bcd" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(204 ""a b d" =~ /^ a\ b[c ]d $/x" "^ a\ b[c ]d $" nil nil nil t "a b d" nil 1 0 "a b d" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(205 ""abcd" =~ /^ a\ b[c ]d $/x" "^ a\ b[c ]d $" nil nil nil t "abcd" nil 1 0 nil nil) +(206 ""ab d" =~ /^ a\ b[c ]d $/x" "^ a\ b[c ]d $" nil nil nil t "ab d" nil 1 0 nil nil) +(207 ""abcdefhijklm" =~ /^(a(b(c)))(d(e(f)))(h(i(j)))(k(l(m)))$/" "^(a(b(c)))(d(e(f)))(h(i(j)))(k(l(m)))$" nil nil nil nil "abcdefhijklm" nil 1 0 "abcdefhijklm" ("abc" "bc" "c" "def" "ef" "f" "hij" "ij" "j" "klm" "lm" "m" nil nil nil nil)) +(208 ""abcdefhijklm" =~ /^(?:a(b(c)))(?:d(e(f)))(?:h(i(j)))(?:k(l(m)))$/" "^(?:a(b(c)))(?:d(e(f)))(?:h(i(j)))(?:k(l(m)))$" nil nil nil nil "abcdefhijklm" nil 1 0 "abcdefhijklm" ("bc" "c" "ef" "f" "ij" "j" "lm" "m" nil nil nil nil nil nil nil nil)) +(209 ""a+ Z0+\x08\n\x1d\x12" =~ /^[\w][\W][\s][\S][\d][\D][\b][\n][\c]][\022]/" "^[\w][\W][\s][\S][\d][\D][\b][\n][\c]][\022]" nil nil nil nil ("a+ Z0+" 8 10 29 18) nil 1 0 ("a+ Z0+" 8 10 29 18) (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(210 "".^\$(*+)|{?,?}" =~ /^[.^$|()*+?{,}]+/" "^[.^$|()*+?{,}]+" nil nil nil nil ".^$(*+)|{?,?}" nil 1 0 ".^$(*+)|{?,?}" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(211 ""z" =~ /^a*\w/" "^a*\w" nil nil nil nil "z" nil 1 0 "z" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(212 ""az" =~ /^a*\w/" "^a*\w" nil nil nil nil "az" nil 1 0 "az" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(213 ""aaaz" =~ /^a*\w/" "^a*\w" nil nil nil nil "aaaz" nil 1 0 "aaaz" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(214 ""a" =~ /^a*\w/" "^a*\w" nil nil nil nil "a" nil 1 0 "a" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(215 ""aa" =~ /^a*\w/" "^a*\w" nil nil nil nil "aa" nil 1 0 "aa" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(216 ""aaaa" =~ /^a*\w/" "^a*\w" nil nil nil nil "aaaa" nil 1 0 "aaaa" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(217 ""a+" =~ /^a*\w/" "^a*\w" nil nil nil nil "a+" nil 1 0 "a" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(218 ""aa+" =~ /^a*\w/" "^a*\w" nil nil nil nil "aa+" nil 1 0 "aa" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(219 ""z" =~ /^a*?\w/" "^a*?\w" nil nil nil nil "z" nil 1 0 "z" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(220 ""az" =~ /^a*?\w/" "^a*?\w" nil nil nil nil "az" nil 1 0 "a" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(221 ""aaaz" =~ /^a*?\w/" "^a*?\w" nil nil nil nil "aaaz" nil 1 0 "a" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(222 ""a" =~ /^a*?\w/" "^a*?\w" nil nil nil nil "a" nil 1 0 "a" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(223 ""aa" =~ /^a*?\w/" "^a*?\w" nil nil nil nil "aa" nil 1 0 "a" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(224 ""aaaa" =~ /^a*?\w/" "^a*?\w" nil nil nil nil "aaaa" nil 1 0 "a" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(225 ""a+" =~ /^a*?\w/" "^a*?\w" nil nil nil nil "a+" nil 1 0 "a" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(226 ""aa+" =~ /^a*?\w/" "^a*?\w" nil nil nil nil "aa+" nil 1 0 "a" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(227 ""az" =~ /^a+\w/" "^a+\w" nil nil nil nil "az" nil 1 0 "az" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(228 ""aaaz" =~ /^a+\w/" "^a+\w" nil nil nil nil "aaaz" nil 1 0 "aaaz" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(229 ""aa" =~ /^a+\w/" "^a+\w" nil nil nil nil "aa" nil 1 0 "aa" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(230 ""aaaa" =~ /^a+\w/" "^a+\w" nil nil nil nil "aaaa" nil 1 0 "aaaa" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(231 ""aa+" =~ /^a+\w/" "^a+\w" nil nil nil nil "aa+" nil 1 0 "aa" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(232 ""az" =~ /^a+?\w/" "^a+?\w" nil nil nil nil "az" nil 1 0 "az" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(233 ""aaaz" =~ /^a+?\w/" "^a+?\w" nil nil nil nil "aaaz" nil 1 0 "aa" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(234 ""aa" =~ /^a+?\w/" "^a+?\w" nil nil nil nil "aa" nil 1 0 "aa" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(235 ""aaaa" =~ /^a+?\w/" "^a+?\w" nil nil nil nil "aaaa" nil 1 0 "aa" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(236 ""aa+" =~ /^a+?\w/" "^a+?\w" nil nil nil nil "aa+" nil 1 0 "aa" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(237 ""1234567890" =~ /^\d{8}\w{2,}/" "^\d{8}\w{2,}" nil nil nil nil "1234567890" nil 1 0 "1234567890" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(238 ""12345678ab" =~ /^\d{8}\w{2,}/" "^\d{8}\w{2,}" nil nil nil nil "12345678ab" nil 1 0 "12345678ab" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(239 ""12345678__" =~ /^\d{8}\w{2,}/" "^\d{8}\w{2,}" nil nil nil nil "12345678__" nil 1 0 "12345678__" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(240 ""1234567" =~ /^\d{8}\w{2,}/" "^\d{8}\w{2,}" nil nil nil nil "1234567" nil 1 0 nil nil) +(241 ""uoie" =~ /^[aeiou\d]{4,5}$/" "^[aeiou\d]{4,5}$" nil nil nil nil "uoie" nil 1 0 "uoie" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(242 ""1234" =~ /^[aeiou\d]{4,5}$/" "^[aeiou\d]{4,5}$" nil nil nil nil "1234" nil 1 0 "1234" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(243 ""12345" =~ /^[aeiou\d]{4,5}$/" "^[aeiou\d]{4,5}$" nil nil nil nil "12345" nil 1 0 "12345" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(244 ""aaaaa" =~ /^[aeiou\d]{4,5}$/" "^[aeiou\d]{4,5}$" nil nil nil nil "aaaaa" nil 1 0 "aaaaa" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(245 ""123456" =~ /^[aeiou\d]{4,5}$/" "^[aeiou\d]{4,5}$" nil nil nil nil "123456" nil 1 0 nil nil) +(246 ""uoie" =~ /^[aeiou\d]{4,5}?/" "^[aeiou\d]{4,5}?" nil nil nil nil "uoie" nil 1 0 "uoie" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(247 ""1234" =~ /^[aeiou\d]{4,5}?/" "^[aeiou\d]{4,5}?" nil nil nil nil "1234" nil 1 0 "1234" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(248 ""12345" =~ /^[aeiou\d]{4,5}?/" "^[aeiou\d]{4,5}?" nil nil nil nil "12345" nil 1 0 "1234" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(249 ""aaaaa" =~ /^[aeiou\d]{4,5}?/" "^[aeiou\d]{4,5}?" nil nil nil nil "aaaaa" nil 1 0 "aaaa" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(250 ""123456" =~ /^[aeiou\d]{4,5}?/" "^[aeiou\d]{4,5}?" nil nil nil nil "123456" nil 1 0 "1234" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(251 ""abc=abcabc" =~ /\A(abc|def)=(\1){2,3}\Z/" "\A(abc|def)=(\1){2,3}\Z" nil nil nil nil "abc=abcabc" nil 1 0 "abc=abcabc" ("abc" "abc" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(252 ""def=defdefdef" =~ /\A(abc|def)=(\1){2,3}\Z/" "\A(abc|def)=(\1){2,3}\Z" nil nil nil nil "def=defdefdef" nil 1 0 "def=defdefdef" ("def" "def" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(253 ""abc=defdef" =~ /\A(abc|def)=(\1){2,3}\Z/" "\A(abc|def)=(\1){2,3}\Z" nil nil nil nil "abc=defdef" nil 1 0 nil nil) +(254 ""abcdefghijkcda2" =~ /^(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)\11*(\3\4)\1(?#)2$/" "^(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)\11*(\3\4)\1(?#)2$" nil nil nil nil "abcdefghijkcda2" nil 1 0 "abcdefghijkcda2" ("a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "cd" nil nil nil nil)) +(255 ""abcdefghijkkkkcda2" =~ /^(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)\11*(\3\4)\1(?#)2$/" "^(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)\11*(\3\4)\1(?#)2$" nil nil nil nil "abcdefghijkkkkcda2" nil 1 0 "abcdefghijkkkkcda2" ("a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "cd" nil nil nil nil)) +(256 ""cataract cataract23" =~ /(cat(a(ract|tonic)|erpillar)) \1()2(3)/" "(cat(a(ract|tonic)|erpillar)) \1()2(3)" nil nil nil nil "cataract cataract23" nil 1 0 "cataract cataract23" ("cataract" "aract" "ract" "" "3" nil nil nil nil nil nil nil nil nil nil nil)) +(257 ""catatonic catatonic23" =~ /(cat(a(ract|tonic)|erpillar)) \1()2(3)/" "(cat(a(ract|tonic)|erpillar)) \1()2(3)" nil nil nil nil "catatonic catatonic23" nil 1 0 "catatonic catatonic23" ("catatonic" "atonic" "tonic" "" "3" nil nil nil nil nil nil nil nil nil nil nil)) +(258 ""caterpillar caterpillar23" =~ /(cat(a(ract|tonic)|erpillar)) \1()2(3)/" "(cat(a(ract|tonic)|erpillar)) \1()2(3)" nil nil nil nil "caterpillar caterpillar23" nil 1 0 "caterpillar caterpillar23" ("caterpillar" "erpillar" nil "" "3" nil nil nil nil nil nil nil nil nil nil nil)) +(259 ""From abcd Mon Sep 01 12:33:02 1997" =~ +/^From +([^ ]+) +[a-zA-Z][a-zA-Z][a-zA-Z] +[a-zA-Z][a-zA-Z][a-zA-Z] +[0-9]?[0-9] +[0-9][0-9]:[0-9][0-9]/" "^From +([^ ]+) +[a-zA-Z][a-zA-Z][a-zA-Z] +[a-zA-Z][a-zA-Z][a-zA-Z] +[0-9]?[0-9] +[0-9][0-9]:[0-9][0-9]" nil nil nil nil "From abcd Mon Sep 01 12:33:02 1997" nil 1 0 "From abcd Mon Sep 01 12:33" ("abcd" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(260 ""From abcd Mon Sep 01 12:33:02 1997" =~ /^From\s+\S+\s+([a-zA-Z]{3}\s+){2}\d{1,2}\s+\d\d:\d\d/" "^From\s+\S+\s+([a-zA-Z]{3}\s+){2}\d{1,2}\s+\d\d:\d\d" nil nil nil nil "From abcd Mon Sep 01 12:33:02 1997" nil 1 0 "From abcd Mon Sep 01 12:33" ("Sep " nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(261 ""From abcd Mon Sep 1 12:33:02 1997" =~ /^From\s+\S+\s+([a-zA-Z]{3}\s+){2}\d{1,2}\s+\d\d:\d\d/" "^From\s+\S+\s+([a-zA-Z]{3}\s+){2}\d{1,2}\s+\d\d:\d\d" nil nil nil nil "From abcd Mon Sep 1 12:33:02 1997" nil 1 0 "From abcd Mon Sep 1 12:33" ("Sep " nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(262 ""From abcd Sep 01 12:33:02 1997" =~ /^From\s+\S+\s+([a-zA-Z]{3}\s+){2}\d{1,2}\s+\d\d:\d\d/" "^From\s+\S+\s+([a-zA-Z]{3}\s+){2}\d{1,2}\s+\d\d:\d\d" nil nil nil nil "From abcd Sep 01 12:33:02 1997" nil 1 0 nil nil) +(263 ""12\n34" =~ /^12.34/s" "^12.34" nil nil t nil "12 +34" nil 1 0 "12 +34" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(264 ""12\r34" =~ /^12.34/s" "^12.34" nil nil t nil ("12" 13 "34") nil 1 0 ("12" 13 "34") (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(265 ""the quick brown\t fox" =~ /\w+(?=\t)/" "\w+(?=\t)" nil nil nil nil ("the quick brown" 9 " fox") nil 1 0 "brown" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(266 ""foobar is foolish see?" =~ /foo(?!bar)(.*)/" "foo(?!bar)(.*)" nil nil nil nil "foobar is foolish see?" nil 1 0 "foolish see?" ("lish see?" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(267 ""foobar crowbar etc" =~ /(?:(?!foo)...|^.{0,2})bar(.*)/" "(?:(?!foo)...|^.{0,2})bar(.*)" nil nil nil nil "foobar crowbar etc" nil 1 0 "rowbar etc" (" etc" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(268 ""barrel" =~ /(?:(?!foo)...|^.{0,2})bar(.*)/" "(?:(?!foo)...|^.{0,2})bar(.*)" nil nil nil nil "barrel" nil 1 0 "barrel" ("rel" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(269 ""2barrel" =~ /(?:(?!foo)...|^.{0,2})bar(.*)/" "(?:(?!foo)...|^.{0,2})bar(.*)" nil nil nil nil "2barrel" nil 1 0 "2barrel" ("rel" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(270 ""A barrel" =~ /(?:(?!foo)...|^.{0,2})bar(.*)/" "(?:(?!foo)...|^.{0,2})bar(.*)" nil nil nil nil "A barrel" nil 1 0 "A barrel" ("rel" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(271 ""abc456" =~ /^(\D*)(?=\d)(?!123)/" "^(\D*)(?=\d)(?!123)" nil nil nil nil "abc456" nil 1 0 "abc" ("abc" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(272 ""abc123" =~ /^(\D*)(?=\d)(?!123)/" "^(\D*)(?=\d)(?!123)" nil nil nil nil "abc123" nil 1 0 nil nil) +(273 ""1234" =~ /^1234(?# test newlines + inside)/" "^1234(?# test newlines + inside)" nil nil nil nil "1234" nil 1 0 "1234" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(274 ""1234" =~ /^1234 #comment in extended re + /x" "^1234 #comment in extended re + " nil nil nil t "1234" nil 1 0 "1234" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(275 ""abcd" =~ /#rhubarb + abcd/x" "#rhubarb + abcd" nil nil nil t "abcd" nil 1 0 "abcd" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(276 ""abcd" =~ /^abcd#rhubarb/x" "^abcd#rhubarb" nil nil nil t "abcd" nil 1 0 "abcd" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(277 ""aaab" =~ /^(a)\1{2,3}(.)/" "^(a)\1{2,3}(.)" nil nil nil nil "aaab" nil 1 0 "aaab" ("a" "b" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(278 ""aaaab" =~ /^(a)\1{2,3}(.)/" "^(a)\1{2,3}(.)" nil nil nil nil "aaaab" nil 1 0 "aaaab" ("a" "b" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(279 ""aaaaab" =~ /^(a)\1{2,3}(.)/" "^(a)\1{2,3}(.)" nil nil nil nil "aaaaab" nil 1 0 "aaaaa" ("a" "a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(280 ""aaaaaab" =~ /^(a)\1{2,3}(.)/" "^(a)\1{2,3}(.)" nil nil nil nil "aaaaaab" nil 1 0 "aaaaa" ("a" "a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(281 ""the abc" =~ /(?!^)abc/" "(?!^)abc" nil nil nil nil "the abc" nil 1 0 "abc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(282 ""abc" =~ /(?!^)abc/" "(?!^)abc" nil nil nil nil "abc" nil 1 0 nil nil) +(283 ""abc" =~ /(?=^)abc/" "(?=^)abc" nil nil nil nil "abc" nil 1 0 "abc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(284 ""the abc" =~ /(?=^)abc/" "(?=^)abc" nil nil nil nil "the abc" nil 1 0 nil nil) +(285 ""aabbbbb" =~ /^[ab]{1,3}(ab*|b)/" "^[ab]{1,3}(ab*|b)" nil nil nil nil "aabbbbb" nil 1 0 "aabb" ("b" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(286 ""aabbbbb" =~ /^[ab]{1,3}?(ab*|b)/" "^[ab]{1,3}?(ab*|b)" nil nil nil nil "aabbbbb" nil 1 0 "aabbbbb" ("abbbbb" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(287 ""aabbbbb" =~ /^[ab]{1,3}?(ab*?|b)/" "^[ab]{1,3}?(ab*?|b)" nil nil nil nil "aabbbbb" nil 1 0 "aa" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(288 ""aabbbbb" =~ /^[ab]{1,3}(ab*?|b)/" "^[ab]{1,3}(ab*?|b)" nil nil nil nil "aabbbbb" nil 1 0 "aabb" ("b" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(289 ""Alan Other <user\@dom.ain>" =~ / (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # optional leading comment +(?: (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # initial word +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) )* # further okay, if led by a period +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +# address +| # or +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # one word, optionally followed by.... +(?: +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] | # atom and space parts, or... +\( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) | # comments, or... + +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +# quoted strings +)* +< (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # leading < +(?: @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* + +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* , (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +)* # further okay, if led by comma +: # closing colon +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* )? # optional route +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # initial word +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) )* # further okay, if led by a period +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +# address spec +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* > # trailing > +# name and address +) (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # optional trailing comment +/x" " (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # optional leading comment +(?: (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # initial word +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) )* # further okay, if led by a period +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +# address +| # or +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # one word, optionally followed by.... +(?: +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] | # atom and space parts, or... +\( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) | # comments, or... + +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +# quoted strings +)* +< (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # leading < +(?: @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* + +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* , (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +)* # further okay, if led by comma +: # closing colon +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* )? # optional route +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # initial word +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) )* # further okay, if led by a period +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +# address spec +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* > # trailing > +# name and address +) (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # optional trailing comment +" nil nil nil t "Alan Other user@dom.ain" nil 1 0 "Alan Other user@dom.ain" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(290 ""<user\@dom.ain>" =~ / (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # optional leading comment +(?: (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # initial word +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) )* # further okay, if led by a period +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +# address +| # or +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # one word, optionally followed by.... +(?: +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] | # atom and space parts, or... +\( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) | # comments, or... + +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +# quoted strings +)* +< (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # leading < +(?: @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* + +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* , (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +)* # further okay, if led by comma +: # closing colon +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* )? # optional route +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # initial word +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) )* # further okay, if led by a period +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +# address spec +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* > # trailing > +# name and address +) (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # optional trailing comment +/x" " (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # optional leading comment +(?: (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # initial word +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) )* # further okay, if led by a period +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +# address +| # or +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # one word, optionally followed by.... +(?: +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] | # atom and space parts, or... +\( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) | # comments, or... + +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +# quoted strings +)* +< (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # leading < +(?: @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* + +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* , (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +)* # further okay, if led by comma +: # closing colon +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* )? # optional route +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # initial word +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) )* # further okay, if led by a period +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +# address spec +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* > # trailing > +# name and address +) (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # optional trailing comment +" nil nil nil t "user@dom.ain" nil 1 0 "user@dom.ain" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(291 ""user\@dom.ain" =~ / (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # optional leading comment +(?: (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # initial word +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) )* # further okay, if led by a period +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +# address +| # or +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # one word, optionally followed by.... +(?: +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] | # atom and space parts, or... +\( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) | # comments, or... + +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +# quoted strings +)* +< (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # leading < +(?: @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* + +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* , (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +)* # further okay, if led by comma +: # closing colon +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* )? # optional route +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # initial word +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) )* # further okay, if led by a period +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +# address spec +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* > # trailing > +# name and address +) (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # optional trailing comment +/x" " (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # optional leading comment +(?: (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # initial word +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) )* # further okay, if led by a period +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +# address +| # or +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # one word, optionally followed by.... +(?: +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] | # atom and space parts, or... +\( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) | # comments, or... + +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +# quoted strings +)* +< (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # leading < +(?: @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* + +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* , (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +)* # further okay, if led by comma +: # closing colon +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* )? # optional route +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # initial word +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) )* # further okay, if led by a period +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +# address spec +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* > # trailing > +# name and address +) (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # optional trailing comment +" nil nil nil t "user@dom.ain" nil 1 0 "user@dom.ain" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(292 ""\"A. Other\" <user.1234\@dom.ain> (a comment)" =~ / (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # optional leading comment +(?: (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # initial word +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) )* # further okay, if led by a period +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +# address +| # or +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # one word, optionally followed by.... +(?: +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] | # atom and space parts, or... +\( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) | # comments, or... + +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +# quoted strings +)* +< (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # leading < +(?: @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* + +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* , (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +)* # further okay, if led by comma +: # closing colon +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* )? # optional route +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # initial word +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) )* # further okay, if led by a period +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +# address spec +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* > # trailing > +# name and address +) (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # optional trailing comment +/x" " (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # optional leading comment +(?: (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # initial word +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) )* # further okay, if led by a period +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +# address +| # or +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # one word, optionally followed by.... +(?: +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] | # atom and space parts, or... +\( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) | # comments, or... + +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +# quoted strings +)* +< (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # leading < +(?: @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* + +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* , (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +)* # further okay, if led by comma +: # closing colon +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* )? # optional route +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # initial word +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) )* # further okay, if led by a period +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +# address spec +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* > # trailing > +# name and address +) (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # optional trailing comment +" nil nil nil t ""A. Other" user.1234@dom.ain (a comment)" nil 1 0 ""A. Other" user.1234@dom.ain (a comment)" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(293 ""A. Other <user.1234\@dom.ain> (a comment)" =~ / (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # optional leading comment +(?: (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # initial word +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) )* # further okay, if led by a period +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +# address +| # or +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # one word, optionally followed by.... +(?: +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] | # atom and space parts, or... +\( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) | # comments, or... + +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +# quoted strings +)* +< (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # leading < +(?: @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* + +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* , (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +)* # further okay, if led by comma +: # closing colon +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* )? # optional route +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # initial word +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) )* # further okay, if led by a period +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +# address spec +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* > # trailing > +# name and address +) (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # optional trailing comment +/x" " (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # optional leading comment +(?: (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # initial word +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) )* # further okay, if led by a period +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +# address +| # or +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # one word, optionally followed by.... +(?: +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] | # atom and space parts, or... +\( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) | # comments, or... + +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +# quoted strings +)* +< (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # leading < +(?: @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* + +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* , (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +)* # further okay, if led by comma +: # closing colon +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* )? # optional route +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # initial word +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) )* # further okay, if led by a period +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +# address spec +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* > # trailing > +# name and address +) (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # optional trailing comment +" nil nil nil t "A. Other user.1234@dom.ain (a comment)" nil 1 0 " Other user.1234@dom.ain (a comment)" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(294 ""\"/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/\"\@x400-re.lay" =~ / (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # optional leading comment +(?: (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # initial word +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) )* # further okay, if led by a period +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +# address +| # or +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # one word, optionally followed by.... +(?: +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] | # atom and space parts, or... +\( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) | # comments, or... + +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +# quoted strings +)* +< (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # leading < +(?: @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* + +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* , (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +)* # further okay, if led by comma +: # closing colon +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* )? # optional route +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # initial word +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) )* # further okay, if led by a period +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +# address spec +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* > # trailing > +# name and address +) (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # optional trailing comment +/x" " (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # optional leading comment +(?: (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # initial word +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) )* # further okay, if led by a period +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +# address +| # or +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # one word, optionally followed by.... +(?: +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] | # atom and space parts, or... +\( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) | # comments, or... + +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +# quoted strings +)* +< (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # leading < +(?: @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* + +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* , (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +)* # further okay, if led by comma +: # closing colon +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* )? # optional route +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # initial word +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) )* # further okay, if led by a period +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +# address spec +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* > # trailing > +# name and address +) (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # optional trailing comment +" nil nil nil t ""/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/"@x400-re.lay" nil 1 0 ""/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/"@x400-re.lay" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(295 ""A missing angle <user\@some.where" =~ / (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # optional leading comment +(?: (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # initial word +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) )* # further okay, if led by a period +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +# address +| # or +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # one word, optionally followed by.... +(?: +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] | # atom and space parts, or... +\( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) | # comments, or... + +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +# quoted strings +)* +< (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # leading < +(?: @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* + +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* , (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +)* # further okay, if led by comma +: # closing colon +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* )? # optional route +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # initial word +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) )* # further okay, if led by a period +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +# address spec +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* > # trailing > +# name and address +) (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # optional trailing comment +/x" " (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # optional leading comment +(?: (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # initial word +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) )* # further okay, if led by a period +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +# address +| # or +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # one word, optionally followed by.... +(?: +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] | # atom and space parts, or... +\( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) | # comments, or... + +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +# quoted strings +)* +< (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # leading < +(?: @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* + +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* , (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +)* # further okay, if led by comma +: # closing colon +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* )? # optional route +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # initial word +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) )* # further okay, if led by a period +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +# address spec +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* > # trailing > +# name and address +) (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # optional trailing comment +" nil nil nil t "A missing angle <user@some.where" nil 1 0 "user@some.where" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(296 ""The quick brown fox" =~ / (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # optional leading comment +(?: (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # initial word +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) )* # further okay, if led by a period +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +# address +| # or +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # one word, optionally followed by.... +(?: +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] | # atom and space parts, or... +\( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) | # comments, or... + +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +# quoted strings +)* +< (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # leading < +(?: @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* + +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* , (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +)* # further okay, if led by comma +: # closing colon +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* )? # optional route +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # initial word +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) )* # further okay, if led by a period +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +# address spec +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* > # trailing > +# name and address +) (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # optional trailing comment +/x" " (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # optional leading comment +(?: (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # initial word +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) )* # further okay, if led by a period +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +# address +| # or +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # one word, optionally followed by.... +(?: +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] | # atom and space parts, or... +\( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) | # comments, or... + +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +# quoted strings +)* +< (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # leading < +(?: @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* + +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* , (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +)* # further okay, if led by comma +: # closing colon +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* )? # optional route +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # initial word +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) )* # further okay, if led by a period +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +# address spec +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* > # trailing > +# name and address +) (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # optional trailing comment +" nil nil nil t "The quick brown fox" nil 1 0 nil nil) +(297 ""Alan Other <user\@dom.ain>" =~ /[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional leading comment +(?: +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# additional words +)* +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +# address +| # or +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +# leading word +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] * # "normal" atoms and or spaces +(?: +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +| +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +) # "special" comment or quoted string +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] * # more "normal" +)* +< +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# < +(?: +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +(?: , +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +)* # additional domains +: +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)? # optional route +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# additional words +)* +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +# address spec +> # > +# name and address +) +/x" "[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional leading comment +(?: +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# additional words +)* +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +# address +| # or +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +# leading word +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] * # "normal" atoms and or spaces +(?: +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +| +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +) # "special" comment or quoted string +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] * # more "normal" +)* +< +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# < +(?: +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +(?: , +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +)* # additional domains +: +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)? # optional route +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# additional words +)* +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +# address spec +> # > +# name and address +) +" nil nil nil t "Alan Other user@dom.ain" nil 1 0 "Alan Other user@dom.ain" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(298 ""<user\@dom.ain>" =~ /[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional leading comment +(?: +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# additional words +)* +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +# address +| # or +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +# leading word +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] * # "normal" atoms and or spaces +(?: +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +| +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +) # "special" comment or quoted string +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] * # more "normal" +)* +< +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# < +(?: +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +(?: , +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +)* # additional domains +: +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)? # optional route +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# additional words +)* +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +# address spec +> # > +# name and address +) +/x" "[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional leading comment +(?: +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# additional words +)* +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +# address +| # or +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +# leading word +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] * # "normal" atoms and or spaces +(?: +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +| +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +) # "special" comment or quoted string +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] * # more "normal" +)* +< +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# < +(?: +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +(?: , +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +)* # additional domains +: +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)? # optional route +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# additional words +)* +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +# address spec +> # > +# name and address +) +" nil nil nil t "user@dom.ain" nil 1 0 "user@dom.ain" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(299 ""user\@dom.ain" =~ /[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional leading comment +(?: +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# additional words +)* +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +# address +| # or +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +# leading word +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] * # "normal" atoms and or spaces +(?: +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +| +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +) # "special" comment or quoted string +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] * # more "normal" +)* +< +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# < +(?: +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +(?: , +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +)* # additional domains +: +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)? # optional route +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# additional words +)* +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +# address spec +> # > +# name and address +) +/x" "[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional leading comment +(?: +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# additional words +)* +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +# address +| # or +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +# leading word +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] * # "normal" atoms and or spaces +(?: +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +| +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +) # "special" comment or quoted string +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] * # more "normal" +)* +< +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# < +(?: +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +(?: , +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +)* # additional domains +: +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)? # optional route +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# additional words +)* +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +# address spec +> # > +# name and address +) +" nil nil nil t "user@dom.ain" nil 1 0 "user@dom.ain" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(300 ""\"A. Other\" <user.1234\@dom.ain> (a comment)" =~ /[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional leading comment +(?: +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# additional words +)* +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +# address +| # or +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +# leading word +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] * # "normal" atoms and or spaces +(?: +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +| +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +) # "special" comment or quoted string +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] * # more "normal" +)* +< +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# < +(?: +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +(?: , +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +)* # additional domains +: +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)? # optional route +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# additional words +)* +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +# address spec +> # > +# name and address +) +/x" "[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional leading comment +(?: +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# additional words +)* +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +# address +| # or +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +# leading word +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] * # "normal" atoms and or spaces +(?: +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +| +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +) # "special" comment or quoted string +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] * # more "normal" +)* +< +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# < +(?: +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +(?: , +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +)* # additional domains +: +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)? # optional route +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# additional words +)* +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +# address spec +> # > +# name and address +) +" nil nil nil t ""A. Other" user.1234@dom.ain (a comment)" nil 1 0 ""A. Other" user.1234@dom.ain" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(301 ""A. Other <user.1234\@dom.ain> (a comment)" =~ /[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional leading comment +(?: +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# additional words +)* +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +# address +| # or +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +# leading word +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] * # "normal" atoms and or spaces +(?: +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +| +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +) # "special" comment or quoted string +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] * # more "normal" +)* +< +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# < +(?: +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +(?: , +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +)* # additional domains +: +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)? # optional route +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# additional words +)* +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +# address spec +> # > +# name and address +) +/x" "[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional leading comment +(?: +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# additional words +)* +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +# address +| # or +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +# leading word +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] * # "normal" atoms and or spaces +(?: +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +| +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +) # "special" comment or quoted string +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] * # more "normal" +)* +< +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# < +(?: +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +(?: , +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +)* # additional domains +: +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)? # optional route +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# additional words +)* +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +# address spec +> # > +# name and address +) +" nil nil nil t "A. Other user.1234@dom.ain (a comment)" nil 1 0 " Other user.1234@dom.ain" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(302 ""\"/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/\"\@x400-re.lay" =~ /[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional leading comment +(?: +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# additional words +)* +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +# address +| # or +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +# leading word +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] * # "normal" atoms and or spaces +(?: +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +| +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +) # "special" comment or quoted string +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] * # more "normal" +)* +< +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# < +(?: +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +(?: , +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +)* # additional domains +: +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)? # optional route +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# additional words +)* +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +# address spec +> # > +# name and address +) +/x" "[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional leading comment +(?: +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# additional words +)* +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +# address +| # or +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +# leading word +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] * # "normal" atoms and or spaces +(?: +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +| +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +) # "special" comment or quoted string +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] * # more "normal" +)* +< +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# < +(?: +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +(?: , +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +)* # additional domains +: +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)? # optional route +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# additional words +)* +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +# address spec +> # > +# name and address +) +" nil nil nil t ""/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/"@x400-re.lay" nil 1 0 ""/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/"@x400-re.lay" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(303 ""A missing angle <user\@some.where" =~ /[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional leading comment +(?: +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# additional words +)* +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +# address +| # or +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +# leading word +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] * # "normal" atoms and or spaces +(?: +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +| +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +) # "special" comment or quoted string +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] * # more "normal" +)* +< +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# < +(?: +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +(?: , +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +)* # additional domains +: +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)? # optional route +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# additional words +)* +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +# address spec +> # > +# name and address +) +/x" "[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional leading comment +(?: +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# additional words +)* +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +# address +| # or +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +# leading word +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] * # "normal" atoms and or spaces +(?: +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +| +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +) # "special" comment or quoted string +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] * # more "normal" +)* +< +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# < +(?: +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +(?: , +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +)* # additional domains +: +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)? # optional route +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# additional words +)* +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +# address spec +> # > +# name and address +) +" nil nil nil t "A missing angle <user@some.where" nil 1 0 "user@some.where" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(304 ""The quick brown fox" =~ /[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional leading comment +(?: +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# additional words +)* +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +# address +| # or +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +# leading word +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] * # "normal" atoms and or spaces +(?: +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +| +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +) # "special" comment or quoted string +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] * # more "normal" +)* +< +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# < +(?: +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +(?: , +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +)* # additional domains +: +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)? # optional route +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# additional words +)* +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +# address spec +> # > +# name and address +) +/x" "[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional leading comment +(?: +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# additional words +)* +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +# address +| # or +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +# leading word +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] * # "normal" atoms and or spaces +(?: +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +| +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +) # "special" comment or quoted string +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] * # more "normal" +)* +< +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# < +(?: +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +(?: , +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +)* # additional domains +: +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)? # optional route +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# additional words +)* +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +# address spec +> # > +# name and address +) +" nil nil nil t "The quick brown fox" nil 1 0 nil nil) +(305 ""abc\0def\00pqr\000xyz\0000AB" =~ /abc\0def\00pqr\000xyz\0000AB/" "abc\0def\00pqr\000xyz\0000AB" nil nil nil nil ("abc" 0 "def" 0 "pqr" 0 "xyz" 0 "0AB") nil 1 0 ("abc" 0 "def" 0 "pqr" 0 "xyz" 0 "0AB") (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(306 ""abc456 abc\0def\00pqr\000xyz\0000ABCDE" =~ /abc\0def\00pqr\000xyz\0000AB/" "abc\0def\00pqr\000xyz\0000AB" nil nil nil nil ("abc456 abc" 0 "def" 0 "pqr" 0 "xyz" 0 "0ABCDE") nil 1 0 ("abc" 0 "def" 0 "pqr" 0 "xyz" 0 "0AB") (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(307 ""abc\x0def\x00pqr\x000xyz\x0000AB" =~ /abc\x0def\x00pqr\x000xyz\x0000AB/" "abc\x0def\x00pqr\x000xyz\x0000AB" nil nil nil nil ("abc" 13 "ef" 0 "pqr" 0 "0xyz" 0 "00AB") nil 1 0 ("abc" 13 "ef" 0 "pqr" 0 "0xyz" 0 "00AB") (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(308 ""abc456 abc\x0def\x00pqr\x000xyz\x0000ABCDE" =~ /abc\x0def\x00pqr\x000xyz\x0000AB/" "abc\x0def\x00pqr\x000xyz\x0000AB" nil nil nil nil ("abc456 abc" 13 "ef" 0 "pqr" 0 "0xyz" 0 "00ABCDE") nil 1 0 ("abc" 13 "ef" 0 "pqr" 0 "0xyz" 0 "00AB") (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(309 ""\0A" =~ /^[\000-\037]/" "^[\000-\037]" nil nil nil nil ("" 0 "A") nil 1 0 ("" 0) (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(310 ""\01B" =~ /^[\000-\037]/" "^[\000-\037]" nil nil nil nil ("" 1 "B") nil 1 0 ("" 1) (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(311 ""\037C" =~ /^[\000-\037]/" "^[\000-\037]" nil nil nil nil ("" 31 "C") nil 1 0 ("" 31) (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(312 ""\0\0\0\0" =~ /\0*/" "\0*" nil nil nil nil ("" 0 0 0 0) nil 1 0 ("" 0 0 0 0) (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(313 ""The A\x0\x0Z" =~ /A\x0{2,3}Z/" "A\x0{2,3}Z" nil nil nil nil ("The A" 0 0 "Z") nil 1 0 ("A" 0 0 "Z") (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(314 ""An A\0\x0\0Z" =~ /A\x0{2,3}Z/" "A\x0{2,3}Z" nil nil nil nil ("An A" 0 0 0 "Z") nil 1 0 ("A" 0 0 0 "Z") (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(315 ""A\0Z" =~ /A\x0{2,3}Z/" "A\x0{2,3}Z" nil nil nil nil ("A" 0 "Z") nil 1 0 nil nil) +(316 ""A\0\x0\0\x0Z" =~ /A\x0{2,3}Z/" "A\x0{2,3}Z" nil nil nil nil ("A" 0 0 0 0 "Z") nil 1 0 nil nil) +(317 ""cowcowbell" =~ /^(cow|)\1(bell)/" "^(cow|)\1(bell)" nil nil nil nil "cowcowbell" nil 1 0 "cowcowbell" ("cow" "bell" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(318 ""bell" =~ /^(cow|)\1(bell)/" "^(cow|)\1(bell)" nil nil nil nil "bell" nil 1 0 "bell" ("" "bell" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(319 ""cowbell" =~ /^(cow|)\1(bell)/" "^(cow|)\1(bell)" nil nil nil nil "cowbell" nil 1 0 nil nil) +(320 ""\040abc" =~ /^\s/" "^\s" nil nil nil nil " abc" nil 1 0 " " (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(321 ""\x0cabc" =~ /^\s/" "^\s" nil nil nil nil ("" 12 "abc") nil 1 0 ("" 12) (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(322 ""\nabc" =~ /^\s/" "^\s" nil nil nil nil " +abc" nil 1 0 " +" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(323 ""\rabc" =~ /^\s/" "^\s" nil nil nil nil ("" 13 "abc") nil 1 0 ("" 13) (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(324 ""\tabc" =~ /^\s/" "^\s" nil nil nil nil ("" 9 "abc") nil 1 0 ("" 9) (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(325 ""abc" =~ /^\s/" "^\s" nil nil nil nil "abc" nil 1 0 nil nil) +(326 (""abc" =~ /^a" 9 "b" 10 " " 13 " " 12 " c/x") "^a b + c" nil nil nil t "abc" nil 1 0 "abc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(327 ""ab" =~ /^(a|)\1*b/" "^(a|)\1*b" nil nil nil nil "ab" nil 1 0 "ab" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(328 ""aaaab" =~ /^(a|)\1*b/" "^(a|)\1*b" nil nil nil nil "aaaab" nil 1 0 "aaaab" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(329 ""b" =~ /^(a|)\1*b/" "^(a|)\1*b" nil nil nil nil "b" nil 1 0 "b" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(330 ""acb" =~ /^(a|)\1*b/" "^(a|)\1*b" nil nil nil nil "acb" nil 1 0 nil nil) +(331 ""aab" =~ /^(a|)\1+b/" "^(a|)\1+b" nil nil nil nil "aab" nil 1 0 "aab" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(332 ""aaaab" =~ /^(a|)\1+b/" "^(a|)\1+b" nil nil nil nil "aaaab" nil 1 0 "aaaab" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(333 ""b" =~ /^(a|)\1+b/" "^(a|)\1+b" nil nil nil nil "b" nil 1 0 "b" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(334 ""ab" =~ /^(a|)\1+b/" "^(a|)\1+b" nil nil nil nil "ab" nil 1 0 nil nil) +(335 ""ab" =~ /^(a|)\1?b/" "^(a|)\1?b" nil nil nil nil "ab" nil 1 0 "ab" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(336 ""aab" =~ /^(a|)\1?b/" "^(a|)\1?b" nil nil nil nil "aab" nil 1 0 "aab" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(337 ""b" =~ /^(a|)\1?b/" "^(a|)\1?b" nil nil nil nil "b" nil 1 0 "b" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(338 ""acb" =~ /^(a|)\1?b/" "^(a|)\1?b" nil nil nil nil "acb" nil 1 0 nil nil) +(339 ""aaab" =~ /^(a|)\1{2}b/" "^(a|)\1{2}b" nil nil nil nil "aaab" nil 1 0 "aaab" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(340 ""b" =~ /^(a|)\1{2}b/" "^(a|)\1{2}b" nil nil nil nil "b" nil 1 0 "b" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(341 ""ab" =~ /^(a|)\1{2}b/" "^(a|)\1{2}b" nil nil nil nil "ab" nil 1 0 nil nil) +(342 ""aab" =~ /^(a|)\1{2}b/" "^(a|)\1{2}b" nil nil nil nil "aab" nil 1 0 nil nil) +(343 ""aaaab" =~ /^(a|)\1{2}b/" "^(a|)\1{2}b" nil nil nil nil "aaaab" nil 1 0 nil nil) +(344 ""aaab" =~ /^(a|)\1{2,3}b/" "^(a|)\1{2,3}b" nil nil nil nil "aaab" nil 1 0 "aaab" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(345 ""aaaab" =~ /^(a|)\1{2,3}b/" "^(a|)\1{2,3}b" nil nil nil nil "aaaab" nil 1 0 "aaaab" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(346 ""b" =~ /^(a|)\1{2,3}b/" "^(a|)\1{2,3}b" nil nil nil nil "b" nil 1 0 "b" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(347 ""ab" =~ /^(a|)\1{2,3}b/" "^(a|)\1{2,3}b" nil nil nil nil "ab" nil 1 0 nil nil) +(348 ""aab" =~ /^(a|)\1{2,3}b/" "^(a|)\1{2,3}b" nil nil nil nil "aab" nil 1 0 nil nil) +(349 ""aaaaab" =~ /^(a|)\1{2,3}b/" "^(a|)\1{2,3}b" nil nil nil nil "aaaaab" nil 1 0 nil nil) +(350 ""abbbbc" =~ /ab{1,3}bc/" "ab{1,3}bc" nil nil nil nil "abbbbc" nil 1 0 "abbbbc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(351 ""abbbc" =~ /ab{1,3}bc/" "ab{1,3}bc" nil nil nil nil "abbbc" nil 1 0 "abbbc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(352 ""abbc" =~ /ab{1,3}bc/" "ab{1,3}bc" nil nil nil nil "abbc" nil 1 0 "abbc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(353 ""abc" =~ /ab{1,3}bc/" "ab{1,3}bc" nil nil nil nil "abc" nil 1 0 nil nil) +(354 ""abbbbbc" =~ /ab{1,3}bc/" "ab{1,3}bc" nil nil nil nil "abbbbbc" nil 1 0 nil nil) +(355 ""track1.title:TBlah blah blah" =~ /([^.]*)\.([^:]*):[T ]+(.*)/" "([^.]*)\.([^:]*):[T ]+(.*)" nil nil nil nil "track1.title:TBlah blah blah" nil 1 0 "track1.title:TBlah blah blah" ("track1" "title" "Blah blah blah" nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(356 ""track1.title:TBlah blah blah" =~ /([^.]*)\.([^:]*):[T ]+(.*)/i" "([^.]*)\.([^:]*):[T ]+(.*)" t nil nil nil "track1.title:TBlah blah blah" nil 1 0 "track1.title:TBlah blah blah" ("track1" "title" "Blah blah blah" nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(357 ""track1.title:TBlah blah blah" =~ /([^.]*)\.([^:]*):[t ]+(.*)/i" "([^.]*)\.([^:]*):[t ]+(.*)" t nil nil nil "track1.title:TBlah blah blah" nil 1 0 "track1.title:TBlah blah blah" ("track1" "title" "Blah blah blah" nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(358 ""WXY_^abc" =~ /^[W-c]+$/" "^[W-c]+$" nil nil nil nil "WXY_^abc" nil 1 0 "WXY_^abc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(359 ""wxy" =~ /^[W-c]+$/" "^[W-c]+$" nil nil nil nil "wxy" nil 1 0 nil nil) +(360 ""WXY_^abc" =~ /^[W-c]+$/i" "^[W-c]+$" t nil nil nil "WXY_^abc" nil 1 0 "WXY_^abc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(361 ""wxy_^ABC" =~ /^[W-c]+$/i" "^[W-c]+$" t nil nil nil "wxy_^ABC" nil 1 0 "wxy_^ABC" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(362 ""WXY_^abc" =~ /^[\x3f-\x5F]+$/i" "^[\x3f-\x5F]+$" t nil nil nil "WXY_^abc" nil 1 0 "WXY_^abc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(363 ""wxy_^ABC" =~ /^[\x3f-\x5F]+$/i" "^[\x3f-\x5F]+$" t nil nil nil "wxy_^ABC" nil 1 0 "wxy_^ABC" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(364 ""abc" =~ /^abc$/m" "^abc$" nil t nil nil "abc" nil 1 0 "abc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(365 ""qqq\nabc" =~ /^abc$/m" "^abc$" nil t nil nil "qqq +abc" nil 1 0 "abc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(366 ""abc\nzzz" =~ /^abc$/m" "^abc$" nil t nil nil "abc +zzz" nil 1 0 "abc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(367 ""qqq\nabc\nzzz" =~ /^abc$/m" "^abc$" nil t nil nil "qqq +abc +zzz" nil 1 0 "abc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(368 ""abc" =~ /^abc$/" "^abc$" nil nil nil nil "abc" nil 1 0 "abc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(369 ""qqq\nabc" =~ /^abc$/" "^abc$" nil nil nil nil "qqq +abc" nil 1 0 nil nil) +(370 ""abc\nzzz" =~ /^abc$/" "^abc$" nil nil nil nil "abc +zzz" nil 1 0 nil nil) +(371 ""qqq\nabc\nzzz" =~ /^abc$/" "^abc$" nil nil nil nil "qqq +abc +zzz" nil 1 0 nil nil) +(372 ""abc" =~ /\Aabc\Z/m" "\Aabc\Z" nil t nil nil "abc" nil 1 0 "abc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(373 ""abc\n" =~ /\Aabc\Z/m" "\Aabc\Z" nil t nil nil "abc +" nil 1 0 "abc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(374 ""qqq\nabc" =~ /\Aabc\Z/m" "\Aabc\Z" nil t nil nil "qqq +abc" nil 1 0 nil nil) +(375 ""abc\nzzz" =~ /\Aabc\Z/m" "\Aabc\Z" nil t nil nil "abc +zzz" nil 1 0 nil nil) +(376 ""qqq\nabc\nzzz" =~ /\Aabc\Z/m" "\Aabc\Z" nil t nil nil "qqq +abc +zzz" nil 1 0 nil nil) +(377 ""abc\ndef" =~ /\A(.)*\Z/s" "\A(.)*\Z" nil nil t nil "abc +def" nil 1 0 "abc +def" ("f" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(378 ""abc\ndef" =~ /\A(.)*\Z/m" "\A(.)*\Z" nil t nil nil "abc +def" nil 1 0 nil nil) +(379 ""b::c" =~ /(?:b)|(?::+)/" "(?:b)|(?::+)" nil nil nil nil "b::c" nil 1 0 "b" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(380 ""c::b" =~ /(?:b)|(?::+)/" "(?:b)|(?::+)" nil nil nil nil "c::b" nil 1 0 "::" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(381 ""az-" =~ /[-az]+/" "[-az]+" nil nil nil nil "az-" nil 1 0 "az-" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(382 ""b" =~ /[-az]+/" "[-az]+" nil nil nil nil "b" nil 1 0 nil nil) +(383 ""za-" =~ /[az-]+/" "[az-]+" nil nil nil nil "za-" nil 1 0 "za-" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(384 ""b" =~ /[az-]+/" "[az-]+" nil nil nil nil "b" nil 1 0 nil nil) +(385 ""a-z" =~ /[a\-z]+/" "[a\-z]+" nil nil nil nil "a-z" nil 1 0 "a-z" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(386 ""b" =~ /[a\-z]+/" "[a\-z]+" nil nil nil nil "b" nil 1 0 nil nil) +(387 ""abcdxyz" =~ /[a-z]+/" "[a-z]+" nil nil nil nil "abcdxyz" nil 1 0 "abcdxyz" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(388 ""12-34" =~ /[\d-]+/" "[\d-]+" nil nil nil nil "12-34" nil 1 0 "12-34" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(389 ""aaa" =~ /[\d-]+/" "[\d-]+" nil nil nil nil "aaa" nil 1 0 nil nil) +(390 ""12-34z" =~ /[\d-z]+/" "[\d-z]+" nil nil nil nil "12-34z" nil 1 0 "12-34z" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(391 ""aaa" =~ /[\d-z]+/" "[\d-z]+" nil nil nil nil "aaa" nil 1 0 nil nil) +(392 ""\\" =~ /\x5c/" "\x5c" nil nil nil nil "\" nil 1 0 "\" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(393 ""the Zoo" =~ /\x20Z/" "\x20Z" nil nil nil nil "the Zoo" nil 1 0 " Z" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(394 ""Zulu" =~ /\x20Z/" "\x20Z" nil nil nil nil "Zulu" nil 1 0 nil nil) +(395 ""abcabc" =~ /(abc)\1/i" "(abc)\1" t nil nil nil "abcabc" nil 1 0 "abcabc" ("abc" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(396 ""ABCabc" =~ /(abc)\1/i" "(abc)\1" t nil nil nil "ABCabc" nil 1 0 "ABCabc" ("ABC" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(397 ""abcABC" =~ /(abc)\1/i" "(abc)\1" t nil nil nil "abcABC" nil 1 0 "abcABC" ("abc" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(398 ""ab{3cd" =~ /ab{3cd/" "ab{3cd" nil nil nil nil "ab{3cd" nil 1 0 "ab{3cd" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(399 ""ab{3,cd" =~ /ab{3,cd/" "ab{3,cd" nil nil nil nil "ab{3,cd" nil 1 0 "ab{3,cd" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(400 ""ab{3,4a}cd" =~ /ab{3,4a}cd/" "ab{3,4a}cd" nil nil nil nil "ab{3,4a}cd" nil 1 0 "ab{3,4a}cd" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(401 ""{4,5a}bc" =~ /{4,5a}bc/" "{4,5a}bc" nil nil nil nil "{4,5a}bc" nil 1 0 "{4,5a}bc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(402 ""a\rb" =~ /^a.b/" "^a.b" nil nil nil nil ("a" 13 "b") nil 1 0 ("a" 13 "b") (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(403 ""a\nb" =~ /^a.b/" "^a.b" nil nil nil nil "a +b" nil 1 0 nil nil) +(404 ""abc" =~ /abc$/" "abc$" nil nil nil nil "abc" nil 1 0 "abc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(405 ""abc\n" =~ /abc$/" "abc$" nil nil nil nil "abc +" nil 1 0 "abc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(406 ""abc\ndef" =~ /abc$/" "abc$" nil nil nil nil "abc +def" nil 1 0 nil nil) +(407 ""abc\x53" =~ /(abc)\123/" "(abc)\123" nil nil nil nil "abcS" nil 1 0 "abcS" ("abc" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(408 ""abc\x93" =~ /(abc)\223/" "(abc)\223" nil nil nil nil ("abc" 147) nil 1 0 ("abc" 147) ("abc" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(409 ""abc\xd3" =~ /(abc)\323/" "(abc)\323" nil nil nil nil ("abc" 211) nil 1 0 ("abc" 211) ("abc" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(410 ""abc\x40" =~ /(abc)\500/" "(abc)\500" nil nil nil nil "abc@" nil 1 0 "abc@" ("abc" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(411 ""abc\100" =~ /(abc)\500/" "(abc)\500" nil nil nil nil "abc@" nil 1 0 "abc@" ("abc" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(412 ""abc\x400" =~ /(abc)\5000/" "(abc)\5000" nil nil nil nil "abc@0" nil 1 0 "abc@0" ("abc" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(413 ""abc\x40\x30" =~ /(abc)\5000/" "(abc)\5000" nil nil nil nil "abc@0" nil 1 0 "abc@0" ("abc" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(414 ""abc\1000" =~ /(abc)\5000/" "(abc)\5000" nil nil nil nil "abc@0" nil 1 0 "abc@0" ("abc" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(415 ""abc\100\x30" =~ /(abc)\5000/" "(abc)\5000" nil nil nil nil "abc@0" nil 1 0 "abc@0" ("abc" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(416 ""abc\100\060" =~ /(abc)\5000/" "(abc)\5000" nil nil nil nil "abc@0" nil 1 0 "abc@0" ("abc" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(417 ""abc\100\60" =~ /(abc)\5000/" "(abc)\5000" nil nil nil nil "abc@0" nil 1 0 "abc@0" ("abc" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(418 ""abc\081" =~ /abc\81/" "abc\81" nil nil nil nil ("abc" 0 "81") nil 1 0 ("abc" 0 "81") (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(419 ""abc\0\x38\x31" =~ /abc\81/" "abc\81" nil nil nil nil ("abc" 0 "81") nil 1 0 ("abc" 0 "81") (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(420 ""abc\091" =~ /abc\91/" "abc\91" nil nil nil nil ("abc" 0 "91") nil 1 0 ("abc" 0 "91") (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(421 ""abc\0\x39\x31" =~ /abc\91/" "abc\91" nil nil nil nil ("abc" 0 "91") nil 1 0 ("abc" 0 "91") (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(422 ""abcdefghijkllS" =~ /(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)(l)\12\123/" "(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)(l)\12\123" nil nil nil nil "abcdefghijkllS" nil 1 0 "abcdefghijkllS" ("a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" nil nil nil nil)) +(423 ""abcdefghijk\12S" =~ /(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)\12\123/" "(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)\12\123" nil nil nil nil "abcdefghijk +S" nil 1 0 "abcdefghijk +S" ("a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" nil nil nil nil nil)) +(424 ""abgdef" =~ /ab\gdef/" "ab\gdef" nil nil nil nil "abgdef" nil 1 0 "abgdef" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(425 ""bc" =~ /a{0}bc/" "a{0}bc" nil nil nil nil "bc" nil 1 0 "bc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(426 ""xyz" =~ /(a|(bc)){0,0}?xyz/" "(a|(bc)){0,0}?xyz" nil nil nil nil "xyz" nil 1 0 "xyz" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(427 ""abc\010de" =~ /abc[\10]de/" "abc[\10]de" nil nil nil nil ("abc" 8 "de") nil 1 0 ("abc" 8 "de") (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(428 ""abc\1de" =~ /abc[\1]de/" "abc[\1]de" nil nil nil nil ("abc" 1 "de") nil 1 0 ("abc" 1 "de") (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(429 ""abc\1de" =~ /(abc)[\1]de/" "(abc)[\1]de" nil nil nil nil ("abc" 1 "de") nil 1 0 ("abc" 1 "de") ("abc" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(430 ""a\nb" =~ /a.b(?s)/" "a.b(?s)" nil nil nil nil "a +b" nil 1 0 nil nil) +(431 ""baNOTccccd" =~ /^([^a])([^\b])([^c]*)([^d]{3,4})/" "^([^a])([^\b])([^c]*)([^d]{3,4})" nil nil nil nil "baNOTccccd" nil 1 0 "baNOTcccc" ("b" "a" "NOT" "cccc" nil nil nil nil nil nil nil nil nil nil nil nil)) +(432 ""baNOTcccd" =~ /^([^a])([^\b])([^c]*)([^d]{3,4})/" "^([^a])([^\b])([^c]*)([^d]{3,4})" nil nil nil nil "baNOTcccd" nil 1 0 "baNOTccc" ("b" "a" "NOT" "ccc" nil nil nil nil nil nil nil nil nil nil nil nil)) +(433 ""baNOTccd" =~ /^([^a])([^\b])([^c]*)([^d]{3,4})/" "^([^a])([^\b])([^c]*)([^d]{3,4})" nil nil nil nil "baNOTccd" nil 1 0 "baNOTcc" ("b" "a" "NO" "Tcc" nil nil nil nil nil nil nil nil nil nil nil nil)) +(434 ""bacccd" =~ /^([^a])([^\b])([^c]*)([^d]{3,4})/" "^([^a])([^\b])([^c]*)([^d]{3,4})" nil nil nil nil "bacccd" nil 1 0 "baccc" ("b" "a" "" "ccc" nil nil nil nil nil nil nil nil nil nil nil nil)) +(435 ""anything" =~ /^([^a])([^\b])([^c]*)([^d]{3,4})/" "^([^a])([^\b])([^c]*)([^d]{3,4})" nil nil nil nil "anything" nil 1 0 nil nil) +(436 ""b\bc" =~ /^([^a])([^\b])([^c]*)([^d]{3,4})/" "^([^a])([^\b])([^c]*)([^d]{3,4})" nil nil nil nil ("b" 8 "c") nil 1 0 nil nil) +(437 ""baccd" =~ /^([^a])([^\b])([^c]*)([^d]{3,4})/" "^([^a])([^\b])([^c]*)([^d]{3,4})" nil nil nil nil "baccd" nil 1 0 nil nil) +(438 ""Abc" =~ /[^a]/" "[^a]" nil nil nil nil "Abc" nil 1 0 "A" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(439 ""Abc" =~ /[^a]/i" "[^a]" t nil nil nil "Abc" nil 1 0 "b" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(440 ""AAAaAbc" =~ /[^a]+/" "[^a]+" nil nil nil nil "AAAaAbc" nil 1 0 "AAA" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(441 ""AAAaAbc" =~ /[^a]+/i" "[^a]+" t nil nil nil "AAAaAbc" nil 1 0 "bc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(442 ""bbb\nccc" =~ /[^a]+/" "[^a]+" nil nil nil nil "bbb +ccc" nil 1 0 "bbb +ccc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(443 ""abc" =~ /[^k]$/" "[^k]$" nil nil nil nil "abc" nil 1 0 "c" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(444 ""abk" =~ /[^k]$/" "[^k]$" nil nil nil nil "abk" nil 1 0 nil nil) +(445 ""abc" =~ /[^k]{2,3}$/" "[^k]{2,3}$" nil nil nil nil "abc" nil 1 0 "abc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(446 ""kbc" =~ /[^k]{2,3}$/" "[^k]{2,3}$" nil nil nil nil "kbc" nil 1 0 "bc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(447 ""kabc" =~ /[^k]{2,3}$/" "[^k]{2,3}$" nil nil nil nil "kabc" nil 1 0 "abc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(448 ""abk" =~ /[^k]{2,3}$/" "[^k]{2,3}$" nil nil nil nil "abk" nil 1 0 nil nil) +(449 ""akb" =~ /[^k]{2,3}$/" "[^k]{2,3}$" nil nil nil nil "akb" nil 1 0 nil nil) +(450 ""akk" =~ /[^k]{2,3}$/" "[^k]{2,3}$" nil nil nil nil "akk" nil 1 0 nil nil) +(451 ""12345678\@a.b.c.d" =~ /^\d{8,}\@.+[^k]$/" "^\d{8,}\@.+[^k]$" nil nil nil nil "12345678@a.b.c.d" nil 1 0 "12345678@a.b.c.d" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(452 ""123456789\@x.y.z" =~ /^\d{8,}\@.+[^k]$/" "^\d{8,}\@.+[^k]$" nil nil nil nil "123456789@x.y.z" nil 1 0 "123456789@x.y.z" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(453 ""12345678\@x.y.uk" =~ /^\d{8,}\@.+[^k]$/" "^\d{8,}\@.+[^k]$" nil nil nil nil "12345678@x.y.uk" nil 1 0 nil nil) +(454 ""1234567\@a.b.c.d" =~ /^\d{8,}\@.+[^k]$/" "^\d{8,}\@.+[^k]$" nil nil nil nil "1234567@a.b.c.d" nil 1 0 nil nil) +(455 ""aaaaaaaaa" =~ /(a)\1{8,}/" "(a)\1{8,}" nil nil nil nil "aaaaaaaaa" nil 1 0 "aaaaaaaaa" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(456 ""aaaaaaaaaa" =~ /(a)\1{8,}/" "(a)\1{8,}" nil nil nil nil "aaaaaaaaaa" nil 1 0 "aaaaaaaaaa" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(457 ""aaaaaaa" =~ /(a)\1{8,}/" "(a)\1{8,}" nil nil nil nil "aaaaaaa" nil 1 0 nil nil) +(458 ""aaaabcd" =~ /[^a]/" "[^a]" nil nil nil nil "aaaabcd" nil 1 0 "b" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(459 ""aaAabcd" =~ /[^a]/" "[^a]" nil nil nil nil "aaAabcd" nil 1 0 "A" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(460 ""aaaabcd" =~ /[^a]/i" "[^a]" t nil nil nil "aaaabcd" nil 1 0 "b" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(461 ""aaAabcd" =~ /[^a]/i" "[^a]" t nil nil nil "aaAabcd" nil 1 0 "b" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(462 ""aaaabcd" =~ /[^az]/" "[^az]" nil nil nil nil "aaaabcd" nil 1 0 "b" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(463 ""aaAabcd" =~ /[^az]/" "[^az]" nil nil nil nil "aaAabcd" nil 1 0 "A" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(464 ""aaaabcd" =~ /[^az]/i" "[^az]" t nil nil nil "aaaabcd" nil 1 0 "b" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(465 ""aaAabcd" =~ /[^az]/i" "[^az]" t nil nil nil "aaAabcd" nil 1 0 "b" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(466 ""\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377" =~ /\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377/" "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377" nil nil nil nil ("" 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 " !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~" 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255) nil 1 0 ("" 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 " !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~" 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255) (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(467 ""xxxxxxxxxxxPSTAIREISLLxxxxxxxxx" =~ /P[^*]TAIRE[^*]{1,6}?LL/" "P[^*]TAIRE[^*]{1,6}?LL" nil nil nil nil "xxxxxxxxxxxPSTAIREISLLxxxxxxxxx" nil 1 0 "PSTAIREISLL" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(468 ""xxxxxxxxxxxPSTAIREISLLxxxxxxxxx" =~ /P[^*]TAIRE[^*]{1,}?LL/" "P[^*]TAIRE[^*]{1,}?LL" nil nil nil nil "xxxxxxxxxxxPSTAIREISLLxxxxxxxxx" nil 1 0 "PSTAIREISLL" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(469 ""1.230003938" =~ /(\.\d\d[1-9]?)\d+/" "(\.\d\d[1-9]?)\d+" nil nil nil nil "1.230003938" nil 1 0 ".230003938" (".23" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(470 ""1.875000282" =~ /(\.\d\d[1-9]?)\d+/" "(\.\d\d[1-9]?)\d+" nil nil nil nil "1.875000282" nil 1 0 ".875000282" (".875" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(471 ""1.235" =~ /(\.\d\d[1-9]?)\d+/" "(\.\d\d[1-9]?)\d+" nil nil nil nil "1.235" nil 1 0 ".235" (".23" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(472 ""1.230003938" =~ /(\.\d\d((?=0)|\d(?=\d)))/" "(\.\d\d((?=0)|\d(?=\d)))" nil nil nil nil "1.230003938" nil 1 0 ".23" (".23" "" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(473 ""1.875000282" =~ /(\.\d\d((?=0)|\d(?=\d)))/" "(\.\d\d((?=0)|\d(?=\d)))" nil nil nil nil "1.875000282" nil 1 0 ".875" (".875" "5" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(474 ""1.235" =~ /(\.\d\d((?=0)|\d(?=\d)))/" "(\.\d\d((?=0)|\d(?=\d)))" nil nil nil nil "1.235" nil 1 0 nil nil) +(475 ""ab" =~ /a(?)b/" "a(?)b" nil nil nil nil "ab" nil 1 0 "ab" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(476 ""Food is on the foo table" =~ /\b(foo)\s+(\w+)/i" "\b(foo)\s+(\w+)" t nil nil nil "Food is on the foo table" nil 1 0 "foo table" ("foo" "table" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(477 ""The food is under the bar in the barn." =~ /foo(.*)bar/" "foo(.*)bar" nil nil nil nil "The food is under the bar in the barn." nil 1 0 "food is under the bar in the bar" ("d is under the bar in the " nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(478 ""The food is under the bar in the barn." =~ /foo(.*?)bar/" "foo(.*?)bar" nil nil nil nil "The food is under the bar in the barn." nil 1 0 "food is under the bar" ("d is under the " nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(479 ""I have 2 numbers: 53147" =~ /(.*)(\d*)/" "(.*)(\d*)" nil nil nil nil "I have 2 numbers: 53147" nil 1 0 "I have 2 numbers: 53147" ("I have 2 numbers: 53147" "" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(480 ""I have 2 numbers: 53147" =~ /(.*)(\d+)/" "(.*)(\d+)" nil nil nil nil "I have 2 numbers: 53147" nil 1 0 "I have 2 numbers: 53147" ("I have 2 numbers: 5314" "7" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(481 ""I have 2 numbers: 53147" =~ /(.*?)(\d*)/" "(.*?)(\d*)" nil nil nil nil "I have 2 numbers: 53147" nil 1 0 "" ("" "" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(482 ""I have 2 numbers: 53147" =~ /(.*?)(\d+)/" "(.*?)(\d+)" nil nil nil nil "I have 2 numbers: 53147" nil 1 0 "I have 2" ("I have " "2" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(483 ""I have 2 numbers: 53147" =~ /(.*)(\d+)$/" "(.*)(\d+)$" nil nil nil nil "I have 2 numbers: 53147" nil 1 0 "I have 2 numbers: 53147" ("I have 2 numbers: 5314" "7" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(484 ""I have 2 numbers: 53147" =~ /(.*?)(\d+)$/" "(.*?)(\d+)$" nil nil nil nil "I have 2 numbers: 53147" nil 1 0 "I have 2 numbers: 53147" ("I have 2 numbers: " "53147" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(485 ""I have 2 numbers: 53147" =~ /(.*)\b(\d+)$/" "(.*)\b(\d+)$" nil nil nil nil "I have 2 numbers: 53147" nil 1 0 "I have 2 numbers: 53147" ("I have 2 numbers: " "53147" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(486 ""I have 2 numbers: 53147" =~ /(.*\D)(\d+)$/" "(.*\D)(\d+)$" nil nil nil nil "I have 2 numbers: 53147" nil 1 0 "I have 2 numbers: 53147" ("I have 2 numbers: " "53147" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(487 ""ABC123" =~ /^\D*(?!123)/" "^\D*(?!123)" nil nil nil nil "ABC123" nil 1 0 "AB" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(488 ""ABC445" =~ /^(\D*)(?=\d)(?!123)/" "^(\D*)(?=\d)(?!123)" nil nil nil nil "ABC445" nil 1 0 "ABC" ("ABC" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(489 ""ABC123" =~ /^(\D*)(?=\d)(?!123)/" "^(\D*)(?=\d)(?!123)" nil nil nil nil "ABC123" nil 1 0 nil nil) +(490 ""W46]789" =~ /^[W-]46]/" "^[W-]46]" nil nil nil nil "W46]789" nil 1 0 "W46]" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(491 ""-46]789" =~ /^[W-]46]/" "^[W-]46]" nil nil nil nil "-46]789" nil 1 0 "-46]" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(492 ""Wall" =~ /^[W-]46]/" "^[W-]46]" nil nil nil nil "Wall" nil 1 0 nil nil) +(493 ""Zebra" =~ /^[W-]46]/" "^[W-]46]" nil nil nil nil "Zebra" nil 1 0 nil nil) +(494 ""42" =~ /^[W-]46]/" "^[W-]46]" nil nil nil nil "42" nil 1 0 nil nil) +(495 ""[abcd]" =~ /^[W-]46]/" "^[W-]46]" nil nil nil nil "[abcd]" nil 1 0 nil nil) +(496 ""]abcd[" =~ /^[W-]46]/" "^[W-]46]" nil nil nil nil "]abcd[" nil 1 0 nil nil) +(497 ""W46]789" =~ /^[W-\]46]/" "^[W-\]46]" nil nil nil nil "W46]789" nil 1 0 "W" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(498 ""Wall" =~ /^[W-\]46]/" "^[W-\]46]" nil nil nil nil "Wall" nil 1 0 "W" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(499 ""Zebra" =~ /^[W-\]46]/" "^[W-\]46]" nil nil nil nil "Zebra" nil 1 0 "Z" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(500 ""Xylophone" =~ /^[W-\]46]/" "^[W-\]46]" nil nil nil nil "Xylophone" nil 1 0 "X" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(501 ""42" =~ /^[W-\]46]/" "^[W-\]46]" nil nil nil nil "42" nil 1 0 "4" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(502 ""[abcd]" =~ /^[W-\]46]/" "^[W-\]46]" nil nil nil nil "[abcd]" nil 1 0 "[" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(503 ""]abcd[" =~ /^[W-\]46]/" "^[W-\]46]" nil nil nil nil "]abcd[" nil 1 0 "]" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(504 ""\\backslash" =~ /^[W-\]46]/" "^[W-\]46]" nil nil nil nil "\backslash" nil 1 0 "\" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(505 ""-46]789" =~ /^[W-\]46]/" "^[W-\]46]" nil nil nil nil "-46]789" nil 1 0 nil nil) +(506 ""well" =~ /^[W-\]46]/" "^[W-\]46]" nil nil nil nil "well" nil 1 0 nil nil) +(507 ""01/01/2000" =~ /\d\d\/\d\d\/\d\d\d\d/" "\d\d\/\d\d\/\d\d\d\d" nil nil nil nil "01/01/2000" nil 1 0 "01/01/2000" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(508 ""word cat dog elephant mussel cow horse canary baboon snake shark otherword" =~ /word (?:[a-zA-Z0-9]+ ){0,10}otherword/" "word (?:[a-zA-Z0-9]+ ){0,10}otherword" nil nil nil nil "word cat dog elephant mussel cow horse canary baboon snake shark otherword" nil 1 0 "word cat dog elephant mussel cow horse canary baboon snake shark otherword" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(509 ""word cat dog elephant mussel cow horse canary baboon snake shark" =~ /word (?:[a-zA-Z0-9]+ ){0,10}otherword/" "word (?:[a-zA-Z0-9]+ ){0,10}otherword" nil nil nil nil "word cat dog elephant mussel cow horse canary baboon snake shark" nil 1 0 nil nil) +(510 ""word cat dog elephant mussel cow horse canary baboon snake shark the quick brown fox and the lazy dog and several other words getting close to thirty by now I hope" =~ /word (?:[a-zA-Z0-9]+ ){0,300}otherword/" "word (?:[a-zA-Z0-9]+ ){0,300}otherword" nil nil nil nil "word cat dog elephant mussel cow horse canary baboon snake shark the quick brown fox and the lazy dog and several other words getting close to thirty by now I hope" nil 1 0 nil nil) +(511 ""bcd" =~ /^(a){0,0}/" "^(a){0,0}" nil nil nil nil "bcd" nil 1 0 "" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(512 ""abc" =~ /^(a){0,0}/" "^(a){0,0}" nil nil nil nil "abc" nil 1 0 "" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(513 ""aab" =~ /^(a){0,0}/" "^(a){0,0}" nil nil nil nil "aab" nil 1 0 "" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(514 ""bcd" =~ /^(a){0,1}/" "^(a){0,1}" nil nil nil nil "bcd" nil 1 0 "" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(515 ""abc" =~ /^(a){0,1}/" "^(a){0,1}" nil nil nil nil "abc" nil 1 0 "a" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(516 ""aab" =~ /^(a){0,1}/" "^(a){0,1}" nil nil nil nil "aab" nil 1 0 "a" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(517 ""bcd" =~ /^(a){0,2}/" "^(a){0,2}" nil nil nil nil "bcd" nil 1 0 "" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(518 ""abc" =~ /^(a){0,2}/" "^(a){0,2}" nil nil nil nil "abc" nil 1 0 "a" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(519 ""aab" =~ /^(a){0,2}/" "^(a){0,2}" nil nil nil nil "aab" nil 1 0 "aa" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(520 ""bcd" =~ /^(a){0,3}/" "^(a){0,3}" nil nil nil nil "bcd" nil 1 0 "" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(521 ""abc" =~ /^(a){0,3}/" "^(a){0,3}" nil nil nil nil "abc" nil 1 0 "a" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(522 ""aab" =~ /^(a){0,3}/" "^(a){0,3}" nil nil nil nil "aab" nil 1 0 "aa" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(523 ""aaa" =~ /^(a){0,3}/" "^(a){0,3}" nil nil nil nil "aaa" nil 1 0 "aaa" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(524 ""bcd" =~ /^(a){0,}/" "^(a){0,}" nil nil nil nil "bcd" nil 1 0 "" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(525 ""abc" =~ /^(a){0,}/" "^(a){0,}" nil nil nil nil "abc" nil 1 0 "a" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(526 ""aab" =~ /^(a){0,}/" "^(a){0,}" nil nil nil nil "aab" nil 1 0 "aa" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(527 ""aaa" =~ /^(a){0,}/" "^(a){0,}" nil nil nil nil "aaa" nil 1 0 "aaa" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(528 ""aaaaaaaa" =~ /^(a){0,}/" "^(a){0,}" nil nil nil nil "aaaaaaaa" nil 1 0 "aaaaaaaa" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(529 ""bcd" =~ /^(a){1,1}/" "^(a){1,1}" nil nil nil nil "bcd" nil 1 0 nil nil) +(530 ""abc" =~ /^(a){1,1}/" "^(a){1,1}" nil nil nil nil "abc" nil 1 0 "a" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(531 ""aab" =~ /^(a){1,1}/" "^(a){1,1}" nil nil nil nil "aab" nil 1 0 "a" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(532 ""bcd" =~ /^(a){1,2}/" "^(a){1,2}" nil nil nil nil "bcd" nil 1 0 nil nil) +(533 ""abc" =~ /^(a){1,2}/" "^(a){1,2}" nil nil nil nil "abc" nil 1 0 "a" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(534 ""aab" =~ /^(a){1,2}/" "^(a){1,2}" nil nil nil nil "aab" nil 1 0 "aa" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(535 ""bcd" =~ /^(a){1,3}/" "^(a){1,3}" nil nil nil nil "bcd" nil 1 0 nil nil) +(536 ""abc" =~ /^(a){1,3}/" "^(a){1,3}" nil nil nil nil "abc" nil 1 0 "a" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(537 ""aab" =~ /^(a){1,3}/" "^(a){1,3}" nil nil nil nil "aab" nil 1 0 "aa" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(538 ""aaa" =~ /^(a){1,3}/" "^(a){1,3}" nil nil nil nil "aaa" nil 1 0 "aaa" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(539 ""bcd" =~ /^(a){1,}/" "^(a){1,}" nil nil nil nil "bcd" nil 1 0 nil nil) +(540 ""abc" =~ /^(a){1,}/" "^(a){1,}" nil nil nil nil "abc" nil 1 0 "a" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(541 ""aab" =~ /^(a){1,}/" "^(a){1,}" nil nil nil nil "aab" nil 1 0 "aa" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(542 ""aaa" =~ /^(a){1,}/" "^(a){1,}" nil nil nil nil "aaa" nil 1 0 "aaa" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(543 ""aaaaaaaa" =~ /^(a){1,}/" "^(a){1,}" nil nil nil nil "aaaaaaaa" nil 1 0 "aaaaaaaa" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(544 ""borfle\nbib.gif\nno" =~ /.*\.gif/" ".*\.gif" nil nil nil nil "borfle +bib.gif +no" nil 1 0 "bib.gif" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(545 ""borfle\nbib.gif\nno" =~ /.{0,}\.gif/" ".{0,}\.gif" nil nil nil nil "borfle +bib.gif +no" nil 1 0 "bib.gif" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(546 ""borfle\nbib.gif\nno" =~ /.*\.gif/m" ".*\.gif" nil t nil nil "borfle +bib.gif +no" nil 1 0 "bib.gif" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(547 ""borfle\nbib.gif\nno" =~ /.*\.gif/s" ".*\.gif" nil nil t nil "borfle +bib.gif +no" nil 1 0 "borfle +bib.gif" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(548 ""borfle\nbib.gif\nno" =~ /.*\.gif/ms" ".*\.gif" nil t t nil "borfle +bib.gif +no" nil 1 0 "borfle +bib.gif" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(549 ""borfle\nbib.gif\nno" =~ /.*$/" ".*$" nil nil nil nil "borfle +bib.gif +no" nil 1 0 "no" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(550 ""borfle\nbib.gif\nno" =~ /.*$/m" ".*$" nil t nil nil "borfle +bib.gif +no" nil 1 0 "borfle" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(551 ""borfle\nbib.gif\nno" =~ /.*$/s" ".*$" nil nil t nil "borfle +bib.gif +no" nil 1 0 "borfle +bib.gif +no" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(552 ""borfle\nbib.gif\nno" =~ /.*$/ms" ".*$" nil t t nil "borfle +bib.gif +no" nil 1 0 "borfle +bib.gif +no" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(553 ""borfle\nbib.gif\nno\n" =~ /.*$/" ".*$" nil nil nil nil "borfle +bib.gif +no +" nil 1 0 "no" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(554 ""borfle\nbib.gif\nno\n" =~ /.*$/m" ".*$" nil t nil nil "borfle +bib.gif +no +" nil 1 0 "borfle" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(555 ""borfle\nbib.gif\nno\n" =~ /.*$/s" ".*$" nil nil t nil "borfle +bib.gif +no +" nil 1 0 "borfle +bib.gif +no +" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(556 ""borfle\nbib.gif\nno\n" =~ /.*$/ms" ".*$" nil t t nil "borfle +bib.gif +no +" nil 1 0 "borfle +bib.gif +no +" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(557 ""abcde\n1234Xyz" =~ /(.*X|^B)/" "(.*X|^B)" nil nil nil nil "abcde +1234Xyz" nil 1 0 "1234X" ("1234X" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(558 ""BarFoo" =~ /(.*X|^B)/" "(.*X|^B)" nil nil nil nil "BarFoo" nil 1 0 "B" ("B" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(559 ""abcde\nBar" =~ /(.*X|^B)/" "(.*X|^B)" nil nil nil nil "abcde +Bar" nil 1 0 nil nil) +(560 ""abcde\n1234Xyz" =~ /(.*X|^B)/m" "(.*X|^B)" nil t nil nil "abcde +1234Xyz" nil 1 0 "1234X" ("1234X" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(561 ""BarFoo" =~ /(.*X|^B)/m" "(.*X|^B)" nil t nil nil "BarFoo" nil 1 0 "B" ("B" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(562 ""abcde\nBar" =~ /(.*X|^B)/m" "(.*X|^B)" nil t nil nil "abcde +Bar" nil 1 0 "B" ("B" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(563 ""abcde\n1234Xyz" =~ /(.*X|^B)/s" "(.*X|^B)" nil nil t nil "abcde +1234Xyz" nil 1 0 "abcde +1234X" ("abcde +1234X" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(564 ""BarFoo" =~ /(.*X|^B)/s" "(.*X|^B)" nil nil t nil "BarFoo" nil 1 0 "B" ("B" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(565 ""abcde\nBar" =~ /(.*X|^B)/s" "(.*X|^B)" nil nil t nil "abcde +Bar" nil 1 0 nil nil) +(566 ""abcde\n1234Xyz" =~ /(.*X|^B)/ms" "(.*X|^B)" nil t t nil "abcde +1234Xyz" nil 1 0 "abcde +1234X" ("abcde +1234X" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(567 ""BarFoo" =~ /(.*X|^B)/ms" "(.*X|^B)" nil t t nil "BarFoo" nil 1 0 "B" ("B" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(568 ""abcde\nBar" =~ /(.*X|^B)/ms" "(.*X|^B)" nil t t nil "abcde +Bar" nil 1 0 "B" ("B" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(569 ""abcde\n1234Xyz" =~ /(?s)(.*X|^B)/" "(?s)(.*X|^B)" nil nil nil nil "abcde +1234Xyz" nil 1 0 "abcde +1234X" ("abcde +1234X" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(570 ""BarFoo" =~ /(?s)(.*X|^B)/" "(?s)(.*X|^B)" nil nil nil nil "BarFoo" nil 1 0 "B" ("B" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(571 ""abcde\nBar" =~ /(?s)(.*X|^B)/" "(?s)(.*X|^B)" nil nil nil nil "abcde +Bar" nil 1 0 nil nil) +(572 ""abcde\n1234Xyz" =~ /(?s:.*X|^B)/" "(?s:.*X|^B)" nil nil nil nil "abcde +1234Xyz" nil 1 0 "abcde +1234X" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(573 ""BarFoo" =~ /(?s:.*X|^B)/" "(?s:.*X|^B)" nil nil nil nil "BarFoo" nil 1 0 "B" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(574 ""abcde\nBar" =~ /(?s:.*X|^B)/" "(?s:.*X|^B)" nil nil nil nil "abcde +Bar" nil 1 0 nil nil) +(575 ""abc\nB" =~ /^.*B/" "^.*B" nil nil nil nil "abc +B" nil 1 0 nil nil) +(576 ""abc\nB" =~ /(?s)^.*B/" "(?s)^.*B" nil nil nil nil "abc +B" nil 1 0 "abc +B" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(577 ""abc\nB" =~ /(?m)^.*B/" "(?m)^.*B" nil nil nil nil "abc +B" nil 1 0 "B" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(578 ""abc\nB" =~ /(?ms)^.*B/" "(?ms)^.*B" nil nil nil nil "abc +B" nil 1 0 "abc +B" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(579 ""abc\nB" =~ /(?ms)^B/" "(?ms)^B" nil nil nil nil "abc +B" nil 1 0 "B" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(580 ""B\n" =~ /(?s)B$/" "(?s)B$" nil nil nil nil "B +" nil 1 0 "B" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(581 ""123456654321" =~ /^[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]/" "^[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]" nil nil nil nil "123456654321" nil 1 0 "123456654321" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(582 ""123456654321" =~ /^\d\d\d\d\d\d\d\d\d\d\d\d/" "^\d\d\d\d\d\d\d\d\d\d\d\d" nil nil nil nil "123456654321" nil 1 0 "123456654321" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(583 ""123456654321" =~ /^[\d][\d][\d][\d][\d][\d][\d][\d][\d][\d][\d][\d]/" "^[\d][\d][\d][\d][\d][\d][\d][\d][\d][\d][\d][\d]" nil nil nil nil "123456654321" nil 1 0 "123456654321" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(584 ""abcabcabcabc" =~ /^[abc]{12}/" "^[abc]{12}" nil nil nil nil "abcabcabcabc" nil 1 0 "abcabcabcabc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(585 ""abcabcabcabc" =~ /^[a-c]{12}/" "^[a-c]{12}" nil nil nil nil "abcabcabcabc" nil 1 0 "abcabcabcabc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(586 ""abcabcabcabc" =~ /^(a|b|c){12}/" "^(a|b|c){12}" nil nil nil nil "abcabcabcabc" nil 1 0 "abcabcabcabc" ("c" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(587 ""n" =~ /^[abcdefghijklmnopqrstuvwxy0123456789]/" "^[abcdefghijklmnopqrstuvwxy0123456789]" nil nil nil nil "n" nil 1 0 "n" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(588 ""z" =~ /^[abcdefghijklmnopqrstuvwxy0123456789]/" "^[abcdefghijklmnopqrstuvwxy0123456789]" nil nil nil nil "z" nil 1 0 nil nil) +(589 ""abcd" =~ /abcde{0,0}/" "abcde{0,0}" nil nil nil nil "abcd" nil 1 0 "abcd" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(590 ""abce" =~ /abcde{0,0}/" "abcde{0,0}" nil nil nil nil "abce" nil 1 0 nil nil) +(591 ""abe" =~ /ab[cd]{0,0}e/" "ab[cd]{0,0}e" nil nil nil nil "abe" nil 1 0 "abe" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(592 ""abcde" =~ /ab[cd]{0,0}e/" "ab[cd]{0,0}e" nil nil nil nil "abcde" nil 1 0 nil nil) +(593 ""abd" =~ /ab(c){0,0}d/" "ab(c){0,0}d" nil nil nil nil "abd" nil 1 0 "abd" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(594 ""abcd" =~ /ab(c){0,0}d/" "ab(c){0,0}d" nil nil nil nil "abcd" nil 1 0 nil nil) +(595 ""a" =~ /a(b*)/" "a(b*)" nil nil nil nil "a" nil 1 0 "a" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(596 ""ab" =~ /a(b*)/" "a(b*)" nil nil nil nil "ab" nil 1 0 "ab" ("b" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(597 ""abbbb" =~ /a(b*)/" "a(b*)" nil nil nil nil "abbbb" nil 1 0 "abbbb" ("bbbb" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(598 ""bbbbb" =~ /a(b*)/" "a(b*)" nil nil nil nil "bbbbb" nil 1 0 nil nil) +(599 ""abe" =~ /ab\d{0}e/" "ab\d{0}e" nil nil nil nil "abe" nil 1 0 "abe" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(600 ""ab1e" =~ /ab\d{0}e/" "ab\d{0}e" nil nil nil nil "ab1e" nil 1 0 nil nil) +(601 ""the \"quick\" brown fox" =~ /"([^\\"]+|\\.)*"/" ""([^\\"]+|\\.)*"" nil nil nil nil "the "quick" brown fox" nil 1 0 ""quick"" ("quick" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(602 ""\"the \\\"quick\\\" brown fox\"" =~ /"([^\\"]+|\\.)*"/" ""([^\\"]+|\\.)*"" nil nil nil nil ""the \"quick\" brown fox"" nil 1 0 ""the \"quick\" brown fox"" (" brown fox" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(603 ""abc" =~ /.*?/" ".*?" nil nil nil nil "abc" nil 1 0 "" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(604 ""abc" =~ /\b/" "\b" nil nil nil nil "abc" nil 1 0 "" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(605 ""abc" =~ /\b/" "\b" nil nil nil nil "abc" nil 1 0 "" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(606 ""abc" =~ /(?#)/" "" nil nil nil nil "abc" nil 1 0 "" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(607 ""<TR BGCOLOR='#DBE9E9'><TD align=left valign=top>43.<a href='joblist.cfm?JobID=94 6735&Keyword='>Word Processor<BR>(N-1286)</a></TD><TD align=left valign=top>Lega lstaff.com</TD><TD align=left valign=top>CA - Statewide</TD></TR>" =~ /<tr([\w\W\s\d][^<>]{0,})><TD([\w\W\s\d][^<>]{0,})>([\d]{0,}\.)(.*)((<BR>([\w\W\s\d][^<>]{0,})|[\s]{0,}))<\/a><\/TD><TD([\w\W\s\d][^<>]{0,})>([\w\W\s\d][^<>]{0,})<\/TD><TD([\w\W\s\d][^<>]{0,})>([\w\W\s\d][^<>]{0,})<\/TD><\/TR>/is" "<tr([\w\W\s\d][^<>]{0,})><TD([\w\W\s\d][^<>]{0,})>([\d]{0,}\.)(.*)((<BR>([\w\W\s\d][^<>]{0,})|[\s]{0,}))<\/a><\/TD><TD([\w\W\s\d][^<>]{0,})>([\w\W\s\d][^<>]{0,})<\/TD><TD([\w\W\s\d][^<>]{0,})>([\w\W\s\d][^<>]{0,})<\/TD><\/TR>" t nil t nil "<TR BGCOLOR='#DBE9E9'><TD align=left valign=top>43.<a href='joblist.cfm?JobID=94 6735&Keyword='>Word Processor<BR>(N-1286)</a></TD><TD align=left valign=top>Lega lstaff.com</TD><TD align=left valign=top>CA - Statewide</TD></TR>" nil 1 0 "<TR BGCOLOR='#DBE9E9'><TD align=left valign=top>43.<a href='joblist.cfm?JobID=94 6735&Keyword='>Word Processor<BR>(N-1286)</a></TD><TD align=left valign=top>Lega lstaff.com</TD><TD align=left valign=top>CA - Statewide</TD></TR>" (" BGCOLOR='#DBE9E9'" " align=left valign=top" "43." "<a href='joblist.cfm?JobID=94 6735&Keyword='>Word Processor<BR>(N-1286)" "" "" nil " align=left valign=top" "Lega lstaff.com" " align=left valign=top" "CA - Statewide" nil nil nil nil nil)) +(608 ""acb" =~ /a[^a]b/" "a[^a]b" nil nil nil nil "acb" nil 1 0 "acb" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(609 ""a\nb" =~ /a[^a]b/" "a[^a]b" nil nil nil nil "a +b" nil 1 0 "a +b" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(610 ""acb" =~ /a.b/" "a.b" nil nil nil nil "acb" nil 1 0 "acb" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(611 ""a\nb" =~ /a.b/" "a.b" nil nil nil nil "a +b" nil 1 0 nil nil) +(612 ""acb" =~ /a[^a]b/s" "a[^a]b" nil nil t nil "acb" nil 1 0 "acb" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(613 ""a\nb" =~ /a[^a]b/s" "a[^a]b" nil nil t nil "a +b" nil 1 0 "a +b" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(614 ""acb" =~ /a.b/s" "a.b" nil nil t nil "acb" nil 1 0 "acb" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(615 ""a\nb" =~ /a.b/s" "a.b" nil nil t nil "a +b" nil 1 0 "a +b" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(616 ""bac" =~ /^(b+?|a){1,2}?c/" "^(b+?|a){1,2}?c" nil nil nil nil "bac" nil 1 0 "bac" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(617 ""bbac" =~ /^(b+?|a){1,2}?c/" "^(b+?|a){1,2}?c" nil nil nil nil "bbac" nil 1 0 "bbac" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(618 ""bbbac" =~ /^(b+?|a){1,2}?c/" "^(b+?|a){1,2}?c" nil nil nil nil "bbbac" nil 1 0 "bbbac" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(619 ""bbbbac" =~ /^(b+?|a){1,2}?c/" "^(b+?|a){1,2}?c" nil nil nil nil "bbbbac" nil 1 0 "bbbbac" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(620 ""bbbbbac" =~ /^(b+?|a){1,2}?c/" "^(b+?|a){1,2}?c" nil nil nil nil "bbbbbac" nil 1 0 "bbbbbac" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(621 ""bac" =~ /^(b+|a){1,2}?c/" "^(b+|a){1,2}?c" nil nil nil nil "bac" nil 1 0 "bac" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(622 ""bbac" =~ /^(b+|a){1,2}?c/" "^(b+|a){1,2}?c" nil nil nil nil "bbac" nil 1 0 "bbac" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(623 ""bbbac" =~ /^(b+|a){1,2}?c/" "^(b+|a){1,2}?c" nil nil nil nil "bbbac" nil 1 0 "bbbac" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(624 ""bbbbac" =~ /^(b+|a){1,2}?c/" "^(b+|a){1,2}?c" nil nil nil nil "bbbbac" nil 1 0 "bbbbac" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(625 ""bbbbbac" =~ /^(b+|a){1,2}?c/" "^(b+|a){1,2}?c" nil nil nil nil "bbbbbac" nil 1 0 "bbbbbac" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(626 ""x\nb\n" =~ /(?!\A)x/m" "(?!\A)x" nil t nil nil "x +b +" nil 1 0 nil nil) +(627 ""a\bx\n" =~ /(?!\A)x/m" "(?!\A)x" nil t nil nil ("a" 8 "x" 10) nil 1 0 "x" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(628 ""\0{ab}" =~ /\x0{ab}/" "\x0{ab}" nil nil nil nil ("" 0 "{ab}") nil 1 0 ("" 0 "{ab}") (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(629 ""CD" =~ /(A|B)*?CD/" "(A|B)*?CD" nil nil nil nil "CD" nil 1 0 "CD" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(630 ""CD" =~ /(A|B)*CD/" "(A|B)*CD" nil nil nil nil "CD" nil 1 0 "CD" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(631 ""ABABAB" =~ /(AB)*?\1/" "(AB)*?\1" nil nil nil nil "ABABAB" nil 1 0 "ABAB" ("AB" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(632 ""ABABAB" =~ /(AB)*\1/" "(AB)*\1" nil nil nil nil "ABABAB" nil 1 0 "ABABAB" ("AB" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(633 ""doesn't matter" =~ /(/" "(" nil nil nil nil "doesn't matter" t 1 0 nil nil) +(634 ""doesn't matter" =~ /(x)\2/" "(x)\2" nil nil nil nil "doesn't matter" t 1 0 nil nil) +(635 ""aaaaaaaaaac" =~ /((a{0,5}){0,5}){0,5}[c]/" "((a{0,5}){0,5}){0,5}[c]" nil nil nil nil "aaaaaaaaaac" nil 1 0 "aaaaaaaaaac" ("" "" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(636 ""aaaaaaaaaa" =~ /((a{0,5}){0,5}){0,5}[c]/" "((a{0,5}){0,5}){0,5}[c]" nil nil nil nil "aaaaaaaaaa" nil 1 0 nil nil) +(637 ""aaaaaaaaaac" =~ /((a{0,5}){0,5})*[c]/" "((a{0,5}){0,5})*[c]" nil nil nil nil "aaaaaaaaaac" nil 1 0 "aaaaaaaaaac" ("" "" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(638 ""aaaaaaaaaa" =~ /((a{0,5}){0,5})*[c]/" "((a{0,5}){0,5})*[c]" nil nil nil nil "aaaaaaaaaa" nil 1 0 nil nil) +(639 ""a" =~ /(\b)*a/" "(\b)*a" nil nil nil nil "a" nil 1 0 "a" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(640 ""ab" =~ /(a)*b/" "(a)*b" nil nil nil nil "ab" nil 1 0 "ab" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(641 ""ab" =~ /(a|)*b/" "(a|)*b" nil nil nil nil "ab" nil 1 0 "ab" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(642 ""b" =~ /(a|)*b/" "(a|)*b" nil nil nil nil "b" nil 1 0 "b" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(643 ""x" =~ /(a|)*b/" "(a|)*b" nil nil nil nil "x" nil 1 0 nil nil) +(644 ""abab" =~ /^(?:(a)|(b))*\1\2$/" "^(?:(a)|(b))*\1\2$" nil nil nil nil "abab" nil 1 0 "abab" ("a" "b" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(645 ""abcxabcydef" =~ /abc[^x]def/" "abc[^x]def" nil nil nil nil "abcxabcydef" nil 1 0 "abcydef" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(646 ""aax" =~ /^(a|\1x)*$/" "^(a|\1x)*$" nil nil nil nil "aax" nil 1 0 "aax" ("ax" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(647 ""aaxa" =~ /^(a|\1x)*$/" "^(a|\1x)*$" nil nil nil nil "aaxa" nil 1 0 "aaxa" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(648 ""@{['']}" =~ /(?#)/" "" nil nil nil nil "" nil 1 0 "" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(649 ""ab" =~ /^(?:(a)|(b))*$/" "^(?:(a)|(b))*$" nil nil nil nil "ab" nil 1 0 "ab" ("a" "b" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(650 ""a" =~ /[\0]/" "[\0]" nil nil nil nil "a" nil 1 0 nil nil) +(651 ""\0" =~ /[\0]/" "[\0]" nil nil nil nil ("" 0) nil 1 0 ("" 0) (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(652 ""a" =~ /[\1]/" "[\1]" nil nil nil nil "a" nil 1 0 nil nil) +(653 ""\1" =~ /[\1]/" "[\1]" nil nil nil nil ("" 1) nil 1 0 ("" 1) (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(654 ""doesn't matter" =~ /\10()()()()()()()()()/" "\10()()()()()()()()()" nil nil nil nil "doesn't matter" nil 1 0 nil nil) +(655 ""a" =~ /\10()()()()()()()()()()/" "\10()()()()()()()()()()" nil nil nil nil "a" nil 1 0 nil nil) +(656 ""ab" =~ /a(?<)b/" "a(?<)b" nil nil nil nil "ab" nil 1 0 "ab" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(657 ""doesn't matter" =~ /[]/" "[]" nil nil nil nil "doesn't matter" t 1 0 nil nil) +(658 ""doesn't matter" =~ /[\]/" "[\]" nil nil nil nil "doesn't matter" t 1 0 nil nil) +(659 ""a" =~ /()/" "()" nil nil nil nil "a" nil 1 0 "" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(660 ""x" =~ /[\x]/" "[\x]" nil nil nil nil "x" nil 1 0 nil nil) +(661 ""\0" =~ /[\x]/" "[\x]" nil nil nil nil ("" 0) nil 1 0 ("" 0) (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(662 ""a" =~ /((a)*)*/" "((a)*)*" nil nil nil nil "a" nil 1 0 "a" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(663 ""a" =~ /()a\1/" "()a\1" nil nil nil nil "a" nil 1 0 "a" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(664 ""a" =~ /a\1()/" "a\1()" nil nil nil nil "a" nil 1 0 nil nil) +(665 ""aaa" =~ /a(?i)a(?-i)a/" "a(?i)a(?-i)a" nil nil nil nil "aaa" nil 1 0 "aaa" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(666 ""aAa" =~ /a(?i)a(?-i)a/" "a(?i)a(?-i)a" nil nil nil nil "aAa" nil 1 0 "aAa" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(667 ""aAA" =~ /a(?i)a(?-i)a/" "a(?i)a(?-i)a" nil nil nil nil "aAA" nil 1 0 nil nil) +(668 ""aaaaa" =~ /a(?i)a(?-i)a(?i)a(?-i)a/" "a(?i)a(?-i)a(?i)a(?-i)a" nil nil nil nil "aaaaa" nil 1 0 "aaaaa" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(669 ""aAaAa" =~ /a(?i)a(?-i)a(?i)a(?-i)a/" "a(?i)a(?-i)a(?i)a(?-i)a" nil nil nil nil "aAaAa" nil 1 0 "aAaAa" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(670 ""AaAaA" =~ /a(?i)a(?-i)a(?i)a(?-i)a/" "a(?i)a(?-i)a(?i)a(?-i)a" nil nil nil nil "AaAaA" nil 1 0 nil nil) +(671 ""aAAAa" =~ /a(?i)a(?-i)a(?i)a(?-i)a/" "a(?i)a(?-i)a(?i)a(?-i)a" nil nil nil nil "aAAAa" nil 1 0 nil nil) +(672 ""AaaaA" =~ /a(?i)a(?-i)a(?i)a(?-i)a/" "a(?i)a(?-i)a(?i)a(?-i)a" nil nil nil nil "AaaaA" nil 1 0 nil nil) +(673 ""AAAAA" =~ /a(?i)a(?-i)a(?i)a(?-i)a/" "a(?i)a(?-i)a(?i)a(?-i)a" nil nil nil nil "AAAAA" nil 1 0 nil nil) +(674 ""aaAAA" =~ /a(?i)a(?-i)a(?i)a(?-i)a/" "a(?i)a(?-i)a(?i)a(?-i)a" nil nil nil nil "aaAAA" nil 1 0 nil nil) +(675 ""AAaaa" =~ /a(?i)a(?-i)a(?i)a(?-i)a/" "a(?i)a(?-i)a(?i)a(?-i)a" nil nil nil nil "AAaaa" nil 1 0 nil nil) +(676 ""a" =~ /\x/" "\x" nil nil nil nil "a" nil 1 0 nil nil) +(677 ""X" =~ /\x/" "\x" nil nil nil nil "X" nil 1 0 nil nil) +(678 ""\0" =~ /\x/" "\x" nil nil nil nil ("" 0) nil 1 0 ("" 0) (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(679 ""a" =~ /[a-c-e]/" "[a-c-e]" nil nil nil nil "a" nil 1 0 "a" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(680 ""b" =~ /[a-c-e]/" "[a-c-e]" nil nil nil nil "b" nil 1 0 "b" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(681 ""d" =~ /[a-c-e]/" "[a-c-e]" nil nil nil nil "d" nil 1 0 nil nil) +(682 ""-" =~ /[a-c-e]/" "[a-c-e]" nil nil nil nil "-" nil 1 0 "-" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(683 ""b" =~ /[b-\d]/" "[b-\d]" nil nil nil nil "b" nil 1 0 "b" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(684 ""c" =~ /[b-\d]/" "[b-\d]" nil nil nil nil "c" nil 1 0 nil nil) +(685 ""d" =~ /[b-\d]/" "[b-\d]" nil nil nil nil "d" nil 1 0 nil nil) +(686 ""-" =~ /[b-\d]/" "[b-\d]" nil nil nil nil "-" nil 1 0 "-" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(687 ""1" =~ /[b-\d]/" "[b-\d]" nil nil nil nil "1" nil 1 0 "1" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(688 ""d" =~ /[\d-f]/" "[\d-f]" nil nil nil nil "d" nil 1 0 nil nil) +(689 ""e" =~ /[\d-f]/" "[\d-f]" nil nil nil nil "e" nil 1 0 nil nil) +(690 ""f" =~ /[\d-f]/" "[\d-f]" nil nil nil nil "f" nil 1 0 "f" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(691 ""-" =~ /[\d-f]/" "[\d-f]" nil nil nil nil "-" nil 1 0 "-" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(692 ""1" =~ /[\d-f]/" "[\d-f]" nil nil nil nil "1" nil 1 0 "1" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(693 ""doesn't matter" =~ /[/" "[" nil nil nil nil "doesn't matter" t 1 0 nil nil) +(694 ""]" =~ /]/" "]" nil nil nil nil "]" nil 1 0 "]" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(695 ""a" =~ /]/" "]" nil nil nil nil "a" nil 1 0 nil nil) +(696 ""doesn't matter" =~ /[]/" "[]" nil nil nil nil "doesn't matter" t 1 0 nil nil) +(697 ""-" =~ /[-a-c]/" "[-a-c]" nil nil nil nil "-" nil 1 0 "-" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(698 ""a" =~ /[-a-c]/" "[-a-c]" nil nil nil nil "a" nil 1 0 "a" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(699 ""b" =~ /[-a-c]/" "[-a-c]" nil nil nil nil "b" nil 1 0 "b" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(700 ""d" =~ /[-a-c]/" "[-a-c]" nil nil nil nil "d" nil 1 0 nil nil) +(701 ""-" =~ /[a-c-]/" "[a-c-]" nil nil nil nil "-" nil 1 0 "-" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(702 ""a" =~ /[a-c-]/" "[a-c-]" nil nil nil nil "a" nil 1 0 "a" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(703 ""b" =~ /[a-c-]/" "[a-c-]" nil nil nil nil "b" nil 1 0 "b" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(704 ""d" =~ /[a-c-]/" "[a-c-]" nil nil nil nil "d" nil 1 0 nil nil) +(705 ""a" =~ /[-]/" "[-]" nil nil nil nil "a" nil 1 0 nil nil) +(706 ""-" =~ /[-]/" "[-]" nil nil nil nil "-" nil 1 0 "-" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(707 ""a" =~ /[--]/" "[--]" nil nil nil nil "a" nil 1 0 nil nil) +(708 ""-" =~ /[--]/" "[--]" nil nil nil nil "-" nil 1 0 "-" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(709 ""a" =~ /[---]/" "[---]" nil nil nil nil "a" nil 1 0 nil nil) +(710 ""-" =~ /[---]/" "[---]" nil nil nil nil "-" nil 1 0 "-" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(711 ""-" =~ /[--b]/" "[--b]" nil nil nil nil "-" nil 1 0 "-" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(712 ""a" =~ /[--b]/" "[--b]" nil nil nil nil "a" nil 1 0 "a" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(713 ""c" =~ /[--b]/" "[--b]" nil nil nil nil "c" nil 1 0 nil nil) +(714 ""doesn't matter" =~ /[b--]/" "[b--]" nil nil nil nil "doesn't matter" t 1 0 nil nil) +(715 ""a{" =~ /a{/" "a{" nil nil nil nil "a{" nil 1 0 "a{" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(716 ""a{}" =~ /a{}/" "a{}" nil nil nil nil "a{}" nil 1 0 "a{}" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(717 ""a{3" =~ /a{3/" "a{3" nil nil nil nil "a{3" nil 1 0 "a{3" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(718 ""a{3," =~ /a{3,/" "a{3," nil nil nil nil "a{3," nil 1 0 "a{3," (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(719 ""a{3,3}" =~ /a{3, 3}/" "a{3, 3}" nil nil nil nil "a{3,3}" nil 1 0 nil nil) +(720 ""a{3, 3}" =~ /a{3, 3}/" "a{3, 3}" nil nil nil nil "a{3, 3}" nil 1 0 "a{3, 3}" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(721 ""aaa" =~ /a{3, 3}/" "a{3, 3}" nil nil nil nil "aaa" nil 1 0 nil nil) +(722 ""a{3,3}" =~ /a{3, 3}/x" "a{3, 3}" nil nil nil t "a{3,3}" nil 1 0 "a{3,3}" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(723 ""a{3, 3}" =~ /a{3, 3}/x" "a{3, 3}" nil nil nil t "a{3, 3}" nil 1 0 nil nil) +(724 ""aaa" =~ /a{3, 3}/x" "a{3, 3}" nil nil nil t "aaa" nil 1 0 nil nil) +(725 ""a{3,}" =~ /a{3, }/" "a{3, }" nil nil nil nil "a{3,}" nil 1 0 nil nil) +(726 ""a{3, }" =~ /a{3, }/" "a{3, }" nil nil nil nil "a{3, }" nil 1 0 "a{3, }" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(727 ""aaa" =~ /a{3, }/" "a{3, }" nil nil nil nil "aaa" nil 1 0 nil nil) +(728 ""a{3,}" =~ /a{3, }/x" "a{3, }" nil nil nil t "a{3,}" nil 1 0 "a{3,}" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(729 ""a{3, }" =~ /a{3, }/x" "a{3, }" nil nil nil t "a{3, }" nil 1 0 nil nil) +(730 ""aaa" =~ /a{3, }/x" "a{3, }" nil nil nil t "aaa" nil 1 0 nil nil) +(731 ""\0 x" =~ /\x x/" "\x x" nil nil nil nil ("" 0 " x") nil 1 0 ("" 0 " x") (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(732 ""\0x" =~ /\x x/" "\x x" nil nil nil nil ("" 0 "x") nil 1 0 nil nil) +(733 ""\0 x" =~ /\x x/x" "\x x" nil nil nil t ("" 0 " x") nil 1 0 nil nil) +(734 ""\0x" =~ /\x x/x" "\x x" nil nil nil t ("" 0 "x") nil 1 0 ("" 0 "x") (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(735 ""\0003" =~ /\x 3/" "\x 3" nil nil nil nil ("" 0 "3") nil 1 0 nil nil) +(736 ""\000 3" =~ /\x 3/" "\x 3" nil nil nil nil ("" 0 " 3") nil 1 0 ("" 0 " 3") (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(737 ""x3" =~ /\x 3/" "\x 3" nil nil nil nil "x3" nil 1 0 nil nil) +(738 ""x 3" =~ /\x 3/" "\x 3" nil nil nil nil "x 3" nil 1 0 nil nil) +(739 ""\0003" =~ /\x 3/x" "\x 3" nil nil nil t ("" 0 "3") nil 1 0 ("" 0 "3") (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(740 ""\000 3" =~ /\x 3/x" "\x 3" nil nil nil t ("" 0 " 3") nil 1 0 nil nil) +(741 ""x3" =~ /\x 3/x" "\x 3" nil nil nil t "x3" nil 1 0 nil nil) +(742 ""x 3" =~ /\x 3/x" "\x 3" nil nil nil t "x 3" nil 1 0 nil nil) +(743 ""a" =~ /^a{ 1}$/" "^a{ 1}$" nil nil nil nil "a" nil 1 0 nil nil) +(744 ""a{ 1}" =~ /^a{ 1}$/" "^a{ 1}$" nil nil nil nil "a{ 1}" nil 1 0 "a{ 1}" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(745 ""a{1}" =~ /^a{ 1}$/" "^a{ 1}$" nil nil nil nil "a{1}" nil 1 0 nil nil) +(746 ""a" =~ /^a{ 1}$/x" "^a{ 1}$" nil nil nil t "a" nil 1 0 nil nil) +(747 ""a{ 1}" =~ /^a{ 1}$/x" "^a{ 1}$" nil nil nil t "a{ 1}" nil 1 0 nil nil) +(748 ""a{1}" =~ /^a{ 1}$/x" "^a{ 1}$" nil nil nil t "a{1}" nil 1 0 "a{1}" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(749 ""{}" =~ /{}/" "{}" nil nil nil nil "{}" nil 1 0 "{}" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(750 ""a" =~ /{}/" "{}" nil nil nil nil "a" nil 1 0 nil nil) +(751 ""doesn't matter" =~ /{1}/" "{1}" nil nil nil nil "doesn't matter" t 1 0 nil nil) +(752 ""doesn't matter" =~ /*/" "*" nil nil nil nil "doesn't matter" t 1 0 nil nil) +(753 ""x" =~ /|/" "|" nil nil nil nil "x" nil 1 0 "" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(754 ""\0000" =~ /\0000/" "\0000" nil nil nil nil ("" 0 "0") nil 1 0 ("" 0 "0") (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(755 ""ab" =~ /a(?<)b/" "a(?<)b" nil nil nil nil "ab" nil 1 0 "ab" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(756 ""ab" =~ /a(?i)b/" "a(?i)b" nil nil nil nil "ab" nil 1 0 "ab" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(757 ""aB" =~ /a(?i)b/" "a(?i)b" nil nil nil nil "aB" nil 1 0 "aB" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(758 ""Ab" =~ /a(?i)b/" "a(?i)b" nil nil nil nil "Ab" nil 1 0 nil nil) +(759 ""doesn't matter" =~ /a(?i=a)/" "a(?i=a)" nil nil nil nil "doesn't matter" t 1 0 nil nil) +(760 ""aa" =~ /a(?<=a){3000}a/" "a(?<=a){3000}a" nil nil nil nil "aa" nil 1 0 "aa" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(761 ""xa" =~ /a(?<=a){3000}a/" "a(?<=a){3000}a" nil nil nil nil "xa" nil 1 0 nil nil) +(762 ""ax" =~ /a(?<=a){3000}a/" "a(?<=a){3000}a" nil nil nil nil "ax" nil 1 0 nil nil) +(763 ""aa" =~ /a(?!=a){3000}a/" "a(?!=a){3000}a" nil nil nil nil "aa" nil 1 0 "aa" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(764 ""ax" =~ /a(?!=a){3000}a/" "a(?!=a){3000}a" nil nil nil nil "ax" nil 1 0 nil nil) +(765 ""xa" =~ /a(?!=a){3000}a/" "a(?!=a){3000}a" nil nil nil nil "xa" nil 1 0 nil nil) +(766 ""aa" =~ /a(){3000}a/" "a(){3000}a" nil nil nil nil "aa" nil 1 0 "aa" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(767 ""ax" =~ /a(){3000}a/" "a(){3000}a" nil nil nil nil "ax" nil 1 0 nil nil) +(768 ""xa" =~ /a(){3000}a/" "a(){3000}a" nil nil nil nil "xa" nil 1 0 nil nil) +(769 ""aa" =~ /a(?:){3000}a/" "a(?:){3000}a" nil nil nil nil "aa" nil 1 0 "aa" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(770 ""ax" =~ /a(?:){3000}a/" "a(?:){3000}a" nil nil nil nil "ax" nil 1 0 nil nil) +(771 ""aa" =~ /a(?<=a)*a/" "a(?<=a)*a" nil nil nil nil "aa" nil 1 0 "aa" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(772 ""ax" =~ /a(?<=a)*a/" "a(?<=a)*a" nil nil nil nil "ax" nil 1 0 nil nil) +(773 ""xa" =~ /a(?<=a)*a/" "a(?<=a)*a" nil nil nil nil "xa" nil 1 0 nil nil) +(774 ""aa" =~ /a(?!=a)*a/" "a(?!=a)*a" nil nil nil nil "aa" nil 1 0 "aa" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(775 ""ax" =~ /a(?!=a)*a/" "a(?!=a)*a" nil nil nil nil "ax" nil 1 0 nil nil) +(776 ""xa" =~ /a(?!=a)*a/" "a(?!=a)*a" nil nil nil nil "xa" nil 1 0 nil nil) +(777 ""aa" =~ /a()*a/" "a()*a" nil nil nil nil "aa" nil 1 0 "aa" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(778 ""ax" =~ /a()*a/" "a()*a" nil nil nil nil "ax" nil 1 0 nil nil) +(779 ""xa" =~ /a()*a/" "a()*a" nil nil nil nil "xa" nil 1 0 nil nil) +(780 ""aa" =~ /a(?:)*a/" "a(?:)*a" nil nil nil nil "aa" nil 1 0 "aa" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(781 ""ax" =~ /a(?:)*a/" "a(?:)*a" nil nil nil nil "ax" nil 1 0 nil nil) +(782 ""xa" =~ /a(?:)*a/" "a(?:)*a" nil nil nil nil "xa" nil 1 0 nil nil) +(783 ""aa" =~ /x(?<=a)*a/" "x(?<=a)*a" nil nil nil nil "aa" nil 1 0 nil nil) +(784 ""xa" =~ /x(?<=a)*a/" "x(?<=a)*a" nil nil nil nil "xa" nil 1 0 "xa" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(785 ""ax" =~ /x(?<=a)*a/" "x(?<=a)*a" nil nil nil nil "ax" nil 1 0 nil nil) +(786 ""aa" =~ /a(?<=(a))*\1/" "a(?<=(a))*\1" nil nil nil nil "aa" nil 1 0 "aa" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(787 ""aa" =~ /a(?<=(a))*?\1/" "a(?<=(a))*?\1" nil nil nil nil "aa" nil 1 0 "aa" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(788 ""aa" =~ /(?=(a)\1)*aa/" "(?=(a)\1)*aa" nil nil nil nil "aa" nil 1 0 "aa" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(789 ""aaaaabbbbb" =~ /^((a|b){2,5}){2}$/" "^((a|b){2,5}){2}$" nil nil nil nil "aaaaabbbbb" nil 1 0 "aaaaabbbbb" ("bbbbb" "b" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(790 ""babc" =~ /^(b*|ba){1,2}bc/" "^(b*|ba){1,2}bc" nil nil nil nil "babc" nil 1 0 "babc" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(791 ""bbabc" =~ /^(b*|ba){1,2}bc/" "^(b*|ba){1,2}bc" nil nil nil nil "bbabc" nil 1 0 "bbabc" ("ba" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(792 ""bababc" =~ /^(b*|ba){1,2}bc/" "^(b*|ba){1,2}bc" nil nil nil nil "bababc" nil 1 0 "bababc" ("ba" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(793 ""bababbc" =~ /^(b*|ba){1,2}bc/" "^(b*|ba){1,2}bc" nil nil nil nil "bababbc" nil 1 0 nil nil) +(794 ""babababc" =~ /^(b*|ba){1,2}bc/" "^(b*|ba){1,2}bc" nil nil nil nil "babababc" nil 1 0 nil nil) +(795 ""aaaaac" =~ /^a{4,5}(?:c|a)c$/" "^a{4,5}(?:c|a)c$" nil nil nil nil "aaaaac" nil 1 0 "aaaaac" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(796 ""aaaaaac" =~ /^a{4,5}(?:c|a)c$/" "^a{4,5}(?:c|a)c$" nil nil nil nil "aaaaaac" nil 1 0 "aaaaaac" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(797 ""aaaaac" =~ /^(a|){4,5}(?:c|a)c$/" "^(a|){4,5}(?:c|a)c$" nil nil nil nil "aaaaac" nil 1 0 "aaaaac" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(798 ""aaaaaac" =~ /^(a|){4,5}(?:c|a)c$/" "^(a|){4,5}(?:c|a)c$" nil nil nil nil "aaaaaac" nil 1 0 "aaaaaac" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(799 ""eeexabc" =~ /(?m:^).abc$/" "(?m:^).abc$" nil nil nil nil "eeexabc" nil 1 0 nil nil) +(800 ""eee\nxabc" =~ /(?m:^).abc$/" "(?m:^).abc$" nil nil nil nil "eee +xabc" nil 1 0 "xabc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(801 ""abc" =~ /(?m:^)abc/" "(?m:^)abc" nil nil nil nil "abc" nil 1 0 "abc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(802 ""\nabc" =~ /(?m:^)abc/" "(?m:^)abc" nil nil nil nil " +abc" nil 1 0 "abc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(803 ""abc" =~ +/^abc/" "^abc" nil nil nil nil "abc" nil 1 0 "abc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(804 ""\nabc" =~ +/^abc/" "^abc" nil nil nil nil " +abc" nil 1 0 nil nil) +(805 ""abc" =~ /\Aabc/" "\Aabc" nil nil nil nil "abc" nil 1 0 "abc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(806 ""\nabc" =~ /\Aabc/" "\Aabc" nil nil nil nil " +abc" nil 1 0 nil nil) +(807 ""foo" =~ /(?<!bar)foo/" "(?<!bar)foo" nil nil nil nil "foo" nil 1 0 "foo" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(808 ""catfood" =~ /(?<!bar)foo/" "(?<!bar)foo" nil nil nil nil "catfood" nil 1 0 "foo" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(809 ""arfootle" =~ /(?<!bar)foo/" "(?<!bar)foo" nil nil nil nil "arfootle" nil 1 0 "foo" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(810 ""rfoosh" =~ /(?<!bar)foo/" "(?<!bar)foo" nil nil nil nil "rfoosh" nil 1 0 "foo" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(811 ""barfoo" =~ /(?<!bar)foo/" "(?<!bar)foo" nil nil nil nil "barfoo" nil 1 0 nil nil) +(812 ""towbarfoo" =~ /(?<!bar)foo/" "(?<!bar)foo" nil nil nil nil "towbarfoo" nil 1 0 nil nil) +(813 ""catfood" =~ /\w{3}(?<!bar)foo/" "\w{3}(?<!bar)foo" nil nil nil nil "catfood" nil 1 0 "catfoo" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(814 ""foo" =~ /\w{3}(?<!bar)foo/" "\w{3}(?<!bar)foo" nil nil nil nil "foo" nil 1 0 nil nil) +(815 ""barfoo" =~ /\w{3}(?<!bar)foo/" "\w{3}(?<!bar)foo" nil nil nil nil "barfoo" nil 1 0 nil nil) +(816 ""towbarfoo" =~ /\w{3}(?<!bar)foo/" "\w{3}(?<!bar)foo" nil nil nil nil "towbarfoo" nil 1 0 nil nil) +(817 ""fooabar" =~ /(?<=(foo)a)bar/" "(?<=(foo)a)bar" nil nil nil nil "fooabar" nil 1 0 "bar" ("foo" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(818 ""bar" =~ /(?<=(foo)a)bar/" "(?<=(foo)a)bar" nil nil nil nil "bar" nil 1 0 nil nil) +(819 ""foobbar" =~ /(?<=(foo)a)bar/" "(?<=(foo)a)bar" nil nil nil nil "foobbar" nil 1 0 nil nil) +(820 ""abc" =~ /\Aabc\z/m" "\Aabc\z" nil t nil nil "abc" nil 1 0 "abc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(821 ""abc\n" =~ /\Aabc\z/m" "\Aabc\z" nil t nil nil "abc +" nil 1 0 nil nil) +(822 ""qqq\nabc" =~ /\Aabc\z/m" "\Aabc\z" nil t nil nil "qqq +abc" nil 1 0 nil nil) +(823 ""abc\nzzz" =~ /\Aabc\z/m" "\Aabc\z" nil t nil nil "abc +zzz" nil 1 0 nil nil) +(824 ""qqq\nabc\nzzz" =~ /\Aabc\z/m" "\Aabc\z" nil t nil nil "qqq +abc +zzz" nil 1 0 nil nil) +(825 ""/this/is/a/very/long/line/in/deed/with/very/many/slashes/in/it/you/see/" =~ "(?>.*/)foo"" "(?>.*/)foo" nil nil nil nil "/this/is/a/very/long/line/in/deed/with/very/many/slashes/in/it/you/see/" nil 1 0 nil nil) +(826 ""/this/is/a/very/long/line/in/deed/with/very/many/slashes/in/and/foo" =~ "(?>.*/)foo"" "(?>.*/)foo" nil nil nil nil "/this/is/a/very/long/line/in/deed/with/very/many/slashes/in/and/foo" nil 1 0 "/this/is/a/very/long/line/in/deed/with/very/many/slashes/in/and/foo" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(827 ""1.230003938" =~ /(?>(\.\d\d[1-9]?))\d+/" "(?>(\.\d\d[1-9]?))\d+" nil nil nil nil "1.230003938" nil 1 0 ".230003938" (".23" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(828 ""1.875000282" =~ /(?>(\.\d\d[1-9]?))\d+/" "(?>(\.\d\d[1-9]?))\d+" nil nil nil nil "1.875000282" nil 1 0 ".875000282" (".875" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(829 ""1.235" =~ /(?>(\.\d\d[1-9]?))\d+/" "(?>(\.\d\d[1-9]?))\d+" nil nil nil nil "1.235" nil 1 0 nil nil) +(830 ""now is the time for all good men to come to the aid of the party" =~ /^((?>\w+)|(?>\s+))*$/" "^((?>\w+)|(?>\s+))*$" nil nil nil nil "now is the time for all good men to come to the aid of the party" nil 1 0 "now is the time for all good men to come to the aid of the party" ("party" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(831 ""this is not a line with only words and spaces!" =~ /^((?>\w+)|(?>\s+))*$/" "^((?>\w+)|(?>\s+))*$" nil nil nil nil "this is not a line with only words and spaces!" nil 1 0 nil nil) +(832 ""12345a" =~ /(\d+)(\w)/" "(\d+)(\w)" nil nil nil nil "12345a" nil 1 0 "12345a" ("12345" "a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(833 ""12345+" =~ /(\d+)(\w)/" "(\d+)(\w)" nil nil nil nil "12345+" nil 1 0 "12345" ("1234" "5" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(834 ""12345a" =~ /((?>\d+))(\w)/" "((?>\d+))(\w)" nil nil nil nil "12345a" nil 1 0 "12345a" ("12345" "a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(835 ""12345+" =~ /((?>\d+))(\w)/" "((?>\d+))(\w)" nil nil nil nil "12345+" nil 1 0 nil nil) +(836 ""aaab" =~ /(?>a+)b/" "(?>a+)b" nil nil nil nil "aaab" nil 1 0 "aaab" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(837 ""aaab" =~ /((?>a+)b)/" "((?>a+)b)" nil nil nil nil "aaab" nil 1 0 "aaab" ("aaab" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(838 ""aaab" =~ /(?>(a+))b/" "(?>(a+))b" nil nil nil nil "aaab" nil 1 0 "aaab" ("aaa" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(839 ""aaabbbccc" =~ /(?>b)+/" "(?>b)+" nil nil nil nil "aaabbbccc" nil 1 0 "bbb" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(840 ""aaabbbbccccd" =~ /(?>a+|b+|c+)*c/" "(?>a+|b+|c+)*c" nil nil nil nil "aaabbbbccccd" nil 1 0 "aaabbbbc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(841 ""((abc(ade)ufh()()x" =~ /((?>[^()]+)|\([^()]*\))+/" "((?>[^()]+)|\([^()]*\))+" nil nil nil nil "((abc(ade)ufh()()x" nil 1 0 "abc(ade)ufh()()x" ("x" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(842 ""(abc)" =~ /\(((?>[^()]+)|\([^()]+\))+\)/" "\(((?>[^()]+)|\([^()]+\))+\)" nil nil nil nil "(abc)" nil 1 0 "(abc)" ("abc" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(843 ""(abc(def)xyz)" =~ /\(((?>[^()]+)|\([^()]+\))+\)/" "\(((?>[^()]+)|\([^()]+\))+\)" nil nil nil nil "(abc(def)xyz)" nil 1 0 "(abc(def)xyz)" ("xyz" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(844 ""((()aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" =~ /\(((?>[^()]+)|\([^()]+\))+\)/" "\(((?>[^()]+)|\([^()]+\))+\)" nil nil nil nil "((()aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" nil 1 0 nil nil) +(845 ""ab" =~ /a(?-i)b/i" "a(?-i)b" t nil nil nil "ab" nil 1 0 "ab" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(846 ""Ab" =~ /a(?-i)b/i" "a(?-i)b" t nil nil nil "Ab" nil 1 0 "Ab" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(847 ""aB" =~ /a(?-i)b/i" "a(?-i)b" t nil nil nil "aB" nil 1 0 nil nil) +(848 ""AB" =~ /a(?-i)b/i" "a(?-i)b" t nil nil nil "AB" nil 1 0 nil nil) +(849 ""a bcd e" =~ /(a (?x)b c)d e/" "(a (?x)b c)d e" nil nil nil nil "a bcd e" nil 1 0 "a bcd e" ("a bc" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(850 ""a b cd e" =~ /(a (?x)b c)d e/" "(a (?x)b c)d e" nil nil nil nil "a b cd e" nil 1 0 nil nil) +(851 ""abcd e" =~ /(a (?x)b c)d e/" "(a (?x)b c)d e" nil nil nil nil "abcd e" nil 1 0 nil nil) +(852 ""a bcde" =~ /(a (?x)b c)d e/" "(a (?x)b c)d e" nil nil nil nil "a bcde" nil 1 0 nil nil) +(853 ""a bcde f" =~ /(a b(?x)c d (?-x)e f)/" "(a b(?x)c d (?-x)e f)" nil nil nil nil "a bcde f" nil 1 0 "a bcde f" ("a bcde f" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(854 ""abcdef" =~ /(a b(?x)c d (?-x)e f)/" "(a b(?x)c d (?-x)e f)" nil nil nil nil "abcdef" nil 1 0 nil nil) +(855 ""abc" =~ /(a(?i)b)c/" "(a(?i)b)c" nil nil nil nil "abc" nil 1 0 "abc" ("ab" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(856 ""aBc" =~ /(a(?i)b)c/" "(a(?i)b)c" nil nil nil nil "aBc" nil 1 0 "aBc" ("aB" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(857 ""abC" =~ /(a(?i)b)c/" "(a(?i)b)c" nil nil nil nil "abC" nil 1 0 nil nil) +(858 ""aBC" =~ /(a(?i)b)c/" "(a(?i)b)c" nil nil nil nil "aBC" nil 1 0 nil nil) +(859 ""Abc" =~ /(a(?i)b)c/" "(a(?i)b)c" nil nil nil nil "Abc" nil 1 0 nil nil) +(860 ""ABc" =~ /(a(?i)b)c/" "(a(?i)b)c" nil nil nil nil "ABc" nil 1 0 nil nil) +(861 ""ABC" =~ /(a(?i)b)c/" "(a(?i)b)c" nil nil nil nil "ABC" nil 1 0 nil nil) +(862 ""AbC" =~ /(a(?i)b)c/" "(a(?i)b)c" nil nil nil nil "AbC" nil 1 0 nil nil) +(863 ""abc" =~ /a(?i:b)c/" "a(?i:b)c" nil nil nil nil "abc" nil 1 0 "abc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(864 ""aBc" =~ /a(?i:b)c/" "a(?i:b)c" nil nil nil nil "aBc" nil 1 0 "aBc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(865 ""ABC" =~ /a(?i:b)c/" "a(?i:b)c" nil nil nil nil "ABC" nil 1 0 nil nil) +(866 ""abC" =~ /a(?i:b)c/" "a(?i:b)c" nil nil nil nil "abC" nil 1 0 nil nil) +(867 ""aBC" =~ /a(?i:b)c/" "a(?i:b)c" nil nil nil nil "aBC" nil 1 0 nil nil) +(868 ""aBc" =~ /a(?i:b)*c/" "a(?i:b)*c" nil nil nil nil "aBc" nil 1 0 "aBc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(869 ""aBBc" =~ /a(?i:b)*c/" "a(?i:b)*c" nil nil nil nil "aBBc" nil 1 0 "aBBc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(870 ""aBC" =~ /a(?i:b)*c/" "a(?i:b)*c" nil nil nil nil "aBC" nil 1 0 nil nil) +(871 ""aBBC" =~ /a(?i:b)*c/" "a(?i:b)*c" nil nil nil nil "aBBC" nil 1 0 nil nil) +(872 ""abcd" =~ /a(?=b(?i)c)\w\wd/" "a(?=b(?i)c)\w\wd" nil nil nil nil "abcd" nil 1 0 "abcd" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(873 ""abCd" =~ /a(?=b(?i)c)\w\wd/" "a(?=b(?i)c)\w\wd" nil nil nil nil "abCd" nil 1 0 "abCd" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(874 ""aBCd" =~ /a(?=b(?i)c)\w\wd/" "a(?=b(?i)c)\w\wd" nil nil nil nil "aBCd" nil 1 0 nil nil) +(875 ""abcD" =~ /a(?=b(?i)c)\w\wd/" "a(?=b(?i)c)\w\wd" nil nil nil nil "abcD" nil 1 0 nil nil) +(876 ""more than million" =~ /(?s-i:more.*than).*million/i" "(?s-i:more.*than).*million" t nil nil nil "more than million" nil 1 0 "more than million" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(877 ""more than MILLION" =~ /(?s-i:more.*than).*million/i" "(?s-i:more.*than).*million" t nil nil nil "more than MILLION" nil 1 0 "more than MILLION" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(878 ""more \n than Million" =~ /(?s-i:more.*than).*million/i" "(?s-i:more.*than).*million" t nil nil nil "more + than Million" nil 1 0 "more + than Million" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(879 ""MORE THAN MILLION" =~ /(?s-i:more.*than).*million/i" "(?s-i:more.*than).*million" t nil nil nil "MORE THAN MILLION" nil 1 0 nil nil) +(880 ""more \n than \n million" =~ /(?s-i:more.*than).*million/i" "(?s-i:more.*than).*million" t nil nil nil "more + than + million" nil 1 0 nil nil) +(881 ""more than million" =~ /(?:(?s-i)more.*than).*million/i" "(?:(?s-i)more.*than).*million" t nil nil nil "more than million" nil 1 0 "more than million" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(882 ""more than MILLION" =~ /(?:(?s-i)more.*than).*million/i" "(?:(?s-i)more.*than).*million" t nil nil nil "more than MILLION" nil 1 0 "more than MILLION" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(883 ""more \n than Million" =~ /(?:(?s-i)more.*than).*million/i" "(?:(?s-i)more.*than).*million" t nil nil nil "more + than Million" nil 1 0 "more + than Million" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(884 ""MORE THAN MILLION" =~ /(?:(?s-i)more.*than).*million/i" "(?:(?s-i)more.*than).*million" t nil nil nil "MORE THAN MILLION" nil 1 0 nil nil) +(885 ""more \n than \n million" =~ /(?:(?s-i)more.*than).*million/i" "(?:(?s-i)more.*than).*million" t nil nil nil "more + than + million" nil 1 0 nil nil) +(886 ""abc" =~ /(?>a(?i)b+)+c/" "(?>a(?i)b+)+c" nil nil nil nil "abc" nil 1 0 "abc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(887 ""aBbc" =~ /(?>a(?i)b+)+c/" "(?>a(?i)b+)+c" nil nil nil nil "aBbc" nil 1 0 "aBbc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(888 ""aBBc" =~ /(?>a(?i)b+)+c/" "(?>a(?i)b+)+c" nil nil nil nil "aBBc" nil 1 0 "aBBc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(889 ""Abc" =~ /(?>a(?i)b+)+c/" "(?>a(?i)b+)+c" nil nil nil nil "Abc" nil 1 0 nil nil) +(890 ""abAb" =~ /(?>a(?i)b+)+c/" "(?>a(?i)b+)+c" nil nil nil nil "abAb" nil 1 0 nil nil) +(891 ""abbC" =~ /(?>a(?i)b+)+c/" "(?>a(?i)b+)+c" nil nil nil nil "abbC" nil 1 0 nil nil) +(892 ""abc" =~ /(?=a(?i)b)\w\wc/" "(?=a(?i)b)\w\wc" nil nil nil nil "abc" nil 1 0 "abc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(893 ""aBc" =~ /(?=a(?i)b)\w\wc/" "(?=a(?i)b)\w\wc" nil nil nil nil "aBc" nil 1 0 "aBc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(894 ""Ab" =~ /(?=a(?i)b)\w\wc/" "(?=a(?i)b)\w\wc" nil nil nil nil "Ab" nil 1 0 nil nil) +(895 ""abC" =~ /(?=a(?i)b)\w\wc/" "(?=a(?i)b)\w\wc" nil nil nil nil "abC" nil 1 0 nil nil) +(896 ""aBC" =~ /(?=a(?i)b)\w\wc/" "(?=a(?i)b)\w\wc" nil nil nil nil "aBC" nil 1 0 nil nil) +(897 ""abxxc" =~ /(?<=a(?i)b)(\w\w)c/" "(?<=a(?i)b)(\w\w)c" nil nil nil nil "abxxc" nil 1 0 "xxc" ("xx" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(898 ""aBxxc" =~ /(?<=a(?i)b)(\w\w)c/" "(?<=a(?i)b)(\w\w)c" nil nil nil nil "aBxxc" nil 1 0 "xxc" ("xx" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(899 ""Abxxc" =~ /(?<=a(?i)b)(\w\w)c/" "(?<=a(?i)b)(\w\w)c" nil nil nil nil "Abxxc" nil 1 0 nil nil) +(900 ""ABxxc" =~ /(?<=a(?i)b)(\w\w)c/" "(?<=a(?i)b)(\w\w)c" nil nil nil nil "ABxxc" nil 1 0 nil nil) +(901 ""abxxC" =~ /(?<=a(?i)b)(\w\w)c/" "(?<=a(?i)b)(\w\w)c" nil nil nil nil "abxxC" nil 1 0 nil nil) +(902 ""aA" =~ /(?:(a)|b)(?(1)A|B)/" "(?:(a)|b)(?(1)A|B)" nil nil nil nil "aA" nil 1 0 "aA" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(903 ""bB" =~ /(?:(a)|b)(?(1)A|B)/" "(?:(a)|b)(?(1)A|B)" nil nil nil nil "bB" nil 1 0 "bB" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(904 ""aB" =~ /(?:(a)|b)(?(1)A|B)/" "(?:(a)|b)(?(1)A|B)" nil nil nil nil "aB" nil 1 0 nil nil) +(905 ""bA" =~ /(?:(a)|b)(?(1)A|B)/" "(?:(a)|b)(?(1)A|B)" nil nil nil nil "bA" nil 1 0 nil nil) +(906 ""aa" =~ /^(a)?(?(1)a|b)+$/" "^(a)?(?(1)a|b)+$" nil nil nil nil "aa" nil 1 0 "aa" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(907 ""b" =~ /^(a)?(?(1)a|b)+$/" "^(a)?(?(1)a|b)+$" nil nil nil nil "b" nil 1 0 "b" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(908 ""bb" =~ /^(a)?(?(1)a|b)+$/" "^(a)?(?(1)a|b)+$" nil nil nil nil "bb" nil 1 0 "bb" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(909 ""ab" =~ /^(a)?(?(1)a|b)+$/" "^(a)?(?(1)a|b)+$" nil nil nil nil "ab" nil 1 0 nil nil) +(910 ""abc:" =~ /^(?(?=abc)\w{3}:|\d\d)$/" "^(?(?=abc)\w{3}:|\d\d)$" nil nil nil nil "abc:" nil 1 0 "abc:" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(911 ""12" =~ /^(?(?=abc)\w{3}:|\d\d)$/" "^(?(?=abc)\w{3}:|\d\d)$" nil nil nil nil "12" nil 1 0 "12" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(912 ""123" =~ /^(?(?=abc)\w{3}:|\d\d)$/" "^(?(?=abc)\w{3}:|\d\d)$" nil nil nil nil "123" nil 1 0 nil nil) +(913 ""xyz" =~ /^(?(?=abc)\w{3}:|\d\d)$/" "^(?(?=abc)\w{3}:|\d\d)$" nil nil nil nil "xyz" nil 1 0 nil nil) +(914 ""abc:" =~ /^(?(?!abc)\d\d|\w{3}:)$/" "^(?(?!abc)\d\d|\w{3}:)$" nil nil nil nil "abc:" nil 1 0 "abc:" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(915 ""12" =~ /^(?(?!abc)\d\d|\w{3}:)$/" "^(?(?!abc)\d\d|\w{3}:)$" nil nil nil nil "12" nil 1 0 "12" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(916 ""123" =~ /^(?(?!abc)\d\d|\w{3}:)$/" "^(?(?!abc)\d\d|\w{3}:)$" nil nil nil nil "123" nil 1 0 nil nil) +(917 ""xyz" =~ /^(?(?!abc)\d\d|\w{3}:)$/" "^(?(?!abc)\d\d|\w{3}:)$" nil nil nil nil "xyz" nil 1 0 nil nil) +(918 ""foobar" =~ /(?(?<=foo)bar|cat)/" "(?(?<=foo)bar|cat)" nil nil nil nil "foobar" nil 1 0 "bar" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(919 ""cat" =~ /(?(?<=foo)bar|cat)/" "(?(?<=foo)bar|cat)" nil nil nil nil "cat" nil 1 0 "cat" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(920 ""fcat" =~ /(?(?<=foo)bar|cat)/" "(?(?<=foo)bar|cat)" nil nil nil nil "fcat" nil 1 0 "cat" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(921 ""focat" =~ /(?(?<=foo)bar|cat)/" "(?(?<=foo)bar|cat)" nil nil nil nil "focat" nil 1 0 "cat" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(922 ""foocat" =~ /(?(?<=foo)bar|cat)/" "(?(?<=foo)bar|cat)" nil nil nil nil "foocat" nil 1 0 nil nil) +(923 ""foobar" =~ /(?(?<!foo)cat|bar)/" "(?(?<!foo)cat|bar)" nil nil nil nil "foobar" nil 1 0 "bar" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(924 ""cat" =~ /(?(?<!foo)cat|bar)/" "(?(?<!foo)cat|bar)" nil nil nil nil "cat" nil 1 0 "cat" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(925 ""fcat" =~ /(?(?<!foo)cat|bar)/" "(?(?<!foo)cat|bar)" nil nil nil nil "fcat" nil 1 0 "cat" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(926 ""focat" =~ /(?(?<!foo)cat|bar)/" "(?(?<!foo)cat|bar)" nil nil nil nil "focat" nil 1 0 "cat" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(927 ""foocat" =~ /(?(?<!foo)cat|bar)/" "(?(?<!foo)cat|bar)" nil nil nil nil "foocat" nil 1 0 nil nil) +(928 ""abcd" =~ /( \( )? [^()]+ (?(1) \) |) /x" "( \( )? [^()]+ (?(1) \) |) " nil nil nil t "abcd" nil 1 0 "abcd" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(929 ""(abcd)" =~ /( \( )? [^()]+ (?(1) \) |) /x" "( \( )? [^()]+ (?(1) \) |) " nil nil nil t "(abcd)" nil 1 0 "(abcd)" ("(" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(930 ""the quick (abcd) fox" =~ /( \( )? [^()]+ (?(1) \) |) /x" "( \( )? [^()]+ (?(1) \) |) " nil nil nil t "the quick (abcd) fox" nil 1 0 "the quick " (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(931 ""(abcd" =~ /( \( )? [^()]+ (?(1) \) |) /x" "( \( )? [^()]+ (?(1) \) |) " nil nil nil t "(abcd" nil 1 0 "abcd" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(932 ""abcd" =~ /( \( )? [^()]+ (?(1) \) ) /x" "( \( )? [^()]+ (?(1) \) ) " nil nil nil t "abcd" nil 1 0 "abcd" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(933 ""(abcd)" =~ /( \( )? [^()]+ (?(1) \) ) /x" "( \( )? [^()]+ (?(1) \) ) " nil nil nil t "(abcd)" nil 1 0 "(abcd)" ("(" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(934 ""the quick (abcd) fox" =~ /( \( )? [^()]+ (?(1) \) ) /x" "( \( )? [^()]+ (?(1) \) ) " nil nil nil t "the quick (abcd) fox" nil 1 0 "the quick " (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(935 ""(abcd" =~ /( \( )? [^()]+ (?(1) \) ) /x" "( \( )? [^()]+ (?(1) \) ) " nil nil nil t "(abcd" nil 1 0 "abcd" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(936 ""12" =~ /^(?(2)a|(1)(2))+$/" "^(?(2)a|(1)(2))+$" nil nil nil nil "12" nil 1 0 "12" ("1" "2" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(937 ""12a" =~ /^(?(2)a|(1)(2))+$/" "^(?(2)a|(1)(2))+$" nil nil nil nil "12a" nil 1 0 "12a" ("1" "2" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(938 ""12aa" =~ /^(?(2)a|(1)(2))+$/" "^(?(2)a|(1)(2))+$" nil nil nil nil "12aa" nil 1 0 "12aa" ("1" "2" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(939 ""1234" =~ /^(?(2)a|(1)(2))+$/" "^(?(2)a|(1)(2))+$" nil nil nil nil "1234" nil 1 0 nil nil) +(940 ""blah blah" =~ /((?i)blah)\s+\1/" "((?i)blah)\s+\1" nil nil nil nil "blah blah" nil 1 0 "blah blah" ("blah" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(941 ""BLAH BLAH" =~ /((?i)blah)\s+\1/" "((?i)blah)\s+\1" nil nil nil nil "BLAH BLAH" nil 1 0 "BLAH BLAH" ("BLAH" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(942 ""Blah Blah" =~ /((?i)blah)\s+\1/" "((?i)blah)\s+\1" nil nil nil nil "Blah Blah" nil 1 0 "Blah Blah" ("Blah" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(943 ""blaH blaH" =~ /((?i)blah)\s+\1/" "((?i)blah)\s+\1" nil nil nil nil "blaH blaH" nil 1 0 "blaH blaH" ("blaH" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(944 ""blah BLAH" =~ /((?i)blah)\s+\1/" "((?i)blah)\s+\1" nil nil nil nil "blah BLAH" nil 1 0 nil nil) +(945 ""Blah blah" =~ /((?i)blah)\s+\1/" "((?i)blah)\s+\1" nil nil nil nil "Blah blah" nil 1 0 nil nil) +(946 ""blaH blah" =~ /((?i)blah)\s+\1/" "((?i)blah)\s+\1" nil nil nil nil "blaH blah" nil 1 0 nil nil) +(947 ""blah blah" =~ /((?i)blah)\s+(?i:\1)/" "((?i)blah)\s+(?i:\1)" nil nil nil nil "blah blah" nil 1 0 "blah blah" ("blah" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(948 ""BLAH BLAH" =~ /((?i)blah)\s+(?i:\1)/" "((?i)blah)\s+(?i:\1)" nil nil nil nil "BLAH BLAH" nil 1 0 "BLAH BLAH" ("BLAH" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(949 ""Blah Blah" =~ /((?i)blah)\s+(?i:\1)/" "((?i)blah)\s+(?i:\1)" nil nil nil nil "Blah Blah" nil 1 0 "Blah Blah" ("Blah" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(950 ""blaH blaH" =~ /((?i)blah)\s+(?i:\1)/" "((?i)blah)\s+(?i:\1)" nil nil nil nil "blaH blaH" nil 1 0 "blaH blaH" ("blaH" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(951 ""blah BLAH" =~ /((?i)blah)\s+(?i:\1)/" "((?i)blah)\s+(?i:\1)" nil nil nil nil "blah BLAH" nil 1 0 "blah BLAH" ("blah" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(952 ""Blah blah" =~ /((?i)blah)\s+(?i:\1)/" "((?i)blah)\s+(?i:\1)" nil nil nil nil "Blah blah" nil 1 0 "Blah blah" ("Blah" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(953 ""blaH blah" =~ /((?i)blah)\s+(?i:\1)/" "((?i)blah)\s+(?i:\1)" nil nil nil nil "blaH blah" nil 1 0 "blaH blah" ("blaH" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(954 ""a" =~ /(?>a*)*/" "(?>a*)*" nil nil nil nil "a" nil 1 0 "a" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(955 ""aa" =~ /(?>a*)*/" "(?>a*)*" nil nil nil nil "aa" nil 1 0 "aa" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(956 ""aaaa" =~ /(?>a*)*/" "(?>a*)*" nil nil nil nil "aaaa" nil 1 0 "aaaa" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(957 ""abc" =~ /(abc|)+/" "(abc|)+" nil nil nil nil "abc" nil 1 0 "abc" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(958 ""abcabc" =~ /(abc|)+/" "(abc|)+" nil nil nil nil "abcabc" nil 1 0 "abcabc" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(959 ""abcabcabc" =~ /(abc|)+/" "(abc|)+" nil nil nil nil "abcabcabc" nil 1 0 "abcabcabc" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(960 ""xyz" =~ /(abc|)+/" "(abc|)+" nil nil nil nil "xyz" nil 1 0 "" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(961 ""a" =~ /([a]*)*/" "([a]*)*" nil nil nil nil "a" nil 1 0 "a" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(962 ""aaaaa" =~ /([a]*)*/" "([a]*)*" nil nil nil nil "aaaaa" nil 1 0 "aaaaa" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(963 ""a" =~ /([ab]*)*/" "([ab]*)*" nil nil nil nil "a" nil 1 0 "a" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(964 ""b" =~ /([ab]*)*/" "([ab]*)*" nil nil nil nil "b" nil 1 0 "b" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(965 ""ababab" =~ /([ab]*)*/" "([ab]*)*" nil nil nil nil "ababab" nil 1 0 "ababab" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(966 ""aaaabcde" =~ /([ab]*)*/" "([ab]*)*" nil nil nil nil "aaaabcde" nil 1 0 "aaaab" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(967 ""bbbb" =~ /([ab]*)*/" "([ab]*)*" nil nil nil nil "bbbb" nil 1 0 "bbbb" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(968 ""b" =~ /([^a]*)*/" "([^a]*)*" nil nil nil nil "b" nil 1 0 "b" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(969 ""bbbb" =~ /([^a]*)*/" "([^a]*)*" nil nil nil nil "bbbb" nil 1 0 "bbbb" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(970 ""aaa" =~ /([^a]*)*/" "([^a]*)*" nil nil nil nil "aaa" nil 1 0 "" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(971 ""cccc" =~ /([^ab]*)*/" "([^ab]*)*" nil nil nil nil "cccc" nil 1 0 "cccc" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(972 ""abab" =~ /([^ab]*)*/" "([^ab]*)*" nil nil nil nil "abab" nil 1 0 "" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(973 ""a" =~ /([a]*?)*/" "([a]*?)*" nil nil nil nil "a" nil 1 0 "" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(974 ""aaaa" =~ /([a]*?)*/" "([a]*?)*" nil nil nil nil "aaaa" nil 1 0 "" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(975 ""a" =~ /([ab]*?)*/" "([ab]*?)*" nil nil nil nil "a" nil 1 0 "" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(976 ""b" =~ /([ab]*?)*/" "([ab]*?)*" nil nil nil nil "b" nil 1 0 "" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(977 ""abab" =~ /([ab]*?)*/" "([ab]*?)*" nil nil nil nil "abab" nil 1 0 "" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(978 ""baba" =~ /([ab]*?)*/" "([ab]*?)*" nil nil nil nil "baba" nil 1 0 "" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(979 ""b" =~ /([^a]*?)*/" "([^a]*?)*" nil nil nil nil "b" nil 1 0 "" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(980 ""bbbb" =~ /([^a]*?)*/" "([^a]*?)*" nil nil nil nil "bbbb" nil 1 0 "" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(981 ""aaa" =~ /([^a]*?)*/" "([^a]*?)*" nil nil nil nil "aaa" nil 1 0 "" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(982 ""c" =~ /([^ab]*?)*/" "([^ab]*?)*" nil nil nil nil "c" nil 1 0 "" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(983 ""cccc" =~ /([^ab]*?)*/" "([^ab]*?)*" nil nil nil nil "cccc" nil 1 0 "" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(984 ""baba" =~ /([^ab]*?)*/" "([^ab]*?)*" nil nil nil nil "baba" nil 1 0 "" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(985 ""a" =~ /(?>a*)*/" "(?>a*)*" nil nil nil nil "a" nil 1 0 "a" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(986 ""aaabcde" =~ /(?>a*)*/" "(?>a*)*" nil nil nil nil "aaabcde" nil 1 0 "aaa" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(987 ""aaaaa" =~ /((?>a*))*/" "((?>a*))*" nil nil nil nil "aaaaa" nil 1 0 "aaaaa" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(988 ""aabbaa" =~ /((?>a*))*/" "((?>a*))*" nil nil nil nil "aabbaa" nil 1 0 "aa" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(989 ""aaaaa" =~ /((?>a*?))*/" "((?>a*?))*" nil nil nil nil "aaaaa" nil 1 0 "" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(990 ""aabbaa" =~ /((?>a*?))*/" "((?>a*?))*" nil nil nil nil "aabbaa" nil 1 0 "" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(991 ""12-sep-98" =~ /(?(?=[^a-z]+[a-z]) \d{2}-[a-z]{3}-\d{2} | \d{2}-\d{2}-\d{2} ) /x" "(?(?=[^a-z]+[a-z]) \d{2}-[a-z]{3}-\d{2} | \d{2}-\d{2}-\d{2} ) " nil nil nil t "12-sep-98" nil 1 0 "12-sep-98" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(992 ""12-09-98" =~ /(?(?=[^a-z]+[a-z]) \d{2}-[a-z]{3}-\d{2} | \d{2}-\d{2}-\d{2} ) /x" "(?(?=[^a-z]+[a-z]) \d{2}-[a-z]{3}-\d{2} | \d{2}-\d{2}-\d{2} ) " nil nil nil t "12-09-98" nil 1 0 "12-09-98" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(993 ""sep-12-98" =~ /(?(?=[^a-z]+[a-z]) \d{2}-[a-z]{3}-\d{2} | \d{2}-\d{2}-\d{2} ) /x" "(?(?=[^a-z]+[a-z]) \d{2}-[a-z]{3}-\d{2} | \d{2}-\d{2}-\d{2} ) " nil nil nil t "sep-12-98" nil 1 0 nil nil) +(994 ""foobarfoo" =~ /(?<=(foo))bar\1/" "(?<=(foo))bar\1" nil nil nil nil "foobarfoo" nil 1 0 "barfoo" ("foo" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(995 ""foobarfootling" =~ /(?<=(foo))bar\1/" "(?<=(foo))bar\1" nil nil nil nil "foobarfootling" nil 1 0 "barfoo" ("foo" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(996 ""foobar" =~ /(?<=(foo))bar\1/" "(?<=(foo))bar\1" nil nil nil nil "foobar" nil 1 0 nil nil) +(997 ""barfoo" =~ /(?<=(foo))bar\1/" "(?<=(foo))bar\1" nil nil nil nil "barfoo" nil 1 0 nil nil) +(998 ""saturday" =~ /(?i:saturday|sunday)/" "(?i:saturday|sunday)" nil nil nil nil "saturday" nil 1 0 "saturday" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(999 ""sunday" =~ /(?i:saturday|sunday)/" "(?i:saturday|sunday)" nil nil nil nil "sunday" nil 1 0 "sunday" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1000 ""Saturday" =~ /(?i:saturday|sunday)/" "(?i:saturday|sunday)" nil nil nil nil "Saturday" nil 1 0 "Saturday" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1001 ""Sunday" =~ /(?i:saturday|sunday)/" "(?i:saturday|sunday)" nil nil nil nil "Sunday" nil 1 0 "Sunday" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1002 ""SATURDAY" =~ /(?i:saturday|sunday)/" "(?i:saturday|sunday)" nil nil nil nil "SATURDAY" nil 1 0 "SATURDAY" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1003 ""SUNDAY" =~ /(?i:saturday|sunday)/" "(?i:saturday|sunday)" nil nil nil nil "SUNDAY" nil 1 0 "SUNDAY" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1004 ""SunDay" =~ /(?i:saturday|sunday)/" "(?i:saturday|sunday)" nil nil nil nil "SunDay" nil 1 0 "SunDay" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1005 ""abcx" =~ /(a(?i)bc|BB)x/" "(a(?i)bc|BB)x" nil nil nil nil "abcx" nil 1 0 "abcx" ("abc" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1006 ""aBCx" =~ /(a(?i)bc|BB)x/" "(a(?i)bc|BB)x" nil nil nil nil "aBCx" nil 1 0 "aBCx" ("aBC" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1007 ""bbx" =~ /(a(?i)bc|BB)x/" "(a(?i)bc|BB)x" nil nil nil nil "bbx" nil 1 0 "bbx" ("bb" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1008 ""BBx" =~ /(a(?i)bc|BB)x/" "(a(?i)bc|BB)x" nil nil nil nil "BBx" nil 1 0 "BBx" ("BB" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1009 ""abcX" =~ /(a(?i)bc|BB)x/" "(a(?i)bc|BB)x" nil nil nil nil "abcX" nil 1 0 nil nil) +(1010 ""aBCX" =~ /(a(?i)bc|BB)x/" "(a(?i)bc|BB)x" nil nil nil nil "aBCX" nil 1 0 nil nil) +(1011 ""bbX" =~ /(a(?i)bc|BB)x/" "(a(?i)bc|BB)x" nil nil nil nil "bbX" nil 1 0 nil nil) +(1012 ""BBX" =~ /(a(?i)bc|BB)x/" "(a(?i)bc|BB)x" nil nil nil nil "BBX" nil 1 0 nil nil) +(1013 ""ac" =~ /^([ab](?i)[cd]|[ef])/" "^([ab](?i)[cd]|[ef])" nil nil nil nil "ac" nil 1 0 "ac" ("ac" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1014 ""aC" =~ /^([ab](?i)[cd]|[ef])/" "^([ab](?i)[cd]|[ef])" nil nil nil nil "aC" nil 1 0 "aC" ("aC" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1015 ""bD" =~ /^([ab](?i)[cd]|[ef])/" "^([ab](?i)[cd]|[ef])" nil nil nil nil "bD" nil 1 0 "bD" ("bD" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1016 ""elephant" =~ /^([ab](?i)[cd]|[ef])/" "^([ab](?i)[cd]|[ef])" nil nil nil nil "elephant" nil 1 0 "e" ("e" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1017 ""Europe" =~ /^([ab](?i)[cd]|[ef])/" "^([ab](?i)[cd]|[ef])" nil nil nil nil "Europe" nil 1 0 "E" ("E" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1018 ""frog" =~ /^([ab](?i)[cd]|[ef])/" "^([ab](?i)[cd]|[ef])" nil nil nil nil "frog" nil 1 0 "f" ("f" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1019 ""France" =~ /^([ab](?i)[cd]|[ef])/" "^([ab](?i)[cd]|[ef])" nil nil nil nil "France" nil 1 0 "F" ("F" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1020 ""Africa" =~ /^([ab](?i)[cd]|[ef])/" "^([ab](?i)[cd]|[ef])" nil nil nil nil "Africa" nil 1 0 nil nil) +(1021 ""ab" =~ /^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)/" "^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)" nil nil nil nil "ab" nil 1 0 "ab" ("ab" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1022 ""aBd" =~ /^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)/" "^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)" nil nil nil nil "aBd" nil 1 0 "aBd" ("aBd" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1023 ""xy" =~ /^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)/" "^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)" nil nil nil nil "xy" nil 1 0 "xy" ("xy" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1024 ""xY" =~ /^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)/" "^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)" nil nil nil nil "xY" nil 1 0 "xY" ("xY" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1025 ""zebra" =~ /^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)/" "^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)" nil nil nil nil "zebra" nil 1 0 "z" ("z" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1026 ""Zambesi" =~ /^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)/" "^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)" nil nil nil nil "Zambesi" nil 1 0 "Z" ("Z" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1027 ""aCD" =~ /^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)/" "^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)" nil nil nil nil "aCD" nil 1 0 nil nil) +(1028 ""XY" =~ /^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)/" "^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)" nil nil nil nil "XY" nil 1 0 nil nil) +(1029 ""foo\nbar" =~ /(?<=foo\n)^bar/m" "(?<=foo\n)^bar" nil t nil nil "foo +bar" nil 1 0 "bar" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1030 ""bar" =~ /(?<=foo\n)^bar/m" "(?<=foo\n)^bar" nil t nil nil "bar" nil 1 0 nil nil) +(1031 ""baz\nbar" =~ /(?<=foo\n)^bar/m" "(?<=foo\n)^bar" nil t nil nil "baz +bar" nil 1 0 nil nil) +(1032 ""barbaz" =~ /(?<=(?<!foo)bar)baz/" "(?<=(?<!foo)bar)baz" nil nil nil nil "barbaz" nil 1 0 "baz" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1033 ""barbarbaz" =~ /(?<=(?<!foo)bar)baz/" "(?<=(?<!foo)bar)baz" nil nil nil nil "barbarbaz" nil 1 0 "baz" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1034 ""koobarbaz" =~ /(?<=(?<!foo)bar)baz/" "(?<=(?<!foo)bar)baz" nil nil nil nil "koobarbaz" nil 1 0 "baz" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1035 ""baz" =~ /(?<=(?<!foo)bar)baz/" "(?<=(?<!foo)bar)baz" nil nil nil nil "baz" nil 1 0 nil nil) +(1036 ""foobarbaz" =~ /(?<=(?<!foo)bar)baz/" "(?<=(?<!foo)bar)baz" nil nil nil nil "foobarbaz" nil 1 0 nil nil) +(1037 ""a" =~ /^(a\1?){4}$/" "^(a\1?){4}$" nil nil nil nil "a" nil 1 0 nil nil) +(1038 ""aa" =~ /^(a\1?){4}$/" "^(a\1?){4}$" nil nil nil nil "aa" nil 1 0 nil nil) +(1039 ""aaa" =~ /^(a\1?){4}$/" "^(a\1?){4}$" nil nil nil nil "aaa" nil 1 0 nil nil) +(1040 ""aaaa" =~ /^(a\1?){4}$/" "^(a\1?){4}$" nil nil nil nil "aaaa" nil 1 0 "aaaa" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1041 ""aaaaa" =~ /^(a\1?){4}$/" "^(a\1?){4}$" nil nil nil nil "aaaaa" nil 1 0 "aaaaa" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1042 ""aaaaaa" =~ /^(a\1?){4}$/" "^(a\1?){4}$" nil nil nil nil "aaaaaa" nil 1 0 "aaaaaa" ("aa" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1043 ""aaaaaaa" =~ /^(a\1?){4}$/" "^(a\1?){4}$" nil nil nil nil "aaaaaaa" nil 1 0 "aaaaaaa" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1044 ""aaaaaaaa" =~ /^(a\1?){4}$/" "^(a\1?){4}$" nil nil nil nil "aaaaaaaa" nil 1 0 nil nil) +(1045 ""aaaaaaaaa" =~ /^(a\1?){4}$/" "^(a\1?){4}$" nil nil nil nil "aaaaaaaaa" nil 1 0 nil nil) +(1046 ""aaaaaaaaaa" =~ /^(a\1?){4}$/" "^(a\1?){4}$" nil nil nil nil "aaaaaaaaaa" nil 1 0 "aaaaaaaaaa" ("aaaa" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1047 ""aaaaaaaaaaa" =~ /^(a\1?){4}$/" "^(a\1?){4}$" nil nil nil nil "aaaaaaaaaaa" nil 1 0 nil nil) +(1048 ""aaaaaaaaaaaa" =~ /^(a\1?){4}$/" "^(a\1?){4}$" nil nil nil nil "aaaaaaaaaaaa" nil 1 0 nil nil) +(1049 ""aaaaaaaaaaaaa" =~ /^(a\1?){4}$/" "^(a\1?){4}$" nil nil nil nil "aaaaaaaaaaaaa" nil 1 0 nil nil) +(1050 ""aaaaaaaaaaaaaa" =~ /^(a\1?){4}$/" "^(a\1?){4}$" nil nil nil nil "aaaaaaaaaaaaaa" nil 1 0 nil nil) +(1051 ""aaaaaaaaaaaaaaa" =~ /^(a\1?){4}$/" "^(a\1?){4}$" nil nil nil nil "aaaaaaaaaaaaaaa" nil 1 0 nil nil) +(1052 ""aaaaaaaaaaaaaaaa" =~ /^(a\1?){4}$/" "^(a\1?){4}$" nil nil nil nil "aaaaaaaaaaaaaaaa" nil 1 0 nil nil) +(1053 ""a" =~ /^(a\1?)(a\1?)(a\2?)(a\3?)$/" "^(a\1?)(a\1?)(a\2?)(a\3?)$" nil nil nil nil "a" nil 1 0 nil nil) +(1054 ""aa" =~ /^(a\1?)(a\1?)(a\2?)(a\3?)$/" "^(a\1?)(a\1?)(a\2?)(a\3?)$" nil nil nil nil "aa" nil 1 0 nil nil) +(1055 ""aaa" =~ /^(a\1?)(a\1?)(a\2?)(a\3?)$/" "^(a\1?)(a\1?)(a\2?)(a\3?)$" nil nil nil nil "aaa" nil 1 0 nil nil) +(1056 ""aaaa" =~ /^(a\1?)(a\1?)(a\2?)(a\3?)$/" "^(a\1?)(a\1?)(a\2?)(a\3?)$" nil nil nil nil "aaaa" nil 1 0 "aaaa" ("a" "a" "a" "a" nil nil nil nil nil nil nil nil nil nil nil nil)) +(1057 ""aaaaa" =~ /^(a\1?)(a\1?)(a\2?)(a\3?)$/" "^(a\1?)(a\1?)(a\2?)(a\3?)$" nil nil nil nil "aaaaa" nil 1 0 "aaaaa" ("a" "aa" "a" "a" nil nil nil nil nil nil nil nil nil nil nil nil)) +(1058 ""aaaaaa" =~ /^(a\1?)(a\1?)(a\2?)(a\3?)$/" "^(a\1?)(a\1?)(a\2?)(a\3?)$" nil nil nil nil "aaaaaa" nil 1 0 "aaaaaa" ("a" "aa" "a" "aa" nil nil nil nil nil nil nil nil nil nil nil nil)) +(1059 ""aaaaaaa" =~ /^(a\1?)(a\1?)(a\2?)(a\3?)$/" "^(a\1?)(a\1?)(a\2?)(a\3?)$" nil nil nil nil "aaaaaaa" nil 1 0 "aaaaaaa" ("a" "aa" "aaa" "a" nil nil nil nil nil nil nil nil nil nil nil nil)) +(1060 ""aaaaaaaa" =~ /^(a\1?)(a\1?)(a\2?)(a\3?)$/" "^(a\1?)(a\1?)(a\2?)(a\3?)$" nil nil nil nil "aaaaaaaa" nil 1 0 nil nil) +(1061 ""aaaaaaaaa" =~ /^(a\1?)(a\1?)(a\2?)(a\3?)$/" "^(a\1?)(a\1?)(a\2?)(a\3?)$" nil nil nil nil "aaaaaaaaa" nil 1 0 nil nil) +(1062 ""aaaaaaaaaa" =~ /^(a\1?)(a\1?)(a\2?)(a\3?)$/" "^(a\1?)(a\1?)(a\2?)(a\3?)$" nil nil nil nil "aaaaaaaaaa" nil 1 0 "aaaaaaaaaa" ("a" "aa" "aaa" "aaaa" nil nil nil nil nil nil nil nil nil nil nil nil)) +(1063 ""aaaaaaaaaaa" =~ /^(a\1?)(a\1?)(a\2?)(a\3?)$/" "^(a\1?)(a\1?)(a\2?)(a\3?)$" nil nil nil nil "aaaaaaaaaaa" nil 1 0 nil nil) +(1064 ""aaaaaaaaaaaa" =~ /^(a\1?)(a\1?)(a\2?)(a\3?)$/" "^(a\1?)(a\1?)(a\2?)(a\3?)$" nil nil nil nil "aaaaaaaaaaaa" nil 1 0 nil nil) +(1065 ""aaaaaaaaaaaaa" =~ /^(a\1?)(a\1?)(a\2?)(a\3?)$/" "^(a\1?)(a\1?)(a\2?)(a\3?)$" nil nil nil nil "aaaaaaaaaaaaa" nil 1 0 nil nil) +(1066 ""aaaaaaaaaaaaaa" =~ /^(a\1?)(a\1?)(a\2?)(a\3?)$/" "^(a\1?)(a\1?)(a\2?)(a\3?)$" nil nil nil nil "aaaaaaaaaaaaaa" nil 1 0 nil nil) +(1067 ""aaaaaaaaaaaaaaa" =~ /^(a\1?)(a\1?)(a\2?)(a\3?)$/" "^(a\1?)(a\1?)(a\2?)(a\3?)$" nil nil nil nil "aaaaaaaaaaaaaaa" nil 1 0 nil nil) +(1068 ""aaaaaaaaaaaaaaaa" =~ /^(a\1?)(a\1?)(a\2?)(a\3?)$/" "^(a\1?)(a\1?)(a\2?)(a\3?)$" nil nil nil nil "aaaaaaaaaaaaaaaa" nil 1 0 nil nil) +(1069 ""abc" =~ /abc/" "abc" nil nil nil nil "abc" nil 1 0 "abc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1070 ""xabcy" =~ /abc/" "abc" nil nil nil nil "xabcy" nil 1 0 "abc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1071 ""ababc" =~ /abc/" "abc" nil nil nil nil "ababc" nil 1 0 "abc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1072 ""xbc" =~ /abc/" "abc" nil nil nil nil "xbc" nil 1 0 nil nil) +(1073 ""axc" =~ /abc/" "abc" nil nil nil nil "axc" nil 1 0 nil nil) +(1074 ""abx" =~ /abc/" "abc" nil nil nil nil "abx" nil 1 0 nil nil) +(1075 ""abc" =~ /ab*c/" "ab*c" nil nil nil nil "abc" nil 1 0 "abc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1076 ""abc" =~ /ab*bc/" "ab*bc" nil nil nil nil "abc" nil 1 0 "abc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1077 ""abbc" =~ /ab*bc/" "ab*bc" nil nil nil nil "abbc" nil 1 0 "abbc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1078 ""abbbbc" =~ /ab*bc/" "ab*bc" nil nil nil nil "abbbbc" nil 1 0 "abbbbc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1079 ""abbbbc" =~ /.{1}/" ".{1}" nil nil nil nil "abbbbc" nil 1 0 "a" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1080 ""abbbbc" =~ /.{3,4}/" ".{3,4}" nil nil nil nil "abbbbc" nil 1 0 "abbb" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1081 ""abbbbc" =~ /ab{0,}bc/" "ab{0,}bc" nil nil nil nil "abbbbc" nil 1 0 "abbbbc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1082 ""abbc" =~ /ab+bc/" "ab+bc" nil nil nil nil "abbc" nil 1 0 "abbc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1083 ""abc" =~ /ab+bc/" "ab+bc" nil nil nil nil "abc" nil 1 0 nil nil) +(1084 ""abq" =~ /ab+bc/" "ab+bc" nil nil nil nil "abq" nil 1 0 nil nil) +(1085 ""abbbbc" =~ /ab+bc/" "ab+bc" nil nil nil nil "abbbbc" nil 1 0 "abbbbc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1086 ""abbbbc" =~ /ab{1,}bc/" "ab{1,}bc" nil nil nil nil "abbbbc" nil 1 0 "abbbbc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1087 ""abbbbc" =~ /ab{1,3}bc/" "ab{1,3}bc" nil nil nil nil "abbbbc" nil 1 0 "abbbbc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1088 ""abbbbc" =~ /ab{3,4}bc/" "ab{3,4}bc" nil nil nil nil "abbbbc" nil 1 0 "abbbbc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1089 ""abq" =~ /ab{4,5}bc/" "ab{4,5}bc" nil nil nil nil "abq" nil 1 0 nil nil) +(1090 ""abbbbc" =~ /ab{4,5}bc/" "ab{4,5}bc" nil nil nil nil "abbbbc" nil 1 0 nil nil) +(1091 ""abbc" =~ /ab?bc/" "ab?bc" nil nil nil nil "abbc" nil 1 0 "abbc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1092 ""abc" =~ /ab?bc/" "ab?bc" nil nil nil nil "abc" nil 1 0 "abc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1093 ""abc" =~ /ab{0,1}bc/" "ab{0,1}bc" nil nil nil nil "abc" nil 1 0 "abc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1094 ""abc" =~ /ab?c/" "ab?c" nil nil nil nil "abc" nil 1 0 "abc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1095 ""abc" =~ /ab{0,1}c/" "ab{0,1}c" nil nil nil nil "abc" nil 1 0 "abc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1096 ""abc" =~ /^abc$/" "^abc$" nil nil nil nil "abc" nil 1 0 "abc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1097 ""abbbbc" =~ /^abc$/" "^abc$" nil nil nil nil "abbbbc" nil 1 0 nil nil) +(1098 ""abcc" =~ /^abc$/" "^abc$" nil nil nil nil "abcc" nil 1 0 nil nil) +(1099 ""abcc" =~ /^abc/" "^abc" nil nil nil nil "abcc" nil 1 0 "abc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1100 ""aabc" =~ /abc$/" "abc$" nil nil nil nil "aabc" nil 1 0 "abc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1101 ""aabc" =~ /abc$/" "abc$" nil nil nil nil "aabc" nil 1 0 "abc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1102 ""aabcd" =~ /abc$/" "abc$" nil nil nil nil "aabcd" nil 1 0 nil nil) +(1103 ""abc" =~ /^/" "^" nil nil nil nil "abc" nil 1 0 "" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1104 ""abc" =~ /$/" "$" nil nil nil nil "abc" nil 1 0 "" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1105 ""abc" =~ /a.c/" "a.c" nil nil nil nil "abc" nil 1 0 "abc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1106 ""axc" =~ /a.c/" "a.c" nil nil nil nil "axc" nil 1 0 "axc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1107 ""axyzc" =~ /a.*c/" "a.*c" nil nil nil nil "axyzc" nil 1 0 "axyzc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1108 ""abd" =~ /a[bc]d/" "a[bc]d" nil nil nil nil "abd" nil 1 0 "abd" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1109 ""axyzd" =~ /a[bc]d/" "a[bc]d" nil nil nil nil "axyzd" nil 1 0 nil nil) +(1110 ""abc" =~ /a[bc]d/" "a[bc]d" nil nil nil nil "abc" nil 1 0 nil nil) +(1111 ""ace" =~ /a[b-d]e/" "a[b-d]e" nil nil nil nil "ace" nil 1 0 "ace" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1112 ""aac" =~ /a[b-d]/" "a[b-d]" nil nil nil nil "aac" nil 1 0 "ac" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1113 ""a-" =~ /a[-b]/" "a[-b]" nil nil nil nil "a-" nil 1 0 "a-" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1114 ""a-" =~ /a[b-]/" "a[b-]" nil nil nil nil "a-" nil 1 0 "a-" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1115 ""a]" =~ /a]/" "a]" nil nil nil nil "a]" nil 1 0 "a]" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1116 ""a]b" =~ /a[]]b/" "a[]]b" nil nil nil nil "a]b" nil 1 0 "a]b" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1117 ""aed" =~ /a[^bc]d/" "a[^bc]d" nil nil nil nil "aed" nil 1 0 "aed" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1118 ""abd" =~ /a[^bc]d/" "a[^bc]d" nil nil nil nil "abd" nil 1 0 nil nil) +(1119 ""abd" =~ /a[^bc]d/" "a[^bc]d" nil nil nil nil "abd" nil 1 0 nil nil) +(1120 ""adc" =~ /a[^-b]c/" "a[^-b]c" nil nil nil nil "adc" nil 1 0 "adc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1121 ""adc" =~ /a[^]b]c/" "a[^]b]c" nil nil nil nil "adc" nil 1 0 "adc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1122 ""a-c" =~ /a[^]b]c/" "a[^]b]c" nil nil nil nil "a-c" nil 1 0 "a-c" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1123 ""a]c" =~ /a[^]b]c/" "a[^]b]c" nil nil nil nil "a]c" nil 1 0 nil nil) +(1124 ""a-" =~ /\ba\b/" "\ba\b" nil nil nil nil "a-" nil 1 0 "a" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1125 ""-a" =~ /\ba\b/" "\ba\b" nil nil nil nil "-a" nil 1 0 "a" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1126 ""-a-" =~ /\ba\b/" "\ba\b" nil nil nil nil "-a-" nil 1 0 "a" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1127 ""xy" =~ /\by\b/" "\by\b" nil nil nil nil "xy" nil 1 0 nil nil) +(1128 ""yz" =~ /\by\b/" "\by\b" nil nil nil nil "yz" nil 1 0 nil nil) +(1129 ""xyz" =~ /\by\b/" "\by\b" nil nil nil nil "xyz" nil 1 0 nil nil) +(1130 ""a-" =~ /\Ba\B/" "\Ba\B" nil nil nil nil "a-" nil 1 0 nil nil) +(1131 ""-a" =~ /\Ba\B/" "\Ba\B" nil nil nil nil "-a" nil 1 0 nil nil) +(1132 ""-a-" =~ /\Ba\B/" "\Ba\B" nil nil nil nil "-a-" nil 1 0 nil nil) +(1133 ""xy" =~ /\By\b/" "\By\b" nil nil nil nil "xy" nil 1 0 "y" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1134 ""yz" =~ /\by\B/" "\by\B" nil nil nil nil "yz" nil 1 0 "y" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1135 ""xyz" =~ /\By\B/" "\By\B" nil nil nil nil "xyz" nil 1 0 "y" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1136 ""a" =~ /\w/" "\w" nil nil nil nil "a" nil 1 0 "a" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1137 ""-" =~ /\W/" "\W" nil nil nil nil "-" nil 1 0 "-" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1138 ""-" =~ /\W/" "\W" nil nil nil nil "-" nil 1 0 "-" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1139 ""a" =~ /\W/" "\W" nil nil nil nil "a" nil 1 0 nil nil) +(1140 ""a b" =~ /a\sb/" "a\sb" nil nil nil nil "a b" nil 1 0 "a b" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1141 ""a-b" =~ /a\Sb/" "a\Sb" nil nil nil nil "a-b" nil 1 0 "a-b" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1142 ""a-b" =~ /a\Sb/" "a\Sb" nil nil nil nil "a-b" nil 1 0 "a-b" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1143 ""a b" =~ /a\Sb/" "a\Sb" nil nil nil nil "a b" nil 1 0 nil nil) +(1144 ""1" =~ /\d/" "\d" nil nil nil nil "1" nil 1 0 "1" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1145 ""-" =~ /\D/" "\D" nil nil nil nil "-" nil 1 0 "-" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1146 ""-" =~ /\D/" "\D" nil nil nil nil "-" nil 1 0 "-" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1147 ""1" =~ /\D/" "\D" nil nil nil nil "1" nil 1 0 nil nil) +(1148 ""a" =~ /[\w]/" "[\w]" nil nil nil nil "a" nil 1 0 "a" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1149 ""-" =~ /[\W]/" "[\W]" nil nil nil nil "-" nil 1 0 "-" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1150 ""-" =~ /[\W]/" "[\W]" nil nil nil nil "-" nil 1 0 "-" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1151 ""a" =~ /[\W]/" "[\W]" nil nil nil nil "a" nil 1 0 nil nil) +(1152 ""a b" =~ /a[\s]b/" "a[\s]b" nil nil nil nil "a b" nil 1 0 "a b" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1153 ""a-b" =~ /a[\S]b/" "a[\S]b" nil nil nil nil "a-b" nil 1 0 "a-b" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1154 ""a-b" =~ /a[\S]b/" "a[\S]b" nil nil nil nil "a-b" nil 1 0 "a-b" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1155 ""a b" =~ /a[\S]b/" "a[\S]b" nil nil nil nil "a b" nil 1 0 nil nil) +(1156 ""1" =~ /[\d]/" "[\d]" nil nil nil nil "1" nil 1 0 "1" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1157 ""-" =~ /[\D]/" "[\D]" nil nil nil nil "-" nil 1 0 "-" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1158 ""-" =~ /[\D]/" "[\D]" nil nil nil nil "-" nil 1 0 "-" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1159 ""1" =~ /[\D]/" "[\D]" nil nil nil nil "1" nil 1 0 nil nil) +(1160 ""abc" =~ /ab|cd/" "ab|cd" nil nil nil nil "abc" nil 1 0 "ab" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1161 ""abcd" =~ /ab|cd/" "ab|cd" nil nil nil nil "abcd" nil 1 0 "ab" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1162 ""def" =~ /()ef/" "()ef" nil nil nil nil "def" nil 1 0 "ef" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1163 ""a(b" =~ /a\(b/" "a\(b" nil nil nil nil "a(b" nil 1 0 "a(b" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1164 ""ab" =~ /a\(*b/" "a\(*b" nil nil nil nil "ab" nil 1 0 "ab" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1165 ""a((b" =~ /a\(*b/" "a\(*b" nil nil nil nil "a((b" nil 1 0 "a((b" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1166 ""a\b" =~ /a\\b/" "a\\b" nil nil nil nil ("a" 8) nil 1 0 nil nil) +(1167 ""abc" =~ /((a))/" "((a))" nil nil nil nil "abc" nil 1 0 "a" ("a" "a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1168 ""abc" =~ /(a)b(c)/" "(a)b(c)" nil nil nil nil "abc" nil 1 0 "abc" ("a" "c" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1169 ""aabbabc" =~ /a+b+c/" "a+b+c" nil nil nil nil "aabbabc" nil 1 0 "abc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1170 ""aabbabc" =~ /a{1,}b{1,}c/" "a{1,}b{1,}c" nil nil nil nil "aabbabc" nil 1 0 "abc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1171 ""abcabc" =~ /a.+?c/" "a.+?c" nil nil nil nil "abcabc" nil 1 0 "abc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1172 ""ab" =~ /(a+|b)*/" "(a+|b)*" nil nil nil nil "ab" nil 1 0 "ab" ("b" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1173 ""ab" =~ /(a+|b){0,}/" "(a+|b){0,}" nil nil nil nil "ab" nil 1 0 "ab" ("b" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1174 ""ab" =~ /(a+|b)+/" "(a+|b)+" nil nil nil nil "ab" nil 1 0 "ab" ("b" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1175 ""ab" =~ /(a+|b){1,}/" "(a+|b){1,}" nil nil nil nil "ab" nil 1 0 "ab" ("b" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1176 ""ab" =~ /(a+|b)?/" "(a+|b)?" nil nil nil nil "ab" nil 1 0 "a" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1177 ""ab" =~ /(a+|b){0,1}/" "(a+|b){0,1}" nil nil nil nil "ab" nil 1 0 "a" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1178 ""cde" =~ /[^ab]*/" "[^ab]*" nil nil nil nil "cde" nil 1 0 "cde" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1179 ""b" =~ /abc/" "abc" nil nil nil nil "b" nil 1 0 nil nil) +(1180 ""abbbcd" =~ +/([abc])*d/" "([abc])*d" nil nil nil nil "abbbcd" nil 1 0 "abbbcd" ("c" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1181 ""abcd" =~ /([abc])*bcd/" "([abc])*bcd" nil nil nil nil "abcd" nil 1 0 "abcd" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1182 ""e" =~ /a|b|c|d|e/" "a|b|c|d|e" nil nil nil nil "e" nil 1 0 "e" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1183 ""ef" =~ /(a|b|c|d|e)f/" "(a|b|c|d|e)f" nil nil nil nil "ef" nil 1 0 "ef" ("e" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1184 ""abcdefg" =~ /abcd*efg/" "abcd*efg" nil nil nil nil "abcdefg" nil 1 0 "abcdefg" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1185 ""xabyabbbz" =~ /ab*/" "ab*" nil nil nil nil "xabyabbbz" nil 1 0 "ab" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1186 ""xayabbbz" =~ /ab*/" "ab*" nil nil nil nil "xayabbbz" nil 1 0 "a" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1187 ""abcde" =~ /(ab|cd)e/" "(ab|cd)e" nil nil nil nil "abcde" nil 1 0 "cde" ("cd" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1188 ""hij" =~ /[abhgefdc]ij/" "[abhgefdc]ij" nil nil nil nil "hij" nil 1 0 "hij" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1189 ""abcdef" =~ /(abc|)ef/" "(abc|)ef" nil nil nil nil "abcdef" nil 1 0 "ef" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1190 ""abcd" =~ /(a|b)c*d/" "(a|b)c*d" nil nil nil nil "abcd" nil 1 0 "bcd" ("b" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1191 ""abc" =~ /(ab|ab*)bc/" "(ab|ab*)bc" nil nil nil nil "abc" nil 1 0 "abc" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1192 ""abc" =~ /a([bc]*)c*/" "a([bc]*)c*" nil nil nil nil "abc" nil 1 0 "abc" ("bc" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1193 ""abcd" =~ /a([bc]*)(c*d)/" "a([bc]*)(c*d)" nil nil nil nil "abcd" nil 1 0 "abcd" ("bc" "d" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1194 ""abcd" =~ /a([bc]+)(c*d)/" "a([bc]+)(c*d)" nil nil nil nil "abcd" nil 1 0 "abcd" ("bc" "d" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1195 ""abcd" =~ /a([bc]*)(c+d)/" "a([bc]*)(c+d)" nil nil nil nil "abcd" nil 1 0 "abcd" ("b" "cd" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1196 ""adcdcde" =~ /a[bcd]*dcdcde/" "a[bcd]*dcdcde" nil nil nil nil "adcdcde" nil 1 0 "adcdcde" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1197 ""abcde" =~ /a[bcd]+dcdcde/" "a[bcd]+dcdcde" nil nil nil nil "abcde" nil 1 0 nil nil) +(1198 ""adcdcde" =~ /a[bcd]+dcdcde/" "a[bcd]+dcdcde" nil nil nil nil "adcdcde" nil 1 0 nil nil) +(1199 ""abc" =~ /(ab|a)b*c/" "(ab|a)b*c" nil nil nil nil "abc" nil 1 0 "abc" ("ab" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1200 ""abcd" =~ /((a)(b)c)(d)/" "((a)(b)c)(d)" nil nil nil nil "abcd" nil 1 0 "abcd" ("abc" "a" "b" "d" nil nil nil nil nil nil nil nil nil nil nil nil)) +(1201 ""alpha" =~ /[a-zA-Z_][a-zA-Z0-9_]*/" "[a-zA-Z_][a-zA-Z0-9_]*" nil nil nil nil "alpha" nil 1 0 "alpha" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1202 ""abh" =~ /^a(bc+|b[eh])g|.h$/" "^a(bc+|b[eh])g|.h$" nil nil nil nil "abh" nil 1 0 "bh" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1203 ""effgz" =~ /(bc+d$|ef*g.|h?i(j|k))/" "(bc+d$|ef*g.|h?i(j|k))" nil nil nil nil "effgz" nil 1 0 "effgz" ("effgz" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1204 ""ij" =~ /(bc+d$|ef*g.|h?i(j|k))/" "(bc+d$|ef*g.|h?i(j|k))" nil nil nil nil "ij" nil 1 0 "ij" ("ij" "j" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1205 ""reffgz" =~ /(bc+d$|ef*g.|h?i(j|k))/" "(bc+d$|ef*g.|h?i(j|k))" nil nil nil nil "reffgz" nil 1 0 "effgz" ("effgz" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1206 ""effg" =~ /(bc+d$|ef*g.|h?i(j|k))/" "(bc+d$|ef*g.|h?i(j|k))" nil nil nil nil "effg" nil 1 0 nil nil) +(1207 ""bcdd" =~ /(bc+d$|ef*g.|h?i(j|k))/" "(bc+d$|ef*g.|h?i(j|k))" nil nil nil nil "bcdd" nil 1 0 nil nil) +(1208 ""a" =~ /((((((((((a))))))))))/" "((((((((((a))))))))))" nil nil nil nil "a" nil 1 0 "a" ("a" "a" "a" "a" "a" "a" "a" "a" "a" "a" nil nil nil nil nil nil)) +(1209 ""aa" =~ /((((((((((a))))))))))\10/" "((((((((((a))))))))))\10" nil nil nil nil "aa" nil 1 0 "aa" ("a" "a" "a" "a" "a" "a" "a" "a" "a" "a" nil nil nil nil nil nil)) +(1210 ""a" =~ /(((((((((a)))))))))/" "(((((((((a)))))))))" nil nil nil nil "a" nil 1 0 "a" ("a" "a" "a" "a" "a" "a" "a" "a" "a" nil nil nil nil nil nil nil)) +(1211 ""aa" =~ /multiple words of text/" "multiple words of text" nil nil nil nil "aa" nil 1 0 nil nil) +(1212 ""uh-uh" =~ /multiple words of text/" "multiple words of text" nil nil nil nil "uh-uh" nil 1 0 nil nil) +(1213 ""multiple words, yeah" =~ /multiple words/" "multiple words" nil nil nil nil "multiple words, yeah" nil 1 0 "multiple words" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1214 ""abcde" =~ /(.*)c(.*)/" "(.*)c(.*)" nil nil nil nil "abcde" nil 1 0 "abcde" ("ab" "de" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1215 ""(a, b)" =~ /\((.*), (.*)\)/" "\((.*), (.*)\)" nil nil nil nil "(a, b)" nil 1 0 "(a, b)" ("a" "b" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1216 ""abcd" =~ /abcd/" "abcd" nil nil nil nil "abcd" nil 1 0 "abcd" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1217 ""abcd" =~ /a(bc)d/" "a(bc)d" nil nil nil nil "abcd" nil 1 0 "abcd" ("bc" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1218 ""ac" =~ /a[-]?c/" "a[-]?c" nil nil nil nil "ac" nil 1 0 "ac" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1219 ""abcabc" =~ /(abc)\1/" "(abc)\1" nil nil nil nil "abcabc" nil 1 0 "abcabc" ("abc" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1220 ""abcabc" =~ /([a-c]*)\1/" "([a-c]*)\1" nil nil nil nil "abcabc" nil 1 0 "abcabc" ("abc" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1221 ""a" =~ /(a)|\1/" "(a)|\1" nil nil nil nil "a" nil 1 0 "a" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1222 ""ab" =~ /(a)|\1/" "(a)|\1" nil nil nil nil "ab" nil 1 0 "a" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1223 ""x" =~ /(a)|\1/" "(a)|\1" nil nil nil nil "x" nil 1 0 nil nil) +(1224 ""ababbbcbc" =~ /(([a-c])b*?\2)*/" "(([a-c])b*?\2)*" nil nil nil nil "ababbbcbc" nil 1 0 "ababb" ("bb" "b" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1225 ""ababbbcbc" =~ /(([a-c])b*?\2){3}/" "(([a-c])b*?\2){3}" nil nil nil nil "ababbbcbc" nil 1 0 "ababbbcbc" ("cbc" "c" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1226 ""aaaxabaxbaaxbbax" =~ /((\3|b)\2(a)x)+/" "((\3|b)\2(a)x)+" nil nil nil nil "aaaxabaxbaaxbbax" nil 1 0 "bbax" ("bbax" "b" "a" nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1227 ""bbaababbabaaaaabbaaaabba" =~ /((\3|b)\2(a)){2,}/" "((\3|b)\2(a)){2,}" nil nil nil nil "bbaababbabaaaaabbaaaabba" nil 1 0 "bbaaaabba" ("bba" "b" "a" nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1228 ""ABC" =~ /abc/i" "abc" t nil nil nil "ABC" nil 1 0 "ABC" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1229 ""XABCY" =~ /abc/i" "abc" t nil nil nil "XABCY" nil 1 0 "ABC" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1230 ""ABABC" =~ /abc/i" "abc" t nil nil nil "ABABC" nil 1 0 "ABC" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1231 ""aaxabxbaxbbx" =~ /abc/i" "abc" t nil nil nil "aaxabxbaxbbx" nil 1 0 nil nil) +(1232 ""XBC" =~ /abc/i" "abc" t nil nil nil "XBC" nil 1 0 nil nil) +(1233 ""AXC" =~ /abc/i" "abc" t nil nil nil "AXC" nil 1 0 nil nil) +(1234 ""ABX" =~ /abc/i" "abc" t nil nil nil "ABX" nil 1 0 nil nil) +(1235 ""ABC" =~ /ab*c/i" "ab*c" t nil nil nil "ABC" nil 1 0 "ABC" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1236 ""ABC" =~ /ab*bc/i" "ab*bc" t nil nil nil "ABC" nil 1 0 "ABC" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1237 ""ABBC" =~ /ab*bc/i" "ab*bc" t nil nil nil "ABBC" nil 1 0 "ABBC" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1238 ""ABBBBC" =~ /ab*?bc/i" "ab*?bc" t nil nil nil "ABBBBC" nil 1 0 "ABBBBC" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1239 ""ABBBBC" =~ /ab{0,}?bc/i" "ab{0,}?bc" t nil nil nil "ABBBBC" nil 1 0 "ABBBBC" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1240 ""ABBC" =~ /ab+?bc/i" "ab+?bc" t nil nil nil "ABBC" nil 1 0 "ABBC" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1241 ""ABC" =~ /ab+bc/i" "ab+bc" t nil nil nil "ABC" nil 1 0 nil nil) +(1242 ""ABQ" =~ /ab+bc/i" "ab+bc" t nil nil nil "ABQ" nil 1 0 nil nil) +(1243 ""ABBBBC" =~ /ab+bc/i" "ab+bc" t nil nil nil "ABBBBC" nil 1 0 "ABBBBC" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1244 ""ABBBBC" =~ /ab{1,}?bc/i" "ab{1,}?bc" t nil nil nil "ABBBBC" nil 1 0 "ABBBBC" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1245 ""ABBBBC" =~ /ab{1,3}?bc/i" "ab{1,3}?bc" t nil nil nil "ABBBBC" nil 1 0 "ABBBBC" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1246 ""ABBBBC" =~ /ab{3,4}?bc/i" "ab{3,4}?bc" t nil nil nil "ABBBBC" nil 1 0 "ABBBBC" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1247 ""ABQ" =~ /ab{4,5}?bc/i" "ab{4,5}?bc" t nil nil nil "ABQ" nil 1 0 nil nil) +(1248 ""ABBBBC" =~ /ab{4,5}?bc/i" "ab{4,5}?bc" t nil nil nil "ABBBBC" nil 1 0 nil nil) +(1249 ""ABBC" =~ /ab??bc/i" "ab??bc" t nil nil nil "ABBC" nil 1 0 "ABBC" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1250 ""ABC" =~ /ab??bc/i" "ab??bc" t nil nil nil "ABC" nil 1 0 "ABC" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1251 ""ABC" =~ /ab{0,1}?bc/i" "ab{0,1}?bc" t nil nil nil "ABC" nil 1 0 "ABC" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1252 ""ABC" =~ /ab??c/i" "ab??c" t nil nil nil "ABC" nil 1 0 "ABC" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1253 ""ABC" =~ /ab{0,1}?c/i" "ab{0,1}?c" t nil nil nil "ABC" nil 1 0 "ABC" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1254 ""ABC" =~ /^abc$/i" "^abc$" t nil nil nil "ABC" nil 1 0 "ABC" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1255 ""ABBBBC" =~ /^abc$/i" "^abc$" t nil nil nil "ABBBBC" nil 1 0 nil nil) +(1256 ""ABCC" =~ /^abc$/i" "^abc$" t nil nil nil "ABCC" nil 1 0 nil nil) +(1257 ""ABCC" =~ /^abc/i" "^abc" t nil nil nil "ABCC" nil 1 0 "ABC" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1258 ""AABC" =~ /abc$/i" "abc$" t nil nil nil "AABC" nil 1 0 "ABC" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1259 ""ABC" =~ /^/i" "^" t nil nil nil "ABC" nil 1 0 "" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1260 ""ABC" =~ /$/i" "$" t nil nil nil "ABC" nil 1 0 "" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1261 ""ABC" =~ /a.c/i" "a.c" t nil nil nil "ABC" nil 1 0 "ABC" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1262 ""AXC" =~ /a.c/i" "a.c" t nil nil nil "AXC" nil 1 0 "AXC" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1263 ""AXYZC" =~ /a.*?c/i" "a.*?c" t nil nil nil "AXYZC" nil 1 0 "AXYZC" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1264 ""AABC" =~ /a.*c/i" "a.*c" t nil nil nil "AABC" nil 1 0 "AABC" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1265 ""AXYZD" =~ /a.*c/i" "a.*c" t nil nil nil "AXYZD" nil 1 0 nil nil) +(1266 ""ABD" =~ /a[bc]d/i" "a[bc]d" t nil nil nil "ABD" nil 1 0 "ABD" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1267 ""ACE" =~ /a[b-d]e/i" "a[b-d]e" t nil nil nil "ACE" nil 1 0 "ACE" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1268 ""ABC" =~ /a[b-d]e/i" "a[b-d]e" t nil nil nil "ABC" nil 1 0 nil nil) +(1269 ""ABD" =~ /a[b-d]e/i" "a[b-d]e" t nil nil nil "ABD" nil 1 0 nil nil) +(1270 ""AAC" =~ /a[b-d]/i" "a[b-d]" t nil nil nil "AAC" nil 1 0 "AC" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1271 ""A-" =~ /a[-b]/i" "a[-b]" t nil nil nil "A-" nil 1 0 "A-" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1272 ""A-" =~ /a[b-]/i" "a[b-]" t nil nil nil "A-" nil 1 0 "A-" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1273 ""A]" =~ /a]/i" "a]" t nil nil nil "A]" nil 1 0 "A]" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1274 ""A]B" =~ /a[]]b/i" "a[]]b" t nil nil nil "A]B" nil 1 0 "A]B" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1275 ""AED" =~ /a[^bc]d/i" "a[^bc]d" t nil nil nil "AED" nil 1 0 "AED" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1276 ""ADC" =~ /a[^-b]c/i" "a[^-b]c" t nil nil nil "ADC" nil 1 0 "ADC" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1277 ""ABD" =~ /a[^-b]c/i" "a[^-b]c" t nil nil nil "ABD" nil 1 0 nil nil) +(1278 ""A-C" =~ /a[^-b]c/i" "a[^-b]c" t nil nil nil "A-C" nil 1 0 nil nil) +(1279 ""ADC" =~ /a[^]b]c/i" "a[^]b]c" t nil nil nil "ADC" nil 1 0 "ADC" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1280 ""ABC" =~ /ab|cd/i" "ab|cd" t nil nil nil "ABC" nil 1 0 "AB" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1281 ""ABCD" =~ /ab|cd/i" "ab|cd" t nil nil nil "ABCD" nil 1 0 "AB" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1282 ""DEF" =~ /()ef/i" "()ef" t nil nil nil "DEF" nil 1 0 "EF" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1283 ""A]C" =~ /$b/i" "$b" t nil nil nil "A]C" nil 1 0 nil nil) +(1284 ""B" =~ /$b/i" "$b" t nil nil nil "B" nil 1 0 nil nil) +(1285 ""A(B" =~ /a\(b/i" "a\(b" t nil nil nil "A(B" nil 1 0 "A(B" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1286 ""AB" =~ /a\(*b/i" "a\(*b" t nil nil nil "AB" nil 1 0 "AB" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1287 ""A((B" =~ /a\(*b/i" "a\(*b" t nil nil nil "A((B" nil 1 0 "A((B" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1288 ""A\B" =~ /a\\b/i" "a\\b" t nil nil nil "AB" nil 1 0 nil nil) +(1289 ""ABC" =~ /((a))/i" "((a))" t nil nil nil "ABC" nil 1 0 "A" ("A" "A" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1290 ""ABC" =~ /(a)b(c)/i" "(a)b(c)" t nil nil nil "ABC" nil 1 0 "ABC" ("A" "C" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1291 ""AABBABC" =~ /a+b+c/i" "a+b+c" t nil nil nil "AABBABC" nil 1 0 "ABC" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1292 ""AABBABC" =~ /a{1,}b{1,}c/i" "a{1,}b{1,}c" t nil nil nil "AABBABC" nil 1 0 "ABC" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1293 ""ABCABC" =~ /a.+?c/i" "a.+?c" t nil nil nil "ABCABC" nil 1 0 "ABC" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1294 ""ABCABC" =~ /a.*?c/i" "a.*?c" t nil nil nil "ABCABC" nil 1 0 "ABC" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1295 ""ABCABC" =~ /a.{0,5}?c/i" "a.{0,5}?c" t nil nil nil "ABCABC" nil 1 0 "ABC" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1296 ""AB" =~ /(a+|b)*/i" "(a+|b)*" t nil nil nil "AB" nil 1 0 "AB" ("B" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1297 ""AB" =~ /(a+|b){0,}/i" "(a+|b){0,}" t nil nil nil "AB" nil 1 0 "AB" ("B" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1298 ""AB" =~ /(a+|b)+/i" "(a+|b)+" t nil nil nil "AB" nil 1 0 "AB" ("B" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1299 ""AB" =~ /(a+|b){1,}/i" "(a+|b){1,}" t nil nil nil "AB" nil 1 0 "AB" ("B" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1300 ""AB" =~ /(a+|b)?/i" "(a+|b)?" t nil nil nil "AB" nil 1 0 "A" ("A" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1301 ""AB" =~ /(a+|b){0,1}/i" "(a+|b){0,1}" t nil nil nil "AB" nil 1 0 "A" ("A" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1302 ""AB" =~ /(a+|b){0,1}?/i" "(a+|b){0,1}?" t nil nil nil "AB" nil 1 0 "" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1303 ""CDE" =~ /[^ab]*/i" "[^ab]*" t nil nil nil "CDE" nil 1 0 "CDE" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1304 ""ABBBCD" =~ +/([abc])*d/i" "([abc])*d" t nil nil nil "ABBBCD" nil 1 0 "ABBBCD" ("C" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1305 ""ABCD" =~ /([abc])*bcd/i" "([abc])*bcd" t nil nil nil "ABCD" nil 1 0 "ABCD" ("A" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1306 ""E" =~ /a|b|c|d|e/i" "a|b|c|d|e" t nil nil nil "E" nil 1 0 "E" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1307 ""EF" =~ /(a|b|c|d|e)f/i" "(a|b|c|d|e)f" t nil nil nil "EF" nil 1 0 "EF" ("E" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1308 ""ABCDEFG" =~ /abcd*efg/i" "abcd*efg" t nil nil nil "ABCDEFG" nil 1 0 "ABCDEFG" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1309 ""XABYABBBZ" =~ /ab*/i" "ab*" t nil nil nil "XABYABBBZ" nil 1 0 "AB" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1310 ""XAYABBBZ" =~ /ab*/i" "ab*" t nil nil nil "XAYABBBZ" nil 1 0 "A" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1311 ""ABCDE" =~ /(ab|cd)e/i" "(ab|cd)e" t nil nil nil "ABCDE" nil 1 0 "CDE" ("CD" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1312 ""HIJ" =~ /[abhgefdc]ij/i" "[abhgefdc]ij" t nil nil nil "HIJ" nil 1 0 "HIJ" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1313 ""ABCDE" =~ /^(ab|cd)e/i" "^(ab|cd)e" t nil nil nil "ABCDE" nil 1 0 nil nil) +(1314 ""ABCDEF" =~ /(abc|)ef/i" "(abc|)ef" t nil nil nil "ABCDEF" nil 1 0 "EF" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1315 ""ABCD" =~ /(a|b)c*d/i" "(a|b)c*d" t nil nil nil "ABCD" nil 1 0 "BCD" ("B" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1316 ""ABC" =~ /(ab|ab*)bc/i" "(ab|ab*)bc" t nil nil nil "ABC" nil 1 0 "ABC" ("A" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1317 ""ABC" =~ /a([bc]*)c*/i" "a([bc]*)c*" t nil nil nil "ABC" nil 1 0 "ABC" ("BC" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1318 ""ABCD" =~ /a([bc]*)(c*d)/i" "a([bc]*)(c*d)" t nil nil nil "ABCD" nil 1 0 "ABCD" ("BC" "D" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1319 ""ABCD" =~ /a([bc]+)(c*d)/i" "a([bc]+)(c*d)" t nil nil nil "ABCD" nil 1 0 "ABCD" ("BC" "D" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1320 ""ABCD" =~ /a([bc]*)(c+d)/i" "a([bc]*)(c+d)" t nil nil nil "ABCD" nil 1 0 "ABCD" ("B" "CD" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1321 ""ADCDCDE" =~ /a[bcd]*dcdcde/i" "a[bcd]*dcdcde" t nil nil nil "ADCDCDE" nil 1 0 "ADCDCDE" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1322 ""ABC" =~ /(ab|a)b*c/i" "(ab|a)b*c" t nil nil nil "ABC" nil 1 0 "ABC" ("AB" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1323 ""ABCD" =~ /((a)(b)c)(d)/i" "((a)(b)c)(d)" t nil nil nil "ABCD" nil 1 0 "ABCD" ("ABC" "A" "B" "D" nil nil nil nil nil nil nil nil nil nil nil nil)) +(1324 ""ALPHA" =~ /[a-zA-Z_][a-zA-Z0-9_]*/i" "[a-zA-Z_][a-zA-Z0-9_]*" t nil nil nil "ALPHA" nil 1 0 "ALPHA" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1325 ""ABH" =~ /^a(bc+|b[eh])g|.h$/i" "^a(bc+|b[eh])g|.h$" t nil nil nil "ABH" nil 1 0 "BH" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1326 ""EFFGZ" =~ /(bc+d$|ef*g.|h?i(j|k))/i" "(bc+d$|ef*g.|h?i(j|k))" t nil nil nil "EFFGZ" nil 1 0 "EFFGZ" ("EFFGZ" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1327 ""IJ" =~ /(bc+d$|ef*g.|h?i(j|k))/i" "(bc+d$|ef*g.|h?i(j|k))" t nil nil nil "IJ" nil 1 0 "IJ" ("IJ" "J" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1328 ""REFFGZ" =~ /(bc+d$|ef*g.|h?i(j|k))/i" "(bc+d$|ef*g.|h?i(j|k))" t nil nil nil "REFFGZ" nil 1 0 "EFFGZ" ("EFFGZ" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1329 ""ADCDCDE" =~ /(bc+d$|ef*g.|h?i(j|k))/i" "(bc+d$|ef*g.|h?i(j|k))" t nil nil nil "ADCDCDE" nil 1 0 nil nil) +(1330 ""EFFG" =~ /(bc+d$|ef*g.|h?i(j|k))/i" "(bc+d$|ef*g.|h?i(j|k))" t nil nil nil "EFFG" nil 1 0 nil nil) +(1331 ""BCDD" =~ /(bc+d$|ef*g.|h?i(j|k))/i" "(bc+d$|ef*g.|h?i(j|k))" t nil nil nil "BCDD" nil 1 0 nil nil) +(1332 ""A" =~ /((((((((((a))))))))))/i" "((((((((((a))))))))))" t nil nil nil "A" nil 1 0 "A" ("A" "A" "A" "A" "A" "A" "A" "A" "A" "A" nil nil nil nil nil nil)) +(1333 ""AA" =~ /((((((((((a))))))))))\10/i" "((((((((((a))))))))))\10" t nil nil nil "AA" nil 1 0 "AA" ("A" "A" "A" "A" "A" "A" "A" "A" "A" "A" nil nil nil nil nil nil)) +(1334 ""A" =~ /(((((((((a)))))))))/i" "(((((((((a)))))))))" t nil nil nil "A" nil 1 0 "A" ("A" "A" "A" "A" "A" "A" "A" "A" "A" nil nil nil nil nil nil nil)) +(1335 ""A" =~ /(?:(?:(?:(?:(?:(?:(?:(?:(?:(a))))))))))/i" "(?:(?:(?:(?:(?:(?:(?:(?:(?:(a))))))))))" t nil nil nil "A" nil 1 0 "A" ("A" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1336 ""C" =~ /(?:(?:(?:(?:(?:(?:(?:(?:(?:(a|b|c))))))))))/i" "(?:(?:(?:(?:(?:(?:(?:(?:(?:(a|b|c))))))))))" t nil nil nil "C" nil 1 0 "C" ("C" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1337 ""AA" =~ /multiple words of text/i" "multiple words of text" t nil nil nil "AA" nil 1 0 nil nil) +(1338 ""UH-UH" =~ /multiple words of text/i" "multiple words of text" t nil nil nil "UH-UH" nil 1 0 nil nil) +(1339 ""MULTIPLE WORDS, YEAH" =~ /multiple words/i" "multiple words" t nil nil nil "MULTIPLE WORDS, YEAH" nil 1 0 "MULTIPLE WORDS" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1340 ""ABCDE" =~ /(.*)c(.*)/i" "(.*)c(.*)" t nil nil nil "ABCDE" nil 1 0 "ABCDE" ("AB" "DE" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1341 ""(A, B)" =~ /\((.*), (.*)\)/i" "\((.*), (.*)\)" t nil nil nil "(A, B)" nil 1 0 "(A, B)" ("A" "B" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1342 ""ABCD" =~ /abcd/i" "abcd" t nil nil nil "ABCD" nil 1 0 "ABCD" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1343 ""ABCD" =~ /a(bc)d/i" "a(bc)d" t nil nil nil "ABCD" nil 1 0 "ABCD" ("BC" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1344 ""AC" =~ /a[-]?c/i" "a[-]?c" t nil nil nil "AC" nil 1 0 "AC" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1345 ""ABCABC" =~ /(abc)\1/i" "(abc)\1" t nil nil nil "ABCABC" nil 1 0 "ABCABC" ("ABC" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1346 ""ABCABC" =~ /([a-c]*)\1/i" "([a-c]*)\1" t nil nil nil "ABCABC" nil 1 0 "ABCABC" ("ABC" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1347 ""abad" =~ /a(?!b)./" "a(?!b)." nil nil nil nil "abad" nil 1 0 "ad" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1348 ""abad" =~ /a(?=d)./" "a(?=d)." nil nil nil nil "abad" nil 1 0 "ad" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1349 ""abad" =~ /a(?=c|d)./" "a(?=c|d)." nil nil nil nil "abad" nil 1 0 "ad" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1350 ""ace" =~ /a(?:b|c|d)(.)/" "a(?:b|c|d)(.)" nil nil nil nil "ace" nil 1 0 "ace" ("e" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1351 ""ace" =~ /a(?:b|c|d)*(.)/" "a(?:b|c|d)*(.)" nil nil nil nil "ace" nil 1 0 "ace" ("e" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1352 ""ace" =~ /a(?:b|c|d)+?(.)/" "a(?:b|c|d)+?(.)" nil nil nil nil "ace" nil 1 0 "ace" ("e" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1353 ""acdbcdbe" =~ /a(?:b|c|d)+?(.)/" "a(?:b|c|d)+?(.)" nil nil nil nil "acdbcdbe" nil 1 0 "acd" ("d" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1354 ""acdbcdbe" =~ /a(?:b|c|d)+(.)/" "a(?:b|c|d)+(.)" nil nil nil nil "acdbcdbe" nil 1 0 "acdbcdbe" ("e" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1355 ""acdbcdbe" =~ /a(?:b|c|d){2}(.)/" "a(?:b|c|d){2}(.)" nil nil nil nil "acdbcdbe" nil 1 0 "acdb" ("b" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1356 ""acdbcdbe" =~ /a(?:b|c|d){4,5}(.)/" "a(?:b|c|d){4,5}(.)" nil nil nil nil "acdbcdbe" nil 1 0 "acdbcdb" ("b" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1357 ""acdbcdbe" =~ /a(?:b|c|d){4,5}?(.)/" "a(?:b|c|d){4,5}?(.)" nil nil nil nil "acdbcdbe" nil 1 0 "acdbcd" ("d" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1358 ""foobar" =~ /((foo)|(bar))*/" "((foo)|(bar))*" nil nil nil nil "foobar" nil 1 0 "foobar" ("bar" "foo" "bar" nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1359 ""acdbcdbe" =~ /a(?:b|c|d){6,7}(.)/" "a(?:b|c|d){6,7}(.)" nil nil nil nil "acdbcdbe" nil 1 0 "acdbcdbe" ("e" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1360 ""acdbcdbe" =~ /a(?:b|c|d){6,7}?(.)/" "a(?:b|c|d){6,7}?(.)" nil nil nil nil "acdbcdbe" nil 1 0 "acdbcdbe" ("e" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1361 ""acdbcdbe" =~ /a(?:b|c|d){5,6}(.)/" "a(?:b|c|d){5,6}(.)" nil nil nil nil "acdbcdbe" nil 1 0 "acdbcdbe" ("e" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1362 ""acdbcdbe" =~ /a(?:b|c|d){5,6}?(.)/" "a(?:b|c|d){5,6}?(.)" nil nil nil nil "acdbcdbe" nil 1 0 "acdbcdb" ("b" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1363 ""acdbcdbe" =~ /a(?:b|c|d){5,7}(.)/" "a(?:b|c|d){5,7}(.)" nil nil nil nil "acdbcdbe" nil 1 0 "acdbcdbe" ("e" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1364 ""acdbcdbe" =~ /a(?:b|c|d){5,7}?(.)/" "a(?:b|c|d){5,7}?(.)" nil nil nil nil "acdbcdbe" nil 1 0 "acdbcdb" ("b" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1365 ""ace" =~ /a(?:b|(c|e){1,2}?|d)+?(.)/" "a(?:b|(c|e){1,2}?|d)+?(.)" nil nil nil nil "ace" nil 1 0 "ace" ("c" "e" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1366 ""AB" =~ /^(.+)?B/" "^(.+)?B" nil nil nil nil "AB" nil 1 0 "AB" ("A" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1367 ""." =~ /^([^a-z])|(\^)$/" "^([^a-z])|(\^)$" nil nil nil nil "." nil 1 0 "." ("." nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1368 ""<&OUT" =~ /^[<>]&/" "^[<>]&" nil nil nil nil "<&OUT" nil 1 0 "<&" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1369 ""aaaaaaaaaa" =~ /^(a\1?){4}$/" "^(a\1?){4}$" nil nil nil nil "aaaaaaaaaa" nil 1 0 "aaaaaaaaaa" ("aaaa" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1370 ""AB" =~ /^(a\1?){4}$/" "^(a\1?){4}$" nil nil nil nil "AB" nil 1 0 nil nil) +(1371 ""aaaaaaaaa" =~ /^(a\1?){4}$/" "^(a\1?){4}$" nil nil nil nil "aaaaaaaaa" nil 1 0 nil nil) +(1372 ""aaaaaaaaaaa" =~ /^(a\1?){4}$/" "^(a\1?){4}$" nil nil nil nil "aaaaaaaaaaa" nil 1 0 nil nil) +(1373 ""aaaaaaaaaa" =~ /^(a(?(1)\1)){4}$/" "^(a(?(1)\1)){4}$" nil nil nil nil "aaaaaaaaaa" nil 1 0 "aaaaaaaaaa" ("aaaa" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1374 ""aaaaaaaaa" =~ /^(a(?(1)\1)){4}$/" "^(a(?(1)\1)){4}$" nil nil nil nil "aaaaaaaaa" nil 1 0 nil nil) +(1375 ""aaaaaaaaaaa" =~ /^(a(?(1)\1)){4}$/" "^(a(?(1)\1)){4}$" nil nil nil nil "aaaaaaaaaaa" nil 1 0 nil nil) +(1376 ""foobar" =~ /(?:(f)(o)(o)|(b)(a)(r))*/" "(?:(f)(o)(o)|(b)(a)(r))*" nil nil nil nil "foobar" nil 1 0 "foobar" ("f" "o" "o" "b" "a" "r" nil nil nil nil nil nil nil nil nil nil)) +(1377 ""ab" =~ /(?<=a)b/" "(?<=a)b" nil nil nil nil "ab" nil 1 0 "b" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1378 ""cb" =~ /(?<=a)b/" "(?<=a)b" nil nil nil nil "cb" nil 1 0 nil nil) +(1379 ""b" =~ /(?<=a)b/" "(?<=a)b" nil nil nil nil "b" nil 1 0 nil nil) +(1380 ""ab" =~ /(?<!c)b/" "(?<!c)b" nil nil nil nil "ab" nil 1 0 "b" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1381 ""b" =~ /(?<!c)b/" "(?<!c)b" nil nil nil nil "b" nil 1 0 "b" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1382 ""b" =~ /(?<!c)b/" "(?<!c)b" nil nil nil nil "b" nil 1 0 "b" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1383 ""aba" =~ /(?:..)*a/" "(?:..)*a" nil nil nil nil "aba" nil 1 0 "aba" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1384 ""aba" =~ /(?:..)*?a/" "(?:..)*?a" nil nil nil nil "aba" nil 1 0 "a" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1385 ""abc" =~ /^(?:b|a(?=(.)))*\1/" "^(?:b|a(?=(.)))*\1" nil nil nil nil "abc" nil 1 0 "ab" ("b" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1386 ""abc" =~ /^(){3,5}/" "^(){3,5}" nil nil nil nil "abc" nil 1 0 "" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1387 ""aax" =~ /^(a+)*ax/" "^(a+)*ax" nil nil nil nil "aax" nil 1 0 "aax" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1388 ""aax" =~ /^((a|b)+)*ax/" "^((a|b)+)*ax" nil nil nil nil "aax" nil 1 0 "aax" ("a" "a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1389 ""aax" =~ /^((a|bc)+)*ax/" "^((a|bc)+)*ax" nil nil nil nil "aax" nil 1 0 "aax" ("a" "a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1390 ""cab" =~ /(a|x)*ab/" "(a|x)*ab" nil nil nil nil "cab" nil 1 0 "ab" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1391 ""cab" =~ /(a)*ab/" "(a)*ab" nil nil nil nil "cab" nil 1 0 "ab" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1392 ""ab" =~ /(?:(?i)a)b/" "(?:(?i)a)b" nil nil nil nil "ab" nil 1 0 "ab" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1393 ""ab" =~ /((?i)a)b/" "((?i)a)b" nil nil nil nil "ab" nil 1 0 "ab" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1394 ""Ab" =~ /(?:(?i)a)b/" "(?:(?i)a)b" nil nil nil nil "Ab" nil 1 0 "Ab" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1395 ""Ab" =~ /((?i)a)b/" "((?i)a)b" nil nil nil nil "Ab" nil 1 0 "Ab" ("A" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1396 ""cb" =~ /(?:(?i)a)b/" "(?:(?i)a)b" nil nil nil nil "cb" nil 1 0 nil nil) +(1397 ""aB" =~ /(?:(?i)a)b/" "(?:(?i)a)b" nil nil nil nil "aB" nil 1 0 nil nil) +(1398 ""ab" =~ /(?i:a)b/" "(?i:a)b" nil nil nil nil "ab" nil 1 0 "ab" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1399 ""ab" =~ /((?i:a))b/" "((?i:a))b" nil nil nil nil "ab" nil 1 0 "ab" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1400 ""Ab" =~ /(?i:a)b/" "(?i:a)b" nil nil nil nil "Ab" nil 1 0 "Ab" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1401 ""Ab" =~ /((?i:a))b/" "((?i:a))b" nil nil nil nil "Ab" nil 1 0 "Ab" ("A" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1402 ""aB" =~ /(?i:a)b/" "(?i:a)b" nil nil nil nil "aB" nil 1 0 nil nil) +(1403 ""aB" =~ /(?i:a)b/" "(?i:a)b" nil nil nil nil "aB" nil 1 0 nil nil) +(1404 ""ab" =~ /(?:(?-i)a)b/i" "(?:(?-i)a)b" t nil nil nil "ab" nil 1 0 "ab" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1405 ""ab" =~ /((?-i)a)b/i" "((?-i)a)b" t nil nil nil "ab" nil 1 0 "ab" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1406 ""aB" =~ /(?:(?-i)a)b/i" "(?:(?-i)a)b" t nil nil nil "aB" nil 1 0 "aB" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1407 ""aB" =~ /((?-i)a)b/i" "((?-i)a)b" t nil nil nil "aB" nil 1 0 "aB" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1408 ""aB" =~ /(?:(?-i)a)b/i" "(?:(?-i)a)b" t nil nil nil "aB" nil 1 0 "aB" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1409 ""Ab" =~ /(?:(?-i)a)b/i" "(?:(?-i)a)b" t nil nil nil "Ab" nil 1 0 nil nil) +(1410 ""aB" =~ /(?:(?-i)a)b/i" "(?:(?-i)a)b" t nil nil nil "aB" nil 1 0 "aB" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1411 ""aB" =~ /((?-i)a)b/i" "((?-i)a)b" t nil nil nil "aB" nil 1 0 "aB" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1412 ""Ab" =~ /(?:(?-i)a)b/i" "(?:(?-i)a)b" t nil nil nil "Ab" nil 1 0 nil nil) +(1413 ""AB" =~ /(?:(?-i)a)b/i" "(?:(?-i)a)b" t nil nil nil "AB" nil 1 0 nil nil) +(1414 ""ab" =~ /(?-i:a)b/i" "(?-i:a)b" t nil nil nil "ab" nil 1 0 "ab" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1415 ""ab" =~ /((?-i:a))b/i" "((?-i:a))b" t nil nil nil "ab" nil 1 0 "ab" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1416 ""aB" =~ /(?-i:a)b/i" "(?-i:a)b" t nil nil nil "aB" nil 1 0 "aB" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1417 ""aB" =~ /((?-i:a))b/i" "((?-i:a))b" t nil nil nil "aB" nil 1 0 "aB" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1418 ""AB" =~ /(?-i:a)b/i" "(?-i:a)b" t nil nil nil "AB" nil 1 0 nil nil) +(1419 ""Ab" =~ /(?-i:a)b/i" "(?-i:a)b" t nil nil nil "Ab" nil 1 0 nil nil) +(1420 ""aB" =~ /(?-i:a)b/i" "(?-i:a)b" t nil nil nil "aB" nil 1 0 "aB" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1421 ""aB" =~ /((?-i:a))b/i" "((?-i:a))b" t nil nil nil "aB" nil 1 0 "aB" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1422 ""Ab" =~ /(?-i:a)b/i" "(?-i:a)b" t nil nil nil "Ab" nil 1 0 nil nil) +(1423 ""AB" =~ /(?-i:a)b/i" "(?-i:a)b" t nil nil nil "AB" nil 1 0 nil nil) +(1424 ""AB" =~ /((?-i:a.))b/i" "((?-i:a.))b" t nil nil nil "AB" nil 1 0 nil nil) +(1425 ""a\nB" =~ /((?-i:a.))b/i" "((?-i:a.))b" t nil nil nil "a +B" nil 1 0 nil nil) +(1426 ""a\nB" =~ /((?s-i:a.))b/i" "((?s-i:a.))b" t nil nil nil "a +B" nil 1 0 "a +B" ("a +" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1427 ""cabbbb" =~ /(?:c|d)(?:)(?:a(?:)(?:b)(?:b(?:))(?:b(?:)(?:b)))/" "(?:c|d)(?:)(?:a(?:)(?:b)(?:b(?:))(?:b(?:)(?:b)))" nil nil nil nil "cabbbb" nil 1 0 "cabbbb" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1428 ""caaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" =~ /(?:c|d)(?:)(?:aaaaaaaa(?:)(?:bbbbbbbb)(?:bbbbbbbb(?:))(?:bbbbbbbb(?:)(?:bbbbbbbb)))/" "(?:c|d)(?:)(?:aaaaaaaa(?:)(?:bbbbbbbb)(?:bbbbbbbb(?:))(?:bbbbbbbb(?:)(?:bbbbbbbb)))" nil nil nil nil "caaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" nil 1 0 "caaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1429 ""Ab4ab" =~ /(ab)\d\1/i" "(ab)\d\1" t nil nil nil "Ab4ab" nil 1 0 "Ab4ab" ("Ab" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1430 ""ab4Ab" =~ /(ab)\d\1/i" "(ab)\d\1" t nil nil nil "ab4Ab" nil 1 0 "ab4Ab" ("ab" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1431 ""foobar1234baz" =~ /foo\w*\d{4}baz/" "foo\w*\d{4}baz" nil nil nil nil "foobar1234baz" nil 1 0 "foobar1234baz" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1432 ""x~~" =~ /x(~~)*(?:(?:F)?)?/" "x(~~)*(?:(?:F)?)?" nil nil nil nil "x~~" nil 1 0 "x~~" ("~~" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1433 ""aaac" =~ /^a(?#xxx){3}c/" "^a(?#xxx){3}c" nil nil nil nil "aaac" nil 1 0 "aaac" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1434 ""aaac" =~ /^a(?#xxx)(?#xxx){3}c/" "^a(?#xxx)(?#xxx){3}c" nil nil nil nil "aaac" nil 1 0 "aaac" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1435 ""aaac" =~ /^a (?#xxx) (?#yyy) {3}c/x" "^a (?#xxx) (?#yyy) {3}c" nil nil nil t "aaac" nil 1 0 "aaac" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1436 ""B\nB" =~ /(?<![cd])b/" "(?<![cd])b" nil nil nil nil "B +B" nil 1 0 nil nil) +(1437 ""dbcb" =~ /(?<![cd])b/" "(?<![cd])b" nil nil nil nil "dbcb" nil 1 0 nil nil) +(1438 ""dbaacb" =~ /(?<![cd])[ab]/" "(?<![cd])[ab]" nil nil nil nil "dbaacb" nil 1 0 "a" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1439 ""dbaacb" =~ /(?<!(c|d))[ab]/" "(?<!(c|d))[ab]" nil nil nil nil "dbaacb" nil 1 0 "a" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1440 ""cdaccb" =~ /(?<!cd)[ab]/" "(?<!cd)[ab]" nil nil nil nil "cdaccb" nil 1 0 "b" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1441 ""dbcb" =~ /^(?:a?b?)*$/" "^(?:a?b?)*$" nil nil nil nil "dbcb" nil 1 0 nil nil) +(1442 ""a--" =~ /^(?:a?b?)*$/" "^(?:a?b?)*$" nil nil nil nil "a--" nil 1 0 nil nil) +(1443 ""a\nb\nc\n" =~ /((?s)^a(.))((?m)^b$)/" "((?s)^a(.))((?m)^b$)" nil nil nil nil "a +b +c +" nil 1 0 "a +b" ("a +" " +" "b" nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1444 ""a\nb\nc\n" =~ /((?m)^b$)/" "((?m)^b$)" nil nil nil nil "a +b +c +" nil 1 0 "b" ("b" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1445 ""a\nb\n" =~ /(?m)^b/" "(?m)^b" nil nil nil nil "a +b +" nil 1 0 "b" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1446 ""a\nb\n" =~ /(?m)^(b)/" "(?m)^(b)" nil nil nil nil "a +b +" nil 1 0 "b" ("b" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1447 ""a\nb\n" =~ /((?m)^b)/" "((?m)^b)" nil nil nil nil "a +b +" nil 1 0 "b" ("b" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1448 ""a\nb\n" =~ /\n((?m)^b)/" "\n((?m)^b)" nil nil nil nil "a +b +" nil 1 0 " +b" ("b" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1449 ""a\nb\nc\n" =~ /((?s).)c(?!.)/" "((?s).)c(?!.)" nil nil nil nil "a +b +c +" nil 1 0 " +c" (" +" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1450 ""a\nb\nc\n" =~ /((?s).)c(?!.)/" "((?s).)c(?!.)" nil nil nil nil "a +b +c +" nil 1 0 " +c" (" +" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1451 ""a\nb\nc\n" =~ /((?s)b.)c(?!.)/" "((?s)b.)c(?!.)" nil nil nil nil "a +b +c +" nil 1 0 "b +c" ("b +" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1452 ""a\nb\nc\n" =~ /((?s)b.)c(?!.)/" "((?s)b.)c(?!.)" nil nil nil nil "a +b +c +" nil 1 0 "b +c" ("b +" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1453 ""a\nb\nc\n" =~ /()^b/" "()^b" nil nil nil nil "a +b +c +" nil 1 0 nil nil) +(1454 ""a\nb\nc\n" =~ /()^b/" "()^b" nil nil nil nil "a +b +c +" nil 1 0 nil nil) +(1455 ""a\nb\nc\n" =~ /((?m)^b)/" "((?m)^b)" nil nil nil nil "a +b +c +" nil 1 0 "b" ("b" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1456 ""a" =~ /(?(1)b|a)/" "(?(1)b|a)" nil nil nil nil "a" nil 1 0 "a" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1457 ""a" =~ /(x)?(?(1)a|b)/" "(x)?(?(1)a|b)" nil nil nil nil "a" nil 1 0 nil nil) +(1458 ""a" =~ /(x)?(?(1)a|b)/" "(x)?(?(1)a|b)" nil nil nil nil "a" nil 1 0 nil nil) +(1459 ""a" =~ /(x)?(?(1)b|a)/" "(x)?(?(1)b|a)" nil nil nil nil "a" nil 1 0 "a" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1460 ""a" =~ /()?(?(1)b|a)/" "()?(?(1)b|a)" nil nil nil nil "a" nil 1 0 "a" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1461 ""a" =~ /()?(?(1)a|b)/" "()?(?(1)a|b)" nil nil nil nil "a" nil 1 0 "a" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1462 ""(blah)" =~ /^(\()?blah(?(1)(\)))$/" "^(\()?blah(?(1)(\)))$" nil nil nil nil "(blah)" nil 1 0 "(blah)" ("(" ")" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1463 ""blah" =~ /^(\()?blah(?(1)(\)))$/" "^(\()?blah(?(1)(\)))$" nil nil nil nil "blah" nil 1 0 "blah" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1464 ""a" =~ /^(\()?blah(?(1)(\)))$/" "^(\()?blah(?(1)(\)))$" nil nil nil nil "a" nil 1 0 nil nil) +(1465 ""blah)" =~ /^(\()?blah(?(1)(\)))$/" "^(\()?blah(?(1)(\)))$" nil nil nil nil "blah)" nil 1 0 nil nil) +(1466 ""(blah" =~ /^(\()?blah(?(1)(\)))$/" "^(\()?blah(?(1)(\)))$" nil nil nil nil "(blah" nil 1 0 nil nil) +(1467 ""(blah)" =~ /^(\(+)?blah(?(1)(\)))$/" "^(\(+)?blah(?(1)(\)))$" nil nil nil nil "(blah)" nil 1 0 "(blah)" ("(" ")" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1468 ""blah" =~ /^(\(+)?blah(?(1)(\)))$/" "^(\(+)?blah(?(1)(\)))$" nil nil nil nil "blah" nil 1 0 "blah" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1469 ""blah)" =~ /^(\(+)?blah(?(1)(\)))$/" "^(\(+)?blah(?(1)(\)))$" nil nil nil nil "blah)" nil 1 0 nil nil) +(1470 ""(blah" =~ /^(\(+)?blah(?(1)(\)))$/" "^(\(+)?blah(?(1)(\)))$" nil nil nil nil "(blah" nil 1 0 nil nil) +(1471 ""a" =~ /(?(?!a)b|a)/" "(?(?!a)b|a)" nil nil nil nil "a" nil 1 0 "a" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1472 ""a" =~ /(?(?=a)b|a)/" "(?(?=a)b|a)" nil nil nil nil "a" nil 1 0 nil nil) +(1473 ""a" =~ /(?(?=a)b|a)/" "(?(?=a)b|a)" nil nil nil nil "a" nil 1 0 nil nil) +(1474 ""a" =~ /(?(?=a)a|b)/" "(?(?=a)a|b)" nil nil nil nil "a" nil 1 0 "a" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1475 ""aaab" =~ /(?=(a+?))(\1ab)/" "(?=(a+?))(\1ab)" nil nil nil nil "aaab" nil 1 0 "aab" ("a" "aab" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1476 ""one:" =~ /(\w+:)+/" "(\w+:)+" nil nil nil nil "one:" nil 1 0 "one:" ("one:" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1477 ""a" =~ /$(?<=^(a))/" "$(?<=^(a))" nil nil nil nil "a" nil 1 0 "" ("a" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1478 ""aaab" =~ /(?=(a+?))(\1ab)/" "(?=(a+?))(\1ab)" nil nil nil nil "aaab" nil 1 0 "aab" ("a" "aab" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1479 ""aaab" =~ /^(?=(a+?))\1ab/" "^(?=(a+?))\1ab" nil nil nil nil "aaab" nil 1 0 nil nil) +(1480 ""aaab" =~ /^(?=(a+?))\1ab/" "^(?=(a+?))\1ab" nil nil nil nil "aaab" nil 1 0 nil nil) +(1481 ""abcd" =~ /([\w:]+::)?(\w+)$/" "([\w:]+::)?(\w+)$" nil nil nil nil "abcd" nil 1 0 "abcd" (nil "abcd" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1482 ""xy:z:::abcd" =~ /([\w:]+::)?(\w+)$/" "([\w:]+::)?(\w+)$" nil nil nil nil "xy:z:::abcd" nil 1 0 "xy:z:::abcd" ("xy:z:::" "abcd" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1483 ""aexycd" =~ /^[^bcd]*(c+)/" "^[^bcd]*(c+)" nil nil nil nil "aexycd" nil 1 0 "aexyc" ("c" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1484 ""caab" =~ /(a*)b+/" "(a*)b+" nil nil nil nil "caab" nil 1 0 "aab" ("aa" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1485 ""abcd" =~ /([\w:]+::)?(\w+)$/" "([\w:]+::)?(\w+)$" nil nil nil nil "abcd" nil 1 0 "abcd" (nil "abcd" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1486 ""xy:z:::abcd" =~ /([\w:]+::)?(\w+)$/" "([\w:]+::)?(\w+)$" nil nil nil nil "xy:z:::abcd" nil 1 0 "xy:z:::abcd" ("xy:z:::" "abcd" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1487 ""abcd:" =~ /([\w:]+::)?(\w+)$/" "([\w:]+::)?(\w+)$" nil nil nil nil "abcd:" nil 1 0 nil nil) +(1488 ""abcd:" =~ /([\w:]+::)?(\w+)$/" "([\w:]+::)?(\w+)$" nil nil nil nil "abcd:" nil 1 0 nil nil) +(1489 ""aexycd" =~ /^[^bcd]*(c+)/" "^[^bcd]*(c+)" nil nil nil nil "aexycd" nil 1 0 "aexyc" ("c" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1490 ""aaab" =~ /(?>a+)b/" "(?>a+)b" nil nil nil nil "aaab" nil 1 0 "aaab" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1491 ""a:[b]:" =~ /([[:]+)/" "([[:]+)" nil nil nil nil "a:[b]:" nil 1 0 ":[" (":[" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1492 ""a=[b]=" =~ /([[=]+)/" "([[=]+)" nil nil nil nil "a=[b]=" nil 1 0 "=[" ("=[" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1493 ""a.[b]." =~ /([[.]+)/" "([[.]+)" nil nil nil nil "a.[b]." nil 1 0 ".[" (".[" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1494 ""aaab" =~ /((?>a+)b)/" "((?>a+)b)" nil nil nil nil "aaab" nil 1 0 "aaab" ("aaab" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1495 ""aaab" =~ /(?>(a+))b/" "(?>(a+))b" nil nil nil nil "aaab" nil 1 0 "aaab" ("aaa" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1496 ""((abc(ade)ufh()()x" =~ /((?>[^()]+)|\([^()]*\))+/" "((?>[^()]+)|\([^()]*\))+" nil nil nil nil "((abc(ade)ufh()()x" nil 1 0 "abc(ade)ufh()()x" ("x" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1497 ""aaab" =~ /a\Z/" "a\Z" nil nil nil nil "aaab" nil 1 0 nil nil) +(1498 ""a\nb\n" =~ /a\Z/" "a\Z" nil nil nil nil "a +b +" nil 1 0 nil nil) +(1499 ""a\nb\n" =~ /b\Z/" "b\Z" nil nil nil nil "a +b +" nil 1 0 "b" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1500 ""a\nb" =~ /b\Z/" "b\Z" nil nil nil nil "a +b" nil 1 0 "b" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1501 ""a\nb" =~ /b\z/" "b\z" nil nil nil nil "a +b" nil 1 0 "b" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1502 ""a" =~ /^(?>(?(1)\.|())[^\W_](?>[a-z0-9-]*[^\W_])?)+$/" "^(?>(?(1)\.|())[^\W_](?>[a-z0-9-]*[^\W_])?)+$" nil nil nil nil "a" nil 1 0 "a" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1503 ""abc" =~ /^(?>(?(1)\.|())[^\W_](?>[a-z0-9-]*[^\W_])?)+$/" "^(?>(?(1)\.|())[^\W_](?>[a-z0-9-]*[^\W_])?)+$" nil nil nil nil "abc" nil 1 0 "abc" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1504 ""a-b" =~ /^(?>(?(1)\.|())[^\W_](?>[a-z0-9-]*[^\W_])?)+$/" "^(?>(?(1)\.|())[^\W_](?>[a-z0-9-]*[^\W_])?)+$" nil nil nil nil "a-b" nil 1 0 "a-b" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1505 ""0-9" =~ /^(?>(?(1)\.|())[^\W_](?>[a-z0-9-]*[^\W_])?)+$/" "^(?>(?(1)\.|())[^\W_](?>[a-z0-9-]*[^\W_])?)+$" nil nil nil nil "0-9" nil 1 0 "0-9" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1506 ""a.b" =~ /^(?>(?(1)\.|())[^\W_](?>[a-z0-9-]*[^\W_])?)+$/" "^(?>(?(1)\.|())[^\W_](?>[a-z0-9-]*[^\W_])?)+$" nil nil nil nil "a.b" nil 1 0 "a.b" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1507 ""5.6.7" =~ /^(?>(?(1)\.|())[^\W_](?>[a-z0-9-]*[^\W_])?)+$/" "^(?>(?(1)\.|())[^\W_](?>[a-z0-9-]*[^\W_])?)+$" nil nil nil nil "5.6.7" nil 1 0 "5.6.7" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1508 ""the.quick.brown.fox" =~ /^(?>(?(1)\.|())[^\W_](?>[a-z0-9-]*[^\W_])?)+$/" "^(?>(?(1)\.|())[^\W_](?>[a-z0-9-]*[^\W_])?)+$" nil nil nil nil "the.quick.brown.fox" nil 1 0 "the.quick.brown.fox" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1509 ""a100.b200.300c" =~ /^(?>(?(1)\.|())[^\W_](?>[a-z0-9-]*[^\W_])?)+$/" "^(?>(?(1)\.|())[^\W_](?>[a-z0-9-]*[^\W_])?)+$" nil nil nil nil "a100.b200.300c" nil 1 0 "a100.b200.300c" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1510 ""12-ab.1245" =~ /^(?>(?(1)\.|())[^\W_](?>[a-z0-9-]*[^\W_])?)+$/" "^(?>(?(1)\.|())[^\W_](?>[a-z0-9-]*[^\W_])?)+$" nil nil nil nil "12-ab.1245" nil 1 0 "12-ab.1245" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1511 ""\" =~ /^(?>(?(1)\.|())[^\W_](?>[a-z0-9-]*[^\W_])?)+$/" "^(?>(?(1)\.|())[^\W_](?>[a-z0-9-]*[^\W_])?)+$" nil nil nil nil "" nil 1 0 nil nil) +(1512 "".a" =~ /^(?>(?(1)\.|())[^\W_](?>[a-z0-9-]*[^\W_])?)+$/" "^(?>(?(1)\.|())[^\W_](?>[a-z0-9-]*[^\W_])?)+$" nil nil nil nil ".a" nil 1 0 nil nil) +(1513 ""-a" =~ /^(?>(?(1)\.|())[^\W_](?>[a-z0-9-]*[^\W_])?)+$/" "^(?>(?(1)\.|())[^\W_](?>[a-z0-9-]*[^\W_])?)+$" nil nil nil nil "-a" nil 1 0 nil nil) +(1514 ""a-" =~ /^(?>(?(1)\.|())[^\W_](?>[a-z0-9-]*[^\W_])?)+$/" "^(?>(?(1)\.|())[^\W_](?>[a-z0-9-]*[^\W_])?)+$" nil nil nil nil "a-" nil 1 0 nil nil) +(1515 ""a." =~ /^(?>(?(1)\.|())[^\W_](?>[a-z0-9-]*[^\W_])?)+$/" "^(?>(?(1)\.|())[^\W_](?>[a-z0-9-]*[^\W_])?)+$" nil nil nil nil "a." nil 1 0 nil nil) +(1516 ""a_b" =~ /^(?>(?(1)\.|())[^\W_](?>[a-z0-9-]*[^\W_])?)+$/" "^(?>(?(1)\.|())[^\W_](?>[a-z0-9-]*[^\W_])?)+$" nil nil nil nil "a_b" nil 1 0 nil nil) +(1517 ""a.-" =~ /^(?>(?(1)\.|())[^\W_](?>[a-z0-9-]*[^\W_])?)+$/" "^(?>(?(1)\.|())[^\W_](?>[a-z0-9-]*[^\W_])?)+$" nil nil nil nil "a.-" nil 1 0 nil nil) +(1518 ""a.." =~ /^(?>(?(1)\.|())[^\W_](?>[a-z0-9-]*[^\W_])?)+$/" "^(?>(?(1)\.|())[^\W_](?>[a-z0-9-]*[^\W_])?)+$" nil nil nil nil "a.." nil 1 0 nil nil) +(1519 ""ab..bc" =~ /^(?>(?(1)\.|())[^\W_](?>[a-z0-9-]*[^\W_])?)+$/" "^(?>(?(1)\.|())[^\W_](?>[a-z0-9-]*[^\W_])?)+$" nil nil nil nil "ab..bc" nil 1 0 nil nil) +(1520 ""the.quick.brown.fox-" =~ /^(?>(?(1)\.|())[^\W_](?>[a-z0-9-]*[^\W_])?)+$/" "^(?>(?(1)\.|())[^\W_](?>[a-z0-9-]*[^\W_])?)+$" nil nil nil nil "the.quick.brown.fox-" nil 1 0 nil nil) +(1521 ""the.quick.brown.fox." =~ /^(?>(?(1)\.|())[^\W_](?>[a-z0-9-]*[^\W_])?)+$/" "^(?>(?(1)\.|())[^\W_](?>[a-z0-9-]*[^\W_])?)+$" nil nil nil nil "the.quick.brown.fox." nil 1 0 nil nil) +(1522 ""the.quick.brown.fox_" =~ /^(?>(?(1)\.|())[^\W_](?>[a-z0-9-]*[^\W_])?)+$/" "^(?>(?(1)\.|())[^\W_](?>[a-z0-9-]*[^\W_])?)+$" nil nil nil nil "the.quick.brown.fox_" nil 1 0 nil nil) +(1523 ""the.quick.brown.fox+" =~ /^(?>(?(1)\.|())[^\W_](?>[a-z0-9-]*[^\W_])?)+$/" "^(?>(?(1)\.|())[^\W_](?>[a-z0-9-]*[^\W_])?)+$" nil nil nil nil "the.quick.brown.fox+" nil 1 0 nil nil) +(1524 ""alphabetabcd" =~ /(?>.*)(?<=(abcd|wxyz))/" "(?>.*)(?<=(abcd|wxyz))" nil nil nil nil "alphabetabcd" nil 1 0 "alphabetabcd" ("abcd" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1525 ""endingwxyz" =~ /(?>.*)(?<=(abcd|wxyz))/" "(?>.*)(?<=(abcd|wxyz))" nil nil nil nil "endingwxyz" nil 1 0 "endingwxyz" ("wxyz" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1526 ""a rather long string that doesn't end with one of them" =~ /(?>.*)(?<=(abcd|wxyz))/" "(?>.*)(?<=(abcd|wxyz))" nil nil nil nil "a rather long string that doesn't end with one of them" nil 1 0 nil nil) +(1527 ""word cat dog elephant mussel cow horse canary baboon snake shark otherword" =~ /word (?>(?:(?!otherword)[a-zA-Z0-9]+ ){0,30})otherword/" "word (?>(?:(?!otherword)[a-zA-Z0-9]+ ){0,30})otherword" nil nil nil nil "word cat dog elephant mussel cow horse canary baboon snake shark otherword" nil 1 0 "word cat dog elephant mussel cow horse canary baboon snake shark otherword" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1528 ""word cat dog elephant mussel cow horse canary baboon snake shark" =~ /word (?>(?:(?!otherword)[a-zA-Z0-9]+ ){0,30})otherword/" "word (?>(?:(?!otherword)[a-zA-Z0-9]+ ){0,30})otherword" nil nil nil nil "word cat dog elephant mussel cow horse canary baboon snake shark" nil 1 0 nil nil) +(1529 ""word cat dog elephant mussel cow horse canary baboon snake shark the quick brown fox and the lazy dog and several other words getting close to thirty by now I hope" =~ /word (?>[a-zA-Z0-9]+ ){0,30}otherword/" "word (?>[a-zA-Z0-9]+ ){0,30}otherword" nil nil nil nil "word cat dog elephant mussel cow horse canary baboon snake shark the quick brown fox and the lazy dog and several other words getting close to thirty by now I hope" nil 1 0 nil nil) +(1530 ""999foo" =~ /(?<=\d{3}(?!999))foo/" "(?<=\d{3}(?!999))foo" nil nil nil nil "999foo" nil 1 0 "foo" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1531 ""123999foo" =~ /(?<=\d{3}(?!999))foo/" "(?<=\d{3}(?!999))foo" nil nil nil nil "123999foo" nil 1 0 "foo" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1532 ""123abcfoo" =~ /(?<=\d{3}(?!999))foo/" "(?<=\d{3}(?!999))foo" nil nil nil nil "123abcfoo" nil 1 0 nil nil) +(1533 ""999foo" =~ /(?<=(?!...999)\d{3})foo/" "(?<=(?!...999)\d{3})foo" nil nil nil nil "999foo" nil 1 0 "foo" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1534 ""123999foo" =~ /(?<=(?!...999)\d{3})foo/" "(?<=(?!...999)\d{3})foo" nil nil nil nil "123999foo" nil 1 0 "foo" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1535 ""123abcfoo" =~ /(?<=(?!...999)\d{3})foo/" "(?<=(?!...999)\d{3})foo" nil nil nil nil "123abcfoo" nil 1 0 nil nil) +(1536 ""123abcfoo" =~ /(?<=\d{3}(?!999)...)foo/" "(?<=\d{3}(?!999)...)foo" nil nil nil nil "123abcfoo" nil 1 0 "foo" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1537 ""123456foo" =~ /(?<=\d{3}(?!999)...)foo/" "(?<=\d{3}(?!999)...)foo" nil nil nil nil "123456foo" nil 1 0 "foo" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1538 ""123999foo" =~ /(?<=\d{3}(?!999)...)foo/" "(?<=\d{3}(?!999)...)foo" nil nil nil nil "123999foo" nil 1 0 nil nil) +(1539 ""123abcfoo" =~ /(?<=\d{3}...)(?<!999)foo/" "(?<=\d{3}...)(?<!999)foo" nil nil nil nil "123abcfoo" nil 1 0 "foo" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1540 ""123456foo" =~ /(?<=\d{3}...)(?<!999)foo/" "(?<=\d{3}...)(?<!999)foo" nil nil nil nil "123456foo" nil 1 0 "foo" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1541 ""123999foo" =~ /(?<=\d{3}...)(?<!999)foo/" "(?<=\d{3}...)(?<!999)foo" nil nil nil nil "123999foo" nil 1 0 nil nil) +(1542 ""<a href=abcd xyz" =~ /<a[\s]+href[\s]*=[\s]* # find <a href= + ([\"\'])? # find single or double quote + (?(1) (.*?)\1 | ([^\s]+)) # if quote found, match up to next matching + # quote, otherwise match up to next space +/isx" "<a[\s]+href[\s]*=[\s]* # find <a href= + ([\"\'])? # find single or double quote + (?(1) (.*?)\1 | ([^\s]+)) # if quote found, match up to next matching + # quote, otherwise match up to next space +" t nil t t "<a href=abcd xyz" nil 1 0 "<a href=abcd" (nil nil "abcd" nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1543 ""<a href=\"abcd xyz pqr\" cats" =~ /<a[\s]+href[\s]*=[\s]* # find <a href= + ([\"\'])? # find single or double quote + (?(1) (.*?)\1 | ([^\s]+)) # if quote found, match up to next matching + # quote, otherwise match up to next space +/isx" "<a[\s]+href[\s]*=[\s]* # find <a href= + ([\"\'])? # find single or double quote + (?(1) (.*?)\1 | ([^\s]+)) # if quote found, match up to next matching + # quote, otherwise match up to next space +" t nil t t "<a href="abcd xyz pqr" cats" nil 1 0 "<a href="abcd xyz pqr"" (""" "abcd xyz pqr" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1544 ""<a href=\'abcd xyz pqr\' cats" =~ /<a[\s]+href[\s]*=[\s]* # find <a href= + ([\"\'])? # find single or double quote + (?(1) (.*?)\1 | ([^\s]+)) # if quote found, match up to next matching + # quote, otherwise match up to next space +/isx" "<a[\s]+href[\s]*=[\s]* # find <a href= + ([\"\'])? # find single or double quote + (?(1) (.*?)\1 | ([^\s]+)) # if quote found, match up to next matching + # quote, otherwise match up to next space +" t nil t t "<a href='abcd xyz pqr' cats" nil 1 0 "<a href='abcd xyz pqr'" ("'" "abcd xyz pqr" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1545 ""<a href=abcd xyz" =~ /<a\s+href\s*=\s* # find <a href= + (["'])? # find single or double quote + (?(1) (.*?)\1 | (\S+)) # if quote found, match up to next matching + # quote, otherwise match up to next space +/isx" "<a\s+href\s*=\s* # find <a href= + (["'])? # find single or double quote + (?(1) (.*?)\1 | (\S+)) # if quote found, match up to next matching + # quote, otherwise match up to next space +" t nil t t "<a href=abcd xyz" nil 1 0 "<a href=abcd" (nil nil "abcd" nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1546 ""<a href=\"abcd xyz pqr\" cats" =~ /<a\s+href\s*=\s* # find <a href= + (["'])? # find single or double quote + (?(1) (.*?)\1 | (\S+)) # if quote found, match up to next matching + # quote, otherwise match up to next space +/isx" "<a\s+href\s*=\s* # find <a href= + (["'])? # find single or double quote + (?(1) (.*?)\1 | (\S+)) # if quote found, match up to next matching + # quote, otherwise match up to next space +" t nil t t "<a href="abcd xyz pqr" cats" nil 1 0 "<a href="abcd xyz pqr"" (""" "abcd xyz pqr" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1547 ""<a href = \'abcd xyz pqr\' cats" =~ /<a\s+href\s*=\s* # find <a href= + (["'])? # find single or double quote + (?(1) (.*?)\1 | (\S+)) # if quote found, match up to next matching + # quote, otherwise match up to next space +/isx" "<a\s+href\s*=\s* # find <a href= + (["'])? # find single or double quote + (?(1) (.*?)\1 | (\S+)) # if quote found, match up to next matching + # quote, otherwise match up to next space +" t nil t t "<a href = 'abcd xyz pqr' cats" nil 1 0 "<a href = 'abcd xyz pqr'" ("'" "abcd xyz pqr" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1548 ""<a href=abcd xyz" =~ /<a\s+href(?>\s*)=(?>\s*) # find <a href= + (["'])? # find single or double quote + (?(1) (.*?)\1 | (\S+)) # if quote found, match up to next matching + # quote, otherwise match up to next space +/isx" "<a\s+href(?>\s*)=(?>\s*) # find <a href= + (["'])? # find single or double quote + (?(1) (.*?)\1 | (\S+)) # if quote found, match up to next matching + # quote, otherwise match up to next space +" t nil t t "<a href=abcd xyz" nil 1 0 "<a href=abcd" (nil nil "abcd" nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1549 ""<a href=\"abcd xyz pqr\" cats" =~ /<a\s+href(?>\s*)=(?>\s*) # find <a href= + (["'])? # find single or double quote + (?(1) (.*?)\1 | (\S+)) # if quote found, match up to next matching + # quote, otherwise match up to next space +/isx" "<a\s+href(?>\s*)=(?>\s*) # find <a href= + (["'])? # find single or double quote + (?(1) (.*?)\1 | (\S+)) # if quote found, match up to next matching + # quote, otherwise match up to next space +" t nil t t "<a href="abcd xyz pqr" cats" nil 1 0 "<a href="abcd xyz pqr"" (""" "abcd xyz pqr" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1550 ""<a href = \'abcd xyz pqr\' cats" =~ /<a\s+href(?>\s*)=(?>\s*) # find <a href= + (["'])? # find single or double quote + (?(1) (.*?)\1 | (\S+)) # if quote found, match up to next matching + # quote, otherwise match up to next space +/isx" "<a\s+href(?>\s*)=(?>\s*) # find <a href= + (["'])? # find single or double quote + (?(1) (.*?)\1 | (\S+)) # if quote found, match up to next matching + # quote, otherwise match up to next space +" t nil t t "<a href = 'abcd xyz pqr' cats" nil 1 0 "<a href = 'abcd xyz pqr'" ("'" "abcd xyz pqr" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1551 ""ZABCDEFG" =~ /((Z)+|A)*/" "((Z)+|A)*" nil nil nil nil "ZABCDEFG" nil 1 0 "ZA" ("A" "Z" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1552 ""ZABCDEFG" =~ /(Z()|A)*/" "(Z()|A)*" nil nil nil nil "ZABCDEFG" nil 1 0 "ZA" ("A" "" nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1553 ""ZABCDEFG" =~ /(Z(())|A)*/" "(Z(())|A)*" nil nil nil nil "ZABCDEFG" nil 1 0 "ZA" ("A" "" "" nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1554 ""ZABCDEFG" =~ /((?>Z)+|A)*/" "((?>Z)+|A)*" nil nil nil nil "ZABCDEFG" nil 1 0 "ZA" ("A" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1555 ""ZABCDEFG" =~ /((?>)+|A)*/" "((?>)+|A)*" nil nil nil nil "ZABCDEFG" nil 1 0 "" ("" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1556 ""abbab" =~ /a*/" "a*" nil nil nil nil "abbab" nil 1 0 "a" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1557 ""abcde" =~ /^[a-\d]/" "^[a-\d]" nil nil nil nil "abcde" nil 1 0 "a" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1558 ""-things" =~ /^[a-\d]/" "^[a-\d]" nil nil nil nil "-things" nil 1 0 "-" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1559 ""0digit" =~ /^[a-\d]/" "^[a-\d]" nil nil nil nil "0digit" nil 1 0 "0" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1560 ""bcdef" =~ /^[a-\d]/" "^[a-\d]" nil nil nil nil "bcdef" nil 1 0 nil nil) +(1561 ""abcde" =~ /^[\d-a]/" "^[\d-a]" nil nil nil nil "abcde" nil 1 0 "a" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1562 ""-things" =~ /^[\d-a]/" "^[\d-a]" nil nil nil nil "-things" nil 1 0 "-" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1563 ""0digit" =~ /^[\d-a]/" "^[\d-a]" nil nil nil nil "0digit" nil 1 0 "0" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1564 ""bcdef" =~ /^[\d-a]/" "^[\d-a]" nil nil nil nil "bcdef" nil 1 0 nil nil) +(1565 ""abcdef" =~ /(?<=abc).*(?=def)/" "(?<=abc).*(?=def)" nil nil nil nil "abcdef" nil 1 0 "" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1566 ""abcxdef" =~ /(?<=abc).*(?=def)/" "(?<=abc).*(?=def)" nil nil nil nil "abcxdef" nil 1 0 "x" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1567 ""abcxdefxdef" =~ /(?<=abc).*(?=def)/" "(?<=abc).*(?=def)" nil nil nil nil "abcxdefxdef" nil 1 0 "xdefx" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1568 ""abcdef" =~ /(?<=abc).*?(?=def)/" "(?<=abc).*?(?=def)" nil nil nil nil "abcdef" nil 1 0 "" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1569 ""abcxdef" =~ /(?<=abc).*?(?=def)/" "(?<=abc).*?(?=def)" nil nil nil nil "abcxdef" nil 1 0 "x" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1570 ""abcxdefxdef" =~ /(?<=abc).*?(?=def)/" "(?<=abc).*?(?=def)" nil nil nil nil "abcxdefxdef" nil 1 0 "x" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1571 ""abcdef" =~ /(?<=abc).+(?=def)/" "(?<=abc).+(?=def)" nil nil nil nil "abcdef" nil 1 0 nil nil) +(1572 ""abcxdef" =~ /(?<=abc).+(?=def)/" "(?<=abc).+(?=def)" nil nil nil nil "abcxdef" nil 1 0 "x" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1573 ""abcxdefxdef" =~ /(?<=abc).+(?=def)/" "(?<=abc).+(?=def)" nil nil nil nil "abcxdefxdef" nil 1 0 "xdefx" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1574 ""abcdef" =~ /(?<=abc).+?(?=def)/" "(?<=abc).+?(?=def)" nil nil nil nil "abcdef" nil 1 0 nil nil) +(1575 ""abcxdef" =~ /(?<=abc).+?(?=def)/" "(?<=abc).+?(?=def)" nil nil nil nil "abcxdef" nil 1 0 "x" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1576 ""abcxdefxdef" =~ /(?<=abc).+?(?=def)/" "(?<=abc).+?(?=def)" nil nil nil nil "abcxdefxdef" nil 1 0 "x" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1577 ""-abcdef" =~ /(?<=\b)(.*)/" "(?<=\b)(.*)" nil nil nil nil "-abcdef" nil 1 0 "abcdef" ("abcdef" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1578 ""abcdef" =~ /(?<=\b)(.*)/" "(?<=\b)(.*)" nil nil nil nil "abcdef" nil 1 0 "abcdef" ("abcdef" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1579 ""-abcdef" =~ /(?<=\B)(.*)/" "(?<=\B)(.*)" nil nil nil nil "-abcdef" nil 1 0 "-abcdef" ("-abcdef" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1580 ""abcdef" =~ /(?<=\B)(.*)/" "(?<=\B)(.*)" nil nil nil nil "abcdef" nil 1 0 "bcdef" ("bcdef" nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1581 ""'a'" =~ /^'[ab]'/" "^'[ab]'" nil nil nil nil "'a'" nil 1 0 "'a'" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1582 ""'b'" =~ /^'[ab]'/" "^'[ab]'" nil nil nil nil "'b'" nil 1 0 "'b'" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1583 ""x'a'" =~ /^'[ab]'/" "^'[ab]'" nil nil nil nil "x'a'" nil 1 0 nil nil) +(1584 ""'a'x" =~ /^'[ab]'/" "^'[ab]'" nil nil nil nil "'a'x" nil 1 0 "'a'" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1585 ""'ab'" =~ /^'[ab]'/" "^'[ab]'" nil nil nil nil "'ab'" nil 1 0 nil nil) +(1586 ""'a'" =~ /^'[ab]'$/" "^'[ab]'$" nil nil nil nil "'a'" nil 1 0 "'a'" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1587 ""'b'" =~ /^'[ab]'$/" "^'[ab]'$" nil nil nil nil "'b'" nil 1 0 "'b'" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1588 ""x'a'" =~ /^'[ab]'$/" "^'[ab]'$" nil nil nil nil "x'a'" nil 1 0 nil nil) +(1589 ""'a'x" =~ /^'[ab]'$/" "^'[ab]'$" nil nil nil nil "'a'x" nil 1 0 nil nil) +(1590 ""'ab'" =~ /^'[ab]'$/" "^'[ab]'$" nil nil nil nil "'ab'" nil 1 0 nil nil) +(1591 ""'a'" =~ /'[ab]'$/" "'[ab]'$" nil nil nil nil "'a'" nil 1 0 "'a'" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1592 ""'b'" =~ /'[ab]'$/" "'[ab]'$" nil nil nil nil "'b'" nil 1 0 "'b'" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1593 ""x'a'" =~ /'[ab]'$/" "'[ab]'$" nil nil nil nil "x'a'" nil 1 0 "'a'" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1594 ""'a'x" =~ /'[ab]'$/" "'[ab]'$" nil nil nil nil "'a'x" nil 1 0 nil nil) +(1595 ""'ab'" =~ /'[ab]'$/" "'[ab]'$" nil nil nil nil "'ab'" nil 1 0 nil nil) +(1596 ""'a'" =~ /'[ab]'/" "'[ab]'" nil nil nil nil "'a'" nil 1 0 "'a'" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1597 ""'b'" =~ /'[ab]'/" "'[ab]'" nil nil nil nil "'b'" nil 1 0 "'b'" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1598 ""x'a'" =~ /'[ab]'/" "'[ab]'" nil nil nil nil "x'a'" nil 1 0 "'a'" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1599 ""'a'x" =~ /'[ab]'/" "'[ab]'" nil nil nil nil "'a'x" nil 1 0 "'a'" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1600 ""'ab'" =~ /'[ab]'/" "'[ab]'" nil nil nil nil "'ab'" nil 1 0 nil nil) +(1601 ""abc" =~ /abc\E/" "abc\E" nil nil nil nil "abc" nil 1 0 "abc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1602 ""abcE" =~ /abc\E/" "abc\E" nil nil nil nil "abcE" nil 1 0 "abc" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1603 ""abcx" =~ /abc[\Ex]/" "abc[\Ex]" nil nil nil nil "abcx" nil 1 0 "abcx" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1604 ""abcE" =~ /abc[\Ex]/" "abc[\Ex]" nil nil nil nil "abcE" nil 1 0 nil nil) +(1605 ""a*" =~ /^\Qa*\E$/" "^\Qa*\E$" nil nil nil nil "a*" nil 1 0 "a*" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1606 ""a" =~ /^\Qa*\E$/" "^\Qa*\E$" nil nil nil nil "a" nil 1 0 nil nil) +(1607 ""a*x" =~ /\Qa*x\E/" "\Qa*x\E" nil nil nil nil "a*x" nil 1 0 "a*x" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1608 ""a*" =~ /\Qa*x\E/" "\Qa*x\E" nil nil nil nil "a*" nil 1 0 nil nil) +(1609 ""a*x" =~ /\Qa*x/" "\Qa*x" nil nil nil nil "a*x" nil 1 0 "a*x" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1610 ""a*" =~ /\Qa*x/" "\Qa*x" nil nil nil nil "a*" nil 1 0 nil nil) +(1611 ""a*x" =~ /\Q\Qa*x\E\E/" "\Q\Qa*x\E\E" nil nil nil nil "a*x" nil 1 0 nil nil) +(1612 ""a\\*x" =~ /\Q\Qa*x\E\E/" "\Q\Qa*x\E\E" nil nil nil nil "a\*x" nil 1 0 "a\*x" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1613 ""a*x" =~ /\Q\Qa*x\E/" "\Q\Qa*x\E" nil nil nil nil "a*x" nil 1 0 nil nil) +(1614 ""a\\*x" =~ /\Q\Qa*x\E/" "\Q\Qa*x\E" nil nil nil nil "a\*x" nil 1 0 "a\*x" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1615 ""a[x]" =~ /a\Q[x\E]/" "a\Q[x\E]" nil nil nil nil "a[x]" nil 1 0 "a[x]" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1616 ""ax" =~ /a\Q[x\E]/" "a\Q[x\E]" nil nil nil nil "ax" nil 1 0 nil nil) +(1617 ""a" =~ /a#comment\Q... +{2}/x" "a#comment\Q... +{2}" nil nil nil t "a" nil 1 0 nil nil) +(1618 ""aa" =~ /a#comment\Q... +{2}/x" "a#comment\Q... +{2}" nil nil nil t "aa" nil 1 0 "aa" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1619 ""a" =~ /a(?#comment\Q... +){2}/x" "a(?#comment\Q... +){2}" nil nil nil t "a" nil 1 0 nil nil) +(1620 ""aa" =~ /a(?#comment\Q... +){2}/x" "a(?#comment\Q... +){2}" nil nil nil t "aa" nil 1 0 "aa" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1621 ""a." =~ /(?x)a#\Q +./" "(?x)a#\Q +." nil nil nil nil "a." nil 1 0 "a." (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1622 ""aa" =~ /(?x)a#\Q +./" "(?x)a#\Q +." nil nil nil nil "aa" nil 1 0 nil nil) +(1623 ""abcdxklqj" =~ /ab(?=.*q)cd/" "ab(?=.*q)cd" nil nil nil nil "abcdxklqj" nil 1 0 "abcd" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)) +(1624 ""ab" =~ /a(?!.*$)b/" "a(?!.*$)b" nil nil nil nil "ab" nil 1 0 nil nil) +(1625 ""Axi" =~ /.{2}[a-z]/" ".{2}[a-z]" nil nil nil nil "Axi" nil 1 0 "Axi" (nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil))
Added: branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/testinput =================================================================== --- branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/testinput 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/testinput 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,3948 @@ +/the quick brown fox/ + the quick brown fox + The quick brown FOX + What do you know about the quick brown fox? + What do you know about THE QUICK BROWN FOX? + +/The quick brown fox/i + the quick brown fox + The quick brown FOX + What do you know about the quick brown fox? + What do you know about THE QUICK BROWN FOX? + +/abcd\t\n\r\f\a\e\071\x3b$\?caxyz/ + abcd\t\n\r\f\a\e9;$\?caxyz + +/a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/ + abxyzpqrrrabbxyyyypqAzz + abxyzpqrrrabbxyyyypqAzz + aabxyzpqrrrabbxyyyypqAzz + aaabxyzpqrrrabbxyyyypqAzz + aaaabxyzpqrrrabbxyyyypqAzz + abcxyzpqrrrabbxyyyypqAzz + aabcxyzpqrrrabbxyyyypqAzz + aaabcxyzpqrrrabbxyyyypAzz + aaabcxyzpqrrrabbxyyyypqAzz + aaabcxyzpqrrrabbxyyyypqqAzz + aaabcxyzpqrrrabbxyyyypqqqAzz + aaabcxyzpqrrrabbxyyyypqqqqAzz + aaabcxyzpqrrrabbxyyyypqqqqqAzz + aaabcxyzpqrrrabbxyyyypqqqqqqAzz + aaaabcxyzpqrrrabbxyyyypqAzz + abxyzzpqrrrabbxyyyypqAzz + aabxyzzzpqrrrabbxyyyypqAzz + aaabxyzzzzpqrrrabbxyyyypqAzz + aaaabxyzzzzpqrrrabbxyyyypqAzz + abcxyzzpqrrrabbxyyyypqAzz + aabcxyzzzpqrrrabbxyyyypqAzz + aaabcxyzzzzpqrrrabbxyyyypqAzz + aaaabcxyzzzzpqrrrabbxyyyypqAzz + aaaabcxyzzzzpqrrrabbbxyyyypqAzz + aaaabcxyzzzzpqrrrabbbxyyyyypqAzz + aaabcxyzpqrrrabbxyyyypABzz + aaabcxyzpqrrrabbxyyyypABBzz + >>>aaabxyzpqrrrabbxyyyypqAzz + >aaaabxyzpqrrrabbxyyyypqAzz + >>>>abcxyzpqrrrabbxyyyypqAzz + abxyzpqrrabbxyyyypqAzz + abxyzpqrrrrabbxyyyypqAzz + abxyzpqrrrabxyyyypqAzz + aaaabcxyzzzzpqrrrabbbxyyyyyypqAzz + aaaabcxyzzzzpqrrrabbbxyyypqAzz + aaabcxyzpqrrrabbxyyyypqqqqqqqAzz + +/^(abc){1,2}zz/ + abczz + abcabczz + zz + abcabcabczz + >>abczz + +/^(b+?|a){1,2}?c/ + bc + bbc + bbbc + bac + bbac + aac + abbbbbbbbbbbc + bbbbbbbbbbbac + aaac + abbbbbbbbbbbac + +/^(b+|a){1,2}c/ + bc + bbc + bbbc + bac + bbac + aac + abbbbbbbbbbbc + bbbbbbbbbbbac + aaac + abbbbbbbbbbbac + +/^(b+|a){1,2}?bc/ + bbc + +/^(b*|ba){1,2}?bc/ + babc + bbabc + bababc + bababbc + babababc + +/^(ba|b*){1,2}?bc/ + babc + bbabc + bababc + bababbc + babababc + +/^\ca\cA\c[\c{\c:/ + \x01\x01\e;z + +/^[ab]cde]/ + athing + bthing + ]thing + cthing + dthing + ething + fthing + [thing + \thing + +/^[]cde]/ + ]thing + cthing + dthing + ething + athing + fthing + +/^[^ab]cde]/ + fthing + [thing + \thing + athing + bthing + ]thing + cthing + dthing + ething + +/^[^]cde]/ + athing + fthing + ]thing + cthing + dthing + ething + +/^\�/ + � + +/^�/ + � + +/^[0-9]+$/ + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 100 + abc + +/^.*nter/ + enter + inter + uponter + +/^xxx[0-9]+$/ + xxx0 + xxx1234 + xxx + +/^.+[0-9][0-9][0-9]$/ + x123 + xx123 + 123456 + 123 + x1234 + +/^.+?[0-9][0-9][0-9]$/ + x123 + xx123 + 123456 + 123 + x1234 + +/^([^!]+)!(.+)=apquxz.ixr.zzz.ac.uk$/ + abc!pqr=apquxz.ixr.zzz.ac.uk + !pqr=apquxz.ixr.zzz.ac.uk + abc!=apquxz.ixr.zzz.ac.uk + abc!pqr=apquxz:ixr.zzz.ac.uk + abc!pqr=apquxz.ixr.zzz.ac.ukk + +/:/ + Well, we need a colon: somewhere + Fail if we don't + +/([\da-f:]+)$/i + 0abc + abc + fed + E + :: + 5f03:12C0::932e + fed def + Any old stuff + 0zzz + gzzz + fed\x20 + Any old rubbish + +/^.*.(\d{1,3}).(\d{1,3}).(\d{1,3})$/ + .1.2.3 + A.12.123.0 + .1.2.3333 + 1.2.3 + 1234.2.3 + +/^(\d+)\s+IN\s+SOA\s+(\S+)\s+(\S+)\s*(\s*$/ + 1 IN SOA non-sp1 non-sp2( + 1 IN SOA non-sp1 non-sp2 ( + 1IN SOA non-sp1 non-sp2( + +/^[a-zA-Z\d][a-zA-Z\d-]*(.[a-zA-Z\d][a-zA-z\d-]*)*.$/ + a. + Z. + 2. + ab-c.pq-r. + sxk.zzz.ac.uk. + x-.y-. + -abc.peq. + +/^*.[a-z]([a-z-\d]*[a-z\d]+)?(.[a-z]([a-z-\d]*[a-z\d]+)?)*$/ + *.a + *.b0-a + *.c3-b.c + *.c-a.b-c + *.0 + *.a- + *.a-b.c- + *.c-a.0-c + +/^(?=ab(de))(abd)(e)/ + abde + +/^(?!(ab)de|x)(abd)(f)/ + abdf + +/^(?=(ab(cd)))(ab)/ + abcd + +/^[\da-f](.[\da-f])*$/i + a.b.c.d + A.B.C.D + a.b.c.1.2.3.C + +/^".*"\s*(;.*)?$/ + "1234" + "abcd" ; + "" ; rhubarb + "1234" : things + +/^$/ + \ + +/ ^ a (?# begins with a) b\sc (?# then b c) $ (?# then end)/x + ab c + abc + ab cde + +/(?x) ^ a (?# begins with a) b\sc (?# then b c) $ (?# then end)/ + ab c + abc + ab cde + +/^ a\ b[c ]d $/x + a bcd + a b d + abcd + ab d + +/^(a(b(c)))(d(e(f)))(h(i(j)))(k(l(m)))$/ + abcdefhijklm + +/^(?:a(b(c)))(?:d(e(f)))(?:h(i(j)))(?:k(l(m)))$/ + abcdefhijklm + +/^[\w][\W][\s][\S][\d][\D][\b][\n][\c]][\022]/ + a+ Z0+\x08\n\x1d\x12 + +/^[.^$|()*+?{,}]+/ + .^$(*+)|{?,?} + +/^a*\w/ + z + az + aaaz + a + aa + aaaa + a+ + aa+ + +/^a*?\w/ + z + az + aaaz + a + aa + aaaa + a+ + aa+ + +/^a+\w/ + az + aaaz + aa + aaaa + aa+ + +/^a+?\w/ + az + aaaz + aa + aaaa + aa+ + +/^\d{8}\w{2,}/ + 1234567890 + 12345678ab + 12345678__ + 1234567 + +/^[aeiou\d]{4,5}$/ + uoie + 1234 + 12345 + aaaaa + 123456 + +/^[aeiou\d]{4,5}?/ + uoie + 1234 + 12345 + aaaaa + 123456 + +/\A(abc|def)=(\1){2,3}\Z/ + abc=abcabc + def=defdefdef + abc=defdef + +/^(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)\11*(\3\4)\1(?#)2$/ + abcdefghijkcda2 + abcdefghijkkkkcda2 + +/(cat(a(ract|tonic)|erpillar)) \1()2(3)/ + cataract cataract23 + catatonic catatonic23 + caterpillar caterpillar23 + + +/^From +([^ ]+) +[a-zA-Z][a-zA-Z][a-zA-Z] +[a-zA-Z][a-zA-Z][a-zA-Z] +[0-9]?[0-9] +[0-9][0-9]:[0-9][0-9]/ + From abcd Mon Sep 01 12:33:02 1997 + +/^From\s+\S+\s+([a-zA-Z]{3}\s+){2}\d{1,2}\s+\d\d:\d\d/ + From abcd Mon Sep 01 12:33:02 1997 + From abcd Mon Sep 1 12:33:02 1997 + From abcd Sep 01 12:33:02 1997 + +/^12.34/s + 12\n34 + 12\r34 + +/\w+(?=\t)/ + the quick brown\t fox + +/foo(?!bar)(.*)/ + foobar is foolish see? + +/(?:(?!foo)...|^.{0,2})bar(.*)/ + foobar crowbar etc + barrel + 2barrel + A barrel + +/^(\D*)(?=\d)(?!123)/ + abc456 + abc123 + +/^1234(?# test newlines + inside)/ + 1234 + +/^1234 #comment in extended re + /x + 1234 + +/#rhubarb + abcd/x + abcd + +/^abcd#rhubarb/x + abcd + +/^(a)\1{2,3}(.)/ + aaab + aaaab + aaaaab + aaaaaab + +/(?!^)abc/ + the abc + abc + +/(?=^)abc/ + abc + the abc + +/^[ab]{1,3}(ab*|b)/ + aabbbbb + +/^[ab]{1,3}?(ab*|b)/ + aabbbbb + +/^[ab]{1,3}?(ab*?|b)/ + aabbbbb + +/^[ab]{1,3}(ab*?|b)/ + aabbbbb + +/ (?: [\040\t] | ( +(?: [^\\x80-\xff\n\015()] | \ [^\x80-\xff] | ( (?: [^\\x80-\xff\n\015()] | \ [^\x80-\xff] )* ) )* +) )* # optional leading comment +(?: (?: +[^(\040)<>@,;:".\[]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\[]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # initial word +(?: (?: [\040\t] | ( +(?: [^\\x80-\xff\n\015()] | \ [^\x80-\xff] | ( (?: [^\\x80-\xff\n\015()] | \ [^\x80-\xff] )* ) )* +) )* . (?: [\040\t] | ( +(?: [^\\x80-\xff\n\015()] | \ [^\x80-\xff] | ( (?: [^\\x80-\xff\n\015()] | \ [^\x80-\xff] )* ) )* +) )* (?: +[^(\040)<>@,;:".\[]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\[]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) )* # further okay, if led by a period +(?: [\040\t] | ( +(?: [^\\x80-\xff\n\015()] | \ [^\x80-\xff] | ( (?: [^\\x80-\xff\n\015()] | \ [^\x80-\xff] )* ) )* +) )* @ (?: [\040\t] | ( +(?: [^\\x80-\xff\n\015()] | \ [^\x80-\xff] | ( (?: [^\\x80-\xff\n\015()] | \ [^\x80-\xff] )* ) )* +) )* (?: +[^(\040)<>@,;:".\[]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\[]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| [ # [ +(?: [^\\x80-\xff\n\015[]] | \ [^\x80-\xff] )* # stuff +] # ] +) # initial subdomain +(?: # +(?: [\040\t] | ( +(?: [^\\x80-\xff\n\015()] | \ [^\x80-\xff] | ( (?: [^\\x80-\xff\n\015()] | \ [^\x80-\xff] )* ) )* +) )* . # if led by a period... +(?: [\040\t] | ( +(?: [^\\x80-\xff\n\015()] | \ [^\x80-\xff] | ( (?: [^\\x80-\xff\n\015()] | \ [^\x80-\xff] )* ) )* +) )* (?: +[^(\040)<>@,;:".\[]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\[]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| [ # [ +(?: [^\\x80-\xff\n\015[]] | \ [^\x80-\xff] )* # stuff +] # ] +) # ...further okay +)* +# address +| # or +(?: +[^(\040)<>@,;:".\[]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\[]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # one word, optionally followed by.... +(?: +[^()<>@,;:".\[]\x80-\xff\000-\010\012-\037] | # atom and space parts, or... +( +(?: [^\\x80-\xff\n\015()] | \ [^\x80-\xff] | ( (?: [^\\x80-\xff\n\015()] | \ [^\x80-\xff] )* ) )* +) | # comments, or... + +" (?: # opening quote... +[^\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +# quoted strings +)* +< (?: [\040\t] | ( +(?: [^\\x80-\xff\n\015()] | \ [^\x80-\xff] | ( (?: [^\\x80-\xff\n\015()] | \ [^\x80-\xff] )* ) )* +) )* # leading < +(?: @ (?: [\040\t] | ( +(?: [^\\x80-\xff\n\015()] | \ [^\x80-\xff] | ( (?: [^\\x80-\xff\n\015()] | \ [^\x80-\xff] )* ) )* +) )* (?: +[^(\040)<>@,;:".\[]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\[]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| [ # [ +(?: [^\\x80-\xff\n\015[]] | \ [^\x80-\xff] )* # stuff +] # ] +) # initial subdomain +(?: # +(?: [\040\t] | ( +(?: [^\\x80-\xff\n\015()] | \ [^\x80-\xff] | ( (?: [^\\x80-\xff\n\015()] | \ [^\x80-\xff] )* ) )* +) )* . # if led by a period... +(?: [\040\t] | ( +(?: [^\\x80-\xff\n\015()] | \ [^\x80-\xff] | ( (?: [^\\x80-\xff\n\015()] | \ [^\x80-\xff] )* ) )* +) )* (?: +[^(\040)<>@,;:".\[]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\[]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| [ # [ +(?: [^\\x80-\xff\n\015[]] | \ [^\x80-\xff] )* # stuff +] # ] +) # ...further okay +)* + +(?: (?: [\040\t] | ( +(?: [^\\x80-\xff\n\015()] | \ [^\x80-\xff] | ( (?: [^\\x80-\xff\n\015()] | \ [^\x80-\xff] )* ) )* +) )* , (?: [\040\t] | ( +(?: [^\\x80-\xff\n\015()] | \ [^\x80-\xff] | ( (?: [^\\x80-\xff\n\015()] | \ [^\x80-\xff] )* ) )* +) )* @ (?: [\040\t] | ( +(?: [^\\x80-\xff\n\015()] | \ [^\x80-\xff] | ( (?: [^\\x80-\xff\n\015()] | \ [^\x80-\xff] )* ) )* +) )* (?: +[^(\040)<>@,;:".\[]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\[]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| [ # [ +(?: [^\\x80-\xff\n\015[]] | \ [^\x80-\xff] )* # stuff +] # ] +) # initial subdomain +(?: # +(?: [\040\t] | ( +(?: [^\\x80-\xff\n\015()] | \ [^\x80-\xff] | ( (?: [^\\x80-\xff\n\015()] | \ [^\x80-\xff] )* ) )* +) )* . # if led by a period... +(?: [\040\t] | ( +(?: [^\\x80-\xff\n\015()] | \ [^\x80-\xff] | ( (?: [^\\x80-\xff\n\015()] | \ [^\x80-\xff] )* ) )* +) )* (?: +[^(\040)<>@,;:".\[]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\[]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| [ # [ +(?: [^\\x80-\xff\n\015[]] | \ [^\x80-\xff] )* # stuff +] # ] +) # ...further okay +)* +)* # further okay, if led by comma +: # closing colon +(?: [\040\t] | ( +(?: [^\\x80-\xff\n\015()] | \ [^\x80-\xff] | ( (?: [^\\x80-\xff\n\015()] | \ [^\x80-\xff] )* ) )* +) )* )? # optional route +(?: +[^(\040)<>@,;:".\[]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\[]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # initial word +(?: (?: [\040\t] | ( +(?: [^\\x80-\xff\n\015()] | \ [^\x80-\xff] | ( (?: [^\\x80-\xff\n\015()] | \ [^\x80-\xff] )* ) )* +) )* . (?: [\040\t] | ( +(?: [^\\x80-\xff\n\015()] | \ [^\x80-\xff] | ( (?: [^\\x80-\xff\n\015()] | \ [^\x80-\xff] )* ) )* +) )* (?: +[^(\040)<>@,;:".\[]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\[]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) )* # further okay, if led by a period +(?: [\040\t] | ( +(?: [^\\x80-\xff\n\015()] | \ [^\x80-\xff] | ( (?: [^\\x80-\xff\n\015()] | \ [^\x80-\xff] )* ) )* +) )* @ (?: [\040\t] | ( +(?: [^\\x80-\xff\n\015()] | \ [^\x80-\xff] | ( (?: [^\\x80-\xff\n\015()] | \ [^\x80-\xff] )* ) )* +) )* (?: +[^(\040)<>@,;:".\[]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\[]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| [ # [ +(?: [^\\x80-\xff\n\015[]] | \ [^\x80-\xff] )* # stuff +] # ] +) # initial subdomain +(?: # +(?: [\040\t] | ( +(?: [^\\x80-\xff\n\015()] | \ [^\x80-\xff] | ( (?: [^\\x80-\xff\n\015()] | \ [^\x80-\xff] )* ) )* +) )* . # if led by a period... +(?: [\040\t] | ( +(?: [^\\x80-\xff\n\015()] | \ [^\x80-\xff] | ( (?: [^\\x80-\xff\n\015()] | \ [^\x80-\xff] )* ) )* +) )* (?: +[^(\040)<>@,;:".\[]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\[]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| [ # [ +(?: [^\\x80-\xff\n\015[]] | \ [^\x80-\xff] )* # stuff +] # ] +) # ...further okay +)* +# address spec +(?: [\040\t] | ( +(?: [^\\x80-\xff\n\015()] | \ [^\x80-\xff] | ( (?: [^\\x80-\xff\n\015()] | \ [^\x80-\xff] )* ) )* +) )* > # trailing > +# name and address +) (?: [\040\t] | ( +(?: [^\\x80-\xff\n\015()] | \ [^\x80-\xff] | ( (?: [^\\x80-\xff\n\015()] | \ [^\x80-\xff] )* ) )* +) )* # optional trailing comment +/x + Alan Other <user@dom.ain> + <user@dom.ain> + user@dom.ain + "A. Other" <user.1234@dom.ain> (a comment) + A. Other <user.1234@dom.ain> (a comment) + "/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/"@x400-re.lay + A missing angle <user@some.where + The quick brown fox + +/[\040\t]* # Nab whitespace. +(?: +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \ [^\x80-\xff] | +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: \ [^\x80-\xff] [^\\x80-\xff\n\015()] * )* # (special normal*)* +) # ) +) # special +[^\\x80-\xff\n\015()] * # normal* +)* # )* +) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional leading comment +(?: +(?: +[^(\040)<>@,;:".\[]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\[]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\x80-\xff\n\015"] * # normal +(?: \ [^\x80-\xff] [^\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \ [^\x80-\xff] | +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: \ [^\x80-\xff] [^\\x80-\xff\n\015()] * )* # (special normal*)* +) # ) +) # special +[^\\x80-\xff\n\015()] * # normal* +)* # )* +) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +. +[\040\t]* # Nab whitespace. +(?: +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \ [^\x80-\xff] | +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: \ [^\x80-\xff] [^\\x80-\xff\n\015()] * )* # (special normal*)* +) # ) +) # special +[^\\x80-\xff\n\015()] * # normal* +)* # )* +) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\[]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\[]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\x80-\xff\n\015"] * # normal +(?: \ [^\x80-\xff] [^\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \ [^\x80-\xff] | +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: \ [^\x80-\xff] [^\\x80-\xff\n\015()] * )* # (special normal*)* +) # ) +) # special +[^\\x80-\xff\n\015()] * # normal* +)* # )* +) # ) +[\040\t]* )* # If comment found, allow more spaces. +# additional words +)* +@ +[\040\t]* # Nab whitespace. +(?: +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \ [^\x80-\xff] | +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: \ [^\x80-\xff] [^\\x80-\xff\n\015()] * )* # (special normal*)* +) # ) +) # special +[^\\x80-\xff\n\015()] * # normal* +)* # )* +) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\[]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\[]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +[ # [ +(?: [^\\x80-\xff\n\015[]] | \ [^\x80-\xff] )* # stuff +] # ] +) +[\040\t]* # Nab whitespace. +(?: +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \ [^\x80-\xff] | +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: \ [^\x80-\xff] [^\\x80-\xff\n\015()] * )* # (special normal*)* +) # ) +) # special +[^\\x80-\xff\n\015()] * # normal* +)* # )* +) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +. +[\040\t]* # Nab whitespace. +(?: +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \ [^\x80-\xff] | +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: \ [^\x80-\xff] [^\\x80-\xff\n\015()] * )* # (special normal*)* +) # ) +) # special +[^\\x80-\xff\n\015()] * # normal* +)* # )* +) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\[]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\[]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +[ # [ +(?: [^\\x80-\xff\n\015[]] | \ [^\x80-\xff] )* # stuff +] # ] +) +[\040\t]* # Nab whitespace. +(?: +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \ [^\x80-\xff] | +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: \ [^\x80-\xff] [^\\x80-\xff\n\015()] * )* # (special normal*)* +) # ) +) # special +[^\\x80-\xff\n\015()] * # normal* +)* # )* +) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +# address +| # or +(?: +[^(\040)<>@,;:".\[]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\[]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\x80-\xff\n\015"] * # normal +(?: \ [^\x80-\xff] [^\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +# leading word +[^()<>@,;:".\[]\x80-\xff\000-\010\012-\037] * # "normal" atoms and or spaces +(?: +(?: +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \ [^\x80-\xff] | +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: \ [^\x80-\xff] [^\\x80-\xff\n\015()] * )* # (special normal*)* +) # ) +) # special +[^\\x80-\xff\n\015()] * # normal* +)* # )* +) # ) +| +" # " +[^\\x80-\xff\n\015"] * # normal +(?: \ [^\x80-\xff] [^\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +) # "special" comment or quoted string +[^()<>@,;:".\[]\x80-\xff\000-\010\012-\037] * # more "normal" +)* +< +[\040\t]* # Nab whitespace. +(?: +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \ [^\x80-\xff] | +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: \ [^\x80-\xff] [^\\x80-\xff\n\015()] * )* # (special normal*)* +) # ) +) # special +[^\\x80-\xff\n\015()] * # normal* +)* # )* +) # ) +[\040\t]* )* # If comment found, allow more spaces. +# < +(?: +@ +[\040\t]* # Nab whitespace. +(?: +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \ [^\x80-\xff] | +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: \ [^\x80-\xff] [^\\x80-\xff\n\015()] * )* # (special normal*)* +) # ) +) # special +[^\\x80-\xff\n\015()] * # normal* +)* # )* +) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\[]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\[]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +[ # [ +(?: [^\\x80-\xff\n\015[]] | \ [^\x80-\xff] )* # stuff +] # ] +) +[\040\t]* # Nab whitespace. +(?: +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \ [^\x80-\xff] | +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: \ [^\x80-\xff] [^\\x80-\xff\n\015()] * )* # (special normal*)* +) # ) +) # special +[^\\x80-\xff\n\015()] * # normal* +)* # )* +) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +. +[\040\t]* # Nab whitespace. +(?: +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \ [^\x80-\xff] | +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: \ [^\x80-\xff] [^\\x80-\xff\n\015()] * )* # (special normal*)* +) # ) +) # special +[^\\x80-\xff\n\015()] * # normal* +)* # )* +) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\[]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\[]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +[ # [ +(?: [^\\x80-\xff\n\015[]] | \ [^\x80-\xff] )* # stuff +] # ] +) +[\040\t]* # Nab whitespace. +(?: +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \ [^\x80-\xff] | +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: \ [^\x80-\xff] [^\\x80-\xff\n\015()] * )* # (special normal*)* +) # ) +) # special +[^\\x80-\xff\n\015()] * # normal* +)* # )* +) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +(?: , +[\040\t]* # Nab whitespace. +(?: +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \ [^\x80-\xff] | +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: \ [^\x80-\xff] [^\\x80-\xff\n\015()] * )* # (special normal*)* +) # ) +) # special +[^\\x80-\xff\n\015()] * # normal* +)* # )* +) # ) +[\040\t]* )* # If comment found, allow more spaces. +@ +[\040\t]* # Nab whitespace. +(?: +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \ [^\x80-\xff] | +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: \ [^\x80-\xff] [^\\x80-\xff\n\015()] * )* # (special normal*)* +) # ) +) # special +[^\\x80-\xff\n\015()] * # normal* +)* # )* +) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\[]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\[]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +[ # [ +(?: [^\\x80-\xff\n\015[]] | \ [^\x80-\xff] )* # stuff +] # ] +) +[\040\t]* # Nab whitespace. +(?: +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \ [^\x80-\xff] | +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: \ [^\x80-\xff] [^\\x80-\xff\n\015()] * )* # (special normal*)* +) # ) +) # special +[^\\x80-\xff\n\015()] * # normal* +)* # )* +) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +. +[\040\t]* # Nab whitespace. +(?: +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \ [^\x80-\xff] | +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: \ [^\x80-\xff] [^\\x80-\xff\n\015()] * )* # (special normal*)* +) # ) +) # special +[^\\x80-\xff\n\015()] * # normal* +)* # )* +) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\[]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\[]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +[ # [ +(?: [^\\x80-\xff\n\015[]] | \ [^\x80-\xff] )* # stuff +] # ] +) +[\040\t]* # Nab whitespace. +(?: +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \ [^\x80-\xff] | +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: \ [^\x80-\xff] [^\\x80-\xff\n\015()] * )* # (special normal*)* +) # ) +) # special +[^\\x80-\xff\n\015()] * # normal* +)* # )* +) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +)* # additional domains +: +[\040\t]* # Nab whitespace. +(?: +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \ [^\x80-\xff] | +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: \ [^\x80-\xff] [^\\x80-\xff\n\015()] * )* # (special normal*)* +) # ) +) # special +[^\\x80-\xff\n\015()] * # normal* +)* # )* +) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)? # optional route +(?: +[^(\040)<>@,;:".\[]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\[]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\x80-\xff\n\015"] * # normal +(?: \ [^\x80-\xff] [^\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \ [^\x80-\xff] | +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: \ [^\x80-\xff] [^\\x80-\xff\n\015()] * )* # (special normal*)* +) # ) +) # special +[^\\x80-\xff\n\015()] * # normal* +)* # )* +) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +. +[\040\t]* # Nab whitespace. +(?: +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \ [^\x80-\xff] | +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: \ [^\x80-\xff] [^\\x80-\xff\n\015()] * )* # (special normal*)* +) # ) +) # special +[^\\x80-\xff\n\015()] * # normal* +)* # )* +) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\[]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\[]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\x80-\xff\n\015"] * # normal +(?: \ [^\x80-\xff] [^\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \ [^\x80-\xff] | +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: \ [^\x80-\xff] [^\\x80-\xff\n\015()] * )* # (special normal*)* +) # ) +) # special +[^\\x80-\xff\n\015()] * # normal* +)* # )* +) # ) +[\040\t]* )* # If comment found, allow more spaces. +# additional words +)* +@ +[\040\t]* # Nab whitespace. +(?: +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \ [^\x80-\xff] | +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: \ [^\x80-\xff] [^\\x80-\xff\n\015()] * )* # (special normal*)* +) # ) +) # special +[^\\x80-\xff\n\015()] * # normal* +)* # )* +) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\[]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\[]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +[ # [ +(?: [^\\x80-\xff\n\015[]] | \ [^\x80-\xff] )* # stuff +] # ] +) +[\040\t]* # Nab whitespace. +(?: +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \ [^\x80-\xff] | +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: \ [^\x80-\xff] [^\\x80-\xff\n\015()] * )* # (special normal*)* +) # ) +) # special +[^\\x80-\xff\n\015()] * # normal* +)* # )* +) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +. +[\040\t]* # Nab whitespace. +(?: +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \ [^\x80-\xff] | +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: \ [^\x80-\xff] [^\\x80-\xff\n\015()] * )* # (special normal*)* +) # ) +) # special +[^\\x80-\xff\n\015()] * # normal* +)* # )* +) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\[]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\[]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +[ # [ +(?: [^\\x80-\xff\n\015[]] | \ [^\x80-\xff] )* # stuff +] # ] +) +[\040\t]* # Nab whitespace. +(?: +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \ [^\x80-\xff] | +( # ( +[^\\x80-\xff\n\015()] * # normal* +(?: \ [^\x80-\xff] [^\\x80-\xff\n\015()] * )* # (special normal*)* +) # ) +) # special +[^\\x80-\xff\n\015()] * # normal* +)* # )* +) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +# address spec +> # > +# name and address +) +/x + Alan Other <user@dom.ain> + <user@dom.ain> + user@dom.ain + "A. Other" <user.1234@dom.ain> (a comment) + A. Other <user.1234@dom.ain> (a comment) + "/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/"@x400-re.lay + A missing angle <user@some.where + The quick brown fox + +/abc\0def\00pqr\000xyz\0000AB/ + abc\0def\00pqr\000xyz\0000AB + abc456 abc\0def\00pqr\000xyz\0000ABCDE + +/abc\x0def\x00pqr\x000xyz\x0000AB/ + abc\x0def\x00pqr\x000xyz\x0000AB + abc456 abc\x0def\x00pqr\x000xyz\x0000ABCDE + +/^[\000-\037]/ + \0A + \01B + \037C + +/\0*/ + \0\0\0\0 + +/A\x0{2,3}Z/ + The A\x0\x0Z + An A\0\x0\0Z + A\0Z + A\0\x0\0\x0Z + +/^(cow|)\1(bell)/ + cowcowbell + bell + cowbell + +/^\s/ + \040abc + \x0cabc + \nabc + \rabc + \tabc + abc + +/^a b + c/x + abc + +/^(a|)\1*b/ + ab + aaaab + b + acb + +/^(a|)\1+b/ + aab + aaaab + b + ab + +/^(a|)\1?b/ + ab + aab + b + acb + +/^(a|)\1{2}b/ + aaab + b + ab + aab + aaaab + +/^(a|)\1{2,3}b/ + aaab + aaaab + b + ab + aab + aaaaab + +/ab{1,3}bc/ + abbbbc + abbbc + abbc + abc + abbbbbc + +/([^.]*).([^:]*):[T ]+(.*)/ + track1.title:TBlah blah blah + +/([^.]*).([^:]*):[T ]+(.*)/i + track1.title:TBlah blah blah + +/([^.]*).([^:]*):[t ]+(.*)/i + track1.title:TBlah blah blah + +/^[W-c]+$/ + WXY_^abc + wxy + +/^[W-c]+$/i + WXY_^abc + wxy_^ABC + +/^[\x3f-\x5F]+$/i + WXY_^abc + wxy_^ABC + +/^abc$/m + abc + qqq\nabc + abc\nzzz + qqq\nabc\nzzz + +/^abc$/ + abc + qqq\nabc + abc\nzzz + qqq\nabc\nzzz + +/\Aabc\Z/m + abc + abc\n + qqq\nabc + abc\nzzz + qqq\nabc\nzzz + +/\A(.)*\Z/s + abc\ndef + +/\A(.)*\Z/m + abc\ndef + +/(?:b)|(?::+)/ + b::c + c::b + +/[-az]+/ + az- + b + +/[az-]+/ + za- + b + +/[a-z]+/ + a-z + b + +/[a-z]+/ + abcdxyz + +/[\d-]+/ + 12-34 + aaa + +/[\d-z]+/ + 12-34z + aaa + +/\x5c/ + \ + +/\x20Z/ + the Zoo + Zulu + +/(abc)\1/i + abcabc + ABCabc + abcABC + +/ab{3cd/ + ab{3cd + +/ab{3,cd/ + ab{3,cd + +/ab{3,4a}cd/ + ab{3,4a}cd + +/{4,5a}bc/ + {4,5a}bc + +/^a.b/ + a\rb + a\nb + +/abc$/ + abc + abc\n + abc\ndef + +/(abc)\123/ + abc\x53 + +/(abc)\223/ + abc\x93 + +/(abc)\323/ + abc\xd3 + +/(abc)\500/ + abc\x40 + abc\100 + +/(abc)\5000/ + abc\x400 + abc\x40\x30 + abc\1000 + abc\100\x30 + abc\100\060 + abc\100\60 + +/abc\81/ + abc\081 + abc\0\x38\x31 + +/abc\91/ + abc\091 + abc\0\x39\x31 + +/(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)(l)\12\123/ + abcdefghijkllS + +/(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)\12\123/ + abcdefghijk\12S + +/ab\gdef/ + abgdef + +/a{0}bc/ + bc + +/(a|(bc)){0,0}?xyz/ + xyz + +/abc[\10]de/ + abc\010de + +/abc[\1]de/ + abc\1de + +/(abc)[\1]de/ + abc\1de + +/a.b(?s)/ + a\nb + +/^([^a])([^\b])([^c]*)([^d]{3,4})/ + baNOTccccd + baNOTcccd + baNOTccd + bacccd + anything + b\bc + baccd + +/[^a]/ + Abc + +/[^a]/i + Abc + +/[^a]+/ + AAAaAbc + +/[^a]+/i + AAAaAbc + +/[^a]+/ + bbb\nccc + +/[^k]$/ + abc + abk + +/[^k]{2,3}$/ + abc + kbc + kabc + abk + akb + akk + +/^\d{8,}@.+[^k]$/ + 12345678@a.b.c.d + 123456789@x.y.z + 12345678@x.y.uk + 1234567@a.b.c.d + +/(a)\1{8,}/ + aaaaaaaaa + aaaaaaaaaa + aaaaaaa + +/[^a]/ + aaaabcd + aaAabcd + +/[^a]/i + aaaabcd + aaAabcd + +/[^az]/ + aaaabcd + aaAabcd + +/[^az]/i + aaaabcd + aaAabcd + +/\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377/ + \000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377 + +/P[^*]TAIRE[^*]{1,6}?LL/ + xxxxxxxxxxxPSTAIREISLLxxxxxxxxx + +/P[^*]TAIRE[^*]{1,}?LL/ + xxxxxxxxxxxPSTAIREISLLxxxxxxxxx + +/(.\d\d[1-9]?)\d+/ + 1.230003938 + 1.875000282 + 1.235 + +/(.\d\d((?=0)|\d(?=\d)))/ + 1.230003938 + 1.875000282 + 1.235 + +/a(?)b/ + ab + +/\b(foo)\s+(\w+)/i + Food is on the foo table + +/foo(.*)bar/ + The food is under the bar in the barn. + +/foo(.*?)bar/ + The food is under the bar in the barn. + +/(.*)(\d*)/ + I have 2 numbers: 53147 + +/(.*)(\d+)/ + I have 2 numbers: 53147 + +/(.*?)(\d*)/ + I have 2 numbers: 53147 + +/(.*?)(\d+)/ + I have 2 numbers: 53147 + +/(.*)(\d+)$/ + I have 2 numbers: 53147 + +/(.*?)(\d+)$/ + I have 2 numbers: 53147 + +/(.*)\b(\d+)$/ + I have 2 numbers: 53147 + +/(.*\D)(\d+)$/ + I have 2 numbers: 53147 + +/^\D*(?!123)/ + ABC123 + +/^(\D*)(?=\d)(?!123)/ + ABC445 + ABC123 + +/^[W-]46]/ + W46]789 + -46]789 + Wall + Zebra + 42 + [abcd] + ]abcd[ + +/^[W-]46]/ + W46]789 + Wall + Zebra + Xylophone + 42 + [abcd] + ]abcd[ + \backslash + -46]789 + well + +/\d\d/\d\d/\d\d\d\d/ + 01/01/2000 + +/word (?:[a-zA-Z0-9]+ ){0,10}otherword/ + word cat dog elephant mussel cow horse canary baboon snake shark otherword + word cat dog elephant mussel cow horse canary baboon snake shark + +/word (?:[a-zA-Z0-9]+ ){0,300}otherword/ + word cat dog elephant mussel cow horse canary baboon snake shark the quick brown fox and the lazy dog and several other words getting close to thirty by now I hope + +/^(a){0,0}/ + bcd + abc + aab + +/^(a){0,1}/ + bcd + abc + aab + +/^(a){0,2}/ + bcd + abc + aab + +/^(a){0,3}/ + bcd + abc + aab + aaa + +/^(a){0,}/ + bcd + abc + aab + aaa + aaaaaaaa + +/^(a){1,1}/ + bcd + abc + aab + +/^(a){1,2}/ + bcd + abc + aab + +/^(a){1,3}/ + bcd + abc + aab + aaa + +/^(a){1,}/ + bcd + abc + aab + aaa + aaaaaaaa + +/.*.gif/ + borfle\nbib.gif\nno + +/.{0,}.gif/ + borfle\nbib.gif\nno + +/.*.gif/m + borfle\nbib.gif\nno + +/.*.gif/s + borfle\nbib.gif\nno + +/.*.gif/ms + borfle\nbib.gif\nno + +/.*$/ + borfle\nbib.gif\nno + +/.*$/m + borfle\nbib.gif\nno + +/.*$/s + borfle\nbib.gif\nno + +/.*$/ms + borfle\nbib.gif\nno + +/.*$/ + borfle\nbib.gif\nno\n + +/.*$/m + borfle\nbib.gif\nno\n + +/.*$/s + borfle\nbib.gif\nno\n + +/.*$/ms + borfle\nbib.gif\nno\n + +/(.*X|^B)/ + abcde\n1234Xyz + BarFoo + abcde\nBar + +/(.*X|^B)/m + abcde\n1234Xyz + BarFoo + abcde\nBar + +/(.*X|^B)/s + abcde\n1234Xyz + BarFoo + abcde\nBar + +/(.*X|^B)/ms + abcde\n1234Xyz + BarFoo + abcde\nBar + +/(?s)(.*X|^B)/ + abcde\n1234Xyz + BarFoo + abcde\nBar + +/(?s:.*X|^B)/ + abcde\n1234Xyz + BarFoo + abcde\nBar + +/^.*B/ + abc\nB + +/(?s)^.*B/ + abc\nB + +/(?m)^.*B/ + abc\nB + +/(?ms)^.*B/ + abc\nB + +/(?ms)^B/ + abc\nB + +/(?s)B$/ + B\n + +/^[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]/ + 123456654321 + +/^\d\d\d\d\d\d\d\d\d\d\d\d/ + 123456654321 + +/^[\d][\d][\d][\d][\d][\d][\d][\d][\d][\d][\d][\d]/ + 123456654321 + +/^[abc]{12}/ + abcabcabcabc + +/^[a-c]{12}/ + abcabcabcabc + +/^(a|b|c){12}/ + abcabcabcabc + +/^[abcdefghijklmnopqrstuvwxy0123456789]/ + n + z + +/abcde{0,0}/ + abcd + abce + +/ab[cd]{0,0}e/ + abe + abcde + +/ab(c){0,0}d/ + abd + abcd + +/a(b*)/ + a + ab + abbbb + bbbbb + +/ab\d{0}e/ + abe + ab1e + +/"([^\"]+|\.)*"/ + the "quick" brown fox + "the \"quick\" brown fox" + +/.*?/g+ + abc + +/\b/g+ + abc + +/\b/+g + abc + +//g + abc + +/<tr([\w\W\s\d][^<>]{0,})><TD([\w\W\s\d][^<>]{0,})>([\d]{0,}.)(.*)((<BR>([\w\W\s\d][^<>]{0,})|[\s]{0,}))</a></TD><TD([\w\W\s\d][^<>]{0,})>([\w\W\s\d][^<>]{0,})</TD><TD([\w\W\s\d][^<>]{0,})>([\w\W\s\d][^<>]{0,})</TD></TR>/is + <TR BGCOLOR='#DBE9E9'><TD align=left valign=top>43.<a href='joblist.cfm?JobID=94 6735&Keyword='>Word Processor<BR>(N-1286)</a></TD><TD align=left valign=top>Lega lstaff.com</TD><TD align=left valign=top>CA - Statewide</TD></TR> + +/a[^a]b/ + acb + a\nb + +/a.b/ + acb + a\nb + +/a[^a]b/s + acb + a\nb + +/a.b/s + acb + a\nb + +/^(b+?|a){1,2}?c/ + bac + bbac + bbbac + bbbbac + bbbbbac + +/^(b+|a){1,2}?c/ + bac + bbac + bbbac + bbbbac + bbbbbac + +/(?!\A)x/m + x\nb\n + a\bx\n + +/\x0{ab}/ + \0{ab} + +/(A|B)*?CD/ + CD + +/(A|B)*CD/ + CD + +/(AB)*?\1/ + ABABAB + +/(AB)*\1/ + ABABAB + +/(/ + doesn't matter + +/(x)\2/ + doesn't matter + +/((a{0,5}){0,5}){0,5}[c]/ + aaaaaaaaaac + aaaaaaaaaa + +/((a{0,5}){0,5})*[c]/ + aaaaaaaaaac + aaaaaaaaaa + +/(\b)*a/ + a + +/(a)*b/ + ab + +/(a|)*b/ + ab + b + x + +/^(?:(a)|(b))*\1\2$/ + abab + +/abc[^x]def/ + abcxabcydef + +/^(a|\1x)*$/ + aax + aaxa + +// + @{['']} + +/^(?:(a)|(b))*$/ + ab + +/[\0]/ + a + \0 + +/[\1]/ + a + \1 + +/\10()()()()()()()()()/ + doesn't matter + +/\10()()()()()()()()()()/ + a + +/a(?<)b/ + ab + +/[]/ + doesn't matter + +/[]/ + doesn't matter + +/()/ + a + +/[\x]/ + x + \0 + +/((a)*)*/ + a + +/()a\1/ + a + +/a\1()/ + a + +/a(?i)a(?-i)a/ + aaa + aAa + aAA + +/a(?i)a(?-i)a(?i)a(?-i)a/ + aaaaa + aAaAa + AaAaA + aAAAa + AaaaA + AAAAA + aaAAA + AAaaa + +/\x/ + a + X + \0 + +/[a-c-e]/ + a + b + d + - + +/[b-\d]/ + b + c + d + - + 1 + +/[\d-f]/ + d + e + f + - + 1 + +/[/ + doesn't matter + +/]/ + ] + a + +/[]/ + doesn't matter + +/[-a-c]/ + - + a + b + d + +/[a-c-]/ + - + a + b + d + +/[-]/ + a + - + +/[--]/ + a + - + +/[---]/ + a + - + +/[--b]/ + - + a + c + +/[b--]/ + doesn't matter + +/a{/ + a{ + +/a{}/ + a{} + +/a{3/ + a{3 + +/a{3,/ + a{3, + +/a{3, 3}/ + a{3,3} + a{3, 3} + aaa + +/a{3, 3}/x + a{3,3} + a{3, 3} + aaa + +/a{3, }/ + a{3,} + a{3, } + aaa + +/a{3, }/x + a{3,} + a{3, } + aaa + +/\x x/ + \0 x + \0x + +/\x x/x + \0 x + \0x + +/\x 3/ + \0003 + \000 3 + x3 + x 3 + +/\x 3/x + \0003 + \000 3 + x3 + x 3 + +/^a{ 1}$/ + a + a{ 1} + a{1} + +/^a{ 1}$/x + a + a{ 1} + a{1} + +/{}/ + {} + a + +/{1}/ + doesn't matter + +/*/ + doesn't matter + +/|/ + x + +/\0000/ + \0000 + +/a(?<)b/ + ab + +/a(?i)b/ + ab + aB + Ab + +/a(?i=a)/ + doesn't matter + +/a(?<=a){3000}a/ + aa + xa + ax + +/a(?!=a){3000}a/ + aa + ax + xa + +/a(){3000}a/ + aa + ax + xa + +/a(?:){3000}a/ + aa + ax + +/a(?<=a)*a/ + aa + ax + xa + +/a(?!=a)*a/ + aa + ax + xa + +/a()*a/ + aa + ax + xa + +/a(?:)*a/ + aa + ax + xa + +/x(?<=a)*a/ + aa + xa + ax + +/a(?<=(a))*\1/ + aa + +/a(?<=(a))*?\1/ + aa + +/(?=(a)\1)*aa/ + aa + +/^((a|b){2,5}){2}$/ + aaaaabbbbb + +/^(b*|ba){1,2}bc/ + babc + bbabc + bababc + bababbc + babababc + +/^a{4,5}(?:c|a)c$/ + aaaaac + aaaaaac + +/^(a|){4,5}(?:c|a)c$/ + aaaaac + aaaaaac + +/(?m:^).abc$/ + eeexabc + eee\nxabc + +/(?m:^)abc/ + abc + \nabc + + +/^abc/ + abc + \nabc + +/\Aabc/ + abc + \nabc + +/(?<!bar)foo/ + foo + catfood + arfootle + rfoosh + barfoo + towbarfoo + +/\w{3}(?<!bar)foo/ + catfood + foo + barfoo + towbarfoo + +/(?<=(foo)a)bar/ + fooabar + bar + foobbar + +/\Aabc\z/m + abc + abc\n + qqq\nabc + abc\nzzz + qqq\nabc\nzzz + +"(?>.*/)foo" + /this/is/a/very/long/line/in/deed/with/very/many/slashes/in/it/you/see/ + +"(?>.*/)foo" + /this/is/a/very/long/line/in/deed/with/very/many/slashes/in/and/foo + +/(?>(.\d\d[1-9]?))\d+/ + 1.230003938 + 1.875000282 + 1.235 + +/^((?>\w+)|(?>\s+))*$/ + now is the time for all good men to come to the aid of the party + this is not a line with only words and spaces! + +/(\d+)(\w)/ + 12345a + 12345+ + +/((?>\d+))(\w)/ + 12345a + 12345+ + +/(?>a+)b/ + aaab + +/((?>a+)b)/ + aaab + +/(?>(a+))b/ + aaab + +/(?>b)+/ + aaabbbccc + +/(?>a+|b+|c+)*c/ + aaabbbbccccd + +/((?>[^()]+)|([^()]*))+/ + ((abc(ade)ufh()()x + +/(((?>[^()]+)|([^()]+))+)/ + (abc) + (abc(def)xyz) + ((()aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + +/a(?-i)b/i + ab + Ab + aB + AB + +/(a (?x)b c)d e/ + a bcd e + a b cd e + abcd e + a bcde + +/(a b(?x)c d (?-x)e f)/ + a bcde f + abcdef + +/(a(?i)b)c/ + abc + aBc + abC + aBC + Abc + ABc + ABC + AbC + +/a(?i:b)c/ + abc + aBc + ABC + abC + aBC + +/a(?i:b)*c/ + aBc + aBBc + aBC + aBBC + +/a(?=b(?i)c)\w\wd/ + abcd + abCd + aBCd + abcD + +/(?s-i:more.*than).*million/i + more than million + more than MILLION + more \n than Million + MORE THAN MILLION + more \n than \n million + +/(?:(?s-i)more.*than).*million/i + more than million + more than MILLION + more \n than Million + MORE THAN MILLION + more \n than \n million + +/(?>a(?i)b+)+c/ + abc + aBbc + aBBc + Abc + abAb + abbC + +/(?=a(?i)b)\w\wc/ + abc + aBc + Ab + abC + aBC + +/(?<=a(?i)b)(\w\w)c/ + abxxc + aBxxc + Abxxc + ABxxc + abxxC + +/(?:(a)|b)(?(1)A|B)/ + aA + bB + aB + bA + +/^(a)?(?(1)a|b)+$/ + aa + b + bb + ab + +/^(?(?=abc)\w{3}:|\d\d)$/ + abc: + 12 + 123 + xyz + +/^(?(?!abc)\d\d|\w{3}:)$/ + abc: + 12 + 123 + xyz + +/(?(?<=foo)bar|cat)/ + foobar + cat + fcat + focat + foocat + +/(?(?<!foo)cat|bar)/ + foobar + cat + fcat + focat + foocat + +/( ( )? [^()]+ (?(1) ) |) /x + abcd + (abcd) + the quick (abcd) fox + (abcd + +/( ( )? [^()]+ (?(1) ) ) /x + abcd + (abcd) + the quick (abcd) fox + (abcd + +/^(?(2)a|(1)(2))+$/ + 12 + 12a + 12aa + 1234 + +/((?i)blah)\s+\1/ + blah blah + BLAH BLAH + Blah Blah + blaH blaH + blah BLAH + Blah blah + blaH blah + +/((?i)blah)\s+(?i:\1)/ + blah blah + BLAH BLAH + Blah Blah + blaH blaH + blah BLAH + Blah blah + blaH blah + +/(?>a*)*/ + a + aa + aaaa + +/(abc|)+/ + abc + abcabc + abcabcabc + xyz + +/([a]*)*/ + a + aaaaa + +/([ab]*)*/ + a + b + ababab + aaaabcde + bbbb + +/([^a]*)*/ + b + bbbb + aaa + +/([^ab]*)*/ + cccc + abab + +/([a]*?)*/ + a + aaaa + +/([ab]*?)*/ + a + b + abab + baba + +/([^a]*?)*/ + b + bbbb + aaa + +/([^ab]*?)*/ + c + cccc + baba + +/(?>a*)*/ + a + aaabcde + +/((?>a*))*/ + aaaaa + aabbaa + +/((?>a*?))*/ + aaaaa + aabbaa + +/(?(?=[^a-z]+[a-z]) \d{2}-[a-z]{3}-\d{2} | \d{2}-\d{2}-\d{2} ) /x + 12-sep-98 + 12-09-98 + sep-12-98 + +/(?<=(foo))bar\1/ + foobarfoo + foobarfootling + foobar + barfoo + +/(?i:saturday|sunday)/ + saturday + sunday + Saturday + Sunday + SATURDAY + SUNDAY + SunDay + +/(a(?i)bc|BB)x/ + abcx + aBCx + bbx + BBx + abcX + aBCX + bbX + BBX + +/^([ab](?i)[cd]|[ef])/ + ac + aC + bD + elephant + Europe + frog + France + Africa + +/^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)/ + ab + aBd + xy + xY + zebra + Zambesi + aCD + XY + +/(?<=foo\n)^bar/m + foo\nbar + bar + baz\nbar + +/(?<=(?<!foo)bar)baz/ + barbaz + barbarbaz + koobarbaz + baz + foobarbaz + +/^(a\1?){4}$/ + a + aa + aaa + aaaa + aaaaa + aaaaaa + aaaaaaa + aaaaaaaa + aaaaaaaaa + aaaaaaaaaa + aaaaaaaaaaa + aaaaaaaaaaaa + aaaaaaaaaaaaa + aaaaaaaaaaaaaa + aaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaa + +/^(a\1?)(a\1?)(a\2?)(a\3?)$/ + a + aa + aaa + aaaa + aaaaa + aaaaaa + aaaaaaa + aaaaaaaa + aaaaaaaaa + aaaaaaaaaa + aaaaaaaaaaa + aaaaaaaaaaaa + aaaaaaaaaaaaa + aaaaaaaaaaaaaa + aaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaa + +/abc/ + abc + xabcy + ababc + xbc + axc + abx + +/ab*c/ + abc + +/ab*bc/ + abc + abbc + abbbbc + +/.{1}/ + abbbbc + +/.{3,4}/ + abbbbc + +/ab{0,}bc/ + abbbbc + +/ab+bc/ + abbc + abc + abq + +/ab{1,}bc/ + +/ab+bc/ + abbbbc + +/ab{1,}bc/ + abbbbc + +/ab{1,3}bc/ + abbbbc + +/ab{3,4}bc/ + abbbbc + +/ab{4,5}bc/ + abq + abbbbc + +/ab?bc/ + abbc + abc + +/ab{0,1}bc/ + abc + +/ab?bc/ + +/ab?c/ + abc + +/ab{0,1}c/ + abc + +/^abc$/ + abc + abbbbc + abcc + +/^abc/ + abcc + +/^abc$/ + +/abc$/ + aabc + aabc + aabcd + +/^/ + abc + +/$/ + abc + +/a.c/ + abc + axc + +/a.*c/ + axyzc + +/a[bc]d/ + abd + axyzd + abc + +/a[b-d]e/ + ace + +/a[b-d]/ + aac + +/a[-b]/ + a- + +/a[b-]/ + a- + +/a]/ + a] + +/a[]]b/ + a]b + +/a[^bc]d/ + aed + abd + abd + +/a[^-b]c/ + adc + +/a[^]b]c/ + adc + a-c + a]c + +/\ba\b/ + a- + -a + -a- + +/\by\b/ + xy + yz + xyz + +/\Ba\B/ + a- + -a + -a- + +/\By\b/ + xy + +/\by\B/ + yz + +/\By\B/ + xyz + +/\w/ + a + +/\W/ + - + - + a + +/a\sb/ + a b + +/a\Sb/ + a-b + a-b + a b + +/\d/ + 1 + +/\D/ + - + - + 1 + +/[\w]/ + a + +/[\W]/ + - + - + a + +/a[\s]b/ + a b + +/a[\S]b/ + a-b + a-b + a b + +/[\d]/ + 1 + +/[\D]/ + - + - + 1 + +/ab|cd/ + abc + abcd + +/()ef/ + def + +/$b/ + +/a(b/ + a(b + +/a(*b/ + ab + a((b + +/a\b/ + a\b + +/((a))/ + abc + +/(a)b(c)/ + abc + +/a+b+c/ + aabbabc + +/a{1,}b{1,}c/ + aabbabc + +/a.+?c/ + abcabc + +/(a+|b)*/ + ab + +/(a+|b){0,}/ + ab + +/(a+|b)+/ + ab + +/(a+|b){1,}/ + ab + +/(a+|b)?/ + ab + +/(a+|b){0,1}/ + ab + +/[^ab]*/ + cde + +/abc/ + b + + +/a*/ + + +/([abc])*d/ + abbbcd + +/([abc])*bcd/ + abcd + +/a|b|c|d|e/ + e + +/(a|b|c|d|e)f/ + ef + +/abcd*efg/ + abcdefg + +/ab*/ + xabyabbbz + xayabbbz + +/(ab|cd)e/ + abcde + +/[abhgefdc]ij/ + hij + +/^(ab|cd)e/ + +/(abc|)ef/ + abcdef + +/(a|b)c*d/ + abcd + +/(ab|ab*)bc/ + abc + +/a([bc]*)c*/ + abc + +/a([bc]*)(c*d)/ + abcd + +/a([bc]+)(c*d)/ + abcd + +/a([bc]*)(c+d)/ + abcd + +/a[bcd]*dcdcde/ + adcdcde + +/a[bcd]+dcdcde/ + abcde + adcdcde + +/(ab|a)b*c/ + abc + +/((a)(b)c)(d)/ + abcd + +/[a-zA-Z_][a-zA-Z0-9_]*/ + alpha + +/^a(bc+|b[eh])g|.h$/ + abh + +/(bc+d$|ef*g.|h?i(j|k))/ + effgz + ij + reffgz + effg + bcdd + +/((((((((((a))))))))))/ + a + +/((((((((((a))))))))))\10/ + aa + +/(((((((((a)))))))))/ + a + +/multiple words of text/ + aa + uh-uh + +/multiple words/ + multiple words, yeah + +/(.*)c(.*)/ + abcde + +/((.*), (.*))/ + (a, b) + +/[k]/ + +/abcd/ + abcd + +/a(bc)d/ + abcd + +/a[-]?c/ + ac + +/(abc)\1/ + abcabc + +/([a-c]*)\1/ + abcabc + +/(a)|\1/ + a + ab + x + +/(([a-c])b*?\2)*/ + ababbbcbc + +/(([a-c])b*?\2){3}/ + ababbbcbc + +/((\3|b)\2(a)x)+/ + aaaxabaxbaaxbbax + +/((\3|b)\2(a)){2,}/ + bbaababbabaaaaabbaaaabba + +/abc/i + ABC + XABCY + ABABC + aaxabxbaxbbx + XBC + AXC + ABX + +/ab*c/i + ABC + +/ab*bc/i + ABC + ABBC + +/ab*?bc/i + ABBBBC + +/ab{0,}?bc/i + ABBBBC + +/ab+?bc/i + ABBC + +/ab+bc/i + ABC + ABQ + +/ab{1,}bc/i + +/ab+bc/i + ABBBBC + +/ab{1,}?bc/i + ABBBBC + +/ab{1,3}?bc/i + ABBBBC + +/ab{3,4}?bc/i + ABBBBC + +/ab{4,5}?bc/i + ABQ + ABBBBC + +/ab??bc/i + ABBC + ABC + +/ab{0,1}?bc/i + ABC + +/ab??bc/i + +/ab??c/i + ABC + +/ab{0,1}?c/i + ABC + +/^abc$/i + ABC + ABBBBC + ABCC + +/^abc/i + ABCC + +/^abc$/i + +/abc$/i + AABC + +/^/i + ABC + +/$/i + ABC + +/a.c/i + ABC + AXC + +/a.*?c/i + AXYZC + +/a.*c/i + AABC + AXYZD + +/a[bc]d/i + ABD + +/a[b-d]e/i + ACE + ABC + ABD + +/a[b-d]/i + AAC + +/a[-b]/i + A- + +/a[b-]/i + A- + +/a]/i + A] + +/a[]]b/i + A]B + +/a[^bc]d/i + AED + +/a[^-b]c/i + ADC + ABD + A-C + +/a[^]b]c/i + ADC + +/ab|cd/i + ABC + ABCD + +/()ef/i + DEF + +/$b/i + A]C + B + +/a(b/i + A(B + +/a(*b/i + AB + A((B + +/a\b/i + A\B + +/((a))/i + ABC + +/(a)b(c)/i + ABC + +/a+b+c/i + AABBABC + +/a{1,}b{1,}c/i + AABBABC + +/a.+?c/i + ABCABC + +/a.*?c/i + ABCABC + +/a.{0,5}?c/i + ABCABC + +/(a+|b)*/i + AB + +/(a+|b){0,}/i + AB + +/(a+|b)+/i + AB + +/(a+|b){1,}/i + AB + +/(a+|b)?/i + AB + +/(a+|b){0,1}/i + AB + +/(a+|b){0,1}?/i + AB + +/[^ab]*/i + CDE + +/abc/i + +/a*/i + + +/([abc])*d/i + ABBBCD + +/([abc])*bcd/i + ABCD + +/a|b|c|d|e/i + E + +/(a|b|c|d|e)f/i + EF + +/abcd*efg/i + ABCDEFG + +/ab*/i + XABYABBBZ + XAYABBBZ + +/(ab|cd)e/i + ABCDE + +/[abhgefdc]ij/i + HIJ + +/^(ab|cd)e/i + ABCDE + +/(abc|)ef/i + ABCDEF + +/(a|b)c*d/i + ABCD + +/(ab|ab*)bc/i + ABC + +/a([bc]*)c*/i + ABC + +/a([bc]*)(c*d)/i + ABCD + +/a([bc]+)(c*d)/i + ABCD + +/a([bc]*)(c+d)/i + ABCD + +/a[bcd]*dcdcde/i + ADCDCDE + +/a[bcd]+dcdcde/i + +/(ab|a)b*c/i + ABC + +/((a)(b)c)(d)/i + ABCD + +/[a-zA-Z_][a-zA-Z0-9_]*/i + ALPHA + +/^a(bc+|b[eh])g|.h$/i + ABH + +/(bc+d$|ef*g.|h?i(j|k))/i + EFFGZ + IJ + REFFGZ + ADCDCDE + EFFG + BCDD + +/((((((((((a))))))))))/i + A + +/((((((((((a))))))))))\10/i + AA + +/(((((((((a)))))))))/i + A + +/(?:(?:(?:(?:(?:(?:(?:(?:(?:(a))))))))))/i + A + +/(?:(?:(?:(?:(?:(?:(?:(?:(?:(a|b|c))))))))))/i + C + +/multiple words of text/i + AA + UH-UH + +/multiple words/i + MULTIPLE WORDS, YEAH + +/(.*)c(.*)/i + ABCDE + +/((.*), (.*))/i + (A, B) + +/[k]/i + +/abcd/i + ABCD + +/a(bc)d/i + ABCD + +/a[-]?c/i + AC + +/(abc)\1/i + ABCABC + +/([a-c]*)\1/i + ABCABC + +/a(?!b)./ + abad + +/a(?=d)./ + abad + +/a(?=c|d)./ + abad + +/a(?:b|c|d)(.)/ + ace + +/a(?:b|c|d)*(.)/ + ace + +/a(?:b|c|d)+?(.)/ + ace + acdbcdbe + +/a(?:b|c|d)+(.)/ + acdbcdbe + +/a(?:b|c|d){2}(.)/ + acdbcdbe + +/a(?:b|c|d){4,5}(.)/ + acdbcdbe + +/a(?:b|c|d){4,5}?(.)/ + acdbcdbe + +/((foo)|(bar))*/ + foobar + +/a(?:b|c|d){6,7}(.)/ + acdbcdbe + +/a(?:b|c|d){6,7}?(.)/ + acdbcdbe + +/a(?:b|c|d){5,6}(.)/ + acdbcdbe + +/a(?:b|c|d){5,6}?(.)/ + acdbcdbe + +/a(?:b|c|d){5,7}(.)/ + acdbcdbe + +/a(?:b|c|d){5,7}?(.)/ + acdbcdbe + +/a(?:b|(c|e){1,2}?|d)+?(.)/ + ace + +/^(.+)?B/ + AB + +/^([^a-z])|(^)$/ + . + +/^[<>]&/ + <&OUT + +/^(a\1?){4}$/ + aaaaaaaaaa + AB + aaaaaaaaa + aaaaaaaaaaa + +/^(a(?(1)\1)){4}$/ + aaaaaaaaaa + aaaaaaaaa + aaaaaaaaaaa + +/(?:(f)(o)(o)|(b)(a)(r))*/ + foobar + +/(?<=a)b/ + ab + cb + b + +/(?<!c)b/ + ab + b + b + +/(?:..)*a/ + aba + +/(?:..)*?a/ + aba + +/^(?:b|a(?=(.)))*\1/ + abc + +/^(){3,5}/ + abc + +/^(a+)*ax/ + aax + +/^((a|b)+)*ax/ + aax + +/^((a|bc)+)*ax/ + aax + +/(a|x)*ab/ + cab + +/(a)*ab/ + cab + +/(?:(?i)a)b/ + ab + +/((?i)a)b/ + ab + +/(?:(?i)a)b/ + Ab + +/((?i)a)b/ + Ab + +/(?:(?i)a)b/ + cb + aB + +/((?i)a)b/ + +/(?i:a)b/ + ab + +/((?i:a))b/ + ab + +/(?i:a)b/ + Ab + +/((?i:a))b/ + Ab + +/(?i:a)b/ + aB + aB + +/((?i:a))b/ + +/(?:(?-i)a)b/i + ab + +/((?-i)a)b/i + ab + +/(?:(?-i)a)b/i + aB + +/((?-i)a)b/i + aB + +/(?:(?-i)a)b/i + aB + Ab + +/((?-i)a)b/i + +/(?:(?-i)a)b/i + aB + +/((?-i)a)b/i + aB + +/(?:(?-i)a)b/i + Ab + AB + +/((?-i)a)b/i + +/(?-i:a)b/i + ab + +/((?-i:a))b/i + ab + +/(?-i:a)b/i + aB + +/((?-i:a))b/i + aB + +/(?-i:a)b/i + AB + Ab + +/((?-i:a))b/i + +/(?-i:a)b/i + aB + +/((?-i:a))b/i + aB + +/(?-i:a)b/i + Ab + AB + +/((?-i:a))b/i + +/((?-i:a.))b/i + AB + a\nB + +/((?s-i:a.))b/i + a\nB + +/(?:c|d)(?:)(?:a(?:)(?:b)(?:b(?:))(?:b(?:)(?:b)))/ + cabbbb + +/(?:c|d)(?:)(?:aaaaaaaa(?:)(?:bbbbbbbb)(?:bbbbbbbb(?:))(?:bbbbbbbb(?:)(?:bbbbbbbb)))/ + caaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb + +/(ab)\d\1/i + Ab4ab + ab4Ab + +/foo\w*\d{4}baz/ + foobar1234baz + +/x(~~)*(?:(?:F)?)?/ + x~~ + +/^a(?#xxx){3}c/ + aaac + +/^a(?#xxx)(?#xxx){3}c/ + aaac + +/^a (?#xxx) (?#yyy) {3}c/x + aaac + +/(?<![cd])b/ + B\nB + dbcb + +/(?<![cd])[ab]/ + dbaacb + +/(?<!(c|d))b/ + +/(?<!(c|d))[ab]/ + dbaacb + +/(?<!cd)[ab]/ + cdaccb + +/^(?:a?b?)*$/ + dbcb + a-- + +/((?s)^a(.))((?m)^b$)/ + a\nb\nc\n + +/((?m)^b$)/ + a\nb\nc\n + +/(?m)^b/ + a\nb\n + +/(?m)^(b)/ + a\nb\n + +/((?m)^b)/ + a\nb\n + +/\n((?m)^b)/ + a\nb\n + +/((?s).)c(?!.)/ + a\nb\nc\n + a\nb\nc\n + +/((?s)b.)c(?!.)/ + a\nb\nc\n + a\nb\nc\n + +/^b/ + +/()^b/ + a\nb\nc\n + a\nb\nc\n + +/((?m)^b)/ + a\nb\nc\n + +/(?(1)a|b)/ + +/(?(1)b|a)/ + a + +/(x)?(?(1)a|b)/ + a + a + +/(x)?(?(1)b|a)/ + a + +/()?(?(1)b|a)/ + a + +/()(?(1)b|a)/ + +/()?(?(1)a|b)/ + a + +/^(()?blah(?(1)()))$/ + (blah) + blah + a + blah) + (blah + +/^((+)?blah(?(1)()))$/ + (blah) + blah + blah) + (blah + +/(?(?!a)a|b)/ + +/(?(?!a)b|a)/ + a + +/(?(?=a)b|a)/ + a + a + +/(?(?=a)a|b)/ + a + +/(?=(a+?))(\1ab)/ + aaab + +/^(?=(a+?))\1ab/ + +/(\w+:)+/ + one: + +/$(?<=^(a))/ + a + +/(?=(a+?))(\1ab)/ + aaab + +/^(?=(a+?))\1ab/ + aaab + aaab + +/([\w:]+::)?(\w+)$/ + abcd + xy:z:::abcd + +/^[^bcd]*(c+)/ + aexycd + +/(a*)b+/ + caab + +/([\w:]+::)?(\w+)$/ + abcd + xy:z:::abcd + abcd: + abcd: + +/^[^bcd]*(c+)/ + aexycd + +/(>a+)ab/ + +/(?>a+)b/ + aaab + +/([[:]+)/ + a:[b]: + +/([[=]+)/ + a=[b]= + +/([[.]+)/ + a.[b]. + +/((?>a+)b)/ + aaab + +/(?>(a+))b/ + aaab + +/((?>[^()]+)|([^()]*))+/ + ((abc(ade)ufh()()x + +/a\Z/ + aaab + a\nb\n + +/b\Z/ + a\nb\n + +/b\z/ + +/b\Z/ + a\nb + +/b\z/ + a\nb + +/^(?>(?(1).|())[^\W_](?>[a-z0-9-]*[^\W_])?)+$/ + a + abc + a-b + 0-9 + a.b + 5.6.7 + the.quick.brown.fox + a100.b200.300c + 12-ab.1245 + \ + .a + -a + a- + a. + a_b + a.- + a.. + ab..bc + the.quick.brown.fox- + the.quick.brown.fox. + the.quick.brown.fox_ + the.quick.brown.fox+ + +/(?>.*)(?<=(abcd|wxyz))/ + alphabetabcd + endingwxyz + a rather long string that doesn't end with one of them + +/word (?>(?:(?!otherword)[a-zA-Z0-9]+ ){0,30})otherword/ + word cat dog elephant mussel cow horse canary baboon snake shark otherword + word cat dog elephant mussel cow horse canary baboon snake shark + +/word (?>[a-zA-Z0-9]+ ){0,30}otherword/ + word cat dog elephant mussel cow horse canary baboon snake shark the quick brown fox and the lazy dog and several other words getting close to thirty by now I hope + +/(?<=\d{3}(?!999))foo/ + 999foo + 123999foo + 123abcfoo + +/(?<=(?!...999)\d{3})foo/ + 999foo + 123999foo + 123abcfoo + +/(?<=\d{3}(?!999)...)foo/ + 123abcfoo + 123456foo + 123999foo + +/(?<=\d{3}...)(?<!999)foo/ + 123abcfoo + 123456foo + 123999foo + +/<a[\s]+href[\s]*=[\s]* # find <a href= + (["'])? # find single or double quote + (?(1) (.*?)\1 | ([^\s]+)) # if quote found, match up to next matching + # quote, otherwise match up to next space +/isx + <a href=abcd xyz + <a href="abcd xyz pqr" cats + <a href='abcd xyz pqr' cats + +/<a\s+href\s*=\s* # find <a href= + (["'])? # find single or double quote + (?(1) (.*?)\1 | (\S+)) # if quote found, match up to next matching + # quote, otherwise match up to next space +/isx + <a href=abcd xyz + <a href="abcd xyz pqr" cats + <a href = 'abcd xyz pqr' cats + +/<a\s+href(?>\s*)=(?>\s*) # find <a href= + (["'])? # find single or double quote + (?(1) (.*?)\1 | (\S+)) # if quote found, match up to next matching + # quote, otherwise match up to next space +/isx + <a href=abcd xyz + <a href="abcd xyz pqr" cats + <a href = 'abcd xyz pqr' cats + +/((Z)+|A)*/ + ZABCDEFG + +/(Z()|A)*/ + ZABCDEFG + +/(Z(())|A)*/ + ZABCDEFG + +/((?>Z)+|A)*/ + ZABCDEFG + +/((?>)+|A)*/ + ZABCDEFG + +/a*/g + abbab + +/^[a-\d]/ + abcde + -things + 0digit + bcdef + +/^[\d-a]/ + abcde + -things + 0digit + bcdef + +/(?<=abc).*(?=def)/ + abcdef + abcxdef + abcxdefxdef + +/(?<=abc).*?(?=def)/ + abcdef + abcxdef + abcxdefxdef + +/(?<=abc).+(?=def)/ + abcdef + abcxdef + abcxdefxdef + +/(?<=abc).+?(?=def)/ + abcdef + abcxdef + abcxdefxdef + +/(?<=\b)(.*)/ + -abcdef + abcdef + +/(?<=\B)(.*)/ + -abcdef + abcdef + +/^'[ab]'/ + 'a' + 'b' + x'a' + 'a'x + 'ab' + +/^'[ab]'$/ + 'a' + 'b' + x'a' + 'a'x + 'ab' + +/'[ab]'$/ + 'a' + 'b' + x'a' + 'a'x + 'ab' + +/'[ab]'/ + 'a' + 'b' + x'a' + 'a'x + 'ab' + +/abc\E/ + abc + abcE + +/abc[\Ex]/ + abcx + abcE + +/^\Qa*\E$/ + a* + a + +/\Qa*x\E/ + a*x + a* + +/\Qa*x/ + a*x + a* + +/\Q\Qa*x\E\E/ + a*x + a\*x + +/\Q\Qa*x\E/ + a*x + a\*x + +/a\Q[x\E]/ + a[x] + ax + +/a#comment\Q... +{2}/x + a + aa + +/a(?#comment\Q... +){2}/x + a + aa + +/(?x)a#\Q +./ + a. + aa + +/ab(?=.*q)cd/ + abcdxklqj + +/a(?!.*$)b/ + ab + +/.{2}[a-z]/ + Axi \ No newline at end of file
Added: branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/util.lisp =================================================================== --- branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/util.lisp 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/cl-ppcre-1.3.2/util.lisp 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,299 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-PPCRE; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/cl-ppcre/util.lisp,v 1.36 2007/07/24 21:32:38 edi Exp $ + +;;; Utility functions and constants dealing with the hash-tables +;;; we use to encode character classes + +;;; Hash-tables are treated like sets, i.e. a character C is a member of the +;;; hash-table H iff (GETHASH C H) is true. + +;;; Copyright (c) 2002-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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-package #:cl-ppcre) + +#+:lispworks +(eval-when (:compile-toplevel :load-toplevel :execute) + (import 'lw:with-unique-names)) + +#-:lispworks +(defmacro with-unique-names ((&rest bindings) &body body) + "Syntax: WITH-UNIQUE-NAMES ( { var | (var x) }* ) declaration* form* + +Executes a series of forms with each VAR bound to a fresh, +uninterned symbol. The uninterned symbol is as if returned by a call +to GENSYM with the string denoted by X - or, if X is not supplied, the +string denoted by VAR - as argument. + +The variable bindings created are lexical unless special declarations +are specified. The scopes of the name bindings and declarations do not +include the Xs. + +The forms are evaluated in order, and the values of all but the last +are discarded (that is, the body is an implicit PROGN)." + ;; reference implementation posted to comp.lang.lisp as + ;; cy3bshuf30f.fsf@ljosa.com by Vebjorn Ljosa - see also + ;; http://www.cliki.net/Common%20Lisp%20Utilities + `(let ,(mapcar #'(lambda (binding) + (check-type binding (or cons symbol)) + (if (consp binding) + (destructuring-bind (var x) binding + (check-type var symbol) + `(,var (gensym ,(etypecase x + (symbol (symbol-name x)) + (character (string x)) + (string x))))) + `(,binding (gensym ,(symbol-name binding))))) + bindings) + ,@body)) + +#+:lispworks +(eval-when (:compile-toplevel :load-toplevel :execute) + (setf (macro-function 'with-rebinding) + (macro-function 'lw:rebinding))) + +#-:lispworks +(defmacro with-rebinding (bindings &body body) + "WITH-REBINDING ( { var | (var prefix) }* ) form* + +Evaluates a series of forms in the lexical environment that is +formed by adding the binding of each VAR to a fresh, uninterned +symbol, and the binding of that fresh, uninterned symbol to VAR's +original value, i.e., its value in the current lexical environment. + +The uninterned symbol is created as if by a call to GENSYM with the +string denoted by PREFIX - or, if PREFIX is not supplied, the string +denoted by VAR - as argument. + +The forms are evaluated in order, and the values of all but the last +are discarded (that is, the body is an implicit PROGN)." + ;; reference implementation posted to comp.lang.lisp as + ;; cy3wv0fya0p.fsf@ljosa.com by Vebjorn Ljosa - see also + ;; http://www.cliki.net/Common%20Lisp%20Utilities + (loop for binding in bindings + for var = (if (consp binding) (car binding) binding) + for name = (gensym) + collect `(,name ,var) into renames + collect ``(,,var ,,name) into temps + finally (return `(let ,renames + (with-unique-names ,bindings + `(let (,,@temps) + ,,@body)))))) + +(eval-when (:compile-toplevel :execute :load-toplevel) + (defvar *regex-char-code-limit* char-code-limit + "The upper exclusive bound on the char-codes of characters +which can occur in character classes. Change this value BEFORE +creating scanners if you don't need the (full) Unicode support +of implementations like AllegroCL, CLISP, LispWorks, or SBCL.") + (declaim (type fixnum *regex-char-code-limit*)) + + (defun make-char-hash (test) + (declare #.*special-optimize-settings*) + "Returns a hash-table of all characters satisfying test." + (loop with hash = (make-hash-table) + for c of-type fixnum from 0 below char-code-limit + for chr = (code-char c) + if (and chr (funcall test chr)) + do (setf (gethash chr hash) t) + finally (return hash))) + + (declaim (inline word-char-p)) + + (defun word-char-p (chr) + (declare #.*standard-optimize-settings*) + "Tests whether a character is a "word" character. +In the ASCII charset this is equivalent to a-z, A-Z, 0-9, or _, +i.e. the same as Perl's [\w]." + (or (alphanumericp chr) + (char= chr #_))) + + (unless (boundp '+whitespace-char-string+) + (defconstant +whitespace-char-string+ + (coerce + '(#\Space #\Tab #\Linefeed #\Return #\Page) + 'string) + "A string of all characters which are considered to be whitespace. +Same as Perl's [\s].")) + + (defun whitespacep (chr) + (declare #.*special-optimize-settings*) + "Tests whether a character is whitespace, +i.e. whether it would match [\s] in Perl." + (find chr +whitespace-char-string+ :test #'char=))) + +;; the following DEFCONSTANT statements are wrapped with +;; (UNLESS (BOUNDP ...) ...) to make SBCL happy + +(unless (boundp '+digit-hash+) + (defconstant +digit-hash+ + (make-char-hash (lambda (chr) (char<= #\0 chr #\9))) + "Hash-table containing the digits from 0 to 9.")) + +(unless (boundp '+word-char-hash+) + (defconstant +word-char-hash+ + (make-char-hash #'word-char-p) + "Hash-table containing all "word" characters.")) + +(unless (boundp '+whitespace-char-hash+) + (defconstant +whitespace-char-hash+ + (make-char-hash #'whitespacep) + "Hash-table containing all whitespace characters.")) + +(defun merge-hash (hash1 hash2) + (declare #.*standard-optimize-settings*) + "Returns the "sum" of two hashes. This is a destructive operation +on HASH1." + (cond ((> (hash-table-count hash2) + *regex-char-code-limit*) + ;; don't walk through, e.g., the whole +WORD-CHAR-HASH+ if + ;; the user has set *REGEX-CHAR-CODE-LIMIT* to a lower value + (loop for c of-type fixnum from 0 below *regex-char-code-limit* + for chr = (code-char c) + if (and chr (gethash chr hash2)) + do (setf (gethash chr hash1) t))) + (t + (loop for chr being the hash-keys of hash2 + do (setf (gethash chr hash1) t)))) + hash1) + +(defun merge-inverted-hash (hash1 hash2) + (declare #.*standard-optimize-settings*) + "Returns the "sum" of HASH1 and the "inverse" of HASH2. This is +a destructive operation on HASH1." + (loop for c of-type fixnum from 0 below *regex-char-code-limit* + for chr = (code-char c) + if (and chr (not (gethash chr hash2))) + do (setf (gethash chr hash1) t)) + hash1) + +(defun create-ranges-from-hash (hash &key downcasep) + (declare #.*standard-optimize-settings*) + "Tries to identify up to three intervals (with respect to CHAR<) +which together comprise HASH. Returns NIL if this is not possible. +If DOWNCASEP is true it will treat the hash-table as if it represents +both the lower-case and the upper-case variants of its members and +will only return the respective lower-case intervals." + ;; discard empty hash-tables + (unless (and hash (plusp (hash-table-count hash))) + (return-from create-ranges-from-hash nil)) + (loop with min1 and min2 and min3 + and max1 and max2 and max3 + ;; loop through all characters in HASH, sorted by CHAR< + for chr in (sort (the list + (loop for chr being the hash-keys of hash + collect (if downcasep + (char-downcase chr) + chr))) + #'char<) + for code = (char-code chr) + ;; MIN1, MAX1, etc. are _exclusive_ + ;; bounds of the intervals identified so far + do (cond + ((not min1) + ;; this will only happen once, for the first character + (setq min1 (1- code) + max1 (1+ code))) + ((<= (the fixnum min1) code (the fixnum max1)) + ;; we're here as long as CHR fits into the first interval + (setq min1 (min (the fixnum min1) (1- code)) + max1 (max (the fixnum max1) (1+ code)))) + ((not min2) + ;; we need to open a second interval + ;; this'll also happen only once + (setq min2 (1- code) + max2 (1+ code))) + ((<= (the fixnum min2) code (the fixnum max2)) + ;; CHR fits into the second interval + (setq min2 (min (the fixnum min2) (1- code)) + max2 (max (the fixnum max2) (1+ code)))) + ((not min3) + ;; we need to open the third interval + ;; happens only once + (setq min3 (1- code) + max3 (1+ code))) + ((<= (the fixnum min3) code (the fixnum max3)) + ;; CHR fits into the third interval + (setq min3 (min (the fixnum min3) (1- code)) + max3 (max (the fixnum max3) (1+ code)))) + (t + ;; we're out of luck, CHR doesn't fit + ;; into one of the three intervals + (return nil))) + ;; on success return all bounds + ;; make them inclusive bounds before returning + finally (return (values (code-char (1+ min1)) + (code-char (1- max1)) + (and min2 (code-char (1+ min2))) + (and max2 (code-char (1- max2))) + (and min3 (code-char (1+ min3))) + (and max3 (code-char (1- max3))))))) + +(defmacro maybe-coerce-to-simple-string (string) + (with-unique-names (=string=) + `(let ((,=string= ,string)) + (cond ((simple-string-p ,=string=) + ,=string=) + (t + (coerce ,=string= 'simple-string)))))) + +(declaim (inline nsubseq)) +(defun nsubseq (sequence start &optional (end (length sequence))) + "Return a subsequence by pointing to location in original sequence." + (make-array (- end start) + :element-type (array-element-type sequence) + :displaced-to sequence + :displaced-index-offset start)) + +(defun normalize-var-list (var-list) + "Utility function for REGISTER-GROUPS-BIND and +DO-REGISTER-GROUPS. Creates the long form (a list of (FUNCTION VAR) +entries) out of the short form of VAR-LIST." + (loop for element in var-list + if (consp element) + nconc (loop for var in (rest element) + collect (list (first element) var)) + else + collect (list '(function identity) element))) + +(defun string-list-to-simple-string (string-list) + (declare #.*standard-optimize-settings*) + "Concatenates a list of strings to one simple-string." + ;; this function provided by JP Massar; note that we can't use APPLY + ;; with CONCATENATE here because of CALL-ARGUMENTS-LIMIT + (let ((total-size 0)) + (declare (type fixnum total-size)) + (dolist (string string-list) + #-genera (declare (type string string)) + (incf total-size (length string))) + (let ((result-string (make-sequence 'simple-string total-size)) + (curr-pos 0)) + (declare (type fixnum curr-pos)) + (dolist (string string-list) + #-genera (declare (type string string)) + (replace result-string string :start1 curr-pos) + (incf curr-pos (length string))) + result-string)))
Added: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/CHANGELOG =================================================================== --- branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/CHANGELOG 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/CHANGELOG 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,273 @@ +Version 0.14.6 +2007-11.08 +Fix compilation order (thanks to Tiarnan O'Corrain and Chris Dean) + +Version 0.14.5 +2007-10-21 +Robustified MAKE-SOCKET-STREAM against potential leak (thanks to Alain Picard) +Replaced #-FOO #-FOO constructs for OpenMCL (patch by Michael Weber) +Updated tutorial links + +Version 0.14.4 +2007-10-20 +Made log stream shared on OpenMCL (thanks to Gary Byers) + +Version 0.14.3 +2007-10-07 +Enabled GET-GID-FROM-NAME for newer versions of SBCL (patch by Cyrus Harmon) + +Version 0.14.2 +2007-09-26 +Better handling of PORT parameter in REDIRECT (thanks to Vladimir Sedach) + +Version 0.14.1 +2007-09-24 +Fixed bug where you couldn't set "Server" header (caught by Ralf Mattes) +Documentation clarification for HEADER-OUR function + +Version 0.14.0 +2007-09-18 +Added support for "HttpOnly" cookie attribute + +Version 0.13.0 +2007-09-14 +Added *METHODS-FOR-POST-PARAMETERS* (suggested by Jonathon McKitrick) + +Version 0.12.1 +2007-09-13 +Better support for WITH-TIMEOUT on SBCL/Win32 (thanks to Anton Vodonosov) + +Version 0.12.0 +2007-09-07 +Now uses bound for flexi stream returned by RAW-POST-DATA +Needs FLEXI-STREAMS 0.12.0 or higher + +Version 0.11.2 +2007-09-05 +Fixed typo in docs +Added declaration in server.lisp to appease SBCL + +Version 0.11.1 +2007-05-25 +Fixes for OpenMCL (thanks to Lennart Staflin and Tiarnan O'Corrain) + +Version 0.11.0 +2007-05-25 +Added server names and coupled them with easy handlers (suggested by Mac Chan) +Exported SESSION-COOKIE-VALUE instead of SESSION-STRING (suggested by Slava Akhmechet) +Documentation fixes (thanks to Victor Kryukov and Igor Plekhov) + +Version 0.10.0 +2007-05-12 +Made MAYBE-INVOKE-DEBUGGER a generic function and exported it (suggested by Vladimir Sedach) + +Version 0.9.3 +2007-05-08 +Fixed CREATE-FOLDER-DISPATCHER-AND-HANDLER in the presence of URL-encoded URLs (bug caught by Nicolas Lamirault) + +Version 0.9.2 +2007-05-01 +Made DEF-HTTP-RETURN-CODE more flexible (suggested by Jong-won Choi) + +Version 0.9.1 +2007-04-29 +Added PORT parameter to REDIRECT (suggested by Cyrus Harmon) +Exported REMOVE-SESSION (suggested by Vamsee Kanakala) + +Version 0.9.0 +2007-04-19 +Added socket timeouts for AllegroCL +Catch IO timeout conditions for AllegroCL, SBCL and CMUCL (suggested by Red Daly and others) +Added per-server dispatch tables (suggested by Robert Synnott and Andrei Stebakov) + +Version 0.8.6 +2007-04-18 +USE the CL package explicitly when defining HUNCHENTOOT-MP (bug report by Joel Boehland) + +Version 0.8.5 +2007-04-10 +Correct behaviour for "100 Continue" responses + +Version 0.8.4 +2007-04-09 +Cleanup + +Version 0.8.3 +2007-04-07 +Don't use chunked encoding for empty (NIL) bodies + +Version 0.8.2 +2007-04-05 +Really exported REASON-PHRASE this time (and also *CURRENT-PROCESS*) + +Version 0.8.1 +2007-04-04 +Added HUNCHENTOOT-MP package (suggested by Cyrus Harmon) +Only invoke MARK-AND-SWEEP for 32-bit versions of LW (thanks to Chris Dean) +Exported REASON-PHRASE + +Version 0.8.0 +2007-03-31 +Added *APPROVED-RETURN-CODES*, *HEADER-STREAM*, and +HTTP-FAILED-DEPENDENCY+ +Exported MIME-TYPE and SSL-P +Some minor changes + +Version 0.7.3 +2007-03-28 +Added +HTTP-MULTI-STATUS+ + +Version 0.7.2 +2007-03-09 +Fix test suite to properly handle non-base characters in LW (bug caught by Jong-won Choi) + +Version 0.7.1 +2007-03-09 +Fixed last change (thanks to Marko Kocic) + +Version 0.7.0 +2007-03-09 +Development port (no threads) to SBCL/Win32 (patch by Marko Kocic) +Support for compilation without SSL + +Version 0.6.2 +2007-02-22 +Don't use NSTRING-UPCASE for outgoing headers (bug caught by Saurabh Nanda) +Changed ProxyPass example in docs from /lisp to /hunchentoot + +Version 0.6.1 +2007-01-24 +Reset to "faithful" external format on each iteration (bug caught by Viljo Marrandi and Ury Marshak) + +Version 0.6.0 +2007-01-23 +Accept chunked transfer encoding for mod_lisp request bodies (thanks to Hugh Winkler's mod_lisp additions) +Robustify against erroneous form-data submissions (caught by Ury Marshak) + +Version 0.5.1 +2007-01-18 +Even more flexible behaviour of RAW-POST-DATA + +Version 0.5.0 +2007-01-17 +More flexible behaviour of RAW-POST-DATA +Robustified PARSE-CONTENT-TYPE + +Version 0.4.14 +2007-01-17 +More meaningful results for RAW-POST-DATA + +Version 0.4.13 +2007-01-14 +Added favicon.ico to example website (thanks to Yoni Rabkin Katzenell, Toby, and Uwe von Loh) + +Version 0.4.12 +2006-12-27 +Added Hunchentoot logo by Uwe von Loh + +Version 0.4.11 +2006-12-01 +Exported symbols related to session GC (suggested by Nico de Jager) + +Version 0.4.10 +2006-11-19 +Added *HANDLE-HTTP-ERRORS-P* (thanks to Marijn Haverbeke) +Remove duplicate headers when reading from mod_lisp + +Version 0.4.9 +2006-11-12 +Fixed HEADER-OUT (thanks to Robert J. Macomber) + +Version 0.4.8 +2006-11-06 +Fixed bug in START-OUTPUT which confused mod_lisp + +Version 0.4.7 +2006-11-06 +Changed behaviour of REAL-REMOTE-ADDR (as suggested by Robert J. Macomber) +Fixed COOKIE-OUT (thanks to Robert J. Macomber) + +Version 0.4.6 +2006-11-05 +Don't bind *DISPATCH-TABLE* too early (thanks to Marijn Haverbeke) + +Version 0.4.5 +2006-10-25 +Fixed bug in AUTHORIZATION function (reported by Michael J. Forster) + +Version 0.4.4 +2006-10-12 +Correct SSL check in REDIRECT function +LOG-MESSAGE now checks for (BOUNDP '*SERVER*) + +Version 0.4.3 +2006-10-11 +OpenMCL fixes (by Ralf Stoye) + +Version 0.4.2 +2006-10-10 +No timeouts for mod_lisp servers (as in Hunchentoot 0.3.x) + +Version 0.4.1 +2006-10-10 +Fixed a typo in easy-handlers.lisp (caught by Travis Cross) + +Version 0.4.0 +2006-10-10 +Ported to CMUCL, SBCL, OpenMCL, and AllegroCL +Merged with TBNL +Tons of small changes, too many to list them individually + +Version 0.3.2 +2006-09-14 +Uses TBNL's WITH-DEBUGGER now + +Version 0.3.1 +2006-09-14 +Added *CATCH-ERRORS-P* (from TBNL) + +Version 0.3.0 +2006-09-05 +Accept HTTP requests with chunked transfer encoding +Use Chunga for chunking + +Version 0.2.2 +2006-08-31 +Skip START-OUTPUT advice completely if working for TBNL + +Version 0.2.1 +2006-08-28 +Added write timeouts for LW 5.0 +Updated LW links in documentation + +Version 0.2.0 +2006-08-28 +Serves as infrastructure for TBNL now (to replace KMRCL) +For HTTP/1.1 only send 'Keep-Alive' headers if explicitly requested + +Version 0.1.5 +2006-08-23 +Connection headers are separated by commas, not semicolons + +Version 0.1.4 +2006-08-22 +Refactored streams.lisp to appease LW compiler (thanks to Martin Simmons) +Changed handling of version string +Changed package handling in system definition (thanks to Christophe Rhodes) + +Version 0.1.3 +2006-02-08 +Removed KMRCL workaround + +Version 0.1.2 +2006-01-03 +Mention TBNL version number in server name header + +Version 0.1.1 +2005-12-31 +Fixed package stuff and HYPERDOC support + +Version 0.1.0 +2005-12-31 +Initial public release + +[For earlier changes see the file "CHANGELOG_TBNL" that is included with the release.]
Property changes on: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/CHANGELOG ___________________________________________________________________ Name: svn:executable + *
Added: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/CHANGELOG_TBNL =================================================================== --- branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/CHANGELOG_TBNL 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/CHANGELOG_TBNL 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,340 @@ +Version 0.11.3 +2006-09-30 +Added *FILE-UPLOAD-HOOK* (suggested by Erik Enge) +Fixed DEFINE-EASY-HANDLER for cases where URI is NIL + +Version 0.11.2 +2006-09-20 +DEFINE-EASY-HANDLER: fixed and clarified redefinition +DEFINE-EASY-HANDLER: allow for functions designators as "URIs" +DEFINE-EASY-HANDLER: take file uploads into account +Made logging a little bit more robust +Added mime type for XSL-FO (.fo) + +Version 0.11.1 +2006-09-14 +Cleaner implementation of *CATCH-ERRORS-P* + +Version 0.11.0 +2006-09-14 +Added *CATCH-ERRORS-P* + +Version 0.10.3 +2006-09-05 +Appease SBCL (thanks to Juho Snellman) + +Version 0.10.2 +2006-09-05 +Better reporting of IP addresses and ports if not behind mod_lisp +Improved logging +Fixed REAL-REMOTE-ADDR +Cookies always use UTF-8 encoding (which is opaque to the client anyway) +Read request bodies without 'Content-Length' header (for Hunchentoot) +Removed accented character from test.lisp to appease SBCL (reported by Xristos Kalkanis) + +Version 0.10.1 +2006-08-31 +Only LispWorks: Set read timeout to NIL if connected to mod_lisp + +Version 0.10.0 +2006-08-28 +Based LispWorks version of TBNL on Hunchentoot infrastructure +Added "easy" handlers +Exported GET-BACKTRACE (suggested by Erik Enge) + +Version 0.9.11 +2006-08-16 +Added note about SBCL problems + +Version 0.9.10 +2006-05-24 +Prepare for LW 5.0 release + +Version 0.9.9 +2006-05-12 +Workaround for something like "application/x-www-form-urlencoded;charset=UTF-8" (caught by John Bates) + +Version 0.9.8 +2006-04-25 +For mod_lisp, Lisp-Content-Length header must be sent after Content-Length header + +Version 0.9.7 +2006-02-06 +More robust computation of content length + +Version 0.9.6 +2006-01-22 +Added the missing piece (argh!) + +Version 0.9.5 +2006-01-22 +Made creation of REQUEST object safer (thanks to Robert J. Macomber) +Replaced some erroneous DECLAIMs with DECLAREs (thanks to SBCL's style warnings) +Slight documentation enhancements + +Version 0.9.4 +2006-01-03 +Handle "Expect: 100-continue" for non-Apache front-ends +Re-introduced IGNORE-ERRORS in GET-REQUEST-DATA + +Version 0.9.3 +2006-01-01 +Fixed bug in READ-HTTP-REQUEST + +Version 0.9.2 +2005-12-31 +Protocol of reply is HTTP/1.1 now +Made HTTP/0.9 default protocol of request if none was provided +Some preparations for Hunchentoot +Various minor changes +Small fixes in docs + +Version 0.9.1 +2005-12-25 +Added missing file mime-types.lisp (thanks to Hilverd Reker) + +Version 0.9.0 +2005-12-24 +Experimental support for writing directly to the front-end (see SEND-HEADERS) +Added HANDLE-STATIC-FILE +Changed CREATE-STATIC-FILE-DISPATCHER-AND-HANDLER to use new facilities +Added CREATE-FOLDER-DISPATCHER-AND-HANDLER +Added link to Travis Cross' message w.r.t. SBCL + +Version 0.8.9 +2005-12-16 +Also use :TBNL-BIVALENT-STREAMS if :SB-UNICODE is present + +Version 0.8.8 +2005-12-08 +Made RAW-POST-DATA more useful +Updated docs w.r.t. Araneida (thanks to Alan Shields) + +Version 0.8.7 +2005-11-29 +Made "Content-Length" header SETFable + +Version 0.8.6 +2005-11-18 +Restored original stream-based code for multipart/form-data parsing (got lost somehow) +Wrapped REMOTE-ADDR with IGNORE-ERRORS (just in case) + +Version 0.8.5 +2005-11-14 +Added generic function DISPATCH-REQUEST (thanks to Jeff Caldwell) + +Version 0.8.4 +2005-10-21 +Provide REMOTE-ADDR if connected directly (for LispWorks and AllegroCL) +Show remote user and address (if available) in non-Apache logs +Mention Debian package in docs + +Version 0.8.3 +2005-10-10 +Alert LW users that a patch for OCTETS-TO-STRINGS is available (thanks to LispWorks support) + +Version 0.8.2 +2005-10-06 +Make STRING-TO-OCTETS and OCTETS-TO-STRING safer for LW + +Version 0.8.1 +2005-09-29 +Bugfix in CMUCL version of STRING-TO-OCTETS + +Version 0.8.0 +2005-09-24 +Added the ability to cope with different external formats (incorporating suggestions from Will Glozer and Ivan Shvedunov) +Raw post data is now always saved (so *SAVE-RAW-POST-DATA-P* is gone) + +Version 0.7.0 +2005-09-17 +Added the ability to store arbitrary data within REQUEST objects (suggested by Zach Beane) +Fixed handling of *HTTP-ERROR-HANDLER* +Note: *TBNL-VERSION* was wrong in 0.6.0 and 0.6.1 + +Version 0.6.1 +2005-09-10 +Robustified socket handling code + +Version 0.6.0 +2005-09-08 +Added TBNL-CONTRIB package +Added contrib directory with first entry (from Alceste Scalas) +Updated link to Bill Clementson's blog +Don't redefine what's already there (for LispWorks) + +Version 0.5.5 +2005-04-18 +Make RFC 2388 code an external dependency (thanks to Janis Dzerins) + +Version 0.5.4 +2005-04-03 +Fixed dumb typo (caught by Bob Hutchison) + +Version 0.5.3 +2005-04-03 +Re-introduced automatic front-end selection (originally by Bob Hutchison) + +Version 0.5.2 +2005-03-26 +Fixed bug in modlisp.html where *CLOSE-TBNL-STREAM* could be NIL although it should be T +Set correct content type for 304 replies + +Version 0.5.1 +2005-03-17 +Changed default cookie path in START-SESSION (suggested by Stefan Scholl) +Small bugfixes +More headers from the Araneida front-end +Added *SHOW-ACCESS-LOG-MESSAGES* +Changed "back-end" to "front-end" :) + +Version 0.5.0 +2005-03-17 +Initial support for "stand-alone" version (no front-end) (supplied by Bob Hutchison) +New logging API +Fixes in START-TBNL/STOP-TBNL +Documentation enhancements + +Version 0.4.1 +2005-03-15 +Fixed some typos, removed unused code + +Version 0.4.0 +2005-03-14 +Initial Araneida support (supplied by Bob Hutchison) + +Version 0.3.13 +2005-03-12 +Small bugfix in RFC-1123-DATE (thanks to Bob Hutchison and Stefan Scholl) + +Version 0.3.12 +2005-03-01 +Added *HTTP-ERROR-HANDLER* (suggested and coded by Stefan Scholl) +Exported and documented *SESSION-MAX-TIME* + +Version 0.3.11 +2005-02-21 +Added ability to access raw post data (suggested and coded by Zach Beane) + +Version 0.3.10 +2005-01-24 +Make bivalent streams work with LispWorks 4.4 +UTF-8 demo for LispWorks (thanks to Bob Hutchison) + +Version 0.3.9 +2004-12-31 +Re-compute content length after applying MAYBE-REWRITE-URLS-FOR-SESSION (caught by Stefan Scholl) + +Version 0.3.8 +2004-12-27 +Don't send body for HEAD requests (needs current mod_lisp version) + +Version 0.3.7 +2004-12-22 +Change #\Del to #\Rubout in QUOTE-STRING (AllegroCL complains, #\Del isn't even semi-standard) + +Version 0.3.6 +2004-12-02 +Make REQUIRE-AUTHORIZATION compliant to RFC 2616 (thanks to Stefan Scholl) + +Version 0.3.5 +2004-12-01 +Several small doc fixes (thanks to Stefan Scholl) +Catch requests like "GET http://server/foo.html HTTP/1.0" (suggested by Stefan Scholl) + +Version 0.3.4 +2004-11-29 +Added backtrace code for OpenMCL (provided by Tiarn�n � Corr�in) + +Version 0.3.3 +2004-11-22 +Cleaner handling of macro variables + +Version 0.3.2 +2004-11-11 +Updated docs for mod_lisp2 + +Version 0.3.1 +2004-11-09 +Slight changes to support Chris Hanson's mod_lisp2 +Changed GET-BACKTRACE for newer SBCL versions (thanks to Nikodemus Siivola) + +Version 0.3.0 +2004-11-09 +Initial support for multipart/form-data (thanks to Michael Weber and Janis Dzerins) +Fixed bug in CREATE-STATIC-FILE-DISPATCHER-AND-HANDLER (caught by Bill Clementson) + +Version 0.2.12 +2004-10-15 +Exported and documented DO-SESSIONS + +Version 0.2.11 +2004-09-02 +FORM-URL-ENCODED-LIST-TO-ALIST now decodes names and values + +Version 0.2.10 +2004-08-28 +Allow non-strings to be cookie values (bug caught by Zach Beane) + +Version 0.2.9 +2004-08-11 +Consistent usage of RFC-1123-DATE (provided by Stefan Scholl) +Added all missing http headers from RFC 2616 (provided by Stefan Scholl) +Added support for mod_lisp version strings (see http://common-lisp.net/pipermail/mod-lisp-devel/2004-August/000019.html) +Don't always add session IDs when redirecting + +Version 0.2.8 +2004-07-24 +Fixed typo in html.lisp and improved docs (both caught by Stefan Scholl) + +Version 0.2.7 +2004-07-24 +Add missing exports and docs + +Version 0.2.6 +2004-07-24 +Make CREATE-STATIC-FILE-DISPATCHER-AND-HANDLER thread-safe (caught by Jeff Caldwell) +Added support for 'If-Modified-Since' request headers (provided by Stefan Scholl) + +Version 0.2.5 +2004-07-21 +Added CREATE-STATIC-FILE-DISPATCHER-AND-HANDLER (provided by Stefan Scholl) +Improved test suite + +Version 0.2.4 +2004-07-19 +New variable *CONTENT-TYPES-FOR-URL-REWRITE* (suggested by Stefan Scholl) +Updated index.html regarding new version of mod_lisp + +Version 0.2.3 +2004-06-12 +Bugfix for FORM-URL-ENCODED-LIST-TO-ALIST (bug caught by Jong-won Choi) + +Version 0.2.2 +2004-06-10 +Bugfix for SESSION-GC and RESET-SESSIONS (bug introduced in 0.2.0) + +Version 0.2.1 +2004-06-10 +Only create backtrace if needed (speeds up AllegroCL considerably) + +Version 0.2.0 +2004-06-07 +Added SESSION-STRING and *SESSION-REMOVAL-HOOK* +Added GET-BACKTRACE for AllegroCL + +Version 0.1.2 +2004-05-12 +Removed some more typos in docs (thanks to Karl A. Krueger) +Changed BASE64 to CL-BASE64 in .asd file (thanks to Frank Sonnemans and Nicolas Lamirault) + +Version 0.1.1 +2004-05-08 +Removed some old files from Jeff's port +Fixed a couple of typos in docs + +Version 0.1.0 +2004-05-07 +First public release +Original code by Edi Weitz +Initial doc strings, port to KMRCL, logging code and various other improvements by Jeff Caldwell
Added: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/README =================================================================== --- branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/README 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/README 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,2 @@ +Complete documentation for Hunchentoot including details about how to +install it can be found in the 'doc' directory.
Property changes on: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/README ___________________________________________________________________ Name: svn:executable + *
Added: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/conditions.lisp =================================================================== --- branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/conditions.lisp 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/conditions.lisp 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,60 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: HUNCHENTOOT; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/hunchentoot/conditions.lisp,v 1.1 2007/11/08 20:07:58 edi Exp $ + +;;; Copyright (c) 2004-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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-package :hunchentoot) + +(defvar *catch-errors-p* t + "Whether Hunchentoot should catch and log errors (or rather +invoke the debugger).") + +(defgeneric maybe-invoke-debugger (condition) + (:documentation "This generic function is called whenever a +condition CONDITION is signaled in Hunchentoot. You might want to +specialize it on specific condition classes for debugging purposes.") + (:method (condition) + "The default method invokes the debugger with CONDITION if +*CATCH-ERRORS-P* is NIL." + (unless *catch-errors-p* + (invoke-debugger condition)))) + +(defmacro with-debugger (&body body) + "Executes BODY and invokes the debugger if an error is signaled and +*CATCH-ERRORS-P* is NIL." + `(handler-bind ((error #'maybe-invoke-debugger)) + ,@body)) + +(defmacro ignore-errors (&body body) + "Like CL:IGNORE-ERRORS, but observes *CATCH-ERRORS-P*." + `(cl:ignore-errors (with-debugger ,@body))) + +(defmacro handler-case (expression &rest clauses) + "Like CL:HANDLER-CASE, but observes *CATCH-ERRORS-P*." + `(cl:handler-case (with-debugger ,expression) + ,@clauses)) +
Property changes on: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/conditions.lisp ___________________________________________________________________ Name: svn:executable + *
Added: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/cookie.lisp =================================================================== --- branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/cookie.lisp 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/cookie.lisp 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,121 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: HUNCHENTOOT; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/hunchentoot/cookie.lisp,v 1.7 2007/09/18 14:23:23 edi Exp $ + +;;; Copyright (c) 2004-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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-package :hunchentoot) + +(defclass cookie () + ((name :initarg :name + :reader cookie-name + :type string + :documentation "The name of the cookie - a string.") + (value :initarg :value + :accessor cookie-value + :initform "" + :documentation "The value of the cookie. Will be URL-encoded +when sent to the browser.") + (expires :initarg :expires + :initform nil + :accessor cookie-expires + :documentation "The time (a universal time) when the +cookie expires (or NIL).") + (path :initarg :path + :initform nil + :accessor cookie-path + :documentation "The path this cookie is valid for (or NIL).") + (domain :initarg :domain + :initform nil + :accessor cookie-domain + :documentation "The domain this cookie is valid for (or NIL).") + (secure :initarg :secure + :initform nil + :accessor cookie-secure + :documentation "A generalized boolean denoting whether this +cookie is a secure cookie.") + (http-only :initarg :http-only + :initform nil + :accessor cookie-http-only + :documentation "A generalized boolean denoting whether +this cookie is a `HttpOnly' cookie. + +This is a Microsoft extension that has been implemented in Firefox as +well. See http://msdn2.microsoft.com/en-us/library/ms533046.aspx.")) + (:documentation "Each COOKIE objects describes one outgoing cookie.")) + +(defmethod initialize-instance :around ((cookie cookie) &rest init-args) + "Ensure COOKIE has a correct slot-value for NAME." + (let ((name (getf init-args :name))) + (unless (http-token-p name) + (error "~S is not a legal name for a cookie." name))) + (call-next-method)) + +(defun set-cookie* (cookie &optional (reply *reply*)) + "Adds the COOKIE object COOKIE to the outgoing cookies of the +REPLY object REPLY. If a cookie with the same name +(case-sensitive) already exists, it is replaced." + (let* ((name (cookie-name cookie)) + (place (assoc name (cookies-out reply) :test #'string=))) + (cond + (place + (setf (cdr place) cookie)) + (t + (push (cons name cookie) (cookies-out reply)) + cookie)))) + +(defun set-cookie (name &key (value "") expires path domain secure http-only (reply *reply*)) + "Creates a cookie object from the parameters provided and adds +it to the outgoing cookies of the REPLY object REPLY. If a cookie +with the name NAME (case-sensitive) already exists, it is +replaced." + (set-cookie* (make-instance 'cookie + :name name + :value value + :expires expires + :path path + :domain domain + :secure secure + :http-only http-only) + reply)) + +(defun cookie-date (universal-time) + "Converts UNIVERSAL-TIME to cookie date format." + (and universal-time + (rfc-1123-date universal-time))) + +(defmethod stringify-cookie ((cookie cookie)) + "Converts the COOKIE object COOKIE to a string suitable for a +'Set-Cookie' header to be sent to the client." + (format nil + "~A=~A~:[~;~:*; expires=~A~]~:[~;~:*; path=~A~]~:[~;~:*; domain=~A~]~:[~;; secure~]~:[~;; HttpOnly~]" + (cookie-name cookie) + (url-encode (format nil "~A" (cookie-value cookie)) +utf-8+) + (cookie-date (cookie-expires cookie)) + (cookie-path cookie) + (cookie-domain cookie) + (cookie-secure cookie) + (cookie-http-only cookie))) \ No newline at end of file
Added: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/doc/LICENSE.txt =================================================================== --- branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/doc/LICENSE.txt 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/doc/LICENSE.txt 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,9 @@ +The Hunchentoot logo (the file `hunchentoot.gif' in this directory) +was created by Uwe von Loh and is available from his website at + + http://www.htg1.de/hunchentoot/hunchentoot.html + +It is licensed under a `Creative Commons Attribution-Share Alike 2.0 +Germany License', see + + http://creativecommons.org/licenses/by-sa/2.0/de/
Property changes on: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/doc/LICENSE.txt ___________________________________________________________________ Name: svn:executable + *
Added: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/doc/hunchentoot.gif =================================================================== (Binary files differ)
Property changes on: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/doc/hunchentoot.gif ___________________________________________________________________ Name: svn:executable + * Name: svn:mime-type + application/octet-stream
Added: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/doc/index.html =================================================================== --- branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/doc/index.html 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/doc/index.html 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,2613 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<html> + +<head> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <title>HUNCHENTOOT - The Common Lisp web server formerly known as TBNL</title> + <style type="text/css"> + pre { padding:5px; background-color:#e0e0e0 } + h3, h4 { text-decoration: underline; } + a { text-decoration: none; padding: 1px 2px 1px 2px; } + a:visited { text-decoration: none; padding: 1px 2px 1px 2px; } + a:hover { text-decoration: none; padding: 1px 1px 1px 1px; border: 1px solid #000000; } + a:focus { text-decoration: none; padding: 1px 2px 1px 2px; border: none; } + a.none { text-decoration: none; padding: 0; } + a.none:visited { text-decoration: none; padding: 0; } + a.none:hover { text-decoration: none; border: none; padding: 0; } + a.none:focus { text-decoration: none; border: none; padding: 0; } + a.noborder { text-decoration: none; padding: 0; } + a.noborder:visited { text-decoration: none; padding: 0; } + a.noborder:hover { text-decoration: none; border: none; padding: 0; } + a.noborder:focus { text-decoration: none; border: none; padding: 0; } + pre.none { padding:5px; background-color:#ffffff } + </style> +</head> + +<body bgcolor=white> + +<h2><a href="http://www.htg1.de/hunchentoot/hunchentoot.html" title="Click here for the Hunchentoot logo" class=noborder><img align=top width=93 height=45 border=0 src="hunchentoot.gif"></a> HUNCHENTOOT - The Common Lisp web server formerly known as TBNL</h2> + +<blockquote> +<br> <br><h3><a name=abstract class=none>Abstract</a></h3> + +Hunchentoot is a web server written in Common Lisp and at the same +time a toolkit for building dynamic websites. As a +stand-alone web server, Hunchentoot is capable of HTTP/1.1 chunking +(both directions), persistent connections (keep-alive), and SSL, but +it can also sit behind the +popular <a href='http://httpd.apache.org/'>Apache</a> using +Marc +Battyani's <a +href='http://www.fractalconcept.com/asp/html/mod_lisp.html%27%3Emod_lisp</a>. + +<p> + +Hunchentoot provides facilities like automatic session handling (with +and without cookies), logging (to Apache's log files or to a file in +the file system), customizable error handling, and easy access to GET +and POST parameters sent by the client. It does <em>not</em> include +functionality to programmatically generate HTML output. For this task +you can use any library you like, e.g. (shameless +self-plug) <a href="http://weitz.de/cl-who/">CL-WHO</a> +or <a href="http://weitz.de/html-template/">HTML-TEMPLATE</a>. + +<p> + +Hunchentoot talks with its front-end or with the client over TCP/IP +sockets and uses multiprocessing to handle several requests at the +same time. Therefore, it cannot be implemented completely +in <a +href="http://www.lispworks.com/documentation/HyperSpec/Front/index.htm%22%3Eportab... +Common Lisp</a>. It currently works with +<a href="http://www.lispworks.com/">LispWorks</a> (which is the main development and testing platform), +<a href="http://www.cons.org/cmucl/">CMUCL</a> (with MP +support), <a href="http://sbcl.sourceforge.net/">SBCL</a> (with +Unicode and <a href="http://abstractstuff.livejournal.com/26811.html">thread</a> <a href="http://common-lisp.net/pipermail/tbnl-devel/2006-November/000780.html">support</a>), +<a href="http://openmcl.clozure.com/">OpenMCL</a>, +and <a href="http://www.franz.com/products/allegrocl/">Allegro Common +Lisp</a>. (Note: You can use Hunchentoot with a version of SBCL +without threads, for example on Windows, but this is not recommended +except for development purposes.) Porting to other CL implementations +shouldn't be too hard, see the files <code>port-xxx.lisp</code> +and <code>unix-xxx.lisp</code> which comprise all the +implementation-specific code. + +<p> + +Hunchentoot comes with a <a +href="http://www.opensource.org/licenses/bsd-license.php%22%3EBSD-style +license</a> so you can basically do with it whatever you want. +<p> + +Hunchentoot is for example used by <a href="http://clutu.com/">clutu</a>, <a href="http://twitterbuzz.com/">TwitterBuzz</a>, +<a href="http://www.jalat.com/">Jalat</a>, <a href="http://heikestephan.de/">Heike Stephan</a>, +<a href="http://www.memetrics.com/">xOs</a>, +and <a href="http://syseng.nist.gov/moss">the</a> <a href="http://syseng.nist.gov/se-interop">NIST</a>. + +<p> +<font color=red>Download shortcut:</font> <a href="http://weitz.de/files/hunchentoot.tar.gz">http://weitz.de/files/hunchentoot.tar.gz</a>. +</blockquote> + +<br> <br><h3><a class=none name="contents">Contents</a></h3> +<ol> + <li><a href="#install">Download and installation</a> + <ol> + <li><a href='#proxy'>Hunchentoot behind a proxy</a> + <li><a href='#mod_lisp'>Hunchentoot behind mod_lisp</a> + </ol> + <li><a href="#mail">Support and mailing lists</a> + <li><a href="#example">Examples, tutorials, add-ons</a> + <li><a href="#reference">Function and variable reference</a> + <ol> + <li><a href='#servers'>Servers</a> + <li><a href='#handlers'>Handlers</a> + <li><a href='#requests'>Requests</a> + <li><a href='#replies'>Replies</a> + <li><a href='#cookies'>Cookies</a> + <li><a href='#sessions'>Sessions</a> + <li><a href='#log'>Logging and error handling</a> + <li><a href='#debug'>Debugging Hunchentoot applications</a> + <li><a href='#misc'>Miscellaneous</a> + </ol> + <li><a href="#ht-mp">The HUNCHENTOOT-MP package</a> + <li><a href="#performance">Performance</a> + <li><a href="#history">History</a> + <li><a href="#index">Symbol index</a> + <li><a href="#ack">Acknowledgements</a> +</ol> + +<br> <br><h3><a name="install" class=none>Download and installation</a></h3> + +Hunchentoot depends on a couple of other Lisp libraries which you'll need +to install first: +<ul> + <li>Pierre R. Mai's <a href='http://www.cliki.net/md5'>MD5</a>, + + <li>Kevin Rosenberg's <a href='http://www.cliki.net/cl-base64'>CL-BASE64</a>, + + <li>Janis Dzerins' <a href='http://common-lisp.net/project/rfc2388/'>RFC2388</a>, + + <li>David Lichteblau's <a href='http://common-lisp.net/project/cl-plus-ssl/'>CL+SSL</a> (unless you're using LispWorks), + + <li><a href='http://www.cliki.net/ACL-COMPAT'>ACL-COMPAT</a> (for OpenMCL only), + + <li>and my own <a href='http://weitz.de/flexi-streams/'>FLEXI-STREAMS</a> (0.12.0 or higher), <a href='http://weitz.de/chunga/'>Chunga</a>, <a href='http://weitz.de/cl-ppcre/'>CL-PPCRE</a>, and <a href='http://weitz.de/url-rewrite/'>URL-REWRITE</a> (plus <a href="http://weitz.de/cl-who/">CL-WHO</a> for the <a href="#example">example code</a>). +</ul> +Make sure to use the <em>newest</em> versions of all of these libraries (which might themselves depend on other libraries)! +Note: You can compile Hunchentoot without SSL support - and thus without the need to have CL+SSL - if you add <code>:HUNCHENTOOT-NO-SSL</code> to <a href="http://www.lispworks.com/documentation/HyperSpec/Body/v_featur.htm"><code>*FEATURES*</code></a> <em>before</em> you compile it. +<p> +The preferred method to compile and load Hunchentoot is via <a href="http://www.cliki.net/asdf">ASDF</a>. +<p> +Hunchentoot together with this documentation can be downloaded +from <a +href="http://weitz.de/files/hunchentoot.tar.gz%22%3Ehttp://weitz.de/files/hunchent...</a>. The +current version is 0.14.6. There's also a port +for <a href="http://www.gentoo.org/proj/en/common-lisp/index.xml">Gentoo +Linux</a> thanks to Matthew Kennedy. +<p> +A <a href="http://www.selenic.com/mercurial/wiki/">Mercurial</a> +repository of older versions is available +at <a +href="http://arcanes.fr.eu.org/~pierre/2007/02/weitz/%22%3Ehttp://arcanes.fr.eu.or...</a> +thanks to Pierre Thierry. +<p> +Luís Oliveira maintains a <a href="http://darcs.net/">darcs</a> +repository of Hunchentoot +at <a +href="http://common-lisp.net/~loliveira/ediware/%22%3Ehttp://common-lisp.net/~loli...</a>. + +<h4><a name="proxy" class=none>Hunchentoot behind a proxy</a></h4> + +If you're feeling unsecure about exposing Hunchentoot to the wild, +wild Internet or if your Lisp web application is part of a larger +website, you can hide it behind +a <a href="http://en.wikipedia.org/wiki/Proxy_server">proxy +server</a>. One approach that I have used several times is to employ +Apache's <a +href="http://httpd.apache.org/docs/2.0/mod/mod_proxy.html%22%3Emod_proxy</a> +module with a configuration that looks like this: +<pre> +<a href="http://httpd.apache.org/docs/2.0/mod/mod_proxy.html#proxypass" class=noborder>ProxyPass</a> /hunchentoot http://127.0.0.1:3000/hunchentoot +<a href="http://httpd.apache.org/docs/2.0/mod/mod_proxy.html#proxypassreverse" class=noborder>ProxyPassReverse</a> /hunchentoot http://127.0.0.1:3000/hunchentoot +</pre> +This will tunnel all requests where the URI path begins with <code>"/hunchentoot"</code> to a (Hunchentoot) server listening on port 3000 on the same machine. +<p> +Of course, there are <a href="http://www.red-bean.com/pipermail/lispweb/2006-October/001342.html">several other</a> (more lightweight) web proxies that +you could use instead of Apache. + +<h4><a name="mod_lisp" class=none>Hunchentoot behind mod_lisp</a></h4> + +You can also couple Hunchentoot more tightly with Apache +using <a +href='http://www.fractalconcept.com/asp/html/mod_lisp.html%27%3Emod_lisp</a>. +In this case, Apache will not send proxy requests to Hunchentoot, but +communicate with it directly using a simple, line-based protocol. The +downside of this approach is that it makes debugging harder. (Also, +with mod_lisp, +you <a +href="http://common-lisp.net/pipermail/mod-lisp-devel/2006-October/000098.html%22%... +accept request bodies that use chunked encoding</a>. With the usual +web browsers, this shouldn't be a problem, though.) +<p> +For this setup you need two things: + +<ul> + <li>The <a href='http://httpd.apache.org/'>Apache web server</a>. You can use either 1.3.x or 2.x. It is recommend that you use or build an Apache with <a href='http://httpd.apache.org/docs/dso.html'>DSO support</a>. + + <li>The <a +href='http://www.fractalconcept.com/asp/html/mod_lisp.html%27%3Emod_lisp</a> +Apache module by Marc Battyani. It is beyond the scope of this document to explain the +details of how to install mod_lisp, but if your Apache has DSO support, +it should suffice to issue a command like + +<pre> +apxs -c -i -a mod_lisp.c +</pre> + +as root (and afterwards restart Apache). +<p> +The newest version of mod_lisp is available from <a +href="http://www.fractalconcept.com:8000/public/open-source/mod_lisp/%22%3Ehttp://...</a>. For Apache 1.3.x you +must use mod_lisp.c, for Apache 2.x you must use mod_lisp2.c, which is a reimplementation of Marc's mod_lisp by Chris Hanson. +<p> +You can get pre-compiled modules for the Win32 version of Apache 2 (but probably not the latest version) from <a href="http://www.fractalconcept.com:8000/public/open-source/mod_lisp/windows/">http://www.fractalconcept.com:8000/public/open-source/mod_lisp/windows/</a>. Put the file into Apache's <code>modules</code> folder and add the line +<pre> +LoadModule lisp_module modules/mod_lisp2.so +</pre> +to your <code>httpd.conf</code> file. + +</ul> + +Then you will have to configure Apache and mod_lisp to make them aware +of Hunchentoot. First, in your Apache configuration file (usually +called <code>httpd.conf</code>) add these lines + +<pre> +<a name='LispServer' class=noborder>LispServer</a> 127.0.0.1 3000 "foo" + +<Location /hunchentoot> + SetHandler lisp-handler +</Location> +</pre> + +and afterwards restart Apache. This informs mod_lisp that there's a +Lisp listening on port 3000 and named +"foo" - you can of course use any other name or port or +even put Hunchentoot on another physical machine. (In the latter case you'll +have to replace <code>127.0.0.1</code> with the FQDN or IP address of +this machine.) +<p> +The <code>Location/SetHandler</code> part means that every URL which +starts with <code>/hunchentoot</code> will be handled by mod_lisp (and thus +Hunchentoot) on this server. (Again, you can of course use other locations. See the +Apache documentation for things like <em>virtual hosts</em> or +directives like <code>LocationMatch</code>.) + +<p> + +To interface a Hunchentoot server with mod_lisp, you must start it +with the <code>:MOD-LISP-P</code> keyword parameter +of <a href="#start-server"><code>START-SERVER</code></a> set to a true +value. + +<br> <br><h3><a name="mail" class=none>Support and mailing lists</a></h3> + +For questions, bug reports, feature requests, improvements, or patches +please use +the <a +href="http://common-lisp.net/mailman/listinfo/tbnl-devel%22%3Etbnl-devel +mailing list</a>. If you want to be notified about future releases +subscribe to +the <a +href="http://common-lisp.net/mailman/listinfo/tbnl-announce%22%3Etbnl-announce +mailing list</a>. These mailing lists were made available thanks to +the services of <a href="http://common-lisp.net/">common-lisp.net</a>. +You can <b>search</b> the devel mailing +list <a +href="http://google.com/coop/cse?cx=002927904911724867201%3A0l5rif_cxj0%22%3Ehere</a> +(thanks to Tiarn�n � Corr�in). +<p> +If you want to send patches, please <a href="http://weitz.de/patches.html">read this first</a>. + +<br> <br><h3><a name="example" class=none>Examples, tutorials, add-ons</a></h3> + +Hunchentoot comes with an example website which you can use to see if +it works and which should also demonstrate a couple of the things you +can do with Hunchentoot. Use it as a kind of "Hello World" code to +get yourself started. +<p> +To run the example, +enter the following code into your listener: +<pre> +(<a class=noborder href="http://common-lisp.net/~mmommer/asdf-howto.shtml#sec11">asdf:oos</a> 'asdf:load-op :hunchentoot-test) +(hunchentoot:<a class=noborder href="#start-server">start-server</a> :port 4242) +</pre> +You should now be able to point your browser +at <code>http://localhost:4242/hunchentoot/test</code> and see +something. +<p> +Here are some tutorials done by others: +<ul> +<li>Two <a href="http://myblog.rsynnott.com/2007/09/getting-started-with-hunchento.html">getting</a> <a href="http://myblog.rsynnott.com/2007/10/doing-more-with-hunchentoot-cl-server.html">started</a> articles by Robert Synnott. +<li>A <a href="http://www.lispcast.com/index.php/2007/10/lispcast-writing-a-simple-reddit-clone-in-common-lisp/">"LispCast"</a> by Eric Normand about writing a <a href="http://reddit.com/">Reddit</a> clone using Hunchentoot. Apparently the first part of a <a href="http://bc.tech.coop/blog/071028.html">series</a>. +<li>A <a +href="http://www.jalat.com/blogs/lisp?id=3%22%3Etutorial</a> for (an older version of) Hunchentoot by Asbjørn Bjørnstad. +<li>A <a href="http://www.frank-buss.de/lisp/tbnl.html">TBNL +tutorial</a> from Frank Buss. (Hunchentoot is not <a href="http://weitz.de/tbnl/">TBNL</a>, but the two +are similar enough to make the tutorial worthwhile.) +<li> +For Win32, Bill Clementson +<a +href="http://bc.tech.coop/blog/041105.html%22%3Eexplains</a> how to set up Hunchentoot's predecessor <a href="http://weitz.de/tbnl/">TBNL</a> with +Apache/mod_lisp. See also <a href="http://bc.tech.coop/blog/061013.html">http://bc.tech.coop/blog/061013.html</a>. +</ul> +Check the dates of these tutorials. Some of them might not be a +perfect fit with the latest release of Hunchentoot. Also, the fact +that these tutorials are listed here doesn't necessarily mean that I +endorse them or think that they show idiomatic Lisp code. You'll have +to decide yourself if they're helpful to you or not. +</p> +<p> +Here is some software which extends Hunchentoot or is based on it: +<ul> +<li><a href="http://85.65.214.241/misc/ht-ajax.html">HT-AJAX</a> is +an <a +href="http://en.wikipedia.org/wiki/Ajax_%28programming%29%22%3EAjax</a> +framework for Hunchentoot by Ury Marshak. +<li>Mac +Chan <a +href="http://common-lisp.net/pipermail/tbnl-devel/2007-May/001324.html%22%3Ehas +ported <a href="http://lemonodor.com/">John +Wiseman</a>'s <a +href="http://www.lemonodor.com/archives/000128.html%22%3ELisp Server +Pages</a> to Hunchentoot. +<li><a +href="http://site.znain.com/dl/lisp/hunchentoot-dir-lister/%22%3Ehunchentoot-dir-l...</a> +is a directory listing addition for Hunchentoot by Dimitre Liotev. +<li>Cyrus +Harmon's <a +href="http://cyrusharmon.org/blog/display?id=64%22%3Enuclblog</a> is a +<a href="http://en.wikipedia.org/wiki/Blog">blog</a> engine which uses Hunchentoot. +<li><a href="http://weitz.de/cl-webdav/">CL-WEBDAV</a> is a <a href="http://webdav.org/">WebDAV</a> server based on Hunchentoot. +</ul> + +<br> <br><h3><a class=none name="reference">Function and variable reference</a></h3> + +<h4><a class=none name="servers">Servers</a></h4> + +If you want Hunchentoot to actually do something, you have +to <a href="#start-server">start</a> a server. You can also run +several servers in one image, each one listening to a different port. + +<p><br>[Function] +<br><a class=none name="start-server"><b>start-server</b> <i><tt>&key</tt> port address name dispatch-table mod-lisp-p use-apache-log-p input-chunking-p read-timeout write-timeout setuid setgid ssl-certificate-file ssl-privatekey-file ssl-privatekey-password</i> => <i>server</i></a> + +<blockquote><br> Starts a Hunchentoot server instance and returns it. +<code><i>port</i></code> ist the port the server will be listening on +- the default is 80 (or 443 if SSL information is provided). +If <code><i>address</i></code> is a string denoting an IP address, +then the server only receives connections for that address. This must +be one of the addresses associated with the machine and allowed values +are host names such as <a class=none href="http://www.zappa.com/"><code>"www.zappa.com"</code></a> and address +strings such as <a class=none href="http://72.3.247.29/"><code>"72.3.247.29"</code></a>. +If <code><i>address</i></code> is <code>NIL</code>, then the server +will receive connections to all IP addresses on the machine. This is +the default. +<p> +<code><i>dispatch-table</i></code> can either be +a <a href="#*dispatch-table*">dispatch table</a> which is to be used +by this server or <code>NIL</code> which means that at request +time <a href="#*meta-dispatcher*"><code>*META-DISPATCHER*</code></a> +will be called to retrieve a dispatch table. +<p> +<code><i>name</i></code> should be a symbol which can be used to name +the server. This name can utilized when +defining <a href="#define-easy-handler">easy handlers</a>. The +default name is an uninterned symbol as returned +by <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/f_gensym.htm%22%3E<code>GENSYM</code></a>. +<p> +If <code><i>mod-lisp-p</i></code> is true (the default +is <code>NIL</code>), the server will act as a back-end +for <a href="#mod_lisp">mod_lisp</a>, otherwise it will be a +stand-alone web server. If <code><i>use-apache-log-p</i></code> is +true (which is the default), log messages will be written to the +Apache log file - this parameter has no effect +if <code><i>mod-lisp-p</i></code> is NIL. +<p> +If <code><i>input-chunking-p</i></code> is true (which is the +default), the server will accept request bodies without +a <code>Content-Length</code> header if the client uses chunked +transfer encoding. If you want to use this feature behind mod_lisp, +you should make sure that your combination of Apache and +mod_lisp <a +href="http://common-lisp.net/pipermail/mod-lisp-devel/2006-December/000104.html%22... +cope with that</a>. +<p> +<code><i>read-timeout</i></code> is the read timeout (in seconds) for +the socket stream used by the server - the default value +is <a +href="#*default-read-timeout*"><code>*DEFAULT-READ-TIMEOUT*</code></a>. +This parameter is ignored on OpenMCL. <code><i>write-timeout</i></code> is the write timeout (in +seconds) for the socket stream used by the server - the default value +is <a +href="#*default-write-timeout*"><code>*DEFAULT-WRITE-TIMEOUT*</code></a>. +This parameter is ignored on all implementations except for +LispWorks 5.0 or higher and AllegroCL. You can use <code>NIL</code> in both +cases to denote that you don't want a timeout. +If <code><i>mod-lisp-p</i></code> is true, the timeouts are always set +to <code>NIL</code>. +<p> +On Unix you can use <code><i>setuid</i></code> +and <code><i>setgid</i></code> to change the UID and GID of the +process directly after the server has been started. (You might want +to do this if you're using a privileged port like 80.) <code><i>setuid</i></code> and +<code><i>setgid</i></code> can be integers (the actual IDs) or strings +(for the user and group name respectively). +<p> +If you want your server to use SSL, you must provide the pathname +designator(s) <code><i>ssl-certificate-file</i></code> for the certificate file and +optionally <code><i>ssl-privatekey-file</i></code> for the private key file, both files +must be in PEM format. If you only provide the value for +<code><i>ssl-certificate-file</i></code> it is assumed that both the +certificate and the private key are in one file. If your private key +needs a password you can provide it through +the <code><i>ssl-privatekey-password</i></code> keyword argument. If +you <em>don't</em> use LispWorks, the private key must not be +associated with a password, and the certificate and the private key +must be in separate files. +</blockquote> + +<p><br>[Function] +<br><a class=none name="stop-server"><b>stop-server</b> <i>server</i> => |</a> + +<blockquote><br> +Stops a server started with <a href="#start-server"><code>START-SERVER</code></a>. <code><i>server</i></code> must be an object as returned by <a href="#start-server"><code>START-SERVER</code></a>. +</blockquote> + +<p><br>[Special variable] +<br><a class=none name="*server*"><b>*server*</b></a> + +<blockquote><br> +During the execution of <a href="#handlers">dispatch functions and handlers</a> this variable +is bound to the server object (as returned by <a href="#start-server"><code>START-SERVER</code></a>) which processes the request. +</blockquote> + +<p><br>[Readers] +<br><a class=none name="server-local-port"><b>server-local-port</b> <i>server</i> => <i>port</i></a> +<br><a class=none name="server-address"><b>server-address</b> <i>server</i> => <i>address</i></a> + +<blockquote><br> +These methods can be used to query a Hunchentoot server object. The values correspond to the <code><i>port</i></code> and <code><i>address</i></code> parameters of <a href="#start-server"><code>START-SERVER</code></a>. +</blockquote> + +<p><br>[Accessor] +<br><a class=none name="server-dispatch-table"><b>server-dispatch-table</b> <i>server</i> => <i>dispatch-table</i> +<br><tt>(setf (</tt><b>server-dispatch-table</b> <i>server</i>) <i>new-value</i><tt>)</tt></a> + +<blockquote><br> These methods can be used to get and set +the <a href="#*dispatch-table*">dispatch table</a> of a Hunchentoot +server object. The value corresponds to +the <code><i>dispatch-table</i></code> parameter +of <a href="#start-server"><code>START-SERVER</code></a> and can be +changed at runtime. It can be set to NIL which means that the server +doesn't have its own dispatch table +and <a href="#*meta-dispatcher*"><code>*META-DISPATCHER*</code></a> should be +called instead. +</blockquote> + +<p><br>[Accessor] +<br><a class=none name="server-name"><b>server-name</b> <i>server</i> => <i>name</i> +<br><tt>(setf (</tt><b>server-name</b> <i>server</i>) <i>new-value</i><tt>)</tt></a> +<blockquote><br> These methods can be used to get and set the name of a server +which must be a symbol. +</blockquote> + +<p><br>[Special variable] +<br><a class=none name="*default-read-timeout*"><b>*default-read-timeout*</b></a> + +<blockquote><br> The default value for the <code><i>read-timeout</i></code> keyword +argument to <a href="#start-server"><code>START-SERVER</code></a>. The initial value is 20 (seconds). +</blockquote> + +<p><br>[Special variable] +<br><a class=none name="*default-write-timeout*"><b>*default-write-timeout*</b></a> + +<blockquote><br> The default value for the <code><i>write-timeout</i></code> keyword +argument to <a href="#start-server"><code>START-SERVER</code></a>. The initial value is 20 (seconds). +</blockquote> + +<p><br>[Special variable] +<br><a class=none name="*cleanup-interval*"><b>*cleanup-interval*</b></a> + +<blockquote><br> +Should be <code>NIL</code> or a positive integer. The system calls +<a href="#*cleanup-function*"><code>*CLEANUP-FUNCTION*</code></a> whenever <a href="#*cleanup-interval*"><code>*CLEANUP-INTERVAL*</code></a> new worker threads have +been created unless the value is <code>NIL</code>. The initial value is 100. +</blockquote> + +<p><br>[Special variable] +<br><a class=none name="*cleanup-function*"><b>*cleanup-function*</b></a> + +<blockquote><br> +The function (with no arguments) which is called if <a href="#*cleanup-interval*"><code>*CLEANUP-INTERVAL*</code></a> is not <code>NIL</code>. +The initial value is a function which calls +<code>(<a href="http://www.lispworks.com/documentation/lw50/LWRM/html/lwref-166.htm">HCL</a>:<a href="http://www.lispworks.com/documentation/lw50/LWRM/html/lwref-212.htm"><code>MARK-AND-SWEEP</code></a> 2)</code> on LispWorks and does nothing on other Lisps. +<p> +On LispWorks this is necessary because each <em>worker</em> (which is +created to handle an incoming http request and which dies afterwards +unless the connection is persistent) is a Lisp process and LispWorks +creates processes in generation 2. +<p> +Note that you can also set this value to <code>NIL</code> and tune +LispWork's GC yourself, using for +example <a +href="http://www.lispworks.com/documentation/lw50/LWRM/html/lwref-180.htm%22%3E<code>COLLECT-GENERATION-2</code></a>. +</blockquote> + +<h4><a class=none name="handlers">Handlers</a></h4> + +Hunchentoot handles each incoming request dynamically depending on the +contents of a global <em>dispatch table</em>. The details can be found +below. (See the file <code>test/test.lisp</code> for examples.) + +<p><br>[Special variable] +<br><a class=none name="*dispatch-table*"><b>*dispatch-table*</b></a> + +<blockquote><br> + +The return value of the initial value of <a href="#*meta-dispatcher*"><code>*META-DISPATCHER*</code></a>. +<p> +This is a list of <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_f.htm#function_... +designators</a> for <em>dispatch functions</em> each of which should +be a function of one argument which accepts a <a +href='#requests'><code>REQUEST</code></a> object and, depending on +this object, should either return a <em>handler</em> to handle the +request or <code>NIL</code> which means that the next dispatcher will +be queried. A <em>handler</em> is a designator for a function with no +arguments which usually returns a string or an array of octets to be sent to the client as +the body of the http reply. (Note that if you use symbols as function +designators, you can redefine your handler functions without the need +to change the dispatch functions.) See <a href='#replies'>the section +about replies</a> for more about what handlers can do. +<p> +The dispatchers in a dispatch table are tried in turn +until one of them returns a handler. If this doesn't happen, Hunchentoot will +return a 404 status code (Not Found) to the client. +<p> +The initial value of <code>*DISPATCH-TABLE*</code> is a list which +just contains the symbol <a +href='#default-dispatcher'><code>DEFAULT-DISPATCHER</code></a>. + +</blockquote> + +<p><br>[Function] +<br><a class=none name="default-dispatcher"><b>default-dispatcher</b> <i>request</i> => <i>handler</i></a> + +<blockquote><br> + +This is a function which will always unconditionally return the value of <a +href='#*default-handler*'><code>*DEFAULT-HANDLER*</code></a>. It is intended to be the last element of <a +href='#*dispatch-table*'><code>*DISPATCH-TABLE*</code></a>. + +</blockquote> + +<p><br>[Special variable] +<br><a class=none name="*default-handler*"><b>*default-handler*</b></a> + +<blockquote><br> + +This variable holds the handler which is always returned by <a +href='#default-dispatcher'><code>DEFAULT-DISPATCHER</code></a>. The +default value is a function which unconditonally shows a short Hunchentoot +info page. + +</blockquote> + +<p><br>[Special variable] +<br><a class=none name="*meta-dispatcher*"><b>*meta-dispatcher*</b></a> + +<blockquote><br> The value of this variable should be a function of +one argument. It is called with the current Hunchentoot server +instance (unless the server has <a href="#server-dispatch-table">its +own dispatch table</a>) and must return a dispatch table suitable for +Hunchentoot. The initial value is a function which always +unconditionally returns +<a href="#*dispatch-table*"><code>*DISPATCH-TABLE*</code></a>. +<p> +This can obviously be used to assign different dispatch tables to +different servers (and is useless if you only have one server). +</blockquote> + +<p><br>[Function] +<br><a class=none name="create-prefix-dispatcher"><b>create-prefix-dispatcher</b> <i>prefix handler</i> => <i>dispatch-fn</i></a> + +<blockquote><br> + +A convenience function which will return a dispatcher that returns <code><i>handler</i></code> whenever the path part of the request URI starts with the string <code><i>prefix</i></code>. + +</blockquote> + +<p><br>[Function] +<br><a class=none name="create-regex-dispatcher"><b>create-regex-dispatcher</b> <i>regex handler</i> => <i>dispatch-fn</i></a> + +<blockquote><br> + +A convenience function which will return a dispatcher that returns <code><i>handler</i></code> whenever the path part of the request URI matches the <a href='http://weitz.de/cl-ppcre/'>CL-PPCRE</a> regular expression <code><i>regex</i></code> (which can be a string, an s-expression, or a scanner). + +</blockquote> + +<p><br>[Function] +<br><a class=none name="handle-static-file"><b>handle-static-file</b> <i>path <tt>&optional</tt> content-type</i> => <i>nil</i></a> + +<blockquote><br> +Sends the file denote by the pathname designator +<code><i>path</i></code> with content type +<code><i>content-type</i></code> to the client. Sets the necessary handlers. In particular the function employs +<a href="#handle-if-modified-since"><code>HANDLE-IF-MODIFIED-SINCE</code></a>. +<p> +If <code><i>content-type</i></code> is <code>NIL</code> the function +tries to determine the correct content type from the file's suffix or +falls back to <code>"application/octet-stream"</code> as a last resort. +<p> +Note that this function +calls <a href="#send-headers"><code>SEND-HEADERS</code></a> +internally, so after you've called it, the headers are sent and the +return value of your handler is ignored. +</blockquote> + +<p><br>[Function] +<br><a class=none name="create-static-file-dispatcher-and-handler"><b>create-static-file-dispatcher-and-handler</b> <i>uri path <tt>&optional</tt> content-type</i> => <i>dispatch-fn</i></a> + +<blockquote><br> + +A convenience function which will return a dispatcher that dispatches +to a handler which emits the file denoted by the pathname designator +<code><i>path</i></code> with content type +<code><i>content-type</i></code> +if the <a href='#script-name'><code>SCRIPT-NAME</code></a> of the +request matches the string <code><i>uri</i></code>. Uses <a href="#handle-static-file"><code>HANDLE-STATIC-FILE</code></a> internally. +<p> +If <code><i>content-type</i></code> is <code>NIL</code> the function tries to determine the correct content type from the file's suffix +or falls back to <code>"application/octet-stream"</code> as a last resort. +<a href='#*default-content-type*'><code>*DEFAULT-CONTENT-TYPE*</code></a>. +</blockquote> + +<p><br>[Function] +<br><a class=none name="create-folder-dispatcher-and-handler"><b>create-folder-dispatcher-and-handler</b> <i>uri-prefix base-path <tt>&optional</tt> content-type</i> => <i>dispatch-fn</i></a> + +<blockquote><br> +Creates and returns a dispatch function which will dispatch to a +handler function which emits the file relative to <code><i>base-path</i></code> that is +denoted by the URI of the request relative to <code><i>uri-prefix</i></code>. <code><i>uri-prefix</i></code> +must be a string ending with a slash, <code><i>base-path</i></code> must be a pathname +designator for an existing directory. +Uses <a href="#handle-static-file"><code>HANDLE-STATIC-FILE</code></a> internally. +<p> +If <code><i>content-type</i></code> is <em>not</em> <code>NIL</code>, +it will be used as a the content type for all files in the folder. +Otherwise (which is the default) the content type of each file will be determined <a href="#handle-static-file">as usual</a>. +</blockquote> + +<p><br>[Generic function] +<br><a class=none name="dispatch-request"><b>dispatch-request</b> <i>dispatch-table</i> => <i>result</i></a> + +<blockquote><br> +This is a generic function so users can customize its behaviour. Look at the source code for details. +</blockquote> + +<p><br>[Macro] +<br><a class=none name="define-easy-handler"><b>define-easy-handler</b> <i>description lambda-list [[declaration* | documentation]] form*</i></a> + +<blockquote><br> + +Defines a handler as if +by <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/m_defun.htm%22%3E<code>DEFUN</code></a> +and optionally registers it with a URI so that it will be found +by <a +href="#dispatch-easy-handlers"><code>DISPATCH-EASY-HANDLERS</code></a>. +<p> +<code><i>description</i></code> is either a symbol <code><i>name</i></code> or a list matching the +<a href="http://www.lispworks.com/documentation/HyperSpec/Body/03_de.htm">destructuring lambda list</a> + +<pre> + (name &key uri server-names default-parameter-type default-request-type). +</pre> + +<code><i>lambda-list</i></code> is a list the elements of which are either a symbol +<code><i>var</i></code> or a list matching the destructuring lambda list + +<pre> + (var &key real-name parameter-type init-form request-type). +</pre> + +The resulting handler will be a Lisp function with the +name <code><i>name</i></code> and keyword parameters named by +the <code><i>var</i></code> symbols. Each <code><i>var</i></code> +will be bound to the value of the GET or POST parameter +called <code><i>real-name</i></code> (a string) before the body of the +function is executed. If <code><i>real-name</i></code> is not +provided, it will be computed by <a href="http://www.lispworks.com/documentation/HyperSpec/Body/f_stg_up.htm#string-downcase">downcasing</a> the symbol name +of <code><i>var</i></code>. +<p> +If <code><i>uri</i></code> (which is evaluated) is provided, then it must be a string or +a <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_f.htm#function_... +designator</a> for a unary function. In this case, +the handler will be returned by <a href="#dispatch-easy-handlers"><code>DISPATCH-EASY-HANDLERS</code></a>, if <code><i>uri</i></code> is a +string and the <a href="#script-name">script name</a> of the current request is <code><i>uri</i></code>, or if <code><i>uri</i></code> designates a +function and applying this function to the <a href="#*request*">current <code>REQUEST</code> object</a> +returns a true value. +<p> + +<code><i>server-names</i></code> (which is evaluated) can be a list of +symbols which means that the handler will only be returned +by <a +href="#dispatch-easy-handlers"><code>DISPATCH-EASY-HANDLERS</code></a> +in servers which have one of these names +(see <a +href="#server-name"><code>SERVER-NAME</code></a>). <code><i>server-names</i></code> +can also be the symbol <code>T</code> which means that the handler +will be returned +by <a +href="#dispatch-easy-handlers"><code>DISPATCH-EASY-HANDLERS</code></a> +in <em>every</em> server. +<p> +Whether the GET or POST parameter (or both) will be taken into +consideration, depends on <code><i>request-type</i></code> which can +be <code>:GET</code>, <code>:POST</code>, <code>:BOTH</code>, or <code>NIL</code>. In the last case, the value of +<code><i>default-request-type</i></code> (the default of which +is <code>:BOTH</code>) will be used. +<p> +The value of <code><i>var</i></code> will usually be a string (unless +it resulted from a <a href="#upload">file upload</a> in which case it won't be converted at +all), but if <code><i>parameter-type</i></code> (which is evaluated) +is provided, the string will be converted to another Lisp type by the +following rules: +<p> +If the corresponding GET or POST parameter wasn't provided by the +client, <code><i>var</i></code>'s value will be <code>NIL</code>. If <code><i>parameter-type</i></code> is <code>'STRING</code>, +<code><i>var</i></code>'s value remains as is. If <code><i>parameter-type</i></code> is <code>'INTEGER</code> and the +parameter string consists solely of decimal digits, <code><i>var</i></code>'s value will be +the corresponding integer, otherwise <code>NIL</code>. If <code><i>parameter-type</i></code> is +<code>'KEYWORD</code>, <code><i>var</i></code>'s value will be the +keyword obtained +by <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/f_intern.htm%22%3Einte...</a> +the <a href="http://www.lispworks.com/documentation/HyperSpec/Body/f_stg_up.htm#string-upcase">upcased</a> parameter string into +the <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/11_abc.htm%22%3Ekeywor... +package</a>. If <code><i>parameter-type</i></code> +is <code>'CHARACTER</code> and the parameter string is of length +one, <code><i>var</i></code>'s value will be the single character of +this string, otherwise <code>NIL</code>. +If <code><i>parameter-type</i></code> +is <code>'BOOLEAN</code>, <code><i>var</i></code>'s value will always +be <code>T</code> (unless it is <code>NIL</code> by the first rule +above, of course). If <code><i>parameter-type</i></code> is any other +atom, it is supposed to be +a <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_f.htm#function_... +designator</a> for a unary function which will be called to +convert the string to something else. +<p> +Those were the rules for <em>simple</em> parameter types, but +<code><i>parameter-type</i></code> can also be a list starting with one of the symbols +<code>LIST</code>, <code>ARRAY</code>, or <code>HASH-TABLE</code>. +The second value of the list must always be a simple parameter type as +in the last paragraph - we'll call it the <em>inner type</em> below. +<p> +In the case of <code>'LIST</code>, all GET/POST parameters +called <code><i>real-name</i></code> will be collected, converted to +the inner type as by the rules above, and assembled into a list which +will be the value of +<code><i>var</i></code>. +<p> +In the case of <code>'ARRAY</code>, all GET/POST parameters which have +a name like the result of + +<pre> + (format nil "~A[~A]" real-name n) +</pre> + +where <code><i>n</i></code> is a non-negative integer, will be +assembled into an array where the <code><i>n</i></code>th element will +be set accordingly, after conversion to the inner type. The array, +which will become the value of <code><i>var</i></code>, will be big +enough to hold all matching parameters, but not bigger. Array +elements not set as described above will be <code>NIL</code>. Note +that <code>VAR</code> will always be bound to an array, which may be +empty, so it will never be <code>NIL</code>, even if no appropriate +GET/POST parameters are found. +<p> +The full form of a <code>'HASH-TABLE</code> parameter type is + +<pre> + (hash-table inner-type key-type test-function), +</pre> + +but <code><i>key-type</i></code> and <code><i>test-function</i></code> +can be left out in which case they default to <code>'STRING</code> +and <code>'EQUAL</code>, respectively. For this parameter type, all +GET/POST parameters which have a name like the result of + +<pre> + (format nil "~A{~A}" real-name key) +</pre> + +(where <code><i>key</i></code> is a string that doesn't contain curly brackets) will +become the values (after conversion to <code><i>inner-type</i></code>) of a hash +table with test function <code><i>test-function</i></code> where <code><i>key</i></code> (after +conversion to <code><i>key-type</i></code>) will be the corresponding key. Note that +<code><i>var</i></code> will always be bound to a hash table, which +may be empty, so it will never be <code>NIL</code>, even if no +appropriate GET/POST parameters are found. +<p> +To make matters even more complicated, the three compound parameter +types also have an abbreviated form - just one of the +symbols <code>LIST</code>, <code>ARRAY</code>, +or <code>HASH-TABLE</code>. In this case, the inner type will default +to <code>'STRING</code>. +<p> +If <code><i>parameter-type</i></code> is not provided +or <code>NIL</code>, <code><i>default-parameter-type</i></code> (the +default of which is <code>'STRING</code>) will be used instead. +<p> +If the result of the computations above would be +that <code><i>var</i></code> would be bound to <code>NIL</code>, +then <code><i>init-form</i></code> (if provided) will be evaluated +instead, and <code><i>var</i></code> will be bound to the result of +this evaluation. +<p> +Handlers built with this macro are constructed in such a way that the +resulting Lisp function is useful even outside of Hunchentoot. Specifically, +all the parameter computations above will only happen +if <a href="#*request*"><code>*REQUEST*</code></a> is bound, i.e. if +we're within a Hunchentoot request. Otherwise, <code><i>var</i></code> will +always be bound to the result of +evaluating <code><i>init-form</i></code> unless a corresponding +keyword argument is provided. +<p> +The <a href="#example">example code</a> that comes with Hunchentoot contains an +example which demonstrates some of the features +of <a +href="#define-easy-handler"><code>DEFINE-EASY-HANDLER</code></a>. + +</blockquote> + +<p><br>[Function] +<br><a class=none name="dispatch-easy-handlers"><b>dispatch-easy-handlers</b> <i>request</i> => <i>handler</i></a> + +<blockquote><br> + +This is a dispatcher which returns the appropriate handler defined +with <a +href="#define-easy-handler"><code>DEFINE-EASY-HANDLER</code></a>, if +there is one. The newest handlers are checked +first. <a +href="#define-easy-handler"><code>DEFINE-EASY-HANDLER</code></a> makes +sure that there's always only one handler per name and one per URI. +URIs are compared +by <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/f_equal.htm%22%3E<code>EQUAL</code></a>, +so anonymous functions won't be recognized as being identical. + +</blockquote> + +<h4><a class=none name="requests">Requests</a></h4> + +When a request comes in, Hunchentoot creates a <code>REQUEST</code> object +which is available to the <a href="#handlers">handler</a> via the +special variable <a href='#*request*'><code>*REQUEST*</code></a>. This object holds +all the information available about the request and can be queried +with the functions described in this chapter. Note that the internal +structure of <code>REQUEST</code> objects should be considered opaque and may change +in future releases of Hunchentoot. +<p> +In all of the functions below, the default value +for <code><i>request</i></code> (which is either an optional or a +keyword argument) is the value of <a href='#*request*'><code>*REQUEST*</code></a>, +i.e. handlers will usually not need to provide this argument when +calling the function. +<p> +(Some of the function names in this section might seem a bit strange. +This is because they were initially chosen to be similar to +environment variables in CGI scripts.) + +<p><br>[Special variable] +<br><a class=none name="*request*"><b>*request*</b></a> + +<blockquote><br> + +Holds the current <code>REQUEST</code> object. + +</blockquote> + +<p><br>[Function] +<br><a class=none name="host"><b>host</b> <i><tt>&optional</tt> request</i> => <i>string</i></a> + +<blockquote><br> + +Returns the value of the incoming <code>Host</code> http header. +(This corresponds to +the environment variable <code>HTTP_HOST</code> in CGI +scripts.) + +</blockquote> + +<p><br>[Function] +<br><a class=none name="request-method"><b>request-method</b> <i><tt>&optional</tt> request</i> => <i>keyword</i></a> + +<blockquote><br> + +Returns the request method as a keyword, i.e. something like <code>:POST</code>. (This corresponds to the environment +variable <code>REQUEST_METHOD</code> in CGI scripts.) + +</blockquote> + +<p><br>[Function] +<br><a class=none name="request-uri"><b>request-uri</b> <i><tt>&optional</tt> request</i> => <i>string</i></a> + +<blockquote><br> + +Returns the URI for <code><i>request</i></code>. Note that this not the full URI but only the part behind the +scheme and authority components, so that if the user has typed <code>http://user:password@www.domain.com/xxx/frob.html?foo=bar</code> into his browser, this function will return <code>"/xxx/frob.html?foo=bar"</code>. +(This corresponds to +the environment variable <code>REQUEST_URI</code> in CGI +scripts.) + +</blockquote> + +<p><br>[Function] +<br><a class=none name="script-name"><b>script-name</b> <i><tt>&optional</tt> request</i> => <i>string</i></a> + +<blockquote><br> + +Returns the file name (or path) component of the URI +for <code><i>request</i></code>, i.e. the part of the string returned +by <a href="#request-uri"><code>REQUEST-URI</code></a> in front of the +first question mark (if any). +(This corresponds to +the environment variable <code>SCRIPT_NAME</code> in CGI +scripts.) + +</blockquote> + +<p><br>[Function] +<br><a class=none name="query-string"><b>query-string</b> <i><tt>&optional</tt> request</i> => <i>string</i></a> + +<blockquote><br> + +Returns the query component of the URI +for <code><i>request</i></code>, i.e. the part of the string returned +by <a href="#request-uri"><code>REQUEST-URI</code></a> behind the +first question mark (if any). +(This corresponds to +the environment variable <code>QUERY_STRING</code> in CGI +scripts.) See also <a href="#get-parameter"><code>GET-PARAMETER</code></a> and <a href="#get-parameters"><code>GET-PARAMETERS</code></a>. + +</blockquote> + +<p><br>[Function] +<br><a class=none name="get-parameter"><b>get-parameter</b> <i>name <tt>&optional</tt> request</i> => <i>string</i></a> + +<blockquote><br> +Returns the value of the GET parameter (as provided via the request URI) named by the string <code><i>name</i></code> as a string (or <code>NIL</code> if there ain't no GET parameter with this name). Note that only the first value will be returned if the client provided more than one GET parameter with the name <code><i>name</i></code>. See also <a href="#get-parameters"><code>GET-PARAMETERS</code></a>. +</blockquote> + +<p><br>[Function] +<br><a class=none name="get-parameters"><b>get-parameters</b> <i><tt>&optional</tt> request</i> => <i>alist</i></a> + +<blockquote><br> +Returns an <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_a.htm#alist%22%...</a> of all GET parameters (as provided via the request URI). The <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_c.htm#car%22%3E...</a> of each element of this list is the parameter's name while the <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_c.htm#cdr%22%3E...</a> is its value (as a string). The elements of this list are in the same order as they were within the request URI. See also <a href="#get-parameter"><code>GET-PARAMETER</code></a>. +</blockquote> + +<p><br>[Function] +<br><a class=none name="post-parameter"><b>post-parameter</b> <i>name <tt>&optional</tt> request</i> => <i>string</i></a> + +<blockquote><br> +Returns the value of the POST parameter (as provided in the request's body) named by the string <code><i>name</i></code>. Note that only the first value will be returned if the client provided more than one POST parameter with the name <code><i>name</i></code>. +This value will usually be a string (or <code>NIL</code> if there ain't no POST parameter with this name). If, however, the browser sent a <a class=none name="upload">file</a> through a <a href="http://www.faqs.org/rfcs/rfc2388.html"><code>multipart/form-data</code></a> form, the value of this function is a three-element list +<pre> +(path file-name content-type) +</pre> +where <code><i>path</i></code> is a pathname denoting the place were the uploaded file was stored, <code><i>file-name</i></code> (a string) is the file name sent by the browser, and <code><i>content-type</i></code> (also a string) is the content type sent by the browser. The file denoted by <code><i>path</i></code> will be deleted after the request has been handled - you have to move or copy it somewhere else if you want to keep it. +<p> +POST parameters will only be computed if the content type of the request body was <code>multipart/form-data</code> +or <code>application/x-www-form-urlencoded</code>. +Although this function is called <code>POST-PARAMETER</code>, you can instruct Hunchentoot to compute these parameters for other request methods by setting <a href="#*methods-for-post-parameters*"><code>*METHODS-FOR-POST-PARAMETERS*</code></a>. +<p> +See also <a href="#post-parameters"><code>POST-PARAMETERS</code></a> and <a href="#*tmp-directory*"><code>*TMP-DIRECTORY*</code></a>. +</blockquote> + +<p><br>[Function] +<br><a class=none name="post-parameters"><b>post-parameters</b> <i><tt>&optional</tt> request</i> => <i>alist</i></a> + +<blockquote><br> +Returns an <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_a.htm#alist%22%...</a> of all POST parameters (as provided via the request's body). The <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_c.htm#car%22%3E...</a> of each element of this list is the parameter's name while the <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_c.htm#cdr%22%3E...</a> is its value. The elements of this list are in the same order as they were within the request's body. +<p> +See also <a href="#post-parameter"><code>POST-PARAMETER</code></a>. +</blockquote> + +<p><br>[Special variable] +<br><a class=none name="*methods-for-post-parameters*"><b>*methods-for-post-parameters*</b></a> + +<blockquote><br> A list of the request method types (as keywords) for +which Hunchentoot will try to compute <a href="#post-parameter">"POST" +parameters</a>. The default is the list with the single +element <code>:POST</code>. +</blockquote> + +<p><br>[Special variable] +<br><a class=none name="*file-upload-hook*"><b>*file-upload-hook*</b></a> + +<blockquote><br> If this is not <code>NIL</code>, it should be +a <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_f.htm#function_...</a> +for a unary function which will be called with a pathname for each +file which is <a href="#upload">uploaded</a> to Hunchentoot. The pathname +denotes the temporary file to which the uploaded file is written. The +hook is called directly <em>before</em> the file is created. At this +point, <a href="#*request*"><code>*REQUEST*</code></a> is already +bound to the current <code>REQUEST</code> object, but obviously you +can't access the post parameters yet. +</blockquote> + +<p><br>[Function] +<br><a class=none name="raw-post-data"><b>raw-post-data</b> <tt>&key</tt> <i>request external-format force-text force-binary want-stream</i> => <i>raw-body-or-stream</i></a> + +<blockquote><br> Returns the content sent by the client in the request +body if there was any (unless the content type +was <code>multipart/form-data</code> in which case <code>NIL</code> +is returned). By default, the result is a string if the type of +the <code>Content-Type</code> <a +href="http://www.faqs.org/rfcs/rfc1590.html%22%3Emedia type</a> +is <code>"text"</code>, and a vector of octets otherwise. In the case +of a string, the external format to be used to decode the content will +be determined from the <code>charset</code> parameter sent by the +client (or +otherwise <a +href="#*hunchentoot-default-external-format*"><code>*HUNCHENTOOT-DEFAULT-EXTERNAL-FORMAT*</code></a> +will be used). +<p> +You can also provide an external format explicitly (through +<code><i>external-format</i></code>) in which case the result will +unconditionally be a string. Likewise, you can provide a true value +for <code><i>force-text</i></code> which will force Hunchentoot to act +as if the type of the media type had been <code>"text"</code> +(with <code><i>external-format</i></code> taking precedence if +provided). Or you can provide a true value +for <code><i>force-binary</i></code> which means that you want a +vector of octets at any rate. (If both +<code><i>force-text</i></code> and <code><i>force-binary</i></code> +are true, an error will be signaled.) +<p> +If, however, you provide a true value +for <code><i>want-stream</i></code>, the other parameters are ignored +and you'll get the content (flexi) stream to read from it yourself. +It is then your responsibility to read the correct amount of data, +because otherwise you won't be able to return a response to the +client. The stream will have +its <a href="http://weitz.de/flexi-streams/#flexi-streams">octet +position</a> set to <code>0</code>. If the client provided +a <code>Content-Length</code> header, the stream will also have +a +corresponding <a href="http://weitz.de/flexi-streams/#flexi-streams">bound</a>, +so no matter whether the client used chunked encoding or not, you can +always read until EOF. +<p> +If the content type of the request +was <code>multipart/form-data</code> +or <code>application/x-www-form-urlencoded</code>, the content has +been read by Hunchentoot already and you can't read from the stream +anymore. +<p> +You can call <a href="#raw-post-data"><code>RAW-POST-DATA</code></a> +more than once per request, but you can't mix calls which have +different values for <code><i>want-stream</i></code>. +<p> +Note that this function is slightly misnamed because a client can send +content even if the request method is not POST. +</blockquote> + +<p><br>[Function] +<br><a class=none name="parameter"><b>parameter</b> <i>name <tt>&optional</tt> request</i> => <i>string</i></a> + +<blockquote><br> +Returns the value of the GET or POST parameter named by the string <code><i>name</i></code> as a string (or <code>NIL</code> if there ain't no parameter with this name). If both a GET and a POST parameter with the name <code><i>name</i></code> exist, the GET parameter will be returned. See also <a href="#get-parameter"><code>GET-PARAMETER</code></a> and <a href="#post-parameter"><code>POST-PARAMETER</code></a>. +</blockquote> + +<p><br>[Function] +<br><a class=none name="header-in"><b>header-in</b> <i>name <tt>&optional</tt> request</i> => <i>string</i></a> + +<blockquote><br> Returns the incoming header named by the +keyword <code><i>name</i></code> as a string (or <code>NIL</code> if +there ain't no header with this name). Note that this queries the +headers sent to Hunchentoot by the client <em>or</em> by mod_lisp. In +the latter case this may not only include the incoming http headers +but also +some <a href='http://www.fractalconcept.com/asp/debug'>headers sent by +mod_lisp</a>. +<p>For backwards compatibility, <code><i>name</i></code> +can also be a string which is matched case-insensitively. See +also <a href="#headers-in"><code>HEADERS-IN</code></a>. +</blockquote> + +<p><br>[Function] +<br><a class=none name="headers-in"><b>headers-in</b> <i><tt>&optional</tt> request</i> => <i>alist</i></a> + +<blockquote><br> +Returns an <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_a.htm#alist%22%...</a> of all incoming headers. The <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_c.htm#car%22%3E...</a> of each element of this list is the headers's name (a Lisp keyword) while the <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_c.htm#cdr%22%3E...</a> is its value (as a string). There's no guarantee about the order of this list. See also <a href="#header-in"><code>HEADER-IN</code></a> and the remark about incoming headers there. +</blockquote> + +<p><br>[Function] +<br><a class=none name="authorization"><b>authorization</b> <i><tt>&optional</tt> request</i> => <i>user, password</i></a> + +<blockquote><br> +Returns as two values the user and password (if any) from the incoming <code>Authorization</code> http header. Returns <code>NIL</code> if there is no such header. +</blockquote> + + +<p><br>[Function] +<br><a class=none name="remote-addr"><b>remote-addr</b> <i><tt>&optional</tt> request</i> => <i>string</i></a> + +<blockquote><br> + +Returns the IP address (as a string) of the client which sent the +request. (This corresponds to the environment +variable <code>REMOTE_ADDR</code> in CGI scripts.) See +also <a href="#real-remote-addr"><code>REAL-REMOTE-ADDR</code></a>. + +</blockquote> + +<p><br>[Function] +<br><a class=none name="remote-port"><b>remote-port</b> <i><tt>&optional</tt> request</i> => <i>number</i></a> + +<blockquote><br> + +Returns the IP port (as a number) of the client which sent the request. + +</blockquote> + +<p><br>[Function] +<br><a class=none name="real-remote-addr"><b>real-remote-addr</b> <i><tt>&optional</tt> request</i> => <i>string{, list}</i></a> + +<blockquote><br> + +Returns the value of the +incoming <a +href="http://en.wikipedia.org/wiki/XFF%22%3E<code>X-Forwarded-For</code></a> +http header as the second value in the form of a list of IP addresses +and the first element of this list as the first value if this header +exists. Otherwise returns the value +of <a href="#remote-addr"><code>REMOTE-ADDR</code></a> as the only +value. + +</blockquote> + +<p><br>[Function] +<br><a class=none name="server-addr"><b>server-addr</b> <i><tt>&optional</tt> request</i> => <i>string</i></a> + +<blockquote><br> + +Returns the IP address (as a string) where the request came in. (This +corresponds to the environment variable <code>SERVER_ADDR</code> in +CGI scripts.) + +</blockquote> + +<p><br>[Function] +<br><a class=none name="server-port"><b>server-port</b> <i><tt>&optional</tt> request</i> => <i>number</i></a> + +<blockquote><br> + +Returns the IP port (as a number) where the request came in. + +</blockquote> + +<p><br>[Function] +<br><a class=none name="server-protocol"><b>server-protocol</b> <i><tt>&optional</tt> request</i> => <i>keyword</i></a> + +<blockquote><br> + +Returns the version of the http protocol which is used by the client as a Lisp keyword - this is usually either <code>:HTTP/1.0</code> or <code>:HTTP/1.1</code>. +(This corresponds to the environment +variable <code>SERVER_PROTOCOL</code> in CGI scripts.) + +</blockquote> + +<p><br>[Function] +<br><a class=none name="mod-lisp-id"><b>mod-lisp-id</b> <i><tt>&optional</tt> request</i> => <i>string</i></a> + +<blockquote><br> + +Returns the 'Server ID' sent by mod_lisp. This corresponds to the +third parameter in the "<a +href='#LispServer'>LispServer</a>" directive in Apache's +configuration file and can be interesting if you deploy several different +Apaches or Hunchentoot instances at once. Returns <code>NIL</code> in stand-alone servers. + +</blockquote> + +<p><br>[Function] +<br><a class=none name="ssl-session-id"><b>ssl-session-id</b> <i><tt>&optional</tt> request</i> => <i>string</i></a> + +<blockquote><br> + +Returns Apache's SSL session ID if it exists. Note that SSL sessions aren't related to <a href='#sessions'>Hunchentoot sessions</a>. +(This corresponds to +the environment variable <code>SSL_SESSION_ID</code> in CGI +scripts.) Returns <code>NIL</code> in stand-alone servers. + +</blockquote> + +<p><br>[Function] +<br><a class=none name="user-agent"><b>user-agent</b> <i><tt>&optional</tt> request</i> => <i>string</i></a> + +<blockquote><br> + +Returns the value of the incoming <code>User-Agent</code> http header. +(This corresponds to +the environment variable <code>HTTP_USER_AGENT</code> in CGI +scripts.) + +</blockquote> + +<p><br>[Function] +<br><a class=none name="referer"><b>referer</b> <i><tt>&optional</tt> request</i> => <i>string</i></a> + +<blockquote><br> + +Returns the value of the incoming <code>Referer</code> (sic!) http header. +(This corresponds to +the environment variable <code>HTTP_REFERER</code> in CGI +scripts.) + +</blockquote> + +<p><br>[Function] +<br><a class=none name="cookie-in"><b>cookie-in</b> <i>name <tt>&optional</tt> request</i> => <i>string</i></a> + +<blockquote><br> +Returns the value of the incoming cookie named by the string <code><i>name</i></code> (or <code>NIL</code> if there ain't no cookie with this name). See also <a href="#cookies-in"><code>COOKIES-IN</code></a>. +</blockquote> + +<p><br>[Function] +<br><a class=none name="cookies-in"><b>cookies-in</b> <i><tt>&optional</tt> request</i> => <i>alist</i></a> + +<blockquote><br> +Returns an <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_a.htm#alist%22%...</a> of all incoming cookies. The <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_c.htm#car%22%3E...</a> of each element of this list is the cookie's name while the <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_c.htm#cdr%22%3E...</a> is the cookie's value. See also <a href="#cookie-in"><code>COOKIE-IN</code></a>. +</blockquote> + +<p><br>[Accessor] +<br><a class=none name="aux-request-value"><b>aux-request-value</b> <i>symbol <tt>&optional</tt> request</i> => <i>value, present-p</i> +<br><tt>(setf (</tt><b>aux-request-value</b> <i>symbol <tt>&optional</tt> request</i>) <i>new-value</i><tt>)</tt></a> + +<blockquote><br> +This accessor can be used to associate arbitrary data with the the <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_s.htm#symbol%22...</a> <code><i>symbol</i></code> in the <code>REQUEST</code> +object <code><i>request</i></code>. +<code><i>present-p</i></code> is <em>true</em> if such data was found, +otherwise <code>NIL</code>. +</blockquote> + +<p><br>[Function] +<br><a class=none name="delete-aux-request-value"><b>delete-aux-request-value</b> <i>symbol <tt>&optional</tt> request</i> => |</a> + +<blockquote><br> +Completely removes any data associated with the <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_s.htm#symbol%22...</a> <code><i>symbol</i></code> from the <code>REQUEST</code> +object <code><i>request</i></code>. Note that this is different from +using <a href="#aux-request-value"><code>AUX-REQUEST-VALUE</code></a> to set the data to <code>NIL</code>. +</blockquote> + +<p><br>[Function] +<br><a class=none name="recompute-request-parameters"><b>recompute-request-parameters</b> <i><tt>&key</tt> request external-format</i> => |</a> + +<blockquote><br> Recomputes the GET and POST parameters for +the <code>REQUEST</code> object +<code><i>request</i></code>. This only makes sense if you've changed +the external format and with POST parameters it will only work if the +request body was sent with +the <code>application/x-www-form-urlencoded</code> content type. +<p> +The default value for +<code><i>external-format</i></code> is <a +href="#*hunchentoot-default-external-format*"><code>*HUNCHENTOOT-DEFAULT-EXTERNAL-FORMAT*</code></a>. +See <code>test/test.lisp</code> for an example. +</blockquote> + +<h4><a class=none name="replies">Replies</a></h4> + +It is the responsibility of a <a href='#handlers'>handler</a> function to prepare the reply for the client. This is done by + +<ul> + <li>returning a string or an array of octets which will be the reply's body and + <li>manipulating a <code>REPLY</code> object which will be described in this section. +</ul> + +For each request there's one <code>REPLY</code> object which is accessible +to the handler via the +special variable <a href='#*reply*'>*REPLY*</a>. This object holds +all the information available about the reply and can be accessed +with the functions described in this chapter. Note that the internal +structure of <code>REPLY</code> objects should be considered opaque and may change +in future releases of Hunchentoot. +<p> +In all of the functions below, the default value +for the optional argument <code><i>reply</i></code> is the value of <a href='#*reply*'>*REPLY*</a>, +i.e. handlers will usually not need to provide this argument when +calling the function. +<p> +While Hunchentoot's preferred way of sending data to the client is the +one described above (i.e. the handler returns the whole payload as a +string or an array of octets) you can, if you really need to (for +example for large content bodies), get a stream you can write to +directly. This is achieved by first setting +up <a href="#*reply*"><code>*REPLY*</code></a> and then +calling <a href="#send-headers"><code>SEND-HEADERS</code></a>. Note +that in this case the usual <a href="#log">error handling</a> is +disabled. See the file <code>test/test.lisp</code> for an example. + +<p><br>[Special variable] +<br><a class=none name="*reply*"><b>*reply*</b></a> + +<blockquote><br> + +Holds the current <code>REPLY</code> object. + +</blockquote> + +<p><br>[Accessor] +<br><a class=none name="header-out"><b>header-out</b> <i>name <tt>&optional</tt> reply</i> => <i>string</i> +<br><tt>(setf (</tt><b>header-out</b> <i>name <tt>&optional</tt> reply</i>) <i>new-value</i><tt>)</tt></a> + +<blockquote><br> + +<code>HEADER-OUT</code> returns the outgoing http header named by the +keyword <code><i>name</i></code> if there is one, +otherwise <code>NIL</code>. <code>SETF</code> +of <code>HEADER-OUT</code> changes the current value of the header +named <code><i>name</i></code>. If no header +named <code><i>name</i></code> exists it is created. For backwards +compatibility, <code><i>name</i></code> can also be a string in which +case the association between a header and its name is +case-insensitive. +<p> +Note that the +headers <code>Set-Cookie</code>, <code>Content-Length</code>, +and <code>Content-Type</code> cannot be queried +by <code>HEADER-OUT</code> and <em>must not</em> be set +by <code>SETF</code> of <code>HEADER-OUT</code>. Also, there are a +couple of "technical" headers like <code>Connection</code> +or <code>Transfer-Encoding</code> that you're not supposed to set +yourself. If in doubt, consult the source code or ask on +the <a href="#mail">mailing list</a>. +<p> +See also <a href="#headers-out"><code>HEADERS-OUT</code></a>, <a href="#content-type"><code>CONTENT-TYPE</code></a>, <a href="#content-length"><code>CONTENT-LENGTH</code></a>, <a href="#cookies-out"><code>COOKIES-OUT</code></a>, and <a href="#cookie-out"><code>COOKIE-OUT</code></a>. + +</blockquote> + +<p><br>[Function] +<br><a class=none name="headers-out"><b>headers-out</b> <i><tt>&optional</tt> request</i> => <i>alist</i></a> + +<blockquote><br> +Returns an <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_a.htm#alist%22%...</a> of all outgoing http parameters (except for <code>Set-Cookie</code>, <code>Content-Length</code>, +and <code>Content-Type</code>). The <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_c.htm#car%22%3E...</a> of each element of this list is the headers's name while the <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_c.htm#cdr%22%3E...</a> is its value. This alist should not be manipulated directly, use <code>SETF</code> of <a href="#header-out"><code>HEADER-OUT</code></a> instead. +</blockquote> + +<p><br>[Function] +<br><a class=none name="cookie-out"><b>cookie-out</b> <i>name <tt>&optional</tt> reply</i> => <i>cookie</i></a> + +<blockquote><br> +Returns the outgoing cookie named by the string <code><i>name</i></code> (or <code>NIL</code> if there ain't no cookie with this name). See also <a href="#cookies-out"><code>COOKIES-OUT</code></a> and <a href='#cookies'>the section about cookies</a>. +</blockquote> + +<p><br>[Function] +<br><a class=none name="cookies-out"><b>cookies-out</b> <i><tt>&optional</tt> reply</i> => <i>alist</i></a> + +<blockquote><br> +Returns an <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_a.htm#alist%22%...</a> of all outgoing cookies. The <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_c.htm#car%22%3E...</a> of each element of this list is the cookie's name while the <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_c.htm#cdr%22%3E...</a> is the cookie itself. See also <a href="#cookie-out"><code>COOKIE-OUT</code></a> and <a href='#cookies'>the section about cookies</a>. +</blockquote> + +<p><br>[Accessor] +<br><a class=none name="return-code"><b>return-code</b> <i><tt>&optional</tt> reply</i> => <i>number</i> +<br><tt>(setf (</tt><b>return-code</b> <i><tt>&optional</tt> reply</i>) <i>new-value</i><tt>)</tt></a> + +<blockquote><br> + +<code>RETURN-CODE</code> returns the http return code of the +reply, <code>SETF</code> of <code>RETURN-CODE</code> changes it. The +return code of each <code>REPLY</code> object is initially set to <a +href="#+http-ok+"><code>+HTTP-OK+</code></a>. + +</blockquote> + +<p><br>[Accessor] +<br><a class=none name="content-type"><b>content-type</b> <i><tt>&optional</tt> reply</i> => <i>string</i> +<br><tt>(setf (</tt><b>content-type</b> <i><tt>&optional</tt> reply</i>) <i>new-value</i><tt>)</tt></a> + +<blockquote><br> + +<code>CONTENT-TYPE</code> returns the +outgoing <code>Content-Type</code> http header. <code>SETF</code> +of <code>CONTENT-TYPE</code> changes the current value of this header. The content type of each <code>REPLY</code> object is initially set to the value of <a href="#*default-content-type*"><code>*DEFAULT-CONTENT-TYPE*</code></a>. +</blockquote> + +<p><br>[Accessor] +<br><a class=none name="content-length"><b>content-length</b> <i><tt>&optional</tt> reply</i> => <i>length</i> +<br><tt>(setf (</tt><b>content-length</b> <i><tt>&optional</tt> reply</i>) <i>new-value</i><tt>)</tt></a> + +<blockquote><br> + +<code>CONTENT-LENGTH</code> returns the outgoing +<code>Content-Length</code> http header. <code>SETF</code> of +<code>CONTENT-LENGTH</code> changes the current value of this +header. The content length of each <code>REPLY</code> object is +initially set to <code>NIL</code>. If you leave it like that, +Hunchentoot will automatically try to compute the correct value +using <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/f_length.htm%22%3E<code>LENGTH</code></a>. +If you set the value yourself, you <em>must</em> make sure that it's +the correct length of the body in <em>octets</em> (not in characters). +In this case, Hunchentoot will use the value as is which can lead to +erroneous behaviour if it is wrong - so, use at your own risk. +<p> +Note that setting this value explicitly doesn't mix well with <a +href="#*rewrite-for-session-urls*">URL rewriting</a>. + +</blockquote> + +<p><br>[Function] +<br><a class=none name="send-headers"><b>send-headers</b> => <i>stream</i></a> + +<blockquote><br> +Sends the initial status line and all headers as determined by +the <code>REPLY</code> object <a href="#*reply*"><code>*REPLY*</code></a>. Returns a <a href="http://weitz.de/flexi-streams/#flexi-streams">flexi stream</a> to which the body of +the reply can be written. Once this function has been called, +further changes to <a href="#*reply*"><code>*REPLY*</code></a> don't have any effect. Also, +<a href="#log">automatic handling of errors</a> (i.e. sending the +corresponding status code to the browser, etc.) is turned off for this +request. Likewise, functions +like <a href="#redirect"><code>REDIRECT</code></a> or throwing +to <a href="#handler-done"><code>HANDLER-DONE</code></a> +won't have the desired effect once the headers are sent. +<p> +If your handlers return the full body as a string or as an array of +octets, you should <em>not</em> call this function. If a handler +calls <a href="#send-headers"><code>SEND-HEADERS</code></a>, its return +value is ignored. +<p> +See also <a href="#reply-external-format"><code>REPLY-EXTERNAL-FORMAT</code></a>. +</blockquote> + +<p><br>[Accessor] +<br><a class=none name="reply-external-format"><b>reply-external-format</b> <i><tt>&optional</tt> reply</i> => <i>external-format</i> +<br><tt>(setf (</tt><b>reply-external-format</b> <i><tt>&optional</tt> reply</i>) <i>new-value</i><tt>)</tt></a> + +<blockquote><br> + +Gets and sets the external format of the <code>REPLY</code> +object <code><i>reply</i></code>. This external format is used when +character content is written to the client after the headers have been +sent. In particular, it is the external format of the stream returned by <a href="#send-headers"><code>SEND-HEADERS</code></a> (but of course you can change it because it's a <a href="http://weitz.de/flexi-streams/#flexi-streams">flexi stream</a>). +<p>The initial value for each request is the value +of <a +href="#*hunchentoot-default-external-format*"><code>*HUNCHENTOOT-DEFAULT-EXTERNAL-FORMAT*</code></a>. + +</blockquote> + +<p><br>[Constants] +<br><a class=none name='+http-continue+'><b>+http-continue+</b></a> +<br><a class=none name='+http-switching-protocols+'><b>+http-switching-protocols+</b></a> +<br><a class=none name='+http-ok+'><b>+http-ok+</b></a> +<br><a class=none name='+http-created+'><b>+http-created+</b></a> +<br><a class=none name='+http-accepted+'><b>+http-accepted+</b></a> +<br><a class=none name='+http-non-authoritative-information+'><b>+http-non-authoritative-information+</b></a> +<br><a class=none name='+http-no-content+'><b>+http-no-content+</b></a> +<br><a class=none name='+http-reset-content+'><b>+http-reset-content+</b></a> +<br><a class=none name='+http-partial-content+'><b>+http-partial-content+</b></a> +<br><a class=none name='+http-multi-status+'><b>+http-multi-status+</b></a> +<br><a class=none name='+http-multiple-choices+'><b>+http-multiple-choices+</b></a> +<br><a class=none name='+http-moved-permanently+'><b>+http-moved-permanently+</b></a> +<br><a class=none name='+http-moved-temporarily+'><b>+http-moved-temporarily+</b></a> +<br><a class=none name='+http-see-other+'><b>+http-see-other+</b></a> +<br><a class=none name='+http-not-modified+'><b>+http-not-modified+</b></a> +<br><a class=none name='+http-use-proxy+'><b>+http-use-proxy+</b></a> +<br><a class=none name='+http-temporary-redirect+'><b>+http-temporary-redirect+</b></a> +<br><a class=none name='+http-bad-request+'><b>+http-bad-request+</b></a> +<br><a class=none name='+http-authorization-required+'><b>+http-authorization-required+</b></a> +<br><a class=none name='+http-payment-required+'><b>+http-payment-required+</b></a> +<br><a class=none name='+http-forbidden+'><b>+http-forbidden+</b></a> +<br><a class=none name='+http-not-found+'><b>+http-not-found+</b></a> +<br><a class=none name='+http-method-not-allowed+'><b>+http-method-not-allowed+</b></a> +<br><a class=none name='+http-not-acceptable+'><b>+http-not-acceptable+</b></a> +<br><a class=none name='+http-proxy-authentication-required+'><b>+http-proxy-authentication-required+</b></a> +<br><a class=none name='+http-request-time-out+'><b>+http-request-time-out+</b></a> +<br><a class=none name='+http-conflict+'><b>+http-conflict+</b></a> +<br><a class=none name='+http-gone+'><b>+http-gone+</b></a> +<br><a class=none name='+http-length-required+'><b>+http-length-required+</b></a> +<br><a class=none name='+http-precondition-failed+'><b>+http-precondition-failed+</b></a> +<br><a class=none name='+http-request-entity-too-large+'><b>+http-request-entity-too-large+</b></a> +<br><a class=none name='+http-request-uri-too-large+'><b>+http-request-uri-too-large+</b></a> +<br><a class=none name='+http-unsupported-media-type+'><b>+http-unsupported-media-type+</b></a> +<br><a class=none name='+http-requested-range-not-satisfiable+'><b>+http-requested-range-not-satisfiable+</b></a> +<br><a class=none name='+http-expectation-failed+'><b>+http-expectation-failed+</b></a> +<br><a class=none name='+http-failed-dependency+'><b>+http-failed-dependency+</b></a> +<br><a class=none name='+http-internal-server-error+'><b>+http-internal-server-error+</b></a> +<br><a class=none name='+http-not-implemented+'><b>+http-not-implemented+</b></a> +<br><a class=none name='+http-bad-gateway+'><b>+http-bad-gateway+</b></a> +<br><a class=none name='+http-service-unavailable+'><b>+http-service-unavailable+</b></a> +<br><a class=none name='+http-gateway-time-out+'><b>+http-gateway-time-out+</b></a> +<br><a class=none name='+http-version-not-supported+'><b>+http-version-not-supported+</b></a> + +<blockquote><br> +The values of these constants are 100, 101, 200, 201, 202, 203, 204, 205, 206, 207, 300, 301, 302, 303, 304, 305, 307, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 424, 500, 501, 502, 503, 504, and 505. See <a href="#return-code"><code>RETURN-CODE</code></a>. +</blockquote> + +<p><br>[Special variable] +<br><a class=none name='*default-content-type*'><b>*default-content-type*</b></a> + +<blockquote><br> +The value of this variable is used to initialize the content type of each <code>REPLY</code> object. Its initial value is <code>"text/html; charset=iso-8859-1"</code>. See <a href="#content-type"><code>CONTENT-TYPE</code></a>. +</blockquote> + +<h4><a class=none name="cookies">Cookies</a></h4> + +Outgoing cookies are stored in the request's <code>REPLY</code> object (see <a href="#cookie-out"><code>COOKIE-OUT</code></a> and <a href="#cookies-out"><code>COOKIES-OUT</code></a>). They are CLOS objects defined like this: + +<pre> +(defclass cookie () + ((name :initarg :name + :reader <a class=noborder name='cookie-name'>cookie-name</a> + :type string + :documentation "The name of the cookie - a string.") + (value :initarg :value + :accessor <a class=noborder name='cookie-value'>cookie-value</a> + :initform "" + :documentation "The value of the cookie. Will be URL-encoded when sent to the browser.") + (expires :initarg :expires + :initform nil + :accessor <a class=noborder name='cookie-expires'>cookie-expires</a> + :documentation "The time (a universal time) when the cookie expires (or NIL).") + (path :initarg :path + :initform nil + :accessor <a class=noborder name='cookie-path'>cookie-path</a> + :documentation "The path this cookie is valid for (or NIL).") + (domain :initarg :domain + :initform nil + :accessor <a class=noborder name='cookie-domain'>cookie-domain</a> + :documentation "The domain this cookie is valid for (or NIL).") + (secure :initarg :secure + :initform nil + :accessor <a class=noborder name='cookie-secure'>cookie-secure</a> + :documentation "A generalized boolean denoting whether this is a secure cookie.") + (http-only :initarg :http-only + :initform nil + :accessor <a class=noborder name='cookie-http-only'>cookie-http-only</a> + :documentation "A generalized boolean denoting whether this is a <a href="http://msdn2.microsoft.com/en-us/library/ms533046.aspx">HttpOnly</a> cookie."))) +</pre> + +The <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_r.htm#reader%22...</a> <a href="#cookie-name"><code>COOKIE-NAME</code></a> and +the <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_a.htm#accessor%...</a> +<a href="#cookie-value"><code>COOKIE-VALUE</code></a>, <a +href="#cookie-expires"><code>COOKIE-EXPIRES</code></a>, <a +href="#cookie-path"><code>COOKIE-PATH</code></a>, <a +href="#cookie-domain"><code>COOKIE-DOMAIN</code></a>, <a +href="#cookie-secure"><code>COOKIE-SECURE</code></a>, and <a +href="#cookie-http-only"><code>COOKIE-HTTP-ONLY</code></a> are all exported +from the <code>HUNCHENTOOT</code> package. + +<p><br>[Function] +<br><a class=none name="set-cookie"><b>set-cookie</b> <i>name <tt>&key</tt> value expires path domain secure http-only reply</i> => <i>cookie</i></a> + +<blockquote><br> Creates a <code>COOKIE</code> object from the +parameters provided to this function and adds it to the outgoing +cookies of the <a href='#replies'><code>REPLY</code> +object</a> <code><i>reply</i></code>. If a cookie with the same name +(case-sensitive) already exists, it is replaced. The default +for <code><i>reply</i></code> is <a +href="#*reply*"><code>*REPLY*</code></a>. The default for <code><i>value</i></code> is the empty string. +</blockquote> + +<p><br>[Function] +<br><a class=none name="set-cookie*"><b>set-cookie*</b> <i>cookie <tt>&optional</tt> reply</i> => <i>cookie</i></a> + +<blockquote><br> Adds the <code>COOKIE</code> +object <code><i>cookie</i></code> to the outgoing cookies of the <a +href='#replies'><code>REPLY</code> +object</a> <code><i>reply</i></code>. If a cookie with the same name +(case-sensitive) already exists, it is replaced. The default for <code><i>reply</i></code> is <a href="#*reply*"><code>*REPLY*</code></a>. +</blockquote> + +<h4><a class=none name="sessions">Sessions</a></h4> + +Hunchentoot supports <em>sessions</em>: Once a Hunchentoot page has +called <a href="#start-session"><code>START-SESSION</code></a>, +Hunchentoot uses either cookies or (if the client doesn't send the +cookies back) <a href="#*rewrite-for-session-urls*">rewrites URLs</a> +to keep track of this client, i.e. to provide a kind of 'state' for +the stateless http protocol. The session associated with the client is +an opaque CLOS object which can be used to store arbitrary data +between requests. +<p> +Hunchentoot makes some reasonable effort to prevent eavesdroppers from +hijacking sessions (see below), but this should not be considered +really secure. Don't store sensitive data in sessions and rely +solely on the session mechanism as a safeguard against malicious users +who want to get at this data! +<p> +For each request there's one <code>SESSION</code> object which is accessible +to the handler via the +special variable <a href='#*session*'><code>*SESSION*</code></a>. This object holds +all the information available about the session and can be accessed +with the functions described in this chapter. Note that the internal +structure of <code>SESSION</code> objects should be considered opaque and may change +in future releases of Hunchentoot. +<p> +Sessions are automatically verified for validity and age when +the <a href='#requests'><code>REQUEST</code> object</a> is instantiated, i.e. if <a +href='#*session*'><code>*SESSION*</code></a> is not <code>NIL</code> then this +session is valid (as far as Hunchentoot is concerned) and not too old. Old sessions are <a href="#session-gc">automatically removed</a>. + +<p><br>[Special variable] +<br><a class=none name="*session*"><b>*session*</b></a> + +<blockquote><br> + +Holds the current <code>SESSION</code> object (if any) or <code>NIL</code>. + +</blockquote> + +<p><br>[Function] +<br><a class=none name="start-session"><b>start-session</b> => <i>session</i></a> + +<blockquote><br> Returns <a +href="#*session*"><code>*SESSION*</code></a> if it +isn't <code>NIL</code>, otherwise creates a new <code>SESSION</code> +object and returns it. +</blockquote> + +<p><br>[Accessor] +<br><a class=none name="session-value"><b>session-value</b> <i>symbol <tt>&optional</tt> session</i> => <i>value, present-p</i> +<br><tt>(setf (</tt><b>session-value</b> <i>symbol <tt>&optional</tt> session</i>) <i>new-value</i><tt>)</tt></a> + +<blockquote><br> +This accessor can be used to associate arbitrary data with the the <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_s.htm#symbol%22...</a> <code><i>symbol</i></code> in the <code>SESSION</code> +object <code><i>session</i></code>. +<code><i>present-p</i></code> is <em>true</em> if such data was found, +otherwise <code>NIL</code>. The default value +for <code><i>session</i></code> is <a +href="#*session*"><code>*SESSION*</code></a>. +<p> +If <code>SETF</code> of <code>SESSION-VALUE</code> is called with <code><i>session</i></code> being <code>NIL</code> then a session is automatically instantiated with <a href="#start-session"><code>START-SESSION</code></a>. +</blockquote> + +<p><br>[Function] +<br><a class=none name="delete-session-value"><b>delete-session-value</b> <i>symbol <tt>&optional</tt> session</i> => |</a> + +<blockquote><br> +Completely removes any data associated with the <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_s.htm#symbol%22...</a> <code><i>symbol</i></code> from the <code>SESSION</code> +object <code><i>session</i></code>. Note that this is different from +using <a href="#session-value"><code>SESSION-VALUE</code></a> to set the data to <code>NIL</code>. +The default value +for <code><i>session</i></code> is <a +href="#*session*"><code>*SESSION*</code></a>. +</blockquote> + + +<p><br>[Function] +<br><a class=none name="remove-session"><b>remove-session</b> <i>session</i> => |</a> + +<blockquote><br> +Completely removes the session <code><i>session</i></code> from Hunchentoot's internal session database. See also <a href="#*session-removal-hook*"><code>*SESSION-REMOVAL-HOOK*</code></a>. +</blockquote> + + +<p><br>[Function] +<br><a class=none name="reset-sessions"><b>reset-sessions</b> => |</a> + +<blockquote><br> +This function unconditionally invalidates and destroys <em>all</em> sessions immediately. +</blockquote> + + +<p><br>[Function] +<br><a class=none name="session-cookie-value"><b>session-cookie-value</b> <i>session</i> => <i>string</i></a> + +<blockquote><br> +Returns a unique string that's associated with +the <code>SESSION</code> object <code><i>session</i></code>. This +string is sent to the browser as a cookie value or as a GET parameter, +</blockquote> + + +<p><br>[Function] +<br><a class=none name="session-counter"><b>session-counter</b> <i>session</i> => <i>count</i></a> + +<blockquote><br> +Returns the number of times (requests) the <code>SESSION</code> object <code><i>session</i></code> has been used. +</blockquote> + + + +<p><br>[Accessor] +<br><a class=none name="session-max-time"><b>session-max-time</b> <i>session</i> => <i>seconds</i> +<br><tt>(setf (</tt><b>session-max-time</b> <i>session</i>) <i>seconds</i><tt>)</tt></a> + +<blockquote><br> This gets or sets the maximum time (in seconds) +the <code>SESSION</code> object <code><i>session</i></code> should be +valid before it's invalidated: If a request associated with this +session comes in and the last request for the same session was more +than <code><i>seconds</i></code> seconds ago +than the session is deleted and a new one is started for this client. The default value is determined by <a href="#*session-max-time*"><code>*SESSION-MAX-TIME*</code></a>. +</blockquote> + +<p><br>[Function] +<br><a class=none name="session-remote-addr"><b>session-remote-addr</b> <i>session</i> => <i>address</i></a> + +<blockquote><br> Returns the 'real' remote address (see <a +href="#real-remote-addr"><code>REAL-REMOTE-ADDR</code></a>) of the +client for which the <code>SESSION</code> +object <code><i>session</i></code> was initiated. +</blockquote> + +<p><br>[Function] +<br><a class=none name="session-user-agent"><b>session-user-agent</b> <i>session</i> => <i>address</i></a> + +<blockquote><br> Returns the 'User-Agent' http header (see <a +href="#user-agent"><code>USER-AGENT</code></a>) of the +client for which the <code>SESSION</code> +object <code><i>session</i></code> was initiated. +</blockquote> + +<p><br>[Special variable] +<br><a class=none name="*use-remote-addr-for-sessions*"><b>*use-remote-addr-for-sessions*</b></a> + +<blockquote><br> + +If this value is <em>true</em> (the default is <code>NIL</code>) then +the 'real' remote address (see <a +href="#real-remote-addr"><code>REAL-REMOTE-ADDR</code></a>) of the +client will be encoded into the session identifier, i.e. if this value +changes on the client side, the session will automatically be +invalidated. +<p> +Note that this is not secure, because it's obviously not very hard to +fake an <code>X_FORWARDED_FOR</code> header. On the other hand, +relying on the remote address (see <a +href="#remote-addr"><code>REMOTE-ADDR</code></a>) of the client isn't +an ideal solution either, because some of your users may connect +through http proxies and the proxy they use may change during the +session. But then again, some proxies don't +send <code>X_FORWARDED_FOR</code> headers anyway. Sigh... + +</blockquote> + +<p><br>[Special variable] +<br><a class=none name="*use-user-agent-for-sessions*"><b>*use-user-agent-for-sessions*</b></a> + +<blockquote><br> If this value is <em>true</em> (which is the default) +then the 'User-Agent' http header (see <a +href="#user-agent"><code>USER-AGENT</code></a>) of the client will be +encoded into the session identifier, i.e. if this value changes on the +client side the session will automatically be invalidated. +<p> +While this is intended to make the life of malicious users harder, it +might affect legitimate users as well: I've seen this http +header change with certain browsers when the Java plug-in was used. +</blockquote> + +<p><br>[Special variable] +<br><a class=none name="*rewrite-for-session-urls*"><b>*rewrite-for-session-urls*</b></a> + +<blockquote><br> If this value is <em>true</em> (which is the default) +then content bodies sent by Hunchentoot will be rewritten +(using <a href='http://weitz.de/url-rewrite/'>URL-REWRITE</a>) such +that GET parameters for session handling are appended to all relevant +URLs. This only happens, though, if the body's content type (see <a +href="#content-type"><code>CONTENT-TYPE</code></a>) starts +with one of the strings in <a href="#*content-types-for-url-rewrite*"><code>*CONTENT-TYPES-FOR-URL-REWRITE*</code></a> and unless the client has already sent a cookie named <a href="#*session-cookie-name*"><code>*SESSION-COOKIE-NAME*</code></a>. +<p> +Note that the function which rewrites the body doesn't understand +Javascript, so you have to take care of URLs in Javascript code yourself. +</blockquote> + +<p><br>[Special variable] +<br><a class=none name="*content-types-for-url-rewrite*"><b>*content-types-for-url-rewrite*</b></a> + +<blockquote><br> +This is a list of strings (the initial value is +<code>("text/html" "application/xhtml+xml")</code>) the +content-type of an outgoing body is compared with if <a +href="#*rewrite-for-session-urls*"><code>*REWRITE-FOR-SESSION-URLS*</code></a> +is true. If the content-type starts with one of these strings, then +url-rewriting will happen, otherwise it won't. +</blockquote> + +<p><br>[Special variable] +<br><a class=none name="*session-cookie-name*"><b>*session-cookie-name*</b></a> + +<blockquote><br> + +This is the name that is used for the session-related cookie or GET +parameter sent to the client. Its default value +is <code>"hunchentoot-session"</code>. Note that changing this name while +Hunchentoot is running will invalidate existing sessions. + +</blockquote> + +<p><br>[Special variable] +<br><a class=none name="*session-removal-hook*"><b>*session-removal-hook*</b></a> + +<blockquote><br> +The value of this variable should be a function of one argument, a <code>SESSION</code> object. This function is called directly before the session is destroyed, either by <a href="#reset-sessions"><code>RESET-SESSIONS</code></a>, by <a href="#remove-session"><code>REMOVE-SESSION</code></a>, or when it's invalidated because it's too old. + +</blockquote> + +<p><br>[Special variable] +<br><a class=none name="*session-max-time*"><b>*session-max-time*</b></a> + +<blockquote><br> +The default time (in seconds) after which a session times out - see <a href="#session-max-time"><code>SESSION-MAX-TIME</code></a>. This value is initially set to 1800. +</blockquote> + +<p><br>[Macro] +<br><a class=none name="do-sessions"><b>do-sessions</b> <i>(var</i> <tt>&optional</tt> <i>result-form) statement*</i> => <i>result</i></a> + +<blockquote><br> + +Executes the statements with <code><i>var</i></code> bound to each +existing <code>SESSION</code> object consecutively. An implicit block +named <code>NIL</code> surrounds the body of this macro. Returns the +values returned by <code><i>result-form</i></code> unless +<code>RETURN</code> is executed. The scope of the binding of +<code><i>var</i></code> does <em>not</em> include +<code><i>result-form</i></code>. + +</blockquote> + +<p><br>[Special variable] +<br><a class=none name="*session-gc-frequency*"><b>*session-gc-frequency*</b></a> + +<blockquote><br> +A session garbage collection (see <a href="#session-gc"><code>SESSION-GC</code></a>) will happen every +<a +href="#*session-gc-frequency*"><code>*SESSION-GC-FREQUENCY*</code></a> +requests (counting only requests which use sessions) if the value of +this variable is not <code>NIL</code>. It's default value is 50. +</blockquote> + +<p><br>[Function] +<br><a class=none name="session-gc"><b>session-gc</b> => |</a> + +<blockquote><br> +Deletes sessions which are too old - see +<a href="#session-too-old-p"><code>SESSION-TOO-OLD-P</code></a>. +Usually, you don't call this function directly - +see <a +href="#*session-gc-frequency*"><code>*SESSION-GC-FREQUENCY*</code></a>. +</blockquote> + +<p><br>[Function] +<br><a class=none name="session-too-old-p"><b>session-too-old-p</b> <i>session</i> => generalized-boolean</a> + +<blockquote><br> Returns a true value if the <code>SESSION</code> +object <code><i>session</i></code> is <a href="#session-max-time">too old</a> and would be deleted +during the next <a href="#session-gc">session GC</a>. You don't +have to check this manually for sessions +in <a href="#*session*"><code>*SESSION*</code></a>, but it might be +useful if you want to <a href="#do-sessions">loop through all +sessions</a>. +</blockquote> + + +<h4><a class=none name="log">Logging and error handling</a></h4> + +Hunchentoot provides facilities for writing to Apache's error log +file (when using the mod_lisp front-end) or for logging to an arbitrary file in the file system. Note that, due to the nature of mod_lisp, Apache log mesages don't appear immediately but only after all data has been sent from Hunchentoot to Apache/mod_lisp. +<p> +Furthermore, all errors happening within a <a href='#handlers'>handler</a> which are not +caught by the handler itself are handled by Hunchentoot - see details below. + +<p><br>[Accessor] +<br><a class=none name="log-file"><b>log-file</b> => <i>pathname</i> +<br><tt>(setf (</tt><b>log-file</b>) <i>pathspec</i><tt>)</tt></a> + +<blockquote><br> +The function <code>LOG-FILE</code> returns a pathname designating the log file which is currently used (unless log messages are forwarded to Apache). This destination for log messages can be changed with <code>(SETF LOG-FILE)</code>. The initial location of the log file is implementation-dependent. +</blockquote> + +<p><br>[Generic function] +<br><a class=none name="log-message"><b>log-message</b> <i>log-level format</i> <tt>&rest</tt> <i>args</i> => |</a> + +<blockquote><br> Schedules a message for the Apache log file or writes +it directly to <a href="#log-file">the current log file</a> depending +on the value of the <code><i>use-apache-log-p</i></code> argument +to <a href="#start-server"><code>START-SERVER</code></a>. <code><i>log-level</i></code> +should be one of the +keywords <code>:EMERG</code>, <code>:ALERT</code>, <code>:CRIT</code>, <code>:ERROR</code>, <code>:WARNING</code>, <code>:NOTICE</code>, <code>:INFO</code>, +or <code>:DEBUG</code> which correspond to the various Apache log +levels. <code><i>log-level</i></code> can also be <code>NIL</code> (in +which case mod_lisp's default log level is used. If Apache isn't used, the log level is just written +to the log file unless it's <code>NIL</code>. +<code><i>format</i></code> and <code><i>args</i></code> are used as with +<a href='http://www.lispworks.com/documentation/HyperSpec/Body/f_format.htm'><code>FORMAT</code></a>. +<p> +<code>LOG-MESSAGE</code> is a generic function, so you can specialize it or bypass it completely with an around method. +</blockquote> + +<p><br>[Function] +<br><a class=none name="log-message*"><b>log-message*</b> <i>format</i> <tt>&rest</tt> <i>args</i> => |</a> + +<blockquote><br> +Like <a href="#log-message"><code>LOG-MESSAGE</code></a> but with <code><i>log-level</i></code> set to <a href="#*default-log-level*"><code>*DEFAULT-LOG-LEVEL*</code></a>. +</blockquote> + +<p><br>[Special variable] +<br><a class=none name="*default-log-level*"><b>*default-log-level*</b></a> + +<blockquote><br> +The log level used by <a href="#log-message*"><code>LOG-MESSAGE*</code></a>. The initial value is <code>NIL</code>. +</blockquote> + +<p><br>[Special variable] +<br><a class=none name="*log-lisp-errors-p*"><b>*log-lisp-errors-p*</b></a> + +<blockquote><br> +Whether unhandled errors in <a href='#handlers'>handlers</a> should be logged. See also <a href="#*lisp-errors-log-level*"><code>*LISP-ERRORS-LOG-LEVEL*</code></a>. The default value is <code>T</code>. +</blockquote> + +<p><br>[Special variable] +<br><a class=none name="*lisp-errors-log-level*"><b>*lisp-errors-log-level*</b></a> + +<blockquote><br> +The log level used to log Lisp errors. See also <a href="#*log-lisp-errors-p*"><code>*LOG-LISP-ERRORS-P*</code></a>. The default value is <code>:ERROR</code>. +</blockquote> + +<p><br>[Special variable] +<br><a class=none name="*log-lisp-warnings-p*"><b>*log-lisp-warnings-p*</b></a> + +<blockquote><br> +Whether unhandled warnings in <a href='#handlers'>handlers</a> should be logged. See also <a href="#*lisp-warnings-log-level*"><code>*LISP-WARNINGS-LOG-LEVEL*</code></a>. The default value is <code>T</code>. +</blockquote> + +<p><br>[Special variable] +<br><a class=none name="*lisp-warnings-log-level*"><b>*lisp-warnings-log-level*</b></a> + +<blockquote><br> +The log level used to log Lisp warnings. See also <a href="#*log-lisp-warnings-p*"><code>*LOG-LISP-WARNINGS-P*</code></a>. The default value is <code>:WARNING</code>. +</blockquote> + +<p><br>[Special variable] +<br><a class=none name="*log-lisp-backtraces-p*"><b>*log-lisp-backtraces-p*</b></a> + +<blockquote><br> +Whether backtraces should also be logged in addition to error messages and warnings. This value will only have effect if <a href="#*log-lisp-errors-p*"><code>*LOG-LISP-ERRORS-P*</code></a> or <a href="#*log-lisp-warnings-p*"><code>*LOG-LISP-WARNINGS-P*</code></a> is <em>true</em>. The default value is <code>NIL</code>. +</blockquote> + +<p><br>[Special variable] +<br><a class=none name="*log-prefix*"><b>*log-prefix*</b></a> + +<blockquote><br> +All messages written to the Apache error log by Hunchentoot are prepended by a string which is the value of this variable enclosed in square brackets. If the value is <code>NIL</code>, however, no such prefix will be written. If the value is <code>T</code> (which is the default), the prefix will be <code>"[Hunchentoot]"</code>. +</blockquote> + +<p><br>[Special variable] +<br><a class=none name="*show-lisp-errors-p*"><b>*show-lisp-errors-p*</b></a> + +<blockquote><br> +Whether unhandled Lisp errors should be shown to the user. If this value is <code>NIL</code> (which is the default), only the message <em>An error has occurred</em> will be shown. +</blockquote> + +<p><br>[Special variable] +<br><a class=none name="*show-lisp-backtraces-p*"><b>*show-lisp-backtraces-p*</b></a> + +<blockquote><br> +Whether backtraces should also be shown to the user. This value will only have effect if <a href="#*show-lisp-errors-p*"><code>*SHOW-LISP-ERRORS-P*</code></a> is <em>true</em>. The default value is <code>NIL</code>. +</blockquote> + +<p><br>[Special variable] +<br><a class=none name="*show-access-log-messages*"><b>*show-access-log-messages*</b></a> + +<blockquote><br> +If this variable is <em>true</em> <em>and</em> if the value of the <code><i>use-apache-log-p</i></code> argument to <a href="#start-server"><code>START-SERVER</code></a> was <code>NIL</code>, then for each request a line somewhat similar to what can be found in Apache's access log will be written to the <a href="#log-file">log file</a>. The default value of this variable is <code>T</code>. +</blockquote> + +<p><br>[Special variable] +<br><a class=none +name="*http-error-handler*"><b>*http-error-handler*</b></a> + +<blockquote><br> +This variable holds <code>NIL</code> (the default) or a <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_f.htm#function_... designator</a> for a function of one argument. The function gets called if the responsible <a href="#handlers">handler</a> has set a return code which is not in <a href="#*approved-return-codes*"><code>*APPROVED-RETURN-CODES*</code></a> and <a href="#*handle-http-errors-p*"><code>*HANDLE-HTTP-ERRORS-P*</code></a> is true. It receives the return code as its argument and can return the contents of an error page or <code>NIL</code> if it refuses to handle the error, i.e. if Hunchentoot's default error page should be shown. (Note that the function can access the request and reply data.) +</blockquote> + +<p><br>[Special variable] +<br><a class=none +name="*handle-http-errors-p*"><b>*handle-http-errors-p*</b></a> + +<blockquote><br> This variable holds a generalized boolean that +determines whether return codes not in <a href="#*approved-return-codes*"><code>*APPROVED-RETURN-CODES*</code></a> +are treated specially. When its value is true (the default), either a +default body for the return code or the result of +calling <a +href="#*http-error-handler*"><code>*HTTP-ERROR-HANDLER*</code></a> is +used. When the value is <code>NIL</code>, no special action is taken +and you are expected to supply your own response body to describe the +error. +</blockquote> + +<p><br>[Special variable] +<br><a class=none +name="*approved-return-codes*"><b>*approved-return-codes*</b></a> +<blockquote><br> +A list of return codes the server should not treat as an error - +see <a href="#*handle-http-errors-p*"><code>*HANDLE-HTTP-ERRORS-P*</code></a>. The initial value is the list with the values of +<a href="#+http-ok+"><code>+HTTP-OK+</code></a>, <a href="#+http-no-content+"><code>+HTTP-NO-CONTENT+</code></a>, <a href="#+http-multi-status+"><code>+HTTP-MULTI-STATUS+</code></a>, and <a href="#+http-not-modified+"><code>+HTTP-NOT-MODIFIED+</code></a>. +</blockquote> + +<p><br>[Function] +<br><a class=none name="get-backtrace"><b>get-backtrace</b> <i>condition</i> => <i>backtrace</i></a> + +<blockquote><br> +This is the function that is used internally by Hunchentoot to +show or log backtraces. It accepts a condition object <code><i>condition</i></code> and +returns a string with the corresponding backtrace. +</blockquote> + +<h4><a class=none name="debug">Debugging Hunchentoot applications</a></h4> + +The best option to debug a Hunchentoot application is +probably <a href="#*catch-errors-p*">to use the debugger</a>. +<p> +One important thing you should try if you're behind mod_lisp is to +use <a href="#log">an external log file</a> (as opposed to Apache's +log) because it can reveal error messages that might otherwise get +lost if something's broken in the communication between Hunchentoot +and mod_lisp. +<p> +Good luck... :) + +<p><br>[Special variable] +<br><a class=none name="*catch-errors-p*"><b>*catch-errors-p*</b></a> + +<blockquote><br> If the value of this variable is <code>NIL</code> +(the default is <code>T</code>), then errors which happen while a +request is handled aren't <a href="#log">caught as usual</a>, but +instead your +Lisp's <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_d.htm#debugger%...</a> +is <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/f_invoke.htm%22%3Einvo...</a>. +This variable should obviously always be set to a <em>true</em> value +in a production environment. +See <a +href="#maybe-invoke-debugger"><code>MAYBE-INVOKE-DEBUGGER</code></a> +if you want to fine-tune this behaviour. +</blockquote> + +<p><br>[Generic function] +<br><a class=none name="maybe-invoke-debugger"><b>maybe-invoke-debugger</b> <i>condition</i> => |</a> + +<blockquote><br> +This generic function is called whenever a +<a +href="http://www.lispworks.com/documentation/HyperSpec/Body/09_.htm%22%3Econdition</a> <code><i>condition</i></code> +is signaled in Hunchentoot. You might want to specialize it on +specific condition classes for debugging purposes. The default +method <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/f_invoke.htm%22%3Einvo... +the debugger</a> with <code><i>condition</i></code> if +<a href="#*catch-errors-p*"><code>*CATCH-ERRORS-P*</code></a> is <code>NIL</code>. +</blockquote> + + +<p><br>[Special variable] +<br><a class=none name="*header-stream*"><b>*header-stream*</b></a> + +<blockquote><br> +If this variable is not <code>NIL</code>, it should be bound to a stream to +which incoming and outgoing headers will be written for debugging +purposes. +</blockquote> + +<h4><a class=none name="misc">Miscellaneous</a></h4> + +Various functions and variables which didn't fit into one of the other categories. + +<p><br>[Function] +<br><a class=none name="ssl-p"><b>ssl-p</b> => generalized-boolean</a> + +<blockquote><br> +Whether the current connection to the client is secure. +</blockquote> + +<p><br>[Symbol] +<br><a class=none name="handler-done"><b>handler-done</b></a> + +<blockquote><br> This is a <a +href='http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_c.htm#catch_tag...<em>catch +tag</em></a> which names a <a +href='http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_c.htm#catch%27%...<em>catch</em></a> +which is active during the lifetime of a <a +href='#handlers'>handler</a>. The handler can at any time <a +href='http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_t.htm#throw%27%...<em>throw</em></a> +the outgoing content body (or <code>NIL</code>) to this catch to immediately abort handling the request. See the source code of <a href="#redirect"><code>REDIRECT</code></a> for an example. +</blockquote> + +<p><br>[Function] +<br><a class=none name="no-cache"><b>no-cache</b> => |</a> + +<blockquote><br> +This function will set appropriate outgoing headers to completely prevent caching on virtually all browsers. +</blockquote> + +<p><br>[Function] +<br><a class=none name="handle-if-modified-since"><b>handle-if-modified-since</b> <i>time</i> => |</a> + +<blockquote><br> + +This function is designed to be used inside a <a +href='#handlers'>handler</a>. If the client has sent an +'If-Modified-Since' header (see <a +href='http://www.faqs.org/rfcs/rfc2616.html%27%3ERFC%C2%A02616</a>, +section 14.25) and the time specified matches the universal time +<code><i>time</i></code> then the header <a +href="#+http-not-modified+"><code>+HTTP-NOT-MODIFIED+</code></a> with +no content is immediately returned to the client. +<p> +Note that for this function to be useful you should usually send +'Last-Modified' headers back to the client. See the code of <a +href="#create-static-file-dispatcher-and-handler"><code>CREATE-STATIC-FILE-DISPATCHER-AND-HANDLER</code></a> +for an example. + +</blockquote> + +<p><br>[Function] +<br><a class=none name="rfc-1123-date"><b>rfc-1123-date</b> <tt>&optional</tt> <i>time</i> => <i>string</i></a> + +<blockquote><br> + +This function accepts a universal time <code><i>time</i></code> +(default is the current time) and returns a string which encodes this time according to <a +href='http://www.faqs.org/rfcs/rfc1123.html%27%3ERFC%C2%A01123</a>. This can be used to send a 'Last-Modified' header - see <a +href="#handle-if-modified-since"><code>HANDLE-IF-MODIFIED-SINCE</code></a>. + +</blockquote> + +<p><br>[Function] +<br><a class=none name="redirect"><b>redirect</b> <i>target</i> <tt>&key</tt> <i>host port protocol add-session-id permanently</i> => |</a> + +<blockquote><br> Sends back appropriate headers to redirect the client +to <code><i>target</i></code> (a string). + +If <code><i>target</i></code> is a full URL starting with a scheme, <code><i>host</i></code>, <code><i>port</i></code>, and <code><i>protocol</i></code> +are ignored. Otherwise, <code><i>target</i></code> should denote the path part of a +URL, <code><i>protocol</i></code> must be one of the keywords <code>:HTTP</code> or <code>:HTTPS</code>, and +the URL to redirect to will be constructed from <code><i>host</i></code>, <code><i>port</i></code>, <code><i>protocol</i></code>, +and <code><i>target</i></code>. +<p> +If <code><i>permanently</i></code> +is <em>true</em> (the default is <code>NIL</code>), a 301 status +code will be sent, otherwise a 302 status code. If <code><i>host</i></code> +is not provided, the current host (see <a +href="#host"><code>HOST</code></a>) will be +used. If <code><i>protocol</i></code> is the +keyword <code>:HTTPS</code>, the client will be redirected to a https +URL, if it's <code>:HTTP</code> it'll be sent to a http URL. If +both <code><i>host</i></code> and <code><i>protocol</i></code> aren't +provided, then the value of <code><i>protocol</i></code> will +match the current request. +</blockquote> + +<p><br>[Function] +<br><a class=none name="require-authorization"><b>require-authorization</b> <tt>&optional</tt> <i>realm</i> => |</a> + +<blockquote><br> +Sends back appropriate headers to require basic HTTP authentication (see <a href='http://www.faqs.org/rfcs/rfc2617.html'>RFC 2617</a>) for the realm <code><i>realm</i></code>. The default value for <code><i>realm</i></code> is <code>"Hunchentoot"</code>. +</blockquote> + +<p><br>[Function] +<br><a class=none name="escape-for-html"><b>escape-for-html</b> <i>string</i> => <i>escaped-string</i></a> + +<blockquote><br> +Escapes all occurrences of the characters <code>#<</code>, <code>#></code>, <code>#'</code>, <code>#"</code>, and <code>#&</code> within <code><i>string</i></code> for HTML output. +</blockquote> + +<p><br>[Function] +<br><a class=none name="url-encode"><b>url-encode</b> <i>string</i> <tt>&optional</tt> <i>external-format</i> => <i>url-encoded-string</i></a> + +<blockquote><br> +URL-encodes a string using the external format <code><i>external-format</i></code>. The default for <code><i>external-format</i></code> is the value of <a href="#*hunchentoot-default-external-format*"><code>*HUNCHENTOOT-DEFAULT-EXTERNAL-FORMAT*</code></a>. +</blockquote> + +<p><br>[Function] +<br><a class=none name="url-decode"><b>url-decode</b> <i>string</i> <tt>&optional</tt> <i>external-format</i> => <i>url-encoded-string</i></a> + +<blockquote><br> +URL-decodes a string using the external format <code><i>external-format</i></code>, i.e. this is the inverse of <a href="#url-encode"><code>URL-ENCODE</code></a>. +It is assumed that you'll rarely need this function, if ever. But just in case - here it is. +The default for <code><i>external-format</i></code> is the value of <a href="#*hunchentoot-default-external-format*"><code>*HUNCHENTOOT-DEFAULT-EXTERNAL-FORMAT*</code></a>. +</blockquote> + +<p><br>[Function] +<br><a class=none name="http-token-p"><b>http-token-p</b> <i>object</i> => <i>generalized-boolean</i></a> + +<blockquote><br> This function tests +whether <code><i>object</i></code> is a non-empty string which is +a <em>token</em> according to <a href='http://www.faqs.org/rfcs/rfc2068.html'>RFC 2068</a> (i.e. whether it may be used +for, say, cookie names). +</blockquote> + +<p><br>[Special variable] +<br><a class=none name="*tmp-directory*"><b>*tmp-directory*</b></a> + +<blockquote><br> +This should be a pathname denoting a directory where temporary files can be stored. It is used for <a href="#upload">file uploads</a>. +</blockquote> + +<p><br>[Special variable] +<br><a class=none +name="*hunchentoot-default-external-format*"><b>*hunchentoot-default-external-format*</b></a> + +<blockquote><br> The (<a href="http://weitz.de/flexi-streams/">flexi +stream</a>) external format used when computing +the <a href="#requests"><code>REQUEST</code></a> object. The default +value is the result of evaluating +<pre> +(<a class=noborder href="http://weitz.de/flexi-streams/#make-external-format">flex:make-external-format</a> :latin1 :eol-style :lf) +</pre> +</blockquote> + +<p><br>[Function] +<br><a class=none name="mime-type"><b>mime-type</b> <i>pathspec</i> => <i>string</i></a> + +<blockquote><br> +Given a pathname designator <code><i>pathspec</i></code> returns the <a href="http://en.wikipedia.org/wiki/Internet_media_type">MIME type</a> +(as a string) corresponding to the suffix of the file denoted by +<code><i>pathspec</i></code> (or <code>NIL</code> if none can be +found). This is based on the table coming with the Apache +distribution with some additions. +</blockquote> + +<p><br>[Function] +<br><a class=none name="reason-phrase"><b>reason-phrase</b> <i>return-code</i> => <i>string</i></a> + +<blockquote><br> Returns a reason phrase for the HTTP return +code <code><i>return-code</i></code> (which should be an integer) +or <code>NIL</code> for return codes Hunchentoot doesn't know. +</blockquote> + +<br> <br><h3><a class=none name="ht-mp">The HUNCHENTOOT-MP package</a></h3> + +Hunchentoot creates an +additional <a +href="http://www.lispworks.com/documentation/HyperSpec/Body/11_.htm%22%3Epackage</a> <code>HUNCHENTOOT-MP</code> +which exports a couple of MP-related symbols +(namely <code>*CURRENT-PROCESS*</code>, <code>MAKE-LOCK</code>, <code>WITH-LOCK</code>, <code>PROCESS-RUN-FUNCTION</code>, +and <code>PROCESS-KILL</code>). These functions and macros have to be +in Hunchentoot's small portability shim anyway and even if you don't +spawn your own threads there might be occasions where you want to at +least use the lock-related functionality to write thread-safe portable +code. See the corresponding documentation strings and/or the source +code for more information. + +<br> <br><h3><a class=none name="performance">Performance</a></h3> + +If you're concerned about Hunchentoot's performance, you should first +and foremost check if you aren't wasting your time with premature +optimization. Make a reasonable estimate of the amount of traffic +your website should be able to handle and don't try to benchmark for +loads Google would be proud of. Here's a part of an interview with +someone called John Witchel about his experiences with his +company <em>Red Gorilla</em> that can't be quoted often enough (it +seems the original source of the interview has vanished): + +<blockquote> +<b>Q:</b> If you could go back and change anything, would <em>Red Gorilla</em> still be +in business today? +<p> +<b>A:</b> Yes. I would start small and grow as the demand grew. That's what I'm +doing now. +<p> +Back then we planned to be huge from the outset. So we built this +monster platform on BEA, Sun and Oracle. We had huge dedicated +connectivity pipes. We had two full racks clustered and fully +redundant. We had E450's with RAID-5 and all 4 CPU slots filled, +E250s, F5 load balancers... the cost of keeping that system on was +enormous. The headcount to keep it humming was enormous too. +<p> +The truth is, we could have run the whole company on my laptop using a +cable modem connection. +</blockquote> + +Having said that, my experience is that Hunchentoot doesn't have to +hide when it comes to +serving <a href="#handle-static-file">static files</a>. If +you <em>really</em> have performance problems with Hunchentoot, there +are two things I'm aware of you should watch out for. +<ul> +<li>Check how your Lisp implementation implements multi-processing. +While I write this (April 2007), some Lisps, like CMUCL, still use +their +own <a +href="http://en.wikipedia.org/wiki/Multithreading%22%3E<em>green</em> +threads</a>, and some others, like AllegroCL and LispWorks, use +OS-threads but allow only one Lisp thread at a time. Unless you're +using a Lisp that employs "real" symmetric multi-processing like SBCL +(on some platforms) or OpenMCL, you shouldn't compare apples with +oranges. (Note: For CMUCL, you also shouldn't forget to use the +dreaded <a +href="http://wiki.alu.org/Lisp_Gotchas%22%3E<code>MP::STARTUP-IDLE-AND-TOP-LEVEL-LOOPS</code></a>.) +<li>All text output sent from <a href="#handlers">handlers</a> goes +through two layers +of <a +href="http://www.nhplace.com/kent/CL/Issues/stream-definition-by-user.html%22%3EGr... +streams</a> by default +(<a href="http://weitz.de/flexi-streams/">FLEXI-STREAMS</a> +and <a href="http://weitz.de/chunga/">Chunga</a>). This isn't an +issue for small to medium-sized pages, but can be for large ones. +There are several ways to cope with this +- <a +href="http://common-lisp.net/pipermail/tbnl-devel/2007-March/001093.html%22%3Eretu... +binary data from +handlers</a>, <a +href="http://common-lisp.net/pipermail/tbnl-devel/2007-March/001099.html%22%3Ebypa... +FLEXI-STREAMS</a>, sit behind <a href="#mod_lisp">mod_lisp</a>, etc. +Try it, and if you <em>really</em> think that Hunchentoot is too slow +for what you're trying to do and what you'll need, ask on +the <a href="#href">mailing list</a> and we'll try to help. +</ul> + +<br> <br><h3><a class=none name="history">History</a></h3> + +Hunchentoot's predecessor <a href="http://weitz.de/tbnl/">TBNL</a> +(which is short for "To Be Named Later") grew over the years +as a toolkit that I used for various commercial and private +projects. In August 2003, Daniel Barlow started +a <a href='http://article.gmane.org/gmane.lisp.web/148'>review of web +APIs</a> on the <a href='http://www.red-bean.com/lispweb/'>lispweb</a> +mailing list and +I <a href='http://article.gmane.org/gmane.lisp.web/153'>described</a> +the API of my hitherto-unreleased bunch of code (and christened it +"TBNL"). +<p> +It turned out that <a href='http://www.jeffcaldwell.com/'>Jeff +Caldwell</a> had worked on something similar so he emailed me and +proposed to join our efforts. As I had no immediate plans to release +my code (which was poorly organized, undocumented, and mostly +CMUCL-specific), I gave it to Jeff and he worked towards a release. He +added docstrings, refactored, added some stuff, and based it on KMRCL +to make it portable across several Lisp implementations. +<p> +Unfortunately, Jeff is at least as busy as I am so he didn't find the +time to finish a full release. But in spring 2004 I needed a +documented version of the code for a client of mine who thought +it would be good if the toolkit were publicly available under an open +source license. So I took Jeff's code, refactored again (to sync with +the changes I had done in the meantime), and added documentation. +This resulted in TBNL 0.1.0 (which initially required mod_lisp as its +front-end). Jeff's code (which includes a lot more stuff that I +didn't use) is still available from his own +website <a href='http://tbnl.org/'>tbnl.org</a>. +<p> +In March 2005, Bob Hutchinson sent patches which enabled TBNL to use +other front-ends than mod_lisp. This made me aware that TBNL was +already <em>almost</em> a full web server, so eventually I wrote +Hunchentoot which <em>was</em> a full web server, implemented as a +wrapper around TBNL. Hunchentoot 0.1.0 was released at the end of +2005 and was originally LispWorks-only. +<p> +Hunchentoot 0.4.0, released in October 2006, was the first release +which also worked with other Common Lisp implementations. It is a +major rewrite and also incorporates most of TBNL and replaces +it completely. + +<br> <br><h3><a class=none name="index">Symbol index</a></h3> + +Here are all exported symbols of the <code>HUNCHENTOOT</code> package +in alphabetical order linked to their corresponding entries: + + <ul> + <li><a href="#*approved-return-codes*"><code>*approved-return-codes*</code></a> + <li><a href="#*catch-errors-p*"><code>*catch-errors-p*</code></a> + <li><a href="#*cleanup-function*"><code>*cleanup-function*</code></a> + <li><a href="#*cleanup-interval*"><code>*cleanup-interval*</code></a> + <li><a href="#*content-types-for-url-rewrite*"><code>*content-types-for-url-rewrite*</code></a> + <li><a href="#*default-content-type*"><code>*default-content-type*</code></a> + <li><a href="#*default-handler*"><code>*default-handler*</code></a> + <li><a href="#*default-log-level*"><code>*default-log-level*</code></a> + <li><a href="#*default-read-timeout*"><code>*default-read-timeout*</code></a> + <li><a href="#*default-write-timeout*"><code>*default-write-timeout*</code></a> + <li><a href="#*dispatch-table*"><code>*dispatch-table*</code></a> + <li><a href="#*file-upload-hook*"><code>*file-upload-hook*</code></a> + <li><a href="#*handle-http-errors-p*"><code>*handle-http-errors-p*</code></a> + <li><a href="#*header-stream*"><code>*header-stream*</code></a> + <li><a href="#*http-error-handler*"><code>*http-error-handler*</code></a> + <li><a href="#*hunchentoot-default-external-format*"><code>*hunchentoot-default-external-format*</code></a> + <li><a href="#*lisp-errors-log-level*"><code>*lisp-errors-log-level*</code></a> + <li><a href="#*lisp-warnings-log-level*"><code>*lisp-warnings-log-level*</code></a> + <li><a href="#*log-lisp-backtraces-p*"><code>*log-lisp-backtraces-p*</code></a> + <li><a href="#*log-lisp-errors-p*"><code>*log-lisp-errors-p*</code></a> + <li><a href="#*log-lisp-warnings-p*"><code>*log-lisp-warnings-p*</code></a> + <li><a href="#*log-prefix*"><code>*log-prefix*</code></a> + <li><a href="#*meta-dispatcher*"><code>*meta-dispatcher*</code></a> + <li><a href="#*methods-for-post-parameters*"><code>*methods-for-post-parameters*</code></a> + <li><a href="#*reply*"><code>*reply*</code></a> + <li><a href="#*request*"><code>*request*</code></a> + <li><a href="#*rewrite-for-session-urls*"><code>*rewrite-for-session-urls*</code></a> + <li><a href="#*server*"><code>*server*</code></a> + <li><a href="#*session*"><code>*session*</code></a> + <li><a href="#*session-cookie-name*"><code>*session-cookie-name*</code></a> + <li><a href="#*session-gc-frequency*"><code>*session-gc-frequency*</code></a> + <li><a href="#*session-max-time*"><code>*session-max-time*</code></a> + <li><a href="#*session-removal-hook*"><code>*session-removal-hook*</code></a> + <li><a href="#*show-access-log-messages*"><code>*show-access-log-messages*</code></a> + <li><a href="#*show-lisp-backtraces-p*"><code>*show-lisp-backtraces-p*</code></a> + <li><a href="#*show-lisp-errors-p*"><code>*show-lisp-errors-p*</code></a> + <li><a href="#*tmp-directory*"><code>*tmp-directory*</code></a> + <li><a href="#*use-remote-addr-for-sessions*"><code>*use-remote-addr-for-sessions*</code></a> + <li><a href="#*use-user-agent-for-sessions*"><code>*use-user-agent-for-sessions*</code></a> + <li><a href="#+http-accepted+"><code>+http-accepted+</code></a> + <li><a href="#+http-authorization-required+"><code>+http-authorization-required+</code></a> + <li><a href="#+http-bad-gateway+"><code>+http-bad-gateway+</code></a> + <li><a href="#+http-bad-request+"><code>+http-bad-request+</code></a> + <li><a href="#+http-conflict+"><code>+http-conflict+</code></a> + <li><a href="#+http-continue+"><code>+http-continue+</code></a> + <li><a href="#+http-created+"><code>+http-created+</code></a> + <li><a href="#+http-expectation-failed+"><code>+http-expectation-failed+</code></a> + <li><a href="#+http-failed-dependency+"><code>+http-failed-dependency+</code></a> + <li><a href="#+http-forbidden+"><code>+http-forbidden+</code></a> + <li><a href="#+http-gateway-time-out+"><code>+http-gateway-time-out+</code></a> + <li><a href="#+http-gone+"><code>+http-gone+</code></a> + <li><a href="#+http-internal-server-error+"><code>+http-internal-server-error+</code></a> + <li><a href="#+http-length-required+"><code>+http-length-required+</code></a> + <li><a href="#+http-method-not-allowed+"><code>+http-method-not-allowed+</code></a> + <li><a href="#+http-moved-permanently+"><code>+http-moved-permanently+</code></a> + <li><a href="#+http-moved-temporarily+"><code>+http-moved-temporarily+</code></a> + <li><a href="#+http-multi-status+"><code>+http-multi-status+</code></a> + <li><a href="#+http-multiple-choices+"><code>+http-multiple-choices+</code></a> + <li><a href="#+http-no-content+"><code>+http-no-content+</code></a> + <li><a href="#+http-non-authoritative-information+"><code>+http-non-authoritative-information+</code></a> + <li><a href="#+http-not-acceptable+"><code>+http-not-acceptable+</code></a> + <li><a href="#+http-not-found+"><code>+http-not-found+</code></a> + <li><a href="#+http-not-implemented+"><code>+http-not-implemented+</code></a> + <li><a href="#+http-not-modified+"><code>+http-not-modified+</code></a> + <li><a href="#+http-ok+"><code>+http-ok+</code></a> + <li><a href="#+http-partial-content+"><code>+http-partial-content+</code></a> + <li><a href="#+http-payment-required+"><code>+http-payment-required+</code></a> + <li><a href="#+http-precondition-failed+"><code>+http-precondition-failed+</code></a> + <li><a href="#+http-proxy-authentication-required+"><code>+http-proxy-authentication-required+</code></a> + <li><a href="#+http-request-entity-too-large+"><code>+http-request-entity-too-large+</code></a> + <li><a href="#+http-request-time-out+"><code>+http-request-time-out+</code></a> + <li><a href="#+http-request-uri-too-large+"><code>+http-request-uri-too-large+</code></a> + <li><a href="#+http-requested-range-not-satisfiable+"><code>+http-requested-range-not-satisfiable+</code></a> + <li><a href="#+http-reset-content+"><code>+http-reset-content+</code></a> + <li><a href="#+http-see-other+"><code>+http-see-other+</code></a> + <li><a href="#+http-service-unavailable+"><code>+http-service-unavailable+</code></a> + <li><a href="#+http-switching-protocols+"><code>+http-switching-protocols+</code></a> + <li><a href="#+http-temporary-redirect+"><code>+http-temporary-redirect+</code></a> + <li><a href="#+http-unsupported-media-type+"><code>+http-unsupported-media-type+</code></a> + <li><a href="#+http-use-proxy+"><code>+http-use-proxy+</code></a> + <li><a href="#+http-version-not-supported+"><code>+http-version-not-supported+</code></a> + <li><a href="#authorization"><code>authorization</code></a> + <li><a href="#aux-request-value"><code>aux-request-value</code></a> + <li><a href="#content-length"><code>content-length</code></a> + <li><a href="#content-type"><code>content-type</code></a> + <li><a href="#cookie-domain"><code>cookie-domain</code></a> + <li><a href="#cookie-expires"><code>cookie-expires</code></a> + <li><a href="#cookie-http-only"><code>cookie-http-only</code></a> + <li><a href="#cookie-in"><code>cookie-in</code></a> + <li><a href="#cookie-name"><code>cookie-name</code></a> + <li><a href="#cookie-out"><code>cookie-out</code></a> + <li><a href="#cookie-path"><code>cookie-path</code></a> + <li><a href="#cookie-secure"><code>cookie-secure</code></a> + <li><a href="#cookie-value"><code>cookie-value</code></a> + <li><a href="#cookies-in"><code>cookies-in</code></a> + <li><a href="#cookies-out"><code>cookies-out</code></a> + <li><a href="#create-folder-dispatcher-and-handler"><code>create-folder-dispatcher-and-handler</code></a> + <li><a href="#create-prefix-dispatcher"><code>create-prefix-dispatcher</code></a> + <li><a href="#create-regex-dispatcher"><code>create-regex-dispatcher</code></a> + <li><a href="#create-static-file-dispatcher-and-handler"><code>create-static-file-dispatcher-and-handler</code></a> + <li><a href="#default-dispatcher"><code>default-dispatcher</code></a> + <li><a href="#define-easy-handler"><code>define-easy-handler</code></a> + <li><a href="#delete-aux-request-value"><code>delete-aux-request-value</code></a> + <li><a href="#delete-session-value"><code>delete-session-value</code></a> + <li><a href="#dispatch-easy-handlers"><code>dispatch-easy-handlers</code></a> + <li><a href="#dispatch-request"><code>dispatch-request</code></a> + <li><a href="#do-sessions"><code>do-sessions</code></a> + <li><a href="#escape-for-html"><code>escape-for-html</code></a> + <li><a href="#get-backtrace"><code>get-backtrace</code></a> + <li><a href="#get-parameter"><code>get-parameter</code></a> + <li><a href="#get-parameters"><code>get-parameters</code></a> + <li><a href="#handle-if-modified-since"><code>handle-if-modified-since</code></a> + <li><a href="#handle-static-file"><code>handle-static-file</code></a> + <li><a href="#handler-done"><code>handler-done</code></a> + <li><a href="#header-in"><code>header-in</code></a> + <li><a href="#header-out"><code>header-out</code></a> + <li><a href="#headers-in"><code>headers-in</code></a> + <li><a href="#headers-out"><code>headers-out</code></a> + <li><a href="#host"><code>host</code></a> + <li><a href="#http-token-p"><code>http-token-p</code></a> + <li><a href="#log-file"><code>log-file</code></a> + <li><a href="#log-message"><code>log-message</code></a> + <li><a href="#log-message*"><code>log-message*</code></a> + <li><a href="#maybe-invoke-debugger"><code>maybe-invoke-debugger</code></a> + <li><a href="#mime-type"><code>mime-type</code></a> + <li><a href="#mod-lisp-id"><code>mod-lisp-id</code></a> + <li><a href="#no-cache"><code>no-cache</code></a> + <li><a href="#parameter"><code>parameter</code></a> + <li><a href="#post-parameter"><code>post-parameter</code></a> + <li><a href="#post-parameters"><code>post-parameters</code></a> + <li><a href="#query-string"><code>query-string</code></a> + <li><a href="#raw-post-data"><code>raw-post-data</code></a> + <li><a href="#real-remote-addr"><code>real-remote-addr</code></a> + <li><a href="#reason-phrase"><code>reason-phrase</code></a> + <li><a href="#recompute-request-parameters"><code>recompute-request-parameters</code></a> + <li><a href="#redirect"><code>redirect</code></a> + <li><a href="#referer"><code>referer</code></a> + <li><a href="#remote-addr"><code>remote-addr</code></a> + <li><a href="#remote-port"><code>remote-port</code></a> + <li><a href="#remote-session"><code>remote-session</code></a> + <li><a href="#reply-external-format"><code>reply-external-format</code></a> + <li><a href="#request-method"><code>request-method</code></a> + <li><a href="#request-uri"><code>request-uri</code></a> + <li><a href="#require-authorization"><code>require-authorization</code></a> + <li><a href="#reset-sessions"><code>reset-sessions</code></a> + <li><a href="#return-code"><code>return-code</code></a> + <li><a href="#rfc-1123-date"><code>rfc-1123-date</code></a> + <li><a href="#script-name"><code>script-name</code></a> + <li><a href="#send-headers"><code>send-headers</code></a> + <li><a href="#server-addr"><code>server-addr</code></a> + <li><a href="#server-address"><code>server-address</code></a> + <li><a href="#server-dispatch-table"><code>server-dispatch-table</code></a> + <li><a href="#server-local-port"><code>server-local-port</code></a> + <li><a href="#server-name"><code>server-name</code></a> + <li><a href="#server-port"><code>server-port</code></a> + <li><a href="#server-protocol"><code>server-protocol</code></a> + <li><a href="#session-cookie-value"><code>session-cookie-value</code></a> + <li><a href="#session-counter"><code>session-counter</code></a> + <li><a href="#session-gc"><code>session-gc</code></a> + <li><a href="#session-max-time"><code>session-max-time</code></a> + <li><a href="#session-too-old-p"><code>session-too-old-p</code></a> + <li><a href="#session-remote-addr"><code>session-remote-addr</code></a> + <li><a href="#session-user-agent"><code>session-user-agent</code></a> + <li><a href="#session-value"><code>session-value</code></a> + <li><a href="#set-cookie"><code>set-cookie</code></a> + <li><a href="#set-cookie*"><code>set-cookie*</code></a> + <li><a href="#ssl-p"><code>ssl-p</code></a> + <li><a href="#ssl-session-id"><code>ssl-session-id</code></a> + <li><a href="#start-server"><code>start-server</code></a> + <li><a href="#start-session"><code>start-session</code></a> + <li><a href="#stop-server"><code>stop-server</code></a> + <li><a href="#url-decode"><code>url-decode</code></a> + <li><a href="#url-encode"><code>url-encode</code></a> + <li><a href="#user-agent"><code>user-agent</code></a> + </ul> + +<br> <br><h3><a class=none name="ack">Acknowledgements</a></h3> + +Thanks to Jeff Caldwell - TBNL would not have been released without +his efforts. Thanks to <a href="http://www.fractalconcept.com/">Marc +Battyani</a> for mod_lisp and +to <a href="http://www.swiss.ai.mit.edu/~cph/">Chris Hanson</a> for +mod_lisp2. Thanks +to <a href="http://www.cliki.net/Stefan%20Scholl">Stefan Scholl</a> +and Travis Cross for various additions and fixes to TBNL, +to <a href="http://www.foldr.org/~michaelw/">Michael Weber</a> for +initial file upload code, and +to <a href="http://www.ltn.lv/~jonis/">Janis Dzerins</a> for +his <a href="http://common-lisp.net/project/rfc2388/">RFC 2388 +code</a>. Thanks to Bob Hutchison for his code for multiple front-ends +(which made me realize that TBNL was already pretty close to a "real" +web server) and the initial UTF-8 example. Thanks to John +Foderaro's <a +href="http://opensource.franz.com/aserve/index.html%22%3EAllegroServe</a> +for inspiration. Thanks +to <a href="http://www.htg1.de/">Uwe von Loh</a> for the <a href="http://www.htg1.de/hunchentoot/hunchentoot.html">Hunchentoot +logo</a>. +<p> +Hunchentoot originally used code +from <a href="http://www.cliki.net/ACL-COMPAT">ACL-COMPAT</a>, +specifically the chunking code from Jochen Schmidt. (This has been +replaced by <a href="http://weitz.de/chunga/">Chunga</a>.) When I +ported Hunchentoot to other Lisps than LispWorks, I stole code from +ACL-COMPAT, <a href="http://www.cliki.net/kmrcl">KMRCL</a>, +and <a href="http://www.cliki.net/trivial-sockets">trivial-sockets</a> +for implementation-dependent stuff like sockets and MP. +<p> +Parts of this documentation were prepared +with <a +href="http://weitz.de/documentation-template/%22%3EDOCUMENTATION-TEMPLATE</a>, no animals were harmed. +</p> +<p> +$Header: /usr/local/cvsrep/hunchentoot/doc/index.html,v 1.120 2007/11/08 20:08:00 edi Exp $ +<p><a href="http://weitz.de/index.html">BACK TO MY HOMEPAGE</a> + +</body> +</html>
Property changes on: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/doc/index.html ___________________________________________________________________ Name: svn:executable + *
Added: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/easy-handlers.lisp =================================================================== --- branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/easy-handlers.lisp 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/easy-handlers.lisp 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,319 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: HUNCHENTOOT; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/hunchentoot/easy-handlers.lisp,v 1.12 2007/05/25 11:32:50 edi Exp $ + +;;; Copyright (c) 2004-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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-package :hunchentoot) + +(defun compute-real-name (symbol) + "Computes the `real' paramater name (a string) from the Lisp +symbol SYMBOL. Used in cases where no parameter name is +provided." + ;; we just downcase the symbol's name + (string-downcase symbol)) + +(defun convert-parameter (argument type) + "Converts the string ARGUMENT to TYPE where TYPE is one of the +symbols STRING, CHARACTERS, INTEGER, KEYWORD, or BOOLEAN - or +otherwise a function designator for a function of one argument. +ARGUMENT can also be NIL in which case this function also returns +NIL unconditionally." + (when (listp argument) + ;; this if for the case that ARGUMENT is NIL or the result of a + ;; file upload + (return-from convert-parameter argument)) + (case type + (string argument) + (character (and (= (length argument) 1) + (char argument 0))) + (integer (ignore-errors (parse-integer argument :junk-allowed t))) + (keyword (make-keyword argument :destructivep nil)) + (boolean t) + (otherwise (funcall type argument)))) + +(defun compute-simple-parameter (parameter-name type parameter-reader) + "Retrieves the parameter named PARAMETER-NAME using the reader +PARAMETER-READER and converts it to TYPE." + (convert-parameter (funcall parameter-reader parameter-name) type)) + +(defun compute-list-parameter (parameter-name type parameters) + "Retrieves all parameters from PARAMETERS which are named +PARAMETER-NAME, converts them to TYPE, and returns a list of +them." + (loop for (name . value) in parameters + when (string= name parameter-name) + collect (convert-parameter value type))) + +(defun compute-array-parameter (parameter-name type parameters) + "Retrieves all parameters from PARAMETERS which are named like +"PARAMETER-NAME[N]" (where N is a non-negative integer), +converts them to TYPE, and returns an array where the Nth element +is the corresponding value." + ;; see http://common-lisp.net/pipermail/tbnl-devel/2006-September/000660.html + #+:sbcl (declare (sb-ext:muffle-conditions warning)) + (let* ((index-value-list + (loop for (full-name . value) in parameters + for index = (register-groups-bind (name index-string) + ("^(.*)\[(\d+)\]$" full-name) + (when (string= name parameter-name) + (parse-integer index-string))) + when index + collect (cons index (convert-parameter value type)))) + (array (make-array (1+ (reduce #'max index-value-list + :key #'car + :initial-value -1)) + :initial-element nil))) + (loop for (index . value) in index-value-list + do (setf (aref array index) value)) + array)) + +(defun compute-hash-table-parameter (parameter-name type parameters key-type test-function) + "Retrieves all parameters from PARAMETERS which are named like +"PARAMETER-NAME{FOO}" (where FOO is any sequence of characters +not containing curly brackets), converts them to TYPE, and +returns a hash table with test function TEST-FUNCTION where the +corresponding value is associated with the key FOO (converted to +KEY-TYPE)." + (let ((hash-table (make-hash-table :test test-function))) + (loop for (full-name . value) in parameters + for key = (register-groups-bind (name key-string) + ("^(.*){([^{}]+)}$" full-name) + (when (string= name parameter-name) + (convert-parameter key-string key-type))) + when key + do (setf (gethash key hash-table) + (convert-parameter value type))) + hash-table)) + +(defun compute-parameter (parameter-name parameter-type request-type) + "Computes and returns the parameter(s) called PARAMETER-NAME +and converts it/them according to the value of PARAMETER-TYPE. +REQUEST-TYPE is one of :GET, :POST, or :BOTH." + (when (member parameter-type '(list array hash-table)) + (setq parameter-type (list parameter-type 'string))) + (let ((parameter-reader (ecase request-type + (:get #'get-parameter) + (:post #'post-parameter) + (:both #'parameter))) + (parameters (and (listp parameter-type) + (case request-type + (:get (get-parameters)) + (:post (post-parameters)) + (:both (append (get-parameters) (post-parameters))))))) + (cond ((atom parameter-type) + (compute-simple-parameter parameter-name parameter-type parameter-reader)) + ((and (null (cddr parameter-type)) + (eq (first parameter-type) 'list)) + (compute-list-parameter parameter-name (second parameter-type) parameters)) + ((and (null (cddr parameter-type)) + (eq (first parameter-type) 'array)) + (compute-array-parameter parameter-name (second parameter-type) parameters)) + ((and (null (cddddr parameter-type)) + (eq (first parameter-type) 'hash-table)) + (compute-hash-table-parameter parameter-name (second parameter-type) parameters + (or (third parameter-type) 'string) + (or (fourth parameter-type) 'equal))) + (t (error "Don't know what to do with parameter type ~S." parameter-type))))) + +(defun make-defun-parameter (description default-parameter-type default-request-type) + "Creates a keyword parameter to be used by DEFINE-EASY-HANDLER. +DESCRIPTION is one of the elements of DEFINE-EASY-HANDLER's +LAMBDA-LIST and DEFAULT-PARAMETER-TYPE and DEFAULT-REQUEST-TYPE +are the global default values." + (when (atom description) + (setq description (list description))) + (destructuring-bind (parameter-name &key (real-name (compute-real-name parameter-name)) + parameter-type init-form request-type) + description + `(,parameter-name (or (and (boundp '*request*) + (compute-parameter ,real-name + ,(or parameter-type default-parameter-type) + ,(or request-type default-request-type))) + ,init-form)))) + +(defmacro define-easy-handler (description lambda-list &body body) + "Defines a handler with the body BODY and optionally registers +it with a URI so that it will be found by DISPATCH-EASY-HANDLERS. +DESCRIPTION is either a symbol NAME or a list matching the +destructuring lambda list + + (name &key uri server-names default-parameter-type default-request-type). + +LAMBDA-LIST is a list the elements of which are either a symbol +VAR or a list matching the destructuring lambda list + + (var &key real-name parameter-type init-form request-type). + +The resulting handler will be a Lisp function with the name NAME +and keyword parameters named by the VAR symbols. Each VAR will +be bound to the value of the GET or POST parameter called +REAL-NAME (a string) before BODY is executed. If REAL-NAME is +not provided, it will be computed by downcasing the symbol name +of VAR. + +If URI (which is evaluated) is provided, then it must be a string or +a function designator for a function of one argument. In this case, +the handler will be returned by DISPATCH-EASY-HANDLERS, if URI is a +string and the script name of a request is URI, or if URI designates a +function and applying this function to the current request object +returns a true value. + +SERVER-NAMES (which is evaluated) can be a list of symbols which +means that the handler will be returned by DISPATCH-EASY-HANDLERS in +servers which have one of these names (see SERVER-NAME). +SERVER-NAMES can also be the symbol T which means that the handler +will be returned by DISPATCH-EASY-HANDLERS in every server. + +Whether the GET or POST parameter (or both) will be taken into +consideration, depends on REQUEST-TYPE which can +be :GET, :POST, :BOTH, or NIL. In the last case, the value of +DEFAULT-REQUEST-TYPE (the default of which is :BOTH) will be +used. + +The value of VAR will usually be a string (unless it resulted from a +file upload in which case it won't be converted at all), but if +PARAMETER-TYPE (which is evaluated) is provided, the string will be +converted to another Lisp type by the following rules: + +If the corresponding GET or POST parameter wasn't provided by the +client, VAR's value will be NIL. If PARAMETER-TYPE is 'STRING, VAR's +value remains as is. If PARAMETER-TYPE is 'INTEGER and the parameter +string consists solely of decimal digits, VAR's value will be the +corresponding integer, otherwise NIL. If PARAMETER-TYPE is 'KEYWORD, +VAR's value will be the keyword obtained by interning the upcased +parameter string into the keyword package. If PARAMETER-TYPE is +'CHARACTER and the parameter string is of length one, VAR's value will +be the single character of this string, otherwise NIL. If +PARAMETER-TYPE is 'BOOLEAN, VAR's value will always be T (unless it +is NIL by the first rule above, of course). If PARAMETER-TYPE is any +other atom, it is supposed to be a function designator for a unary +function which will be called to convert the string to something else. + +Those were the rules for `simple' types, but PARAMETER-TYPE can +also be a list starting with one of the symbols LIST, ARRAY, or +HASH-TABLE. The second value of the list must always be a simple +parameter type as in the last paragraph - we'll call it the +`inner type' below. + +In the case of 'LIST, all GET/POST parameters called REAL-NAME +will be collected, converted to the inner type, and assembled +into a list which will be the value of VAR. + +In the case of 'ARRAY, all GET/POST parameters which have a name +like the result of + + (format nil "~A[~A]" real-name n) + +where N is a non-negative integer, will be assembled into an +array where the Nth element will be set accordingly, after +conversion to the inner type. The array, which will become the +value of VAR, will be big enough to hold all matching parameters, +but not bigger. Array elements not set as described above will +be NIL. Note that VAR will always be bound to an array, which +may be empty, so it will never be NIL, even if no appropriate +GET/POST parameters are found. + +The full form of a 'HASH-TABLE parameter type is + + (hash-table inner-type key-type test-function), + +but KEY-TYPE and TEST-FUNCTION can be left out in which case they +default to 'STRING and 'EQUAL, respectively. For this parameter +type, all GET/POST parameters which have a name like the result +of + + (format nil "~A{~A}" real-name key) + +(where KEY is a string that doesn't contain curly brackets) will +become the values (after conversion to INNER-TYPE) of a hash +table with test function TEST-FUNCTION where KEY (after +conversion to KEY-TYPE) will be the corresponding key. Note that +VAR will always be bound to a hash table, which may be empty, so +it will never be NIL, even if no appropriate GET/POST parameters +are found. + +To make matters even more complicated, the three compound +parameter types also have an abbreviated form - just one of the +symbols LIST, ARRAY, or HASH-TABLE. In this case, the inner type +will default to 'STRING. + +If PARAMETER-TYPE is not provided or NIL, DEFAULT-PARAMETER-TYPE +(the default of which is 'STRING) will be used instead. + +If the result of the computations above would be that VAR would +be bound to NIL, then INIT-FORM (if provided) will be evaluated +instead, and VAR will be bound to the result of this evaluation. + +Handlers built with this macro are constructed in such a way that +the resulting Lisp function is useful even outside of +Hunchentoot. Specifically, all the parameter computations above +will only happen if *REQUEST* is bound, i.e. if we're within a +Hunchentoot request. Otherwise, VAR will always be bound to the +result of evaluating INIT-FORM unless a corresponding keyword +argument is provided." + (when (atom description) + (setq description (list description))) + (destructuring-bind (name &key uri (server-names t) + (default-parameter-type ''string) + (default-request-type :both)) + description + `(progn + ,@(when uri + (list + (with-rebinding (uri) + `(progn + (setq *easy-handler-alist* + (delete-if (lambda (list) + (or (equal ,uri (first list)) + (eq ',name (third list)))) + *easy-handler-alist*)) + (push (list ,uri ,server-names ',name) *easy-handler-alist*))))) + (defun ,name (&key ,@(loop for part in lambda-list + collect (make-defun-parameter part + default-parameter-type + default-request-type))) + ,@body)))) + +;; help the LispWorks IDE to find these definitions +#+:lispworks +(dspec:define-form-parser define-easy-handler (description) + `(,define-easy-handler ,(if (atom description) description (first description)))) + +#+:lispworks +(dspec:define-dspec-alias define-easy-handler (name) + `(defun ,name)) + +(defun dispatch-easy-handlers (request) + "This is a dispatcher which returns the appropriate handler +defined with DEFINE-EASY-HANDLER, if there is one." + (loop for (uri server-names easy-handler) in *easy-handler-alist* + when (and (or (eq server-names t) + (find (server-name *server*) server-names :test #'eq)) + (cond ((stringp uri) + (string= (script-name request) uri)) + (t (funcall uri request)))) + do (return easy-handler)))
Property changes on: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/easy-handlers.lisp ___________________________________________________________________ Name: svn:executable + *
Added: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/headers.lisp =================================================================== --- branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/headers.lisp 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/headers.lisp 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,320 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: HUNCHENTOOT; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/hunchentoot/headers.lisp,v 1.24 2007/09/24 13:43:45 edi Exp $ + +;;; Copyright (c) 2004-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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-package :hunchentoot) + +(defun maybe-write-to-header-stream (key &optional value) + (when *header-stream* + (format *header-stream* "~A~@[: ~A~]~%" key + (and value (regex-replace-all "[\r\n]" value " "))) + (force-output *header-stream*))) + +(defun compute-length (content) + "Computes and returns the length of CONTENT in octets. Returns as a +second value CONTENT as a vector of octets. The result depends on the +external format of *REPLY*." + (when (null content) + (return-from compute-length)) + (when (stringp content) + (setq content + (string-to-octets content :external-format (reply-external-format)))) + (values (length content) content)) + +(defmethod write-header-line ((mod-lisp-p (eql nil)) key value) + "Accepts strings KEY and VALUE and writes them directly to the +client as an HTTP header line." + (write-string key *hunchentoot-stream*) + (write-string ": " *hunchentoot-stream*) + ;; remove line breaks + (write-string (regex-replace-all "[\r\n]" value " ") *hunchentoot-stream*) + (write-string +crlf+ *hunchentoot-stream*)) + +(defmethod write-header-line (mod-lisp-p key value) + "Accepts strings KEY and VALUE and writes them, one line at a time, +to the mod_lisp socket stream." + (write-line key *hunchentoot-stream*) + ;; remove line breaks + (write-line (regex-replace-all "[\r\n]" value " ") *hunchentoot-stream*)) + +(defmethod write-header-line :after (mod-lisp-p key value) + (declare (ignorable mod-lisp-p)) + (maybe-write-to-header-stream key value)) + +(defun start-output (&optional (content nil content-provided-p)) + "Sends all headers and maybe the content body to +*HUNCHENTOOT-STREAM*. Returns immediately and does nothing if called +more than once per request. Handles the supported return codes +accordingly. Called by PROCESS-REQUEST and/or SEND-HEADERS. Returns +the stream to write to." + ;; send headers only once + (when *headers-sent* + (return-from start-output)) + (setq *headers-sent* t) + ;; read post data to clear stream + (raw-post-data) + (let* ((mod-lisp-p (server-mod-lisp-p *server*)) + (return-code (return-code)) + (chunkedp (and (server-output-chunking-p *server*) + (eq (server-protocol) :http/1.1) + ;; only turn chunking on if the content + ;; length is unknown at this point... + (null (or (content-length) content-provided-p)) + ;; ...AND if the return code isn't one where + ;; Hunchentoot (or a user error handler) sends its + ;; own content + (member return-code *approved-return-codes*))) + (reason-phrase (reason-phrase return-code)) + (request-method (request-method)) + (head-request-p (eq request-method :head)) + content-modified-p) + (unless mod-lisp-p + (multiple-value-bind (keep-alive-p keep-alive-requested-p) + (keep-alive-p) + (when keep-alive-p + (setq keep-alive-p + ;; use keep-alive if there's a way for the client to + ;; determine when all content is sent (or if there + ;; is no content) + (or chunkedp + head-request-p + (eq (return-code) +http-not-modified+) + (content-length) + content))) + ;; now set headers for keep-alive and chunking + (when chunkedp + (setf (header-out "Transfer-Encoding") "chunked")) + (cond (keep-alive-p + (setf *close-hunchentoot-stream* nil) + (when (or (not (eq (server-protocol) :http/1.1)) + keep-alive-requested-p) + ;; persistent connections are implicitly assumed for + ;; HTTP/1.1, but we return a 'Keep-Alive' header if the + ;; client has explicitly asked for one + (setf (header-out "Connection") "Keep-Alive" + (header-out "Keep-Alive") + (format nil "timeout=~D" (server-read-timeout *server*))))) + (t (setf (header-out "Connection") "Close")))) + (unless (and (header-out-set-p "Server") + (null (header-out "Server"))) + (setf (header-out "Server") (or (header-out "Server") + (server-name-header)))) + (setf (header-out "Date") (rfc-1123-date))) + (unless reason-phrase + (setq content (escape-for-html + (format nil "Unknown http return code: ~A" return-code)) + content-modified-p t + return-code +http-internal-server-error+ + reason-phrase (reason-phrase return-code))) + (unless (or (not *handle-http-errors-p*) + (member return-code *approved-return-codes*)) + ;; call error handler, if any - should return NIL if it can't + ;; handle the error + (let (error-handled-p) + (when *http-error-handler* + (setq error-handled-p (funcall *http-error-handler* return-code) + content (or error-handled-p content) + content-modified-p (or content-modified-p error-handled-p))) + ;; handle common return codes other than 200, which weren't + ;; handled by the error handler + (unless error-handled-p + (setf (content-type) + "text/html; charset=iso-8859-1" + content-modified-p t + content + (format nil "<html><head><title>~D ~A</title></head><body><h1>~:*~A</h1>~A<p><hr>~A</p></body></html>" + return-code reason-phrase + (case return-code + ((#.+http-internal-server-error+) content) + ((#.+http-moved-temporarily+ #.+http-moved-permanently+) + (format nil "The document has moved <a href='~A'>here</a>" + (header-out "Location"))) + ((#.+http-authorization-required+) + "The server could not verify that you are authorized to access the document requested. Either you supplied the wrong credentials (e.g., bad password), or your browser doesn't understand how to supply the credentials required.") + ((#.+http-forbidden+) + (format nil "You don't have permission to access ~A on this server." + (script-name))) + ((#.+http-not-found+) + (format nil "The requested URL ~A was not found on this server." + (script-name))) + ((#.+http-bad-request+) + "Your browser sent a request that this server could not understand.") + (otherwise "")) + (address-string)))))) + ;; start with status line + (cond (mod-lisp-p + (write-header-line t "Status" (format nil "~D ~A" return-code reason-phrase))) + (t + (let ((first-line + (format nil "HTTP/1.1 ~D ~A" return-code reason-phrase))) + (write-string first-line *hunchentoot-stream*) + (write-string +crlf+ *hunchentoot-stream*) + (maybe-write-to-header-stream first-line)))) + (when (and (stringp content) + (not content-modified-p) + (starts-with-one-of-p (or (content-type) "") + *content-types-for-url-rewrite*)) + ;; if the Content-Type header starts with one of the strings + ;; in *CONTENT-TYPES-FOR-URL-REWRITE* then maybe rewrite the + ;; content + (setq content (maybe-rewrite-urls-for-session content))) + (let ((content-length (content-length))) + (unless content-length + (multiple-value-setq (content-length content) (compute-length content))) + ;; write the corresponding headers for the content + (when content-length + (write-header-line mod-lisp-p "Content-Length" (format nil "~D" content-length)) + (when mod-lisp-p + (write-header-line t "Lisp-Content-Length" + (cond (head-request-p "0") + (t (format nil "~D" content-length)))) + (write-header-line t "Keep-Socket" "1") + (setq *close-hunchentoot-stream* nil))) + (when-let (content-type (content-type)) + (write-header-line mod-lisp-p "Content-Type" content-type)) + ;; write all headers from the REPLY object + (loop for (key . value) in (headers-out) + when value + do (write-header-line mod-lisp-p (string-capitalize key) value)) + ;; now the cookies + (loop for (nil . cookie) in (cookies-out) + do (write-header-line mod-lisp-p "Set-Cookie" (stringify-cookie cookie))) + (when mod-lisp-p + ;; send log messages to mod_lisp + (loop for (log-level . message) in (reverse (log-messages *reply*)) + do (write-header-line t (case log-level + ((:emerg) "Log-Emerg") + ((:alert) "Log-Alert") + ((:crit) "Log-Crit") + ((:error) "Log-Error") + ((:warning) "Log-Warning") + ((:notice) "Log-Notice") + ((:info) "Log-Info") + ((:debug) "Log-Debug") + (otherwise "Log")) + message))) + ;; all headers sent + (cond (mod-lisp-p + (write-line "end" *hunchentoot-stream*) + (maybe-write-to-header-stream "end")) + (t + (write-string +crlf+ *hunchentoot-stream*) + (maybe-write-to-header-stream ""))) + ;; access log message + (when (and *show-access-log-messages* + (not (server-use-apache-log-p *server*))) + (ignore-errors + (log-message nil "~:[-~@[ (~A)~]~;~:*~A~@[ (~A)~]~] ~:[-~;~:*~A~] "~A ~A~@[?~A~] ~A" ~A ~:[~*-~;~D~] "~:[-~;~:*~A~]" "~:[-~;~:*~A~]"" + (remote-addr) (header-in :x-forwarded-for) + (authorization) request-method (script-name) + (query-string) (server-protocol) + return-code content content-length + (referer) (user-agent))))) + (setf (flexi-stream-external-format *hunchentoot-stream*) (reply-external-format)) + ;; now optional content + (unless (or (null content) head-request-p) + (ignore-errors + (write-sequence content *hunchentoot-stream*))) + (when chunkedp + ;; turn chunking on after the headers have been sent + (setf (chunked-stream-output-chunking-p + (flexi-stream-stream *hunchentoot-stream*)) t)) + *hunchentoot-stream*)) + +(defun send-headers () + "Sends the initial status line and all headers as determined by +the REPLY object *REPLY*. Returns a stream to which the body of +the reply can be written. Once this function has been called, +further changes to *REPLY* don't have any effect. Also, +automatic handling of errors (i.e. sending the corresponding +status code to the browser, etc.) is turned off for this request. +If your handlers return the full body as a string or as an array +of octets you should NOT call this function." + (start-output)) + +(defun get-request-data () + "Reads incoming headers from mod_lisp or directly from the client +via *HUNCHENTOOT-STREAM*. Returns as multiple values the headers as +an alist, the stream to read the request body from, the method, the +URI, and the protocol of the request. The last three values are only +returned if we're not behind mod_lisp." + (ignore-errors + (let* ((mod-lisp-p (server-mod-lisp-p *server*)) + (first-line (if mod-lisp-p + (read-line *hunchentoot-stream* nil nil) + (cl:handler-case + (read-line* *hunchentoot-stream*) + ((or end-of-file + #+:sbcl sb-sys:io-timeout + #+:cmu sys:io-timeout + #+:allegro excl:socket-error) () + nil))))) + (cond ((null first-line) + ;; socket closed - return immediately + nil) + (mod-lisp-p + ;; we're behind mod_lisp, so we read alternating + ;; key/value lines + (let ((second-line (read-line *hunchentoot-stream* t))) + (maybe-write-to-header-stream first-line second-line) + (let* ((headers + (loop for key = (read-line *hunchentoot-stream* nil nil) + while (and key (string-not-equal key "end")) + for value = (read-line *hunchentoot-stream* t) + collect (cons (make-keyword key) value) + do (maybe-write-to-header-stream key value))) + (content-length (cdr (assoc :content-length headers)))) + ;; add contents of first two lines + (push (cons (make-keyword first-line) second-line) headers) + (values (delete-duplicates headers :test #'eq :key #'car) + (and (or content-length + (server-input-chunking-p *server*)) + *hunchentoot-stream*))))) + (t + ;; we're a stand-alone web server, so we use Chunga to + ;; read the headers + (destructuring-bind (method url-string &optional protocol) + (split "\s+" first-line :limit 3) + (maybe-write-to-header-stream first-line) + (let ((headers (and protocol (read-http-headers *hunchentoot-stream* + *header-stream*)))) + (unless protocol (setq protocol "HTTP/0.9")) + (when (equalp (cdr (assoc :expect headers)) "100-continue") + ;; handle 'Expect: 100-continue' header + (let ((continue-line + (format nil "HTTP/1.1 ~D ~A" + +http-continue+ + (reason-phrase +http-continue+)))) + (write-string continue-line *hunchentoot-stream*) + (write-string +crlf+ *hunchentoot-stream*) + (write-string +crlf+ *hunchentoot-stream*) + (force-output *hunchentoot-stream*) + (maybe-write-to-header-stream continue-line) + (maybe-write-to-header-stream ""))) + (values headers *hunchentoot-stream* (make-keyword method) url-string + (make-keyword (string-trim '(#\Space #\Tab #\NewLine #\Return) protocol)))))))))) \ No newline at end of file
Property changes on: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/headers.lisp ___________________________________________________________________ Name: svn:executable + *
Added: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/hunchentoot-test.asd =================================================================== --- branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/hunchentoot-test.asd 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/hunchentoot-test.asd 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,35 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-USER; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/hunchentoot/hunchentoot-test.asd,v 1.2 2007/01/01 23:50:30 edi Exp $ + +;;; Copyright (c) 2004-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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. + +(asdf:defsystem :hunchentoot-test + :components ((:module "test" + :serial t + :components ((:file "packages") + (:file "test")))) + :depends-on (:hunchentoot :cl-who))
Property changes on: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/hunchentoot-test.asd ___________________________________________________________________ Name: svn:executable + *
Added: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/hunchentoot.asd =================================================================== --- branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/hunchentoot.asd 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/hunchentoot.asd 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,79 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-USER; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/hunchentoot/hunchentoot.asd,v 1.51 2007/11/08 20:07:58 edi Exp $ + +;;; Copyright (c) 2004-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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-package :cl-user) + +(defpackage :hunchentoot-asd + (:use :cl :asdf)) + +(in-package :hunchentoot-asd) + +(defvar *hunchentoot-version* "0.14.6" + "A string denoting the current version of Hunchentoot. Used +for diagnostic output.") + +(export '*hunchentoot-version*) + +(asdf:defsystem :hunchentoot + :serial t + :version #.*hunchentoot-version* + :depends-on (:chunga + :cl-base64 + :cl-ppcre + #-(or :lispworks :hunchentoot-no-ssl) :cl+ssl + :md5 + :rfc2388 + #+:sbcl :sb-bsd-sockets + #+:sbcl :sb-posix + #+:openmcl :acl-compat + :url-rewrite) + :components ((:file "packages") + (:file "conditions") + #+:allegro (:file "port-acl") + #+:cmu (:file "port-cmu") + #+:lispworks (:file "port-lw") + #+:openmcl (:file "port-mcl") + #+:sbcl (:file "port-sbcl") + (:file "specials") + (:file "mime-types") + (:file "util") + (:file "log") + (:file "cookie") + (:file "reply") + (:file "request") + (:file "session") + (:file "misc") + (:file "easy-handlers") + (:file "headers") + #+(and :allegro :unix) (:file "unix-acl") + #+(and :cmu :unix) (:file "unix-cmu") + #+(and :lispworks :unix) (:file "unix-lw") + #+(and :openmcl :unix) (:file "unix-mcl") + #+(and :sbcl :unix (not :win32)) (:file "unix-sbcl") + (:file "server")))
Property changes on: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/hunchentoot.asd ___________________________________________________________________ Name: svn:executable + *
Added: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/log.lisp =================================================================== --- branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/log.lisp 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/log.lisp 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,93 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: HUNCHENTOOT; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/hunchentoot/log.lisp,v 1.9 2007/10/19 23:51:32 edi Exp $ + +;;; Copyright (c) 2004-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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-package :hunchentoot) + +(defgeneric log-message (log-level fmt &rest args)) + +(defmethod log-message (log-level fmt &rest args) + "Sends a formatted message to Apache's error log when the data gets +sent to Apache/mod_lisp and SERVER-USE-APACHE-LOG-P is true, otherwise +logs to the file denoted by LOG-FILE. FMT and ARGS are as in FORMAT. +LOG-LEVEL is a keyword denoting the corresponding Apache error level." + (let ((message (apply #'format nil fmt args))) + (cond ((and (boundp '*server*) + (server-mod-lisp-p *server*) + (server-use-apache-log-p *server*)) + (with-input-from-string (s message) + (loop with prolog = (case *log-prefix* + ((nil) "") + ((t) "[Hunchentoot] ") + (otherwise (format nil "[~A] " *log-prefix*))) + for line = (read-line s nil nil) + while line + do (push (cons log-level + (format nil "~A~A" prolog line)) + (slot-value *reply* 'log-messages))))) + (t (with-lock (*log-file-lock*) + (ignore-errors + (unless *log-file-stream* + (let ((log-file-stream + (open (ensure-directories-exist *log-file*) + :direction :output + :element-type 'octet + :if-does-not-exist :create + :if-exists :append + #+:openmcl #+:openmcl + :sharing :lock))) + (setq *log-file-stream* + (make-flexi-stream log-file-stream + :external-format +utf-8+)))) + (handler-case + (format *log-file-stream* + "[~A~@[ [~A]~]] ~A~%" (iso-time) log-level message) + (error () + (format *log-file-stream* "[~A [EMERG]] A message could not be logged!" + (iso-time)))) + (force-output *log-file-stream*)))))) + (values)) + +(defun log-message* (fmt &rest args) + "Same as LOG-MESSAGE* but with the default log level (as +defined by *DEFAULT-LOG-LEVEL*)." + (apply #'log-message *default-log-level* fmt args)) + +(defun log-file () + "Returns the log file which is currently used." + *log-file*) + +(defun (setf log-file) (pathspec) + "Sets the log file which is to be used." + (with-lock (*log-file-lock*) + (when *log-file-stream* + (ignore-errors + (close *log-file-stream*)) + (setq *log-file-stream* nil)) + (setq *log-file* pathspec))) + \ No newline at end of file
Added: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/mime-types.lisp =================================================================== --- branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/mime-types.lisp 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/mime-types.lisp 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,362 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: HUNCHENTOOT; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/hunchentoot/mime-types.lisp,v 1.3 2007/01/01 23:50:30 edi Exp $ + +;;; Copyright (c) 2004-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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-package :hunchentoot) + +(defparameter *mime-type-list* '(("application/andrew-inset" "ez") + ("application/cu-seeme" "cu") + ("application/dsptype" "tsp") + ("application/futuresplash" "spl") + ("application/hta" "hta") + ("application/java-archive" "jar") + ("application/java-serialized-object" "ser") + ("application/java-vm" "class") + ("application/mac-binhex40" "hqx") + ("application/mac-compactpro" "cpt") + ("application/mathematica" "nb") + ("application/msaccess" "mdb") + ("application/msword" "doc" "dot") + ("application/octet-stream" "bin") + ("application/oda" "oda") + ("application/ogg" "ogg") + ("application/pdf" "pdf") + ("application/pgp-keys" "key") + ("application/pgp-signature" "pgp") + ("application/pics-rules" "prf") + ("application/postscript" "ps" "ai" "eps") + ("application/rar" "rar") + ("application/rdf+xml" "rdf") + ("application/rss+xml" "rss") + ("application/smil" "smi" "smil") + ("application/wordperfect" "wpd") + ("application/wordperfect5.1" "wp5") + ("application/xhtml+xml" "xhtml" "xht") + ("application/xml" "fo" "xml" "xsl") + ("application/zip" "zip") + ("application/vnd.cinderella" "cdy") + ("application/vnd.mozilla.xul+xml" "xul") + ("application/vnd.ms-excel" "xls" "xlb" "xlt") + ("application/vnd.ms-pki.seccat" "cat") + ("application/vnd.ms-pki.stl" "stl") + ("application/vnd.ms-powerpoint" "ppt" "pps") + ("application/vnd.oasis.opendocument.chart" "odc") + ("application/vnd.oasis.opendocument.database" "odb") + ("application/vnd.oasis.opendocument.formula" "odf") + ("application/vnd.oasis.opendocument.graphics" "odg") + ("application/vnd.oasis.opendocument.graphics-template" "otg") + ("application/vnd.oasis.opendocument.image" "odi") + ("application/vnd.oasis.opendocument.presentation" "odp") + ("application/vnd.oasis.opendocument.presentation-template" "otp") + ("application/vnd.oasis.opendocument.spreadsheet" "ods") + ("application/vnd.oasis.opendocument.spreadsheet-template" "ots") + ("application/vnd.oasis.opendocument.text" "odt") + ("application/vnd.oasis.opendocument.text-master" "odm") + ("application/vnd.oasis.opendocument.text-template" "ott") + ("application/vnd.oasis.opendocument.text-web" "oth") + ("application/vnd.rim.cod" "cod") + ("application/vnd.smaf" "mmf") + ("application/vnd.stardivision.calc" "sdc") + ("application/vnd.stardivision.draw" "sda") + ("application/vnd.stardivision.impress" "sdd" "sdp") + ("application/vnd.stardivision.math" "smf") + ("application/vnd.stardivision.writer" "sdw" "vor") + ("application/vnd.stardivision.writer-global" "sgl") + ("application/vnd.sun.xml.calc" "sxc") + ("application/vnd.sun.xml.calc.template" "stc") + ("application/vnd.sun.xml.draw" "sxd") + ("application/vnd.sun.xml.draw.template" "std") + ("application/vnd.sun.xml.impress" "sxi") + ("application/vnd.sun.xml.impress.template" "sti") + ("application/vnd.sun.xml.math" "sxm") + ("application/vnd.sun.xml.writer" "sxw") + ("application/vnd.sun.xml.writer.global" "sxg") + ("application/vnd.sun.xml.writer.template" "stw") + ("application/vnd.symbian.install" "sis") + ("application/vnd.visio" "vsd") + ("application/vnd.wap.wbxml" "wbxml") + ("application/vnd.wap.wmlc" "wmlc") + ("application/vnd.wap.wmlscriptc" "wmlsc") + ("application/x-123" "wk") + ("application/x-abiword" "abw") + ("application/x-apple-diskimage" "dmg") + ("application/x-bcpio" "bcpio") + ("application/x-bittorrent" "torrent") + ("application/x-cdf" "cdf") + ("application/x-cdlink" "vcd") + ("application/x-chess-pgn" "pgn") + ("application/x-cpio" "cpio") + ("application/x-csh" "csh") + ("application/x-debian-package" "deb" "udeb") + ("application/x-director" "dcr" "dir" "dxr") + ("application/x-dms" "dms") + ("application/x-doom" "wad") + ("application/x-dvi" "dvi") + ("application/x-flac" "flac") + ("application/x-font" "pfa" "pfb" "gsf" "pcf") + ("application/x-freemind" "mm") + ("application/x-futuresplash" "spl") + ("application/x-gnumeric" "gnumeric") + ("application/x-go-sgf" "sgf") + ("application/x-graphing-calculator" "gcf") + ("application/x-gtar" "gtar" "tgz" "taz") + ("application/x-hdf" "hdf") + ("application/x-httpd-php" "phtml" "pht" "php") + ("application/x-httpd-php-source" "phps") + ("application/x-httpd-php3" "php3") + ("application/x-httpd-php3-preprocessed" "php3p") + ("application/x-httpd-php4" "php4") + ("application/x-ica" "ica") + ("application/x-internet-signup" "ins" "isp") + ("application/x-iphone" "iii") + ("application/x-iso9660-image" "iso") + ("application/x-java-jnlp-file" "jnlp") + ("application/x-javascript" "js") + ("application/x-jmol" "jmz") + ("application/x-kchart" "chrt") + ("application/x-killustrator" "kil") + ("application/x-koan" "skp" "skd" "skt" "skm") + ("application/x-kpresenter" "kpr" "kpt") + ("application/x-kspread" "ksp") + ("application/x-kword" "kwd" "kwt") + ("application/x-latex" "latex") + ("application/x-lha" "lha") + ("application/x-lzh" "lzh") + ("application/x-lzx" "lzx") + ("application/x-maker" "frm" "maker" "frame" "fm" "fb" "book" "fbdoc") + ("application/x-mif" "mif") + ("application/x-ms-wmd" "wmd") + ("application/x-ms-wmz" "wmz") + ("application/x-msdos-program" "com" "exe" "bat" "dll") + ("application/x-msi" "msi") + ("application/x-netcdf" "nc") + ("application/x-ns-proxy-autoconfig" "pac") + ("application/x-nwc" "nwc") + ("application/x-object" "o") + ("application/x-oz-application" "oza") + ("application/x-pkcs7-certreqresp" "p7r") + ("application/x-pkcs7-crl" "crl") + ("application/x-python-code" "pyc" "pyo") + ("application/x-quicktimeplayer" "qtl") + ("application/x-redhat-package-manager" "rpm") + ("application/x-sh" "sh") + ("application/x-shar" "shar") + ("application/x-shockwave-flash" "swf" "swfl") + ("application/x-stuffit" "sit") + ("application/x-sv4cpio" "sv4cpio") + ("application/x-sv4crc" "sv4crc") + ("application/x-tar" "tar") + ("application/x-tcl" "tcl") + ("application/x-tex-gf" "gf") + ("application/x-tex-pk" "pk") + ("application/x-texinfo" "texinfo" "texi") + ("application/x-trash" "~%" "" "bak" "old" "sik") + ("application/x-troff" "tt" "r" "roff") + ("application/x-troff-man" "man") + ("application/x-troff-me" "me") + ("application/x-troff-ms" "ms") + ("application/x-ustar" "ustar") + ("application/x-wais-source" "src") + ("application/x-wingz" "wz") + ("application/x-x509-ca-cert" "crt") + ("application/x-xcf" "xcf") + ("application/x-xfig" "fig") + ("application/x-xpinstall" "xpi") + ("audio/basic" "au" "snd") + ("audio/midi" "mid" "midi" "kar") + ("audio/mpeg" "mpga" "mpega" "mp2" "mp3" "m4a") + ("audio/mpegurl" "m3u") + ("audio/prs.sid" "sid") + ("audio/x-aiff" "aif" "aiff" "aifc") + ("audio/x-gsm" "gsm") + ("audio/x-mpegurl" "m3u") + ("audio/x-ms-wma" "wma") + ("audio/x-ms-wax" "wax") + ("audio/x-pn-realaudio" "ra" "rm" "ram") + ("audio/x-realaudio" "ra") + ("audio/x-scpls" "pls") + ("audio/x-sd2" "sd2") + ("audio/x-wav" "wav") + ("chemical/x-alchemy" "alc") + ("chemical/x-cache" "cac" "cache") + ("chemical/x-cache-csf" "csf") + ("chemical/x-cactvs-binary" "cbin" "cascii" "ctab") + ("chemical/x-cdx" "cdx") + ("chemical/x-cerius" "cer") + ("chemical/x-chem3d" "c3d") + ("chemical/x-chemdraw" "chm") + ("chemical/x-cif" "cif") + ("chemical/x-cmdf" "cmdf") + ("chemical/x-cml" "cml") + ("chemical/x-compass" "cpa") + ("chemical/x-crossfire" "bsd") + ("chemical/x-csml" "csml" "csm") + ("chemical/x-ctx" "ctx") + ("chemical/x-cxf" "cxf" "cef") + ("chemical/x-embl-dl-nucleotide" "emb" "embl") + ("chemical/x-galactic-spc" "spc") + ("chemical/x-gamess-input" "inp" "gam" "gamin") + ("chemical/x-gaussian-checkpoint" "fch" "fchk") + ("chemical/x-gaussian-cube" "cub") + ("chemical/x-gaussian-input" "gau" "gjc" "gjf") + ("chemical/x-gaussian-log" "gal") + ("chemical/x-gcg8-sequence" "gcg") + ("chemical/x-genbank" "gen") + ("chemical/x-hin" "hin") + ("chemical/x-isostar" "istr" "ist") + ("chemical/x-jcamp-dx" "jdx" "dx") + ("chemical/x-kinemage" "kin") + ("chemical/x-macmolecule" "mcm") + ("chemical/x-macromodel-input" "mmd" "mmod") + ("chemical/x-mdl-molfile" "mol") + ("chemical/x-mdl-rdfile" "rd") + ("chemical/x-mdl-rxnfile" "rxn") + ("chemical/x-mdl-sdfile" "sd" "sdf") + ("chemical/x-mdl-tgf" "tgf") + ("chemical/x-mmcif" "mcif") + ("chemical/x-mol2" "mol2") + ("chemical/x-molconn-Z" "b") + ("chemical/x-mopac-graph" "gpt") + ("chemical/x-mopac-input" "mop" "mopcrt" "mpc" "dat" "zmt") + ("chemical/x-mopac-out" "moo") + ("chemical/x-mopac-vib" "mvb") + ("chemical/x-ncbi-asn1" "asn") + ("chemical/x-ncbi-asn1-ascii" "prt" "ent") + ("chemical/x-ncbi-asn1-binary" "val" "aso") + ("chemical/x-ncbi-asn1-spec" "asn") + ("chemical/x-pdb" "pdb" "ent") + ("chemical/x-rosdal" "ros") + ("chemical/x-swissprot" "sw") + ("chemical/x-vamas-iso14976" "vms") + ("chemical/x-vmd" "vmd") + ("chemical/x-xtel" "xtel") + ("chemical/x-xyz" "xyz") + ("image/gif" "gif") + ("image/ief" "ief") + ("image/jpeg" "jpeg" "jpg" "jpe") + ("image/pcx" "pcx") + ("image/png" "png") + ("image/svg+xml" "svg" "svgz") + ("image/tiff" "tiff" "tif") + ("image/vnd.djvu" "djvu" "djv") + ("image/vnd.wap.wbmp" "wbmp") + ("image/x-cmu-raster" "ras") + ("image/x-coreldraw" "cdr") + ("image/x-coreldrawpattern" "pat") + ("image/x-coreldrawtemplate" "cdt") + ("image/x-corelphotopaint" "cpt") + ("image/x-icon" "ico") + ("image/x-jg" "art") + ("image/x-jng" "jng") + ("image/x-ms-bmp" "bmp") + ("image/x-photoshop" "psd") + ("image/x-portable-anymap" "pnm") + ("image/x-portable-bitmap" "pbm") + ("image/x-portable-graymap" "pgm") + ("image/x-portable-pixmap" "ppm") + ("image/x-rgb" "rgb") + ("image/x-xbitmap" "xbm") + ("image/x-xpixmap" "xpm") + ("image/x-xwindowdump" "xwd") + ("model/iges" "igs" "iges") + ("model/mesh" "msh" "mesh" "silo") + ("model/vrml" "wrl" "vrml") + ("text/calendar" "ics" "icz") + ("text/comma-separated-values" "csv") + ("text/css" "css") + ("text/h323" "323") + ("text/html" "html" "htm" "shtml") + ("text/iuls" "uls") + ("text/mathml" "mml") + ("text/plain" "asc" "txt" "text" "diff" "pot") + ("text/richtext" "rtx") + ("text/rtf" "rtf") + ("text/scriptlet" "sct" "wsc") + ("text/texmacs" "tm" "ts") + ("text/tab-separated-values" "tsv") + ("text/vnd.sun.j2me.app-descriptor" "jad") + ("text/vnd.wap.wml" "wml") + ("text/vnd.wap.wmlscript" "wmls") + ("text/x-bibtex" "bib") + ("text/x-boo" "boo") + ("text/x-c++hdr" "h++" "hpp" "hxx" "hh") + ("text/x-c++src" "c++" "cpp" "cxx" "cc") + ("text/x-chdr" "h") + ("text/x-component" "htc") + ("text/x-csh" "csh") + ("text/x-csrc" "c") + ("text/x-dsrc" "d") + ("text/x-haskell" "hs") + ("text/x-java" "java") + ("text/x-literate-haskell" "lhs") + ("text/x-moc" "moc") + ("text/x-pascal" "pp" "as") + ("text/x-pcs-gcd" "gcd") + ("text/x-perl" "pl" "pm") + ("text/x-python" "py") + ("text/x-setext" "etx") + ("text/x-sh" "sh") + ("text/x-tcl" "tcl" "tk") + ("text/x-tex" "tex" "ltx" "sty" "cls") + ("text/x-vcalendar" "vcs") + ("text/x-vcard" "vcf") + ("video/dl" "dl") + ("video/dv" "dif" "dv") + ("video/fli" "fli") + ("video/gl" "gl") + ("video/mpeg" "mpeg" "mpg" "mpe") + ("video/mp4" "mp4") + ("video/quicktime" "qt" "mov") + ("video/vnd.mpegurl" "mxu") + ("video/x-la-asf" "lsf" "lsx") + ("video/x-mng" "mng") + ("video/x-ms-asf" "asf" "asx") + ("video/x-ms-wm" "wm") + ("video/x-ms-wmv" "wmv") + ("video/x-ms-wmx" "wmx") + ("video/x-ms-wvx" "wvx") + ("video/x-msvideo" "avi") + ("video/x-sgi-movie" "movie") + ("x-conference/x-cooltalk" "ice") + ("x-world/x-vrml" "vrm" "vrml" "wrl")) + "An alist where the cars are MIME types and the cdrs are list +of file suffixes for the corresponding type.") + +(defparameter *mime-type-hash* + (let ((hash (make-hash-table :test #'equalp))) + (loop for (type . suffixes) in *mime-type-list* do + (loop for suffix in suffixes do + (setf (gethash suffix hash) type))) + hash) + "A hash table which maps file suffixes to MIME types.") + +(defun mime-type (pathspec) + "Given a pathname designator PATHSPEC returns the MIME type +(as a string) corresponding to the suffix of the file denoted by +PATHSPEC (or NIL)." + (gethash (pathname-type pathspec) *mime-type-hash*)) \ No newline at end of file
Added: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/misc.lisp =================================================================== --- branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/misc.lisp 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/misc.lisp 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,269 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: HUNCHENTOOT; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/hunchentoot/misc.lisp,v 1.11 2007/09/26 06:37:16 edi Exp $ + +;;; Copyright (c) 2004-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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-package :hunchentoot) + +(let ((scanner-hash (make-hash-table :test #'equal))) + (defun scanner-for-get-param (param-name) + "Returns a CL-PPCRE scanner which matches a GET parameter in a +URL. Scanners are memoized in SCANNER-HASH once they are created." + (or (gethash param-name scanner-hash) + (setf (gethash param-name scanner-hash) + (create-scanner + `(:alternation + ;; session=value at end of URL + (:sequence + (:char-class #? #&) + ,param-name + #= + (:greedy-repetition 0 nil (:inverted-char-class #&)) + :end-anchor) + ;; session=value with other parameters following + (:sequence + (:register (:char-class #? #&)) + ,param-name + #= + (:greedy-repetition 0 nil (:inverted-char-class #&)) + #&)))))) + (defun add-cookie-value-to-url (url &key (cookie-name *session-cookie-name*) + (value (session-cookie-value)) + (replace-ampersands-p t)) + "Removes all GET parameters named COOKIE-NAME from URL and then +adds a new GET parameter with the name COOKIE-NAME and the value +VALUE. If REPLACE-AMPERSANDS-P is true all literal ampersands in URL +are replaced with '&'. The resulting URL is returned." + (unless url + ;; see URL-REWRITE:*URL-REWRITE-FILL-TAGS* + (setq url (request-uri *request*))) + (setq url (regex-replace-all (scanner-for-get-param cookie-name) url "\1")) + (when value + (setq url (format nil "~A~:[?~;&~]~A=~A" + url + (find #? url) + cookie-name + (url-encode value)))) + (when replace-ampersands-p + (setq url (regex-replace-all "&" url "&"))) + url)) + +(defun maybe-rewrite-urls-for-session (html &key (cookie-name *session-cookie-name*) + (value (session-cookie-value))) + "Rewrites the HTML page HTML such that the name/value pair +COOKIE-NAME/COOKIE-VALUE is inserted if the client hasn't sent a +cookie of the same name but only if *REWRITE-FOR-SESSION-URLS* is +true. See the docs for URL-REWRITE:REWRITE-URLS." + (cond ((or (not *rewrite-for-session-urls*) + (null value) + (cookie-in cookie-name)) + html) + (t + (with-input-from-string (*standard-input* html) + (with-output-to-string (*standard-output*) + (url-rewrite:rewrite-urls + (lambda (url) + (add-cookie-value-to-url url + :cookie-name cookie-name + :value value)))))))) + +(defmethod dispatch-request (dispatch-table) + "Dispatches *REQUEST* based upon rules in the DISPATCH-TABLE. +This method provides the default Hunchentoot behavior." + (loop for dispatcher in dispatch-table + for action = (funcall dispatcher *request*) + when action return (funcall action) + finally (setf (return-code *reply*) +http-not-found+))) + +(defun default-dispatcher (request) + "Default dispatch function which handles every request with the +function stored in *DEFAULT-HANDLER*." + (declare (ignore request)) + *default-handler*) + +(defun default-handler () + "The handler that is supposed to serve the request if no other +handler is called." + (log-message :info "Default handler called for script ~A" (script-name)) + (format nil "<html><head><title>Hunchentoot</title></head><body><h2>Hunchentoot Default Page</h2><p>This the Hunchentoot default page. You're most likely seeing it because the server administrator hasn't set up a custom default page yet.</p><p>Hunchentoot is a web server written in <a href='http://www.lisp.org/'>Common Lisp</a>. More info about Hunchentoot can be found at <a href='http://weitz.de/hunchentoot/'>http://weitz.de/hunchentoot/</a>.</p></p><p><hr>~A</p></body></html>" + (address-string))) + +(defun create-prefix-dispatcher (prefix page-function) + "Creates a dispatch function which will dispatch to the +function denoted by PAGE-FUNCTION if the file name of the current +request starts with the string PREFIX." + (lambda (request) + (let ((mismatch (mismatch (script-name request) prefix + :test #'char=))) + (and (or (null mismatch) + (>= mismatch (length prefix))) + page-function)))) + +(defun create-regex-dispatcher (regex page-function) + "Creates a dispatch function which will dispatch to the +function denoted by PAGE-FUNCTION if the file name of the current +request matches the CL-PPCRE regular expression REGEX." + (let ((scanner (create-scanner regex))) + (lambda (request) + (and (scan scanner (script-name request)) + page-function)))) + +(defun handle-static-file (path &optional content-type) + "A function which acts like a Hunchentoot handler for the file +denoted by PATH. Send a content type header corresponding to +CONTENT-TYPE or (if that is NIL) tries to determine the content +type via the file's suffix." + (unless (or (pathname-name path) + (pathname-type path)) + ;; not a file + (setf (return-code) +http-bad-request+) + (throw 'handler-done nil)) + (unless (probe-file path) + ;; does not exist + (setf (return-code) +http-not-found+) + (throw 'handler-done nil)) + (let ((time (or (file-write-date path) (get-universal-time)))) + (setf (content-type) (or content-type + (mime-type path) + "application/octet-stream")) + (handle-if-modified-since time) + (with-open-file (file path + :direction :input + :element-type '(unsigned-byte 8) + :if-does-not-exist nil) + (setf (header-out "Last-Modified") (rfc-1123-date time) + (content-length) (file-length file)) + (let ((out (send-headers))) + (loop with buf = (make-array +buffer-length+ :element-type '(unsigned-byte 8)) + for pos = (read-sequence buf file) + until (zerop pos) + do (write-sequence buf out :end pos) + (finish-output out)))))) + +(defun create-static-file-dispatcher-and-handler (uri path &optional content-type) + "Creates and returns a dispatch function which will dispatch to a +handler function which emits the file denoted by the pathname +designator PATH with content type CONTENT-TYPE if the SCRIPT-NAME of +the request matches the string URI. If CONTENT-TYPE is NIL tries to +determine the content type via the file's suffix." + ;; the dispatcher + (lambda (request) + (when (equal (script-name request) uri) + ;; the handler + (lambda () + (handle-static-file path content-type))))) + +(defun create-folder-dispatcher-and-handler (uri-prefix base-path &optional content-type) + "Creates and returns a dispatch function which will dispatch to a +handler function which emits the file relative to BASE-PATH that is +denoted by the URI of the request relative to URI-PREFIX. URI-PREFIX +must be a string ending with a slash, BASE-PATH must be a pathname +designator for an existing directory. If CONTENT-TYPE is not NIL, +it'll be the content type used for all files in the folder." + (unless (and (stringp uri-prefix) + (plusp (length uri-prefix)) + (char= (char uri-prefix (1- (length uri-prefix))) #/)) + (error "~S must be string ending with a slash." uri-prefix)) + (when (or (pathname-name base-path) + (pathname-type base-path)) + (error "~S is supposed to denote a directory." base-path)) + (flet ((handler () + (let* ((script-name (url-decode (script-name))) + (script-path (enough-namestring (regex-replace-all "\\" script-name "/") + uri-prefix)) + (script-path-directory (pathname-directory script-path))) + (unless (or (stringp script-path-directory) + (null script-path-directory) + (and (listp script-path-directory) + (eq (first script-path-directory) :relative) + (loop for component in (rest script-path-directory) + always (stringp component)))) + (setf (return-code) +http-forbidden+) + (throw 'handler-done nil)) + (handle-static-file (merge-pathnames script-path base-path) content-type)))) + (create-prefix-dispatcher uri-prefix #'handler))) + +(defun no-cache () + "Adds appropriate headers to completely prevent caching on most browsers." + (setf (header-out "Expires") + "Mon, 26 Jul 1997 05:00:00 GMT" + (header-out "Cache-Control") + "no-store, no-cache, must-revalidate, post-check=0, pre-check=0" + (header-out "Pragma") + "no-cache" + (header-out "Last-Modified") + (rfc-1123-date)) + (values)) + +(defun ssl-p () + "Whether the current connection to the client is secure." + (cond ((server-mod-lisp-p *server*) (ssl-session-id *request*)) + (t #-:hunchentoot-no-ssl (server-ssl-certificate-file *server*) + #+:hunchentoot-no-ssl nil))) + +(defun redirect (target &key (host (host *request*) host-provided-p) + port + (protocol (if (ssl-p) :https :http)) + (add-session-id (not (or host-provided-p + (starts-with-scheme-p target) + (cookie-in *session-cookie-name*)))) + permanently) + "Redirects the browser to TARGET which should be a string. If +TARGET is a full URL starting with a scheme, HOST, PORT and PROTOCOL +are ignored. Otherwise, TARGET should denote the path part of a URL, +PROTOCOL must be one of the keywords :HTTP or :HTTPS, and the URL to +redirect to will be constructed from HOST, PORT, PROTOCOL, and TARGET. +Adds a session ID if ADD-SESSION-ID is true. If PERMANENTLY is true, +a 301 request is sent to the browser, otherwise a 302." + (let ((url (if (starts-with-scheme-p target) + target + (format nil "~A://~A~@[:~A~]~A" + (ecase protocol + ((:http) "http") + ((:https) "https")) + (if port + (first (ppcre:split ":" (or host ""))) + host) + port target)))) + (when add-session-id + (setq url (add-cookie-value-to-url url :replace-ampersands-p nil))) + (setf (header-out :location) + url + (return-code *reply*) + (if permanently + +http-moved-permanently+ + +http-moved-temporarily+)) + (throw 'handler-done nil))) + +(defun require-authorization (&optional (realm "Hunchentoot")) + "Sends back appropriate headers to require basic HTTP authentication +(see RFC 2617) for the realm REALM." + (setf (header-out "WWW-Authenticate") + (format nil "Basic realm="~A"" (quote-string realm)) + (return-code *reply*) + +http-authorization-required+) + (throw 'handler-done nil))
Property changes on: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/misc.lisp ___________________________________________________________________ Name: svn:executable + *
Added: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/packages.lisp =================================================================== --- branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/packages.lisp 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/packages.lisp 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,228 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-USER; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/hunchentoot/packages.lisp,v 1.33 2007/09/18 14:23:23 edi Exp $ + +;;; Copyright (c) 2004-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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-package :cl-user) + +(defpackage :hunchentoot-mp + (:nicknames :tbnl-mp) + (:use :cl) + (:export :*current-process* + :make-lock + :with-lock + :process-run-function + :process-kill)) + +(defpackage :hunchentoot + (:nicknames :tbnl) + (:use :cl :cl-ppcre :chunga :flexi-streams :url-rewrite :hunchentoot-mp) + (:shadow :assoc + #+:sbcl :defconstant + :handler-case + :ignore-errors + :url-encode) + ;; see ASDF system definition + (:import-from :hunchentoot-asd :*hunchentoot-version*) + #+:lispworks + (:import-from :lw :with-unique-names :when-let) + (:export :*approved-return-codes* + :*catch-errors-p* + :*cleanup-function* + :*cleanup-interval* + :*content-types-for-url-rewrite* + :*default-content-type* + :*default-handler* + :*default-log-level* + :*default-read-timeout* + :*default-write-timeout* + :*dispatch-table* + :*file-upload-hook* + :*handle-http-errors-p* + :*header-stream* + :*http-error-handler* + :*hunchentoot-default-external-format* + :*lisp-errors-log-level* + :*lisp-warnings-log-level* + :*listener* + :*log-lisp-backtraces-p* + :*log-lisp-errors-p* + :*log-lisp-warnings-p* + :*log-prefix* + :*meta-dispatcher* + :*methods-for-post-parameters* + :*reply* + :*request* + :*rewrite-for-session-urls* + :*server* + :*session* + :*session-cookie-name* + :*session-gc-frequency* + :*session-max-time* + :*session-removal-hook* + :*show-access-log-messages* + :*show-lisp-backtraces-p* + :*show-lisp-errors-p* + :*tmp-directory* + :*use-remote-addr-for-sessions* + :*use-user-agent-for-sessions* + :+http-accepted+ + :+http-authorization-required+ + :+http-bad-gateway+ + :+http-bad-request+ + :+http-conflict+ + :+http-continue+ + :+http-created+ + :+http-expectation-failed+ + :+http-failed-dependency+ + :+http-forbidden+ + :+http-gateway-time-out+ + :+http-gone+ + :+http-internal-server-error+ + :+http-length-required+ + :+http-method-not-allowed+ + :+http-moved-permanently+ + :+http-moved-temporarily+ + :+http-multiple-choices+ + :+http-multi-status+ + :+http-no-content+ + :+http-non-authoritative-information+ + :+http-not-acceptable+ + :+http-not-found+ + :+http-not-implemented+ + :+http-not-modified+ + :+http-ok+ + :+http-partial-content+ + :+http-payment-required+ + :+http-precondition-failed+ + :+http-proxy-authentication-required+ + :+http-request-entity-too-large+ + :+http-request-time-out+ + :+http-request-uri-too-large+ + :+http-requested-range-not-satisfiable+ + :+http-reset-content+ + :+http-see-other+ + :+http-service-unavailable+ + :+http-switching-protocols+ + :+http-temporary-redirect+ + :+http-unsupported-media-type+ + :+http-use-proxy+ + :+http-version-not-supported+ + :authorization + :aux-request-value + :content-length + :content-type + :cookie-domain + :cookie-expires + :cookie-http-only + :cookie-in + :cookie-name + :cookie-out + :cookie-path + :cookie-secure + :cookie-value + :cookies-in + :cookies-out + :create-folder-dispatcher-and-handler + :create-prefix-dispatcher + :create-regex-dispatcher + :create-static-file-dispatcher-and-handler + :default-dispatcher + :define-easy-handler + :delete-aux-request-value + :delete-session-value + :dispatch-easy-handlers + :dispatch-request + :do-sessions + :escape-for-html + :get-backtrace + :get-parameter + :get-parameters + :handle-if-modified-since + :handle-static-file + :handler-done + :header-in + :header-out + :headers-in + :headers-out + :host + :http-token-p + :log-file + :log-message + :log-message* + :maybe-invoke-debugger + :mime-type + :mod-lisp-id + :no-cache + :parameter + :post-parameter + :post-parameters + :query-string + :raw-post-data + :real-remote-addr + :reason-phrase + :recompute-request-parameters + :redirect + :referer + :remote-addr + :remote-port + :remove-session + :reply-external-format + :request-method + :request-uri + :require-authorization + :reset-sessions + :return-code + :rfc-1123-date + :script-name + :send-headers + :server-addr + :server-address + :server-dispatch-table + :server-local-port + :server-name + :server-port + :server-protocol + :session-counter + :session-gc + :session-max-time + :session-too-old-p + :session-remote-addr + :session-cookie-value + :session-user-agent + :session-value + :set-cookie + :set-cookie* + :ssl-p + :ssl-session-id + :start-server + :start-session + :stop-server + :url-decode + :url-encode + :user-agent)) +
Property changes on: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/packages.lisp ___________________________________________________________________ Name: svn:executable + *
Added: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/port-acl.lisp =================================================================== --- branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/port-acl.lisp 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/port-acl.lisp 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,145 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: HUNCHENTOOT; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/hunchentoot/port-acl.lisp,v 1.10 2007/11/03 21:46:18 edi Exp $ + +;;; Copyright (c) 2004-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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-package :hunchentoot) + +(eval-when (:compile-toplevel :load-toplevel :execute) + #-(and :allegro-version>= (version>= 7 0)) + (error "You need at least version 7.0 of AllegroCL.") + ;; make sure code for sockets and OS interface is loaded + (require :sock) + (require :osi)) + +(defun make-lock (name) + "See AllegroCL documentation for MP:MAKE-PROCESS-LOCK." + (mp:make-process-lock :name name)) + +(defmacro with-lock ((lock) &body body) + "See AllegroCL documentation for MP:WITH-PROCESS-LOCK." + `(mp:with-process-lock (,lock) ,@body)) + +(defmacro atomic-incf (place &optional (delta 1)) + "Like INCF but wrapped with SYS:WITHOUT-SCHEDULING so other +threads can't interfer." + `(sys:without-scheduling (incf ,place ,delta))) + +(defmacro with-timeout ((seconds &body timeout-forms) &body body) + "See AllegroCL documentation for SYS:WITH-TIMEOUT." + `(sys:with-timeout (,seconds ,@timeout-forms) ,@body)) + +(defun process-run-function (name function &rest args) + "See AllegroCL documentation for MP:PROCESS-RUN-FUNCTION." + (apply #'mp:process-run-function name function args)) + +(defun process-kill (process) + "See AllegroCL documentation for MP:PROCESS-KILL." + (mp:process-kill process)) + +(define-symbol-macro *current-process* + mp:*current-process*) + +(defun process-allow-scheduling () + "See AllegroCL documentation for MP:PROCESS-ALLOW-SCHEDULE." + (mp:process-allow-schedule)) + +(defun start-up-server (&key service address process-name announce function &allow-other-keys) + "Tries to (partly) emulate LispWorks' COMM:START-UP-SERVER. See +http://www.lispworks.com/documentation/lw50/LWRM/html/lwref-56.htm +for more info." + (let (done) + (flet ((open-socket-and-accept () + (handler-bind ((error (lambda (condition) + (funcall announce nil condition) + (setq done condition) + (return-from open-socket-and-accept)))) + (let (socket) + (unwind-protect + (progn + (setf socket (socket:make-socket :address-family :internet + :type :hiper + :format :bivalent + :connect :passive + :local-host address + :local-port service + :reuse-address t + :backlog 5)) + (funcall announce socket) + (setq done socket) + (loop (funcall function (socket:accept-connection socket :wait t)))) + (when socket + (cl:ignore-errors (close socket)))))))) + (let ((listener-thread (process-run-function process-name #'open-socket-and-accept))) + (mp:process-wait "Waiting for server to start" (lambda () done)) + (typecase done + (socket:socket listener-thread) + (t (values nil done))))))) + +(defun make-socket-stream (socket read-timeout write-timeout) + "Accepts a socket `handle' SOCKET and creates and returns a +corresponding stream, setting its read and write timeout if +applicable. Returns three other values - the address the request +arrived at, and the address and port of the remote host." + ;; in the case of AllegroCL, SOCKET:ACCEPT-CONNECTION already + ;; returned a stream + (socket:set-socket-options socket :nodelay t) + (socket:socket-control socket + :read-timeout read-timeout + :write-timeout write-timeout) + (values socket + (ignore-errors + (socket:ipaddr-to-dotted (socket:local-host socket))) + (ignore-errors + (socket:ipaddr-to-dotted (socket:remote-host socket))) + (ignore-errors + (socket:remote-port socket)))) + +(defun get-backtrace (error) + "This is the function that is used internally by Hunchentoot to +show or log backtraces. It accepts a condition object ERROR and +returns a string with the corresponding backtrace." + (with-output-to-string (s) + (with-standard-io-syntax + (let ((*print-readably* nil) + (*print-miser-width* 40) + (*print-pretty* t) + (tpl:*zoom-print-circle* t) + (tpl:*zoom-print-level* nil) + (tpl:*zoom-print-length* nil)) + (cl:ignore-errors + (format *terminal-io* "~ +~@<An unhandled error condition has been signalled:~3I ~a~I~:@>~%~%" + error)) + (cl:ignore-errors + (let ((*terminal-io* s) + (*standard-output* s)) + (tpl:do-command "zoom" + :from-read-eval-print-loop nil + :count t + :all t))))))) +
Added: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/port-cmu.lisp =================================================================== --- branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/port-cmu.lisp 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/port-cmu.lisp 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,137 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: HUNCHENTOOT; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/hunchentoot/port-cmu.lisp,v 1.9 2007/01/01 23:50:30 edi Exp $ + +;;; Copyright (c) 2004-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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-package :hunchentoot) + +#-:mp +(eval-when (:compile-toplevel :load-toplevel :execute) + (error "This library needs a version of CMUCL with MP support.")) + +(defun make-lock (name) + "See CMUCL documentation for MP:MAKE-LOCK." + (mp:make-lock name)) + +(defmacro with-lock ((lock) &body body) + "See CMUCL documentation for MP:WITH-LOCK-HELD." + `(mp:with-lock-held (,lock) ,@body)) + +(defmacro atomic-incf (place &optional (delta 1)) + "Like INCF but wrapped with MP:WITHOUT-SCHEDULING so other +threads can't interfer." + `(mp:without-scheduling (incf ,place ,delta))) + +(defmacro with-timeout ((seconds &body timeout-forms) &body body) + "See CMUCL documentation for MP:WITH-TIMEOUT." + `(mp:with-timeout (,seconds ,@timeout-forms) ,@body)) + +(defun process-run-function (name function &rest args) + "See CMUCL documentation for MP:MAKE-PROCESS." + (mp:make-process (lambda () + (apply function args)) + :name name)) + +(defun process-kill (process) + "See CMUCL documentation for MP:DESTROY-PROCESS." + (mp:destroy-process process)) + +(define-symbol-macro *current-process* + mp:*current-process*) + +(defun process-allow-scheduling () + "See CMUCL documentation for MP:PROCESS-YIELD." + (mp:process-yield)) + +(defun start-up-server (&key service address process-name announce function &allow-other-keys) + "Tries to (partly) emulate LispWorks' COMM:START-UP-SERVER. See +http://www.lispworks.com/documentation/lw50/LWRM/html/lwref-56.htm +for more info." + (let (done) + (flet ((open-socket-and-accept () + (handler-bind ((error (lambda (condition) + (funcall announce nil condition) + (setq done condition) + (return-from open-socket-and-accept)))) + (let (socket) + (unwind-protect + (progn + (setf socket (ext:create-inet-listener service :stream + :reuse-address t + :backlog 5 + :host (or address 0))) + (funcall announce socket) + (setq done socket) + (loop (funcall function (ext:accept-tcp-connection socket)))) + (when socket + (cl:ignore-errors + (ext:close-socket socket)))))))) + (let ((listener-thread (process-run-function process-name #'open-socket-and-accept))) + (mp:process-wait "Waiting for server to start" (lambda () done)) + (typecase done + (condition (values nil done)) + (t listener-thread)))))) + +(defun format-address (address) + "Converts an integer in network byte order denoting an IP +address into the corresponding string representation." + (format nil "~A.~A.~A.~A" + (ash address -24) + (logand (ash address -16) #xFF) + (logand (ash address -8) #xFF) + (logand address #xFF))) + +(defun make-socket-stream (handle read-timeout write-timeout) + "Accepts a socket `handle' HANDLE and creates and returns a +corresponding stream, setting its read and write timeout if +applicable. Returns three other values - the address the request +arrived at, and the address and port of the remote host." + (declare (ignore write-timeout)) + (let ((local-host (ext:get-socket-host-and-port handle))) + (multiple-value-bind (remote-host remote-port) + (ext:get-peer-host-and-port handle) + (values (sys:make-fd-stream handle + :input t :output t + :element-type '(unsigned-byte 8) + :auto-close t + :buffering :full + :timeout read-timeout + :name (format nil "~A:~A" (format-address remote-host) remote-port)) + (format-address local-host) + (format-address remote-host) + remote-port)))) + +(defun get-backtrace (error) + "This is the function that is used internally by Hunchentoot to +show or log backtraces. It accepts a condition object ERROR and +returns a string with the corresponding backtrace." + (declare (ignore error)) + (with-output-to-string (s) + (let ((debug:*debug-print-level* nil) + (debug:*debug-print-length* nil)) + (debug:backtrace most-positive-fixnum s)))) +
Added: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/port-lw.lisp =================================================================== --- branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/port-lw.lisp 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/port-lw.lisp 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,173 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: HUNCHENTOOT; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/hunchentoot/port-lw.lisp,v 1.10 2007/11/03 21:46:18 edi Exp $ + +;;; Copyright (c) 2004-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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-package :hunchentoot) + +#+(and :lispworks4.4 (or :win32 :linux)) +(let ((id :system-cons-free-chain)) + (unless (scm::patch-id-loaded-p id) + (error "You need a patch to improve the performance of this code. Request patch ~S for ~A for ~A from lisp-support@lispworks.com using the Report Bug command." + id (lisp-implementation-type) + #+:win32 "Windows" + #+:linux "Linux"))) + +(eval-when (:compile-toplevel :load-toplevel :execute) + ;; make sure socket code is loaded + (require "comm")) + +(defun make-lock (name) + "See LispWorks documentation for MP:MAKE-LOCK." + (mp:make-lock :name name)) + +(defmacro with-lock ((lock) &body body) + "See LispWorks documentation for MP:WITH-LOCK." + `(mp:with-lock (,lock) ,@body)) + +(defmacro atomic-incf (place &optional (delta 1)) + "Like INCF but wrapped with MP:WITHOUT-PREEMPTION so other +threads can't interfer." + `(mp:without-preemption (incf ,place ,delta))) + +(defun invoke-with-timeout (duration body-fn timeout-fn) + "Executes the function (with no arguments) BODY-FN and returns +its results but stops execution after DURATION seconds and then +instead calls TIMEOUT-FN and returns its values." + ;; from Portable AllegroServe + (block timeout + (let* ((process mp:*current-process*) + (unsheduledp nil) + (timer (mp:make-timer + #'(lambda () + (mp:process-interrupt process + #'(lambda () + (unless unsheduledp + (return-from timeout + (funcall timeout-fn))))))))) + (mp:schedule-timer-relative timer duration) + (unwind-protect + (funcall body-fn) + (mp:without-interrupts + (mp:unschedule-timer timer) + (setf unsheduledp t)))))) + +(defmacro with-timeout ((seconds &body timeout-forms) &body body) + "Executes the code BODY and returns the results of the last +form but stops execution after SECONDS seconds and then instead +executes the code in TIMEOUT-FORMS." + ;; from Portable AllegroServe + `(invoke-with-timeout ,seconds + #'(lambda () + ,@body) + #'(lambda () + ,@timeout-forms))) + +(defun process-run-function (name function &rest args) + "See LispWorks documentation for MP:PROCESS-RUN-FUNCTION." + (apply #'mp:process-run-function name nil function args)) + +(defun process-kill (process) + "See LispWorks documentation for MP:PROCESS-KILL." + (mp:process-kill process)) + +(define-symbol-macro *current-process* + mp:*current-process*) + +(defun process-allow-scheduling () + "See LispWorks documentation for MP:PROCESS-ALLOW-SCHEDULING." + (mp:process-allow-scheduling)) + +(defun start-up-server (&rest args) + "See LispWorks documentation for COMM:START-UP-SERVER." + (apply #'comm:start-up-server args)) + +(defun make-socket-stream (socket read-timeout write-timeout) + "Accepts a socket `handle' SOCKET and creates and returns a +corresponding stream, setting its read and write timeout if +applicable. Returns three other values - the address the request +arrived at, and the address and port of the remote host." + #-:lispworks5.0 (declare (ignore write-timeout)) + (let ((local-host (comm:get-socket-address socket))) + (multiple-value-bind (remote-host remote-port) + (comm:get-socket-peer-address socket) + (values (make-instance 'comm:socket-stream + :socket socket + :direction :io + :read-timeout read-timeout + #+:lispworks5.0 #+:lispworks5.0 + :write-timeout write-timeout + :element-type '(unsigned-byte 8)) + (ignore-errors + (comm:ip-address-string local-host)) + (ignore-errors + (comm:ip-address-string remote-host)) + remote-port)))) + +#-:hunchentoot-no-ssl +(defun make-ssl-server-stream (socket-stream &key certificate-file privatekey-file privatekey-password) + "Given the server socket stream SOCKET-STREAM attaches SSL to the +stream using the certificate file CERTIFICATE-FILE and the private key +file PRIVATEKEY-FILE. Both of these values must be namestrings +denoting the location of the files. If PRIVATEKEY-PASSWORD is not NIL +then it should be the password for the private key file (if +necessary)." + (flet ((ctx-configure-callback (ctx) + (when privatekey-password + (comm:set-ssl-ctx-password-callback ctx :password privatekey-password)) + (comm:ssl-ctx-use-certificate-file ctx + certificate-file + comm:ssl_filetype_pem) + (comm:ssl-ctx-use-privatekey-file ctx + privatekey-file + comm:ssl_filetype_pem))) + (comm:attach-ssl socket-stream + :ctx-configure-callback #'ctx-configure-callback))) + +(defun get-backtrace (error) + "This is the function that is used internally by Hunchentoot to +show or log backtraces. It accepts a condition object ERROR and +returns a string with the corresponding backtrace." + (declare (ignore error)) + (with-output-to-string (s) + (let ((dbg::*debugger-stack* (dbg::grab-stack nil :how-many most-positive-fixnum)) + (*debug-io* s) + (dbg:*debug-print-level* nil) + (dbg:*debug-print-length* nil)) + (dbg:bug-backtrace nil)))) + +;; some help for the IDE +(dspec:define-dspec-alias defvar-unbound (name) + `(defparameter ,name)) + +(dspec:define-dspec-alias def-http-return-code (name) + `(defconstant ,name)) + +(editor:setup-indent "defvar-unbound" 1 2 4) + +(editor:setup-indent "def-http-return-code" 1 2 4) +
Property changes on: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/port-lw.lisp ___________________________________________________________________ Name: svn:executable + *
Added: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/port-mcl.lisp =================================================================== --- branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/port-mcl.lisp 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/port-mcl.lisp 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,136 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: HUNCHENTOOT; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/hunchentoot/port-mcl.lisp,v 1.9 2007/11/03 21:46:19 edi Exp $ + +;;; Copyright (c) 2004-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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-package :hunchentoot) + +(defun make-lock (name) + "See OpenMCL documentation for CCL:MAKE-LOCK." + (ccl:make-lock name)) + +(defmacro with-lock ((lock) &body body) + "See OpenMCL documentation for CCL:WITH-LOCK-GRABBED." + `(ccl:with-lock-grabbed (,lock) ,@body)) + +(defmacro atomic-incf (place &optional (delta 1)) + "Like INCF, but other threads can't interfer." + `(ccl::atomic-incf-decf ,place ,delta)) + +(defun invoke-with-timeout (seconds bodyfn timeoutfn) + "Executes the function (with no arguments) BODY-FN and returns +its results but stops execution after DURATION seconds and then +instead calls TIMEOUT-FN and returns its values." + ;; from Portable AllegroServe + (block timeout + (let* ((timer (ccl::make-timer-request seconds + #'(lambda () + (return-from timeout (funcall timeoutfn)))))) + (ccl::enqueue-timer-request timer) + (unwind-protect (funcall bodyfn) + (ccl::dequeue-timer-request timer))))) + +(defmacro with-timeout ((seconds &body timeout-forms) &body body) + "Executes the code BODY and returns the results of the last +form but stops execution after SECONDS seconds and then instead +executes the code in TIMEOUT-FORMS." + ;; from Portable AllegroServe + `(invoke-with-timeout ,seconds + #'(lambda () ,@body) + #'(lambda () ,@timeout-forms))) + +(defun process-run-function (name function &rest args) + "See OpenMCL documentation for CCL:PROCESS-RUN-FUNCTION." + (apply #'ccl:process-run-function name function args)) + +(defun process-kill (process) + "See OpenMCL documentation for CCL:PROCESS-KILL." + (ccl:process-kill process)) + +(define-symbol-macro *current-process* + ccl:*current-process*) + +(defun process-allow-scheduling () + "See OpenMCL documentation for CCL:PROCESS-ALLOW-SCHEDULE" + (ccl:process-allow-schedule)) + +(defun start-up-server (&key service address process-name announce function &allow-other-keys) + "Tries to (partly) emulate LispWorks' COMM:START-UP-SERVER. See +http://www.lispworks.com/documentation/lw50/LWRM/html/lwref-56.htm +for more info." + (let (done) + (flet ((open-socket-and-accept () + (handler-bind ((error (lambda (condition) + (funcall announce nil condition) + (setq done condition) + (return-from open-socket-and-accept)))) + (let (socket) + (unwind-protect + (progn + (setf socket (ccl:make-socket :address-family :internet + :type :stream + :connect :passive + :local-host address + :local-port service + :reuse-address t + :backlog 5)) + (funcall announce socket) + (setq done socket) + (loop (funcall function (ccl:accept-connection socket :wait t)))) + (when socket + (cl:ignore-errors + (close socket)))))))) + (let ((listener-thread (process-run-function process-name #'open-socket-and-accept))) + (ccl:process-wait "Waiting for server to start" (lambda () done)) + (typecase done + (condition (values nil done)) + (t listener-thread)))))) + +(defun make-socket-stream (socket read-timeout write-timeout) + "Accepts a socket `handle' SOCKET and creates and returns a +corresponding stream, setting its read and write timeout if +applicable. Returns three other values - the address the request +arrived at, and the address and port of the remote host." + (declare (ignore read-timeout write-timeout)) + (values socket + (ignore-errors + (ccl:ipaddr-to-dotted (ccl:local-host socket))) + (ignore-errors + (ccl:ipaddr-to-dotted (ccl:remote-host socket))) + (ignore-errors + (ccl:remote-port socket)))) + +(defun get-backtrace (error) + "This is the function that is used internally by Hunchentoot to +show or log backtraces. It accepts a condition object ERROR and +returns a string with the corresponding backtrace." + (with-output-to-string (s) + (let ((*debug-io* s)) + (format *terminal-io* "~ +~@<An unhandled error condition has been signalled:~3I ~a~I~:@>~%~%" + error) + (ccl:print-call-history :detailed-p nil))))
Added: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/port-sbcl.lisp =================================================================== --- branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/port-sbcl.lisp 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/port-sbcl.lisp 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,205 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: HUNCHENTOOT; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/hunchentoot/port-sbcl.lisp,v 1.12 2007/09/13 08:35:15 edi Exp $ + +;;; Copyright (c) 2004-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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-package :hunchentoot) + +#-:sb-unicode +(eval-when (:compile-toplevel :load-toplevel :execute) + (error "This library needs a version of SBCL with Unicode support.")) + +#-:sb-thread +(eval-when (:compile-toplevel :load-toplevel :execute) + (warn "Without thread support, this library is only useful for development.")) + +(defmacro defconstant (name value &optional doc) + "Make sure VALUE is evaluated only once (to appease SBCL)." + `(cl:defconstant ,name (if (boundp ',name) (symbol-value ',name) ,value) + ,@(when doc (list doc)))) + +(defun make-lock (name) + "See SBCL documentation for SB-THREAD:MAKE-MUTEX." + (sb-thread:make-mutex :name name)) + +(defmacro with-lock ((lock) &body body) + "See SBCL documentation for SB-THREAD:WITH-RECURSIVE-LOCK." + `(sb-thread:with-recursive-lock (,lock) ,@body)) + +(defvar *incf-mutex* (sb-thread:make-mutex :name "incf-mutex") + "The mutex used for ATOMIC-INCF.") + +(defmacro atomic-incf (place &optional (delta 1)) + "Like INCF but protected by a mutex, so other threads can't +interfer." + `(with-lock (*incf-mutex*) (incf ,place ,delta))) + +;; determine whether SB-EXT:WITH-TIMEOUT is supported; we can't just +;; use (FIND-SYMBOL "WITH-TIMEOUT" "SB-EXT") because sometimes (for +;; example in SBCL 1.0.6 for Win32) the function is present, but +;; doesn't work +(eval-when (:compile-toplevel :load-toplevel :execute) + (defun ensured-sleep-millis (milliseconds) + "Sleeps (in fact loops) not less then MILLISECONDS number of +milliseconds; the minimal sleep time is one internal time unit. Don't +use this function for large time values, because it eats processor +power." + (do ((start-time (get-internal-real-time))) + ((< (+ start-time (ceiling (* internal-time-units-per-second + (/ milliseconds 1000)))) + (get-internal-real-time))))) + (cl:handler-case + (sb-ext:with-timeout 0.0000001 (ensured-sleep-millis 5)) + (sb-ext:timeout () + (pushnew :hunchentoot-sbcl-with-timeout *features*)) + (t ()))) + +(defmacro with-timeout ((seconds &body timeout-forms) &body body) + "Executes the code BODY and returns the results of the last +form but stops execution after SECONDS seconds and then instead +executes the code in TIMEOUT-FORMS." + (declare (ignorable seconds timeout-forms body)) + #-:hunchentoot-sbcl-with-timeout `(cl:progn ,@body) + #+:hunchentoot-sbcl-with-timeout + `(cl:handler-case + (sb-ext:with-timeout ,seconds ,@body) + (sb-ext:timeout () ,@timeout-forms))) + +(defun process-run-function (name function &rest args) + "See SBCL documentation for SB-THREAD:MAKE-THREAD." + (declare (ignorable name)) + #+:sb-thread + (sb-thread:make-thread (lambda () + (apply function args)) + :name name) + #-:sb-thread + (apply function args)) + +(defun process-kill (process) + "See SBCL documentation for SB-THREAD:TERMINATE-THREAD." + (sb-thread:terminate-thread process)) + +(define-symbol-macro *current-process* + sb-thread:*current-thread*) + +(defun process-allow-scheduling () + "Used to simulate a function like PROCESS-ALLOW-SCHEDULING +which can be found in most other Lisps." + (sleep .1)) + +(defun resolve-hostname (name) + "Converts from different types to represent an IP address to +the canonical representation which is an array with four +integers." + (typecase name + (null #(0 0 0 0)) + (string (car (sb-bsd-sockets:host-ent-addresses + (sb-bsd-sockets:get-host-by-name name)))) + (integer (make-array 4 :initial-contents (list (ash name -24) + (logand (ash name -16) #xFF) + (logand (ash name -8) #xFF) + (logand name #xFF)))) + (t name))) + +(defun start-up-server (&key service address process-name announce function &allow-other-keys) + "Tries to (partly) emulate LispWorks' COMM:START-UP-SERVER. See +http://www.lispworks.com/documentation/lw50/LWRM/html/lwref-56.htm +for more info." + (let (done) + (flet ((open-socket-and-accept () + (handler-bind ((error (lambda (condition) + (funcall announce nil condition) + (setq done condition) + (return-from open-socket-and-accept)))) + (let (socket) + (unwind-protect + (progn + (setf socket (make-instance 'sb-bsd-sockets:inet-socket + :type :stream + :protocol :tcp) + (sb-bsd-sockets:sockopt-reuse-address socket) t) + (sb-bsd-sockets:socket-bind socket (resolve-hostname address) service) + (sb-bsd-sockets:socket-listen socket 5) + (funcall announce socket) + (setq done socket) + (loop (funcall function (sb-bsd-sockets:socket-accept socket)))) + (when socket + (cl:ignore-errors + (sb-bsd-sockets:socket-close socket)))))))) + (let ((listener-thread (process-run-function process-name #'open-socket-and-accept))) + (loop until done do (sleep .1)) + (typecase done + (sb-bsd-sockets:inet-socket listener-thread) + (t (values nil done))))))) + +(defun format-address (address) + "Converts an array of four integers denoting an IP address into +the corresponding string representation." + (format nil "~{~A~^.~}" (coerce address 'list))) + +(defun make-socket-stream (socket read-timeout write-timeout) + "Accepts a socket `handle' SOCKET and creates and returns a +corresponding stream, setting its read and write timeout if +applicable. Returns three other values - the address the request +arrived at, and the address and port of the remote host." + (declare (ignore write-timeout)) + (let ((local-host (sb-bsd-sockets:socket-name socket))) + (multiple-value-bind (remote-host remote-port) + (sb-bsd-sockets:socket-peername socket) + (values (sb-bsd-sockets:socket-make-stream socket + :input t + :output t + :element-type '(unsigned-byte 8) + :timeout read-timeout + :buffering :full) + (format-address local-host) + (format-address remote-host) + remote-port)))) + +;; determine how we're going to access the backtrace in the next +;; function +(eval-when (:compile-toplevel :load-toplevel :execute) + (when (find-symbol "*DEBUG-PRINT-VARIABLE-ALIST*" :sb-debug) + (pushnew :hunchentoot-sbcl-debug-print-variable-alist *features*))) + +(defun get-backtrace (error) + "This is the function that is used internally by Hunchentoot to +show or log backtraces. It accepts a condition object ERROR and +returns a string with the corresponding backtrace." + (declare (ignore error)) + (with-output-to-string (s) + #+:hunchentoot-sbcl-debug-print-variable-alist + (let ((sb-debug:*debug-print-variable-alist* + (list* '(*print-level* . nil) + '(*print-length* . nil) + sb-debug:*debug-print-variable-alist*))) + (sb-debug:backtrace most-positive-fixnum s)) + #-:hunchentoot-sbcl-debug-print-variable-alist + (let ((sb-debug:*debug-print-level* nil) + (sb-debug:*debug-print-length* nil)) + (sb-debug:backtrace most-positive-fixnum s)))) +
Added: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/reply.lisp =================================================================== --- branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/reply.lisp 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/reply.lisp 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,144 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: HUNCHENTOOT; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/hunchentoot/reply.lisp,v 1.19 2007/09/24 13:43:45 edi Exp $ + +;;; Copyright (c) 2004-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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-package :hunchentoot) + +(defclass reply () + ((content-type :initform *default-content-type* + :documentation "The outgoing 'Content-Type' http +header which defaults to the value of *DEFAULT-CONTENT-TYPE*.") + (content-length :initform nil + :documentation "The outgoing 'Content-Length' +http header which defaults NIL. If this is NIL, Hunchentoot will +compute the content length.") + (headers-out :initform nil + :documentation "An alist of the outgoing http headers +not including the 'Set-Cookie', 'Content-Length', and 'Content-Type' +headers. Use the functions HEADER-OUT and (SETF HEADER-OUT) to +modify this slot.") + (return-code :initform +http-ok+ + :documentation "The http return code of this +reply. The return codes Hunchentoot can handle are defined in +specials.lisp.") + (external-format :initform *hunchentoot-default-external-format* + :documentation "The external format of the reply - +used for character output.") + (log-messages :initform nil + :reader log-messages + :documentation "A list (in reverse chronological +order) of the messages which are to be written to the Apache error +log. This slot's value should only be modified by the functions +defined in log.lisp.") + (cookies-out :initform nil + :documentation "The outgoing cookies. This slot's +value should only be modified by the functions defined in +cookies.lisp.")) + (:documentation "Objects of this class hold all the information +about an outgoing reply. They are created automatically by +Hunchentoot and can be accessed and modified by the corresponding +handler.")) + +(defun headers-out (&optional (reply *reply*)) + "Returns an alist of the outgoing headers associated with the +REPLY object REPLY." + (slot-value reply 'headers-out)) + +(defun cookies-out (&optional (reply *reply*)) + "Returns an alist of the outgoing cookies associated with the +REPLY object REPLY." + (slot-value reply 'cookies-out)) + +(defun (setf cookies-out) (new-value &optional (reply *reply*)) + "Returns an alist of the outgoing cookies associated with the +REPLY object REPLY." + (setf (slot-value reply 'cookies-out) new-value)) + +(defun content-type (&optional (reply *reply*)) + "The outgoing 'Content-Type' http header of REPLY." + (slot-value reply 'content-type)) + +(defun (setf content-type) (new-value &optional (reply *reply*)) + "Sets the outgoing 'Content-Type' http header of REPLY." + (setf (slot-value reply 'content-type) new-value)) + +(defun content-length (&optional (reply *reply*)) + "The outgoing 'Content-Length' http header of REPLY." + (slot-value reply 'content-length)) + +(defun (setf content-length) (new-value &optional (reply *reply*)) + "Sets the outgoing 'Content-Length' http header of REPLY." + (setf (slot-value reply 'content-length) new-value)) + +(defun return-code (&optional (reply *reply*)) + "The http return code of REPLY. The return codes Hunchentoot can +handle are defined in specials.lisp." + (slot-value reply 'return-code)) + +(defun (setf return-code) (new-value &optional (reply *reply*)) + "Sets the http return code of REPLY." + (setf (slot-value reply 'return-code) new-value)) + +(defun reply-external-format (&optional (reply *reply*)) + "The external format of REPLY which is used for character output." + (slot-value reply 'external-format)) + +(defun (setf reply-external-format) (new-value &optional (reply *reply*)) + "Sets the external format of REPLY." + (setf (slot-value reply 'external-format) new-value)) + +(defun header-out-set-p (name &optional (reply *reply*)) + "Returns a true value if the outgoing http header named NAME has +been specified already. NAME should be a keyword or a string." + (assoc name (headers-out reply))) + +(defun header-out (name &optional (reply *reply*)) + "Returns the current value of the outgoing http header named NAME. +NAME should be a keyword or a string." + (cdr (assoc name (headers-out reply)))) + +(defun cookie-out (name &optional (reply *reply*)) + "Returns the current value of the outgoing cookie named +NAME. Search is case-sensitive." + (cdr (assoc name (cookies-out reply) :test #'string=))) + +(defsetf header-out (name &optional (reply '*reply*)) + (new-value) + "Changes the current value of the outgoing http header named NAME (a +keyword or a string). If a header with this name doesn't exist, it is +created." + (with-rebinding (name reply) + (with-unique-names (symbol place) + `(let* ((,symbol (if (stringp ,name) (make-keyword ,name :destructivep nil) ,name)) + (,place (assoc ,symbol (headers-out ,reply) :test #'string-equal))) + (cond + (,place + (setf (cdr ,place) ,new-value)) + (t + (push (cons ,symbol ,new-value) (slot-value ,reply 'headers-out)) + ,new-value)))))) \ No newline at end of file
Added: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/request.lisp =================================================================== --- branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/request.lisp 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/request.lisp 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,474 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: HUNCHENTOOT; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/hunchentoot/request.lisp,v 1.33 2007/09/14 12:12:33 edi Exp $ + +;;; Copyright (c) 2004-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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-package :hunchentoot) + +(defclass request () + ((headers-in :initarg :headers-in + :documentation "An alist of the incoming headers. Note +that these might be the headers coming in from mod_lisp which are +different from the headers sent by the client.") + (method :initarg :method + :documentation "The request method as a keyword. This slot +is only filled if we're not behind mod_lisp.") + (uri :initarg :uri + :documentation "The request URI as a string. This slot is +only filled if we're not behind mod_lisp.") + (server-protocol :initarg :server-protocol + :documentation "The HTTP protocol as a keyword. +This slot is only filled if we're not behind mod_lisp.") + (content-stream :initarg :content-stream + :reader content-stream + :documentation "A stream from which the request +body can be read if there is one.") + (cookies-in :initform nil + :documentation "An alist of the cookies sent by the client.") + (get-parameters :initform nil + :documentation "An alist of the GET parameters sent +by the client.") + (post-parameters :initform nil + :documentation "An alist of the POST parameters +sent by the client.") + (script-name :initform nil + :documentation "The URI requested by the client without +the query string.") + (query-string :initform nil + :documentation "The query string of this request.") + (session :initform nil + :accessor session + :documentation "The session object associated with this +request.") + (aux-data :initform nil + :accessor aux-data + :documentation "Used to keep a user-modifiable alist with +arbitrary data during the request.") + (raw-post-data :initform nil + :documentation "The raw string sent as the body of a +POST request, populated only if not a multipart/form-data request.")) + (:documentation "Objects of this class hold all the information +about an incoming request. They are created automatically by +Hunchentoot and can be accessed by the corresponding handler.")) + +(defun parse-rfc2388-form-data (stream content-type-header) + "Creates an alist of POST parameters from the stream STREAM which is +supposed to be of content type 'multipart/form-data'." + (let* ((parsed-content-type-header (rfc2388:parse-header content-type-header :value)) + (boundary (or (cdr (rfc2388:find-parameter + "BOUNDARY" + (rfc2388:header-parameters parsed-content-type-header))) + (return-from parse-rfc2388-form-data)))) + (loop for part in (rfc2388:parse-mime stream boundary) + for headers = (rfc2388:mime-part-headers part) + for content-disposition-header = (rfc2388:find-content-disposition-header headers) + for name = (cdr (rfc2388:find-parameter + "NAME" + (rfc2388:header-parameters content-disposition-header))) + when name + collect (cons name + (let ((contents (rfc2388:mime-part-contents part))) + (if (pathnamep contents) + (list contents + (rfc2388:get-file-name headers) + (rfc2388:content-type part :as-string t)) + contents)))))) + +(defun get-post-data (&key (request *request*) want-stream (already-read 0)) + "Reads the request body from the stream and stores the raw contents +(as an array of octets) in the corresponding slot of the REQUEST +object. Returns just the stream if WANT-STREAM is true. If there's a +Content-Length header, it is assumed, that ALREADY-READ octets have +already been read." + (let* ((headers-in (headers-in request)) + (content-length (when-let (content-length-header (cdr (assoc :content-length headers-in))) + (parse-integer content-length-header :junk-allowed t))) + (content-stream (content-stream request))) + (setf (slot-value request 'raw-post-data) + (cond (want-stream + (setf (flexi-stream-position *hunchentoot-stream*) 0) + (when content-length + (setf (flexi-stream-bound content-stream) content-length)) + content-stream) + ((and content-length (> content-length already-read)) + (decf content-length already-read) + (when (input-chunking-p) + ;; see RFC 2616, section 4.4 + (log-message :warn "Got Content-Length header although input chunking is on.")) + (let ((content (make-array content-length :element-type 'octet))) + (read-sequence content content-stream) + content)) + ((input-chunking-p) + (loop with buffer = (make-array +buffer-length+ :element-type 'octet) + with content = (make-array 0 :element-type 'octet :adjustable t) + for index = 0 then (+ index pos) + for pos = (read-sequence buffer content-stream) + do (adjust-array content (+ index pos)) + (replace content buffer :start1 index :end2 pos) + while (= pos +buffer-length+) + finally (return content))))))) + +(defmethod initialize-instance :after ((request request) &rest init-args) + "The only initarg for a REQUEST object is :HEADERS-IN. All other +slot values are computed in this :AFTER method." + (declare (ignore init-args)) + (with-slots (headers-in cookies-in get-parameters post-parameters script-name query-string session) + request + (handler-case + (progn + (when (server-mod-lisp-p *server*) + ;; convert these two values to keywords + (let ((method-pair (assoc :method headers-in))) + (setf (cdr method-pair) (make-keyword (cdr method-pair)))) + (let ((protocol-pair (assoc :server-protocol headers-in))) + (setf (cdr protocol-pair) (make-keyword (cdr protocol-pair)))) + ;; and convert these two values to integers + (let ((remote-ip-port-pair (assoc :remote-ip-port headers-in))) + (setf (cdr remote-ip-port-pair) (parse-integer (cdr remote-ip-port-pair) + :junk-allowed t))) + (let ((server-ip-port-pair (assoc :server-ip-port headers-in))) + (setf (cdr server-ip-port-pair) (parse-integer (cdr server-ip-port-pair) + :junk-allowed t)))) + ;; compute SCRIPT-NAME and QUERY-STRING slots from + ;; REQUEST_URI environment variable + (let* ((uri (request-uri request)) + (match-start (position #? uri))) + (cond + (match-start + (setq script-name (subseq uri 0 match-start) + query-string (subseq uri (1+ match-start)))) + (t (setq script-name uri)))) + ;; some clients (e.g. ASDF-INSTALL) send requests like + ;; "GET http://server/foo.html HTTP/1.0"... + (setq script-name (regex-replace "^https?://[^/]+" script-name "")) + ;; compute GET parameters from query string and cookies from + ;; the incoming 'Cookie' header + (setq get-parameters + (form-url-encoded-list-to-alist (split "&" query-string)) + cookies-in + (form-url-encoded-list-to-alist (split "\s*[,;]\s*" (cdr (assoc :cookie headers-in))) + +utf-8+) + session (session-verify request) + *session* session) + ;; if the content-type is 'application/x-www-form-urlencoded' + ;; or 'multipart/form-data', compute the post parameters from + ;; the content body + (when (member (request-method request) *methods-for-post-parameters* :test #'eq) + (when-let (content-type (cdr (assoc :content-type headers-in))) + (multiple-value-bind (type subtype external-format) + (parse-content-type content-type t) + (setq post-parameters + (cond ((and (string-equal type "application") + (string-equal subtype "x-www-form-urlencoded")) + (unless (or (assoc :content-length headers-in) + (input-chunking-p)) + (error "Can't read request body because there's no~ +Content-Length header and input chunking is off.")) + (form-url-encoded-list-to-alist + (split "&" (raw-post-data :request request + ;; ASCII would suffice according to RFC... + :external-format +latin-1+)) + external-format)) + ((and (string-equal type "multipart") + (string-equal subtype "form-data")) + (setf (slot-value request 'raw-post-data) t) + (handler-case + (let* ((*request* request) + (content-stream (content-stream request)) + (start (flexi-stream-position content-stream))) + (prog1 + (parse-rfc2388-form-data content-stream content-type) + (let* ((end (flexi-stream-position content-stream)) + (stray-data (get-post-data :already-read (- end start)))) + (when (and stray-data (plusp (length stray-data))) + (warn "~A octets of stray data after form-data sent by client." + (length stray-data)))) + (setf (slot-value request 'raw-post-data) t))) + (error (msg) + (log-message :error + "While parsing multipart/form-data parameters: ~A" + msg) + nil))))))))) + (error (cond) + (log-message* "Error when creating REQUEST object: ~A" cond) + ;; we assume it's not our fault... + (setf (return-code) +http-bad-request+))))) + +(defun recompute-request-parameters (&key (request *request*) + (external-format *hunchentoot-default-external-format*)) + "Recomputes the GET and POST parameters for the REQUEST object +REQUEST. This only makes sense if you're switching external formats +during the request." + (with-slots (headers-in get-parameters post-parameters query-string) + request + (setq get-parameters + (form-url-encoded-list-to-alist (split "&" query-string) external-format) + post-parameters + (when-let (raw-post-data (raw-post-data :request request + :external-format +latin-1+)) + (and (when-let (content-type (cdr (assoc :content-type headers-in))) + (multiple-value-bind (type subtype) + (parse-content-type content-type) + (and (string-equal type "application") + (string-equal subtype "x-www-form-urlencoded")))) + (form-url-encoded-list-to-alist (split "&" raw-post-data) external-format))))) + (values)) + +(defun script-name (&optional (request *request*)) + "Returns the file name of the REQUEST object REQUEST. That's the +requested URI without the query string (i.e the GET parameters)." + (slot-value request 'script-name)) + +(defun query-string (&optional (request *request*)) + "Returns the query string of the REQUEST object REQUEST. That's +the part behind the question mark (i.e. the GET parameters)." + (slot-value request 'query-string)) + +(defun get-parameters (&optional (request *request*)) + "Returns an alist of the GET parameters associated with the REQUEST +object REQUEST." + (slot-value request 'get-parameters)) + +(defun post-parameters (&optional (request *request*)) + "Returns an alist of the POST parameters associated with the REQUEST +object REQUEST." + (slot-value request 'post-parameters)) + +(defun headers-in (&optional (request *request*)) + "Returns an alist of the incoming headers associated with the +REQUEST object REQUEST." + (slot-value request 'headers-in)) + +(defun cookies-in (&optional (request *request*)) + "Returns an alist of all cookies associated with the REQUEST object +REQUEST." + (slot-value request 'cookies-in)) + +(defun header-in (name &optional (request *request*)) + "Returns the incoming header with name NAME. NAME can be a keyword +(recommended) or a string." + (cdr (assoc name (headers-in request)))) + +(defun authorization (&optional (request *request*)) + "Returns as two values the user and password (if any) as encoded in +the 'AUTHORIZATION' header. Returns NIL if there is no such header." + (let* ((authorization (header-in :authorization request)) + (start (and authorization + (> (length authorization) 5) + (string-equal "Basic" authorization :end2 5) + (scan "\S" authorization :start 5)))) + (when start + (destructuring-bind (&optional user password) + (split ":" (base64:base64-string-to-string (subseq authorization start))) + (values user password))))) + +(defun remote-addr (&optional (request *request*)) + "Returns the address the current request originated from." + (cond ((server-mod-lisp-p *server*) (header-in :remote-ip-addr request)) + (t *remote-host*))) + +(defun real-remote-addr (&optional (request *request*)) + "Returns the 'X-Forwarded-For' incoming http header as the +second value in the form of a list of IP addresses and the first +element of this list as the first value if this header exists. +Otherwise returns the value of REMOTE-ADDR as the only value." + (let ((x-forwarded-for (header-in :x-forwarded-for request))) + (cond (x-forwarded-for (let ((addresses (split "\s*,\s*" x-forwarded-for))) + (values (first addresses) addresses))) + (t (remote-addr request))))) + +(defun server-addr (&optional (request *request*)) + "Returns the address at which the current request arrived." + (cond ((server-mod-lisp-p *server*) (header-in :server-ip-addr request)) + (t *local-host*))) + +(defun remote-port (&optional (request *request*)) + "Returns the port the current request originated from." + (cond ((server-mod-lisp-p *server*) (header-in :remote-ip-port request)) + (t *remote-port*))) + +(defun server-port (&optional (request *request*)) + "Returns the port at which the current request arrived." + (cond ((server-mod-lisp-p *server*) (header-in :server-ip-port request)) + (t (server-local-port *server*)))) + +(defun host (&optional (request *request*)) + "Returns the 'Host' incoming http header value." + (header-in :host request)) + +(defun request-uri (&optional (request *request*)) + "Returns the request URI." + (cond ((server-mod-lisp-p *server*) (header-in :url request)) + (t (slot-value request 'uri)))) + +(defun request-method (&optional (request *request*)) + "Returns the request method as a Lisp keyword." + (cond ((server-mod-lisp-p *server*) (header-in :method request)) + (t (slot-value request 'method)))) + +(defun server-protocol (&optional (request *request*)) + "Returns the request protocol as a Lisp keyword." + (cond ((server-mod-lisp-p *server*) (header-in :server-protocol request)) + (t (slot-value request 'server-protocol)))) + +(defun mod-lisp-id (&optional (request *request*)) + "Returns the 'Server ID' sent by mod_lisp. This value is set in +Apache's server configuration file and is of course only available if +mod_lisp is the front-end." + (and (or (server-mod-lisp-p *server*) + (warn "Calling MOD-LISP-ID although ~S is a stand-alone server." + *server*)) + (header-in :server-id request))) + +(defun ssl-session-id (&optional (request *request*)) + "Returns the 'SSL_SESSION_ID' header sent my mod_lisp and is of +course only available if mod_lisp is the front-end." + (and (or (server-mod-lisp-p *server*) + (warn "Calling SSL-SESSION-ID although ~S is a stand-alone server." + *server*)) + (header-in :ssl-session-id request))) + +(defun user-agent (&optional (request *request*)) + "Returns the 'User-Agent' http header." + (header-in :user-agent request)) + +(defun cookie-in (name &optional (request *request*)) + "Returns the cookie with the name NAME (a string) as sent by the +browser - or NIL if there is none." + (cdr (assoc name (cookies-in request) :test #'string=))) + +(defun referer (&optional (request *request*)) + "Returns the 'Referer' (sic!) http header." + (header-in :referer request)) + +(defun get-parameter (name &optional (request *request*)) + "Returns the GET parameter with name NAME (a string) - or NIL if +there is none. Search is case-sensitive." + (cdr (assoc name (get-parameters request) :test #'string=))) + +(defun post-parameter (name &optional (request *request*)) + "Returns the POST parameter with name NAME (a string) - or NIL if +there is none. Search is case-sensitive." + (cdr (assoc name (post-parameters request) :test #'string=))) + +(defun parameter (name &optional (request *request*)) + "Returns the GET or the POST parameter with name NAME (a string) - +or NIL if there is none. If both a GET and a POST parameter with the +same name exist the GET parameter is returned. Search is +case-sensitive." + (or (get-parameter name request) + (post-parameter name request))) + +(defun handle-if-modified-since (time &optional (request *request*)) + "Handles the 'If-Modified-Since' header of REQUEST. The date string +is compared to the one generated from the supplied universal time +TIME." + (let ((if-modified-since (header-in :if-modified-since request)) + (time-string (rfc-1123-date time))) + ;; simple string comparison is sufficient; see RFC 2616 14.25 + (when (and if-modified-since + (equal if-modified-since time-string)) + (setf (return-code) +http-not-modified+) + (throw 'handler-done nil)) + (values))) + +(defun raw-post-data (&key (request *request*) external-format force-binary force-text want-stream) + "Returns the content sent by the client if there was any (unless +the content type was "multipart/form-data"). By default, the result +is a string if the type of the `Content-Type' media type is "text", +and a vector of octets otherwise. In the case of a string, the +external format to be used to decode the content will be determined +from the `charset' parameter sent by the client (or otherwise +*HUNCHENTOOT-DEFAULT-EXTERNAL-FORMAT* will be used). + +You can also provide an external format explicitly (through +EXTERNAL-FORMAT) in which case the result will unconditionally be a +string. Likewise, you can provide a true value for FORCE-TEXT which +will force Hunchentoot to act as if the type of the media type had +been "text". Or you can provide a true value for FORCE-BINARY which +means that you want a vector of octets at any rate. + +If, however, you provide a true value for WANT-STREAM, the other +parameters are ignored and you'll get the content (flexi) stream to +read from it yourself. It is then your responsibility to read the +correct amount of data, because otherwise you won't be able to return +a response to the client. If the content type of the request was +`multipart/form-data' or `application/x-www-form-urlencoded', the +content has been read by Hunchentoot already and you can't read from +the stream anymore. + +You can call RAW-POST-DATA more than once per request, but you can't +mix calls which have different values for WANT-STREAM. + +Note that this function is slightly misnamed because a client can send +content even if the request method is not POST." + (when (and force-binary force-text) + (error "It doesn't make sense to set both FORCE-BINARY and FORCE-TEXT to a true value.")) + (unless (or external-format force-binary) + (setq external-format + (when-let (content-type (cdr (assoc :content-type (headers-in request)))) + (nth-value 2 (parse-content-type content-type force-text))))) + (let ((raw-post-data (or (slot-value request 'raw-post-data) + (get-post-data :request request :want-stream want-stream)))) + (cond ((typep raw-post-data 'stream) raw-post-data) + ((member raw-post-data '(t nil)) nil) + (external-format (octets-to-string raw-post-data :external-format external-format)) + (t raw-post-data)))) + +(defun aux-request-value (symbol &optional (request *request*)) + "Returns the value associated with SYMBOL from the request object +REQUEST (the default is the current request) if it exists. The +second return value is true if such a value was found." + (when request + (let ((found (assoc symbol (aux-data request)))) + (values (cdr found) found)))) + +(defsetf aux-request-value (symbol &optional request) + (new-value) + "Sets the value associated with SYMBOL from the request object +REQUEST (default is *REQUEST*). If there is already a value +associated with SYMBOL it will be replaced." + (with-rebinding (symbol) + (with-unique-names (place %request) + `(let* ((,%request (or ,request *request*)) + (,place (assoc ,symbol (aux-data ,%request)))) + (cond + (,place + (setf (cdr ,place) ,new-value)) + (t + (push (cons ,symbol ,new-value) + (aux-data ,%request)) + ,new-value)))))) + +(defun delete-aux-request-value (symbol &optional (request *request*)) + "Removes the value associated with SYMBOL from the request object +REQUEST." + (when request + (setf (aux-data request) + (delete symbol (aux-data request) + :key #'car :test #'eq))) + (values))
Added: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/server.lisp =================================================================== --- branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/server.lisp 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/server.lisp 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,440 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-USER; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/hunchentoot/server.lisp,v 1.38 2007/11/03 21:46:19 edi Exp $ + +;;; Copyright (c) 2004-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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-package :hunchentoot) + +(defclass server () + ((socket :accessor server-socket + :documentation "The socket the server is listening on.") + (port :initarg :port + :reader server-local-port + :documentation "The port the server is listening on. +See START-SERVER.") + (address :initarg :address + :reader server-address + :documentation "The address the server is listening +on. See START-SERVER.") + (name :initarg :name + :accessor server-name + :documentation "The optional name of the server, a symbol.") + (dispatch-table :initarg :dispatch-table + :accessor server-dispatch-table + :documentation "The dispatch-table used by this +server. Can be NIL to denote that *META-DISPATCHER* should be called +instead.") + (output-chunking-p :initarg :output-chunking-p + :reader server-output-chunking-p + :documentation "Whether the server may use output chunking.") + (input-chunking-p :initarg :input-chunking-p + :reader server-input-chunking-p + :documentation "Whether the server may use input chunking.") + (read-timeout :initarg :read-timeout + :reader server-read-timeout + :documentation "The read-timeout of the server.") + (write-timeout :initarg :write-timeout + :reader server-write-timeout + :documentation "The write-timeout of the server.") + (listener :accessor server-listener + :documentation "The Lisp process which listens for +incoming requests and starts new worker threads for each new +connection.") + (workers :initform nil + :accessor server-workers + :documentation "A list of currently active worker threads.") + (mod-lisp-p :initform nil + :initarg :mod-lisp-p + :reader server-mod-lisp-p + :documentation "Whether this is a genuine +Hunchentoot server or "just" infrastructure for mod_lisp.") + (use-apache-log-p :initarg :use-apache-log-p + :reader server-use-apache-log-p + :documentation "Whether the server should use +Apache's log file. Only applicable if MOD-LISP-P is true.") + #-:hunchentoot-no-ssl + (ssl-certificate-file :initarg :ssl-certificate-file + :reader server-ssl-certificate-file + :documentation "The namestring of a +certificate file if SSL is used, NIL otherwise.") + #-:hunchentoot-no-ssl + (ssl-privatekey-file :initarg :ssl-privatekey-file + :reader server-ssl-privatekey-file + :documentation "The namestring of a +private key file if SSL is used, NIL otherwise.") + #-:hunchentoot-no-ssl + (ssl-privatekey-password :initarg :ssl-privatekey-password + :reader server-ssl-privatekey-password + :documentation "The password for the +private key file or NIL.") + (lock :initform (make-lock (format nil "hunchentoot-lock-~A" + *server-counter*)) + :reader server-lock + :documentation "A lock which is used to make sure that +we can shutdown the server cleanly.")) + (:documentation "An object of this class contains all relevant +information about a running Hunchentoot server instance.")) + +(defun start-server (&key (port 80 port-provided-p) + address + dispatch-table + (name (gensym)) + (mod-lisp-p nil) + (use-apache-log-p mod-lisp-p) + (input-chunking-p t) + (read-timeout *default-read-timeout*) + (write-timeout *default-write-timeout*) + #+(and :unix (not :win32)) setuid + #+(and :unix (not :win32)) setgid + #-:hunchentoot-no-ssl ssl-certificate-file + #-:hunchentoot-no-ssl (ssl-privatekey-file ssl-certificate-file) + #-:hunchentoot-no-ssl ssl-privatekey-password) + "Starts a Hunchentoot server and returns the SERVER object (which +can be stopped with STOP-SERVER). PORT is the port the server will be +listening on - the default is 80 (or 443 if SSL information is +provided). If ADDRESS is a string denoting an IP address, then the +server only receives connections for that address. This must be one +of the addresses associated with the machine and allowed values are +host names such as "www.nowhere.com" and address strings like +"204.71.177.75". If ADDRESS is NIL, then the server will receive +connections to all IP addresses on the machine. This is the default. + +DISPATCH-TABLE can either be a dispatch table which is to be used by +this server or NIL which means that at request time *META-DISPATCHER* +will be called to retrieve a dispatch table. + +NAME should be a symbol which can be used to name the server. This +name can utilized when defining "easy handlers" - see +DEFINE-EASY-HANDLER. The default name is an uninterned symbol as +returned by GENSYM. + +If MOD-LISP-P is true, the server will act as a back-end for mod_lisp, +otherwise it will be a stand-alone web server. If USE-APACHE-LOG-P is +true, log messages will be written to the Apache log file - this +parameter has no effect if MOD-LISP-P is NIL. + +If INPUT-CHUNKING-P is true, the server will accept request bodies +without a `Content-Length' header if the client uses chunked transfer +encoding. If you want to use this feature together with mod_lisp, you +should make sure that your combination of Apache and mod_lisp can do +that - see: + + http://common-lisp.net/pipermail/mod-lisp-devel/2006-December/000104.html. + +On LispWorks 5.0 or higher and AllegroCL, READ-TIMEOUT and +WRITE-TIMEOUT are the read and write timeouts (in seconds) of +the server - use NIL for no timeout at all. (See the LispWorks +documentation for STREAM:SOCKET-STREAM for details.) On +LispWorks 4.4.6 or lower, SBCL, and CMUCL WRITE-TIMEOUT is +ignored. On OpenMCL both parameters are ignored. + +On Unix you can use SETUID and SETGID to change the UID and GID of the +process directly after the server has been started. (You might want +to do this if you're using a privileged port like 80.) SETUID and +SETGID can be integers (the actual IDs) or strings (for the user and +group name respectively). + +If you want your server to use SSL you must provide the pathname +designator(s) SSL-CERTIFICATE-FILE for the certificate file and +optionally SSL-PRIVATEKEY-FILE for the private key file, both files +must be in PEM format. If you only provide the value for +SSL-CERTIFICATE-FILE it is assumed that both the certificate and the +private key are in one file. If your private key needs a password you +can provide it through the SSL-PRIVATEKEY-PASSWORD keyword argument, +but this works only on LispWorks - for other Lisps the key must not be +associated with a password." + (declare (ignorable port-provided-p)) + ;; initialize the session secret if needed + (unless (boundp '*session-secret*) + (reset-session-secret)) + (let ((output-chunking-p t)) + #-:hunchentoot-no-ssl + (when ssl-certificate-file + ;; disable output chunking for SSL connections + (setq output-chunking-p nil) + (unless port-provided-p (setq port 443))) + ;; no timeouts if behind mod_lisp + (when mod-lisp-p + (setq read-timeout nil + write-timeout nil)) + ;; use a new process/lock name for each server + (atomic-incf *server-counter*) + ;; create the SERVER object + (let ((server (make-instance 'server + :port port + :address address + :name name + :dispatch-table dispatch-table + :output-chunking-p (and output-chunking-p (not mod-lisp-p)) + :input-chunking-p input-chunking-p + #-:hunchentoot-no-ssl :ssl-certificate-file + #-:hunchentoot-no-ssl(and ssl-certificate-file + (namestring ssl-certificate-file)) + #-:hunchentoot-no-ssl :ssl-privatekey-file + #-:hunchentoot-no-ssl (and ssl-privatekey-file + (namestring ssl-privatekey-file)) + #-:hunchentoot-no-ssl :ssl-privatekey-password + #-:hunchentoot-no-ssl ssl-privatekey-password + :mod-lisp-p mod-lisp-p + :use-apache-log-p (and mod-lisp-p use-apache-log-p) + :read-timeout read-timeout + :write-timeout write-timeout))) + (multiple-value-bind (process condition) + ;; start up the actual server + (start-up-server :service port + :address address + :process-name (format nil "hunchentoot-listener-~A" *server-counter*) + ;; this function is called once on + ;; startup - we use it to record the + ;; socket + :announce (lambda (socket &optional condition) + (cond (socket + (setf (server-socket server) socket)) + (condition + (error condition)))) + ;; this function is called whenever a + ;; connection is made + :function (lambda (handle) + (with-lock ((server-lock server)) + (incf *worker-counter*) + ;; check if we need to + ;; perform a global GC + (when (and *cleanup-interval* + (zerop (mod *worker-counter* *cleanup-interval*))) + (when *cleanup-function* + (funcall *cleanup-function*))) + ;; start a worker thread + ;; for this connection + ;; and remember it + (push (process-run-function (format nil "hunchentoot-worker-~A" + *worker-counter*) + #'process-connection + server handle) + (server-workers server)))) + ;; wait until the server was + ;; successfully started or an error + ;; condition is returned + :wait t) + (cond (process + ;; remember the listener so we can kill it later + (setf (server-listener server) process)) + (condition + (error condition)))) + #+(and :unix (not :win32)) + (when setgid + ;; we must make sure to call setgid before we call setuid or + ;; suddenly we aren't root anymore... + (etypecase setgid + (integer (setgid setgid)) + (string (setgid (get-gid-from-name setgid))))) + #+(and :unix (not :win32)) + (when setuid + (etypecase setuid + (integer (setuid setuid)) + (string (setuid (get-uid-from-name setuid))))) + server))) + +(defun stop-server (server) + "Stops the Hunchentoot server SERVER." + ;; use lock so that the listener can't start new workers + (with-lock ((server-lock server)) + ;; kill all worker threads + (dolist (worker (server-workers server)) + (ignore-errors (process-kill worker)) + (process-allow-scheduling)) + ;; finally, kill main listener + (when-let (listener (server-listener server)) + (process-kill listener))) + (values)) + +(defun process-connection (server handle) + "This function is called by the server in a newly-created thread +with the SERVER object itself and a socket 'handle' from which a +stream can be created. It reads the request headers and hands over to +PROCESS-REQUEST. This is done in a loop until the stream has to be +closed or until a read timeout occurs." + (handler-bind ((error + ;; abort if there's an error which isn't caught inside + (lambda (cond) + (log-message *lisp-errors-log-level* + "Error while processing connection: ~A" cond) + (return-from process-connection))) + (warning + ;; log all warnings which aren't caught inside + (lambda (cond) + (log-message *lisp-warnings-log-level* + "Warning while processing connection: ~A" cond)))) + (with-debugger + (let (*hunchentoot-stream* *local-host* *remote-host* *remote-port*) + (unwind-protect + ;; bind important special variables + (let ((*server* server)) + ;; create binary stream from socket handle + (multiple-value-setq (*hunchentoot-stream* *local-host* *remote-host* *remote-port*) + (make-socket-stream handle + (server-read-timeout server) + (server-write-timeout server))) + ;; attach SSL to the stream if necessary + #-:hunchentoot-no-ssl + (when (server-ssl-certificate-file server) + #+:lispworks + (make-ssl-server-stream *hunchentoot-stream* + :certificate-file (server-ssl-certificate-file server) + :privatekey-file (server-ssl-privatekey-file server) + :privatekey-password (server-ssl-privatekey-password server)) + #-:lispworks + (setq *hunchentoot-stream* + (cl+ssl:make-ssl-server-stream *hunchentoot-stream* + :certificate (server-ssl-certificate-file server) + :key (server-ssl-privatekey-file server)))) + ;; wrap with chunking-enabled stream if necessary + (when (or (server-input-chunking-p server) + (server-output-chunking-p server)) + (setq *hunchentoot-stream* (make-chunked-stream *hunchentoot-stream*))) + ;; now wrap with flexi stream with "faithful" external format + (setq *hunchentoot-stream* + (make-flexi-stream *hunchentoot-stream* :external-format +latin-1+)) + ;; loop until we have to close the stream - as + ;; determined by *CLOSE-HUNCHENTOOT-STREAM* + (unwind-protect + (loop + (let ((*close-hunchentoot-stream* t)) + ;; reset to "faithful" format on each iteration + ;; and reset bound of stream as well + (setf (flexi-stream-external-format *hunchentoot-stream*) +latin-1+ + (flexi-stream-bound *hunchentoot-stream*) nil) + (multiple-value-bind (headers-in content-stream method url-string server-protocol) + (get-request-data) + (unless (and ;; check if there was a request at all + (cond ((server-mod-lisp-p server) headers-in) + (t method)) + (prog1 + (process-request headers-in content-stream method + url-string server-protocol) + ;; always turn chunking off at this point + (when (or (server-input-chunking-p server) + (server-output-chunking-p server)) + (setf (chunked-stream-output-chunking-p + (flexi-stream-stream *hunchentoot-stream*)) nil + (chunked-stream-input-chunking-p + (flexi-stream-stream *hunchentoot-stream*)) nil)) + (force-output* *hunchentoot-stream*)) + ;; continue until we have to close + ;; the stream + (not *close-hunchentoot-stream*)) + (return))))) + (ignore-errors (force-output* *hunchentoot-stream*)))) + (when *hunchentoot-stream* + (ignore-errors (close *hunchentoot-stream* :abort t))) + (ignore-errors + (with-lock ((server-lock server)) + ;; remove this worker from the list of all workers + (setf (server-workers server) + (delete *current-process* (server-workers server)))))))))) + +(defun process-request (headers-in content-stream method url-string server-protocol) + "This function is called by PROCESS-CONNECTION after the incoming +headers have been read. It sets up the REQUEST and REPLY objects, +dispatches to a handler, and finally sends the output to the client +using START-OUTPUT. If all goes as planned, the function returns T." + (let (*tmp-files* *headers-sent*) + (unwind-protect + (progn + (when (server-input-chunking-p *server*) + (let ((transfer-encodings (cdr (assoc :transfer-encoding headers-in)))) + (when transfer-encodings + (setq transfer-encodings + (split "\s*,\*" transfer-encodings))) + (when (member "chunked" transfer-encodings :test #'equalp) + ;; turn chunking on before we read the request body + (setf (chunked-stream-input-chunking-p + (flexi-stream-stream *hunchentoot-stream*)) t)))) + (let* ((*session* nil) + ;; first create a REPLY object so we can immediately start + ;; logging (in case we're logging to mod_lisp) + (*reply* (make-instance 'reply)) + (*request* (make-instance 'request + :headers-in headers-in + :content-stream content-stream + :method method + :uri url-string + :server-protocol server-protocol)) + (*dispatch-table* (or (server-dispatch-table *server*) + (funcall *meta-dispatcher* *server*))) + backtrace) + (multiple-value-bind (body error) + (catch 'handler-done + (handler-bind ((error + (lambda (cond) + ;; only generate backtrace if needed + (setq backtrace + (and (or (and *show-lisp-errors-p* + *show-lisp-backtraces-p*) + (and *log-lisp-errors-p* + *log-lisp-backtraces-p*)) + (get-backtrace cond))) + (when *log-lisp-errors-p* + (log-message *lisp-errors-log-level* + "~A~:[~*~;~%~A~]" + cond + *log-lisp-backtraces-p* + backtrace)) + ;; if the headers were already sent + ;; the error happens within the body + ;; and we have to close the stream + (when *headers-sent* + (setq *close-hunchentoot-stream* t)) + (throw 'handler-done + (values nil cond)))) + (warning + (lambda (cond) + (when *log-lisp-warnings-p* + (log-message *lisp-warnings-log-level* + "~A~:[~*~;~%~A~]" + cond + *log-lisp-backtraces-p* + backtrace))))) + (with-debugger + ;; skip dispatch if bad request + (when (eq (return-code) +http-ok+) + ;; now do the work + (dispatch-request *dispatch-table*))))) + (when error + (setf (return-code *reply*) + +http-internal-server-error+)) + (start-output (cond ((and error *show-lisp-errors-p*) + (format nil "<pre>~A~:[~*~;~%~%~A~]</pre>" + (escape-for-html (format nil "~A" error)) + *show-lisp-backtraces-p* + (escape-for-html (format nil "~A" backtrace)))) + (error + "An error has occured") + (t body)))) + t)) + (dolist (path *tmp-files*) + (when (and (pathnamep path) (probe-file path)) + (ignore-errors (delete-file path)))))))
Property changes on: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/server.lisp ___________________________________________________________________ Name: svn:executable + *
Added: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/session.lisp =================================================================== --- branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/session.lisp 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/session.lisp 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,286 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: HUNCHENTOOT; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/hunchentoot/session.lisp,v 1.11 2007/06/04 19:24:12 edi Exp $ + +;;; Copyright (c) 2004-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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-package :hunchentoot) + +(let ((session-id-counter 0)) + (defun get-next-session-id () + "Returns the next sequential session id." + (incf session-id-counter))) + +(let ((global-session-usage-counter 0)) + (defun count-session-usage () + "Counts session usage globally and triggers session gc if necessary." + (when (and *session-gc-frequency* + (zerop (mod (incf global-session-usage-counter) + *session-gc-frequency*))) + (session-gc)))) + + +(defclass session () + ((session-id :initform (get-next-session-id) + :reader session-id + :type integer + :documentation "The unique ID (an INTEGER) of the session.") + (session-string :reader session-string + :documentation "The session strings encodes enough +data to safely retrieve this session. It is sent to the browser as a +cookie value or as a GET parameter.") + (user-agent :initform (user-agent *request*) + :reader session-user-agent + :documentation "The incoming 'User-Agent' header that +was sent when this session was created.") + (remote-addr :initform (real-remote-addr *request*) + :reader session-remote-addr + :documentation "The remote IP address of the client when +this sessions was started as returned by REAL-REMOTE-ADDR.") + (session-start :initform (get-universal-time) + :reader session-start + :documentation "The time this session was started.") + (last-click :initform (get-universal-time) + :reader session-last-click + :documentation "The last time this session was used.") + (session-data :initarg :session-data + :initform nil + :reader session-data + :documentation "Data associated with this session - +see SESSION-VALUE.") + (session-counter :initform 0 + :reader session-counter + :documentation "The number of times this session +has been used.") + (max-time :initarg :max-time + :initform *session-max-time* + :accessor session-max-time + :type fixnum + :documentation "The time (in seconds) after which this +session expires if it's not used.")) + (:documentation "SESSION objects are automatically maintained +by Hunchentoot. They should not be created explicitly with +MAKE-INSTANCE but implicitly with START-SESSION. Note that +SESSION objects can only be created when the special variable +*REQUEST* is bound to a REQUEST object.")) + +(defun encode-session-string (id user-agent remote-addr start) + "Create a uniquely encoded session string based on the values ID, +USER-AGENT, REMOTE-ADDR, and START" + ;; *SESSION-SECRET* is used twice due to known theoretical + ;; vulnerabilities of MD5 encoding + (md5-hex (concatenate 'string + *session-secret* + (md5-hex (format nil "~A~A~@[~A~]~@[~A~]~A" + *session-secret* + id + (and *use-user-agent-for-sessions* + user-agent) + (and *use-remote-addr-for-sessions* + remote-addr) + start))))) + +(defun stringify-session (session) + "Creates a string representing the SESSION object SESSION. See +ENCODE-SESSION-STRING." + (encode-session-string (session-id session) + (session-user-agent session) + (session-remote-addr session) + (session-start session))) + +(defmethod initialize-instance :after ((session session) &rest init-args) + "Set SESSION-STRING slot after the session has been initialized." + (declare (ignore init-args)) + (setf (slot-value session 'session-string) (stringify-session session))) + +(defun session-gc () + "Removes sessions from *session-data* which are too old - see +SESSION-TOO-OLD-P." + (with-lock (*session-data-lock*) + (setq *session-data* + (loop for id-session-pair in *session-data* + for (nil . session) = id-session-pair + when (session-too-old-p session) + do (funcall *session-removal-hook* session) + else + collect id-session-pair))) + (values)) + +(defun session-value (symbol &optional (session *session*)) + "Returns the value associated with SYMBOL from the session object +SESSION (the default is the current session) if it exists." + (when session + (let ((found (assoc symbol (session-data session)))) + (values (cdr found) found)))) + +(defsetf session-value (symbol &optional session) + (new-value) + "Sets the value associated with SYMBOL from the session object +SESSION. If there is already a value associated with SYMBOL it will be +replaced. Will automatically start a session if none was supplied and +there's no session for the current request." + (with-rebinding (symbol) + (with-unique-names (place %session) + `(with-lock (*session-data-lock*) + (let* ((,%session (or ,session (start-session))) + (,place (assoc ,symbol (session-data ,%session)))) + (cond + (,place + (setf (cdr ,place) ,new-value)) + (t + (push (cons ,symbol ,new-value) + (slot-value ,%session 'session-data)) + ,new-value))))))) + +(defun delete-session-value (symbol &optional (session *session*)) + "Removes the value associated with SYMBOL from the current session +object if there is one." + (when session + (setf (slot-value session 'session-data) + (delete symbol (session-data session) + :key #'car :test #'eq))) + (values)) + +(defun session-cookie-value (&optional (session (session *request*))) + "Returns a string which can be used to safely restore the +session if as session has already been established. This is used +as the value stored in the session cookie or in the corresponding +GET parameter." + (and session + (format nil + "~A:~A" + (session-id session) + (session-string session)))) + +(defun start-session () + "Returns the current SESSION object. If there is no current session, +creates one and updates the corresponding data structures. In this +case the function will also send a session cookie to the browser." + (count-session-usage) + (let ((session (session *request*))) + (when session + (return-from start-session session)) + (setf session (make-instance 'session) + (session *request*) session) + (with-lock (*session-data-lock*) + (setq *session-data* (acons (session-id session) session *session-data*))) + (set-cookie *session-cookie-name* + :value (session-cookie-value session) + :path "/") + (setq *session* session))) + +(defun remove-session (session) + "Completely removes the SESSION object SESSION from Hunchentoot's +internal session database." + (with-lock (*session-data-lock*) + (funcall *session-removal-hook* session) + (setq *session-data* + (delete (session-id session) *session-data* + :key #'car :test #'=))) + (values)) + +(defun session-too-old-p (session) + "Returns true if the SESSION object SESSION has not been active in +the last (SESSION-MAX-TIME SESSION) seconds." + (< (+ (session-last-click session) (session-max-time session)) + (get-universal-time))) + +(defun get-stored-session (id) + "Returns the SESSION object corresponding to the number ID if the +session has not expired. Will remove the session if it has expired but +will not create a new one." + (let ((session + (cdr (assoc id *session-data* :test #'=)))) + (when (and session + (session-too-old-p session)) + (when *reply* + (log-message :notice "Session with ID ~A too old" id)) + (remove-session session) + (setq session nil)) + session)) + +(defun session-verify (request) + "Tries to get a session identifier from the cookies (or +alternatively from the GET parameters) sent by the client. This +identifier is then checked for validity against the REQUEST object +REQUEST. On success the corresponding session object (if not too old) +is returned (and updated). Otherwise NIL is returned." + (let ((session-identifier (or (cookie-in *session-cookie-name* request) + (get-parameter *session-cookie-name* request)))) + (unless (and session-identifier + (stringp session-identifier) + (plusp (length session-identifier))) + (return-from session-verify nil)) + (destructuring-bind (id-string session-string) + (split ":" session-identifier :limit 2) + (let* ((id (and (scan "^\d+$" id-string) + (parse-integer id-string + :junk-allowed t))) + (session (and id + (get-stored-session id))) + (user-agent (user-agent request)) + (remote-addr (remote-addr request))) + (unless (and session + session-string + (string= session-string + (session-string session)) + (string= session-string + (encode-session-string id + user-agent + (real-remote-addr request) + (session-start session)))) + (when *reply* + (cond ((null session) + (log-message :notice "No session for session identifier '~A' (User-Agent: '~A', IP: '~A')" + session-identifier user-agent remote-addr)) + (t + (log-message :warning "Fake session identifier '~A' (User-Agent: '~A', IP: '~A')" + session-identifier user-agent remote-addr)))) + (when session + (remove-session session)) + (return-from session-verify nil)) + (incf (slot-value session 'session-counter)) + (setf (slot-value session 'last-click) (get-universal-time)) + session)))) + +(defun reset-sessions () + "Removes ALL stored sessions and creates a new session secret." + (reset-session-secret) + (with-lock (*session-data-lock*) + (loop for (nil . session) in *session-data* + do (funcall *session-removal-hook* session)) + (setq *session-data* nil)) + (values)) + +(defmacro do-sessions ((var &optional result-form) &body body) + "Executes BODY with VAR bound to each existing SESSION object +consecutively. Returns the values returned by RESULT-FORM unless +RETURN is executed. The scope of the binding of VAR does not include +RESULT-FORM." + (let ((=temp= (gensym))) + `(dolist (,=temp= *session-data* ,result-form) + (let ((,var (cdr ,=temp=))) + ,@body)))) \ No newline at end of file
Added: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/specials.lisp =================================================================== --- branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/specials.lisp 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/specials.lisp 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,385 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: HUNCHENTOOT; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/hunchentoot/specials.lisp,v 1.31 2007/11/08 20:07:58 edi Exp $ + +;;; Copyright (c) 2004-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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-package :hunchentoot) + +(eval-when (:compile-toplevel :execute :load-toplevel) + (defmacro defvar-unbound (name &optional (doc-string "")) + "Convenience macro to declare unbound special variables with a +documentation string." + `(progn + (defvar ,name) + (setf (documentation ',name 'variable) ,doc-string))) + + (defvar *http-reason-phrase-map* (make-hash-table) + "Used to map numerical return codes to reason phrases.") + + (defmacro def-http-return-code (name value reason-phrase) + "Shortcut to define constants for return codes. NAME is a +Lisp symbol, VALUE is the numerical value of the return code, and +REASON-PHRASE is the phrase (a string) to be shown in the +server's status line." + `(eval-when (:compile-toplevel :execute :load-toplevel) + (defconstant ,name ,value ,(format nil "HTTP return code (~A) for '~A'." + value reason-phrase)) + (setf (gethash ,value *http-reason-phrase-map*) ,reason-phrase)))) + +(defconstant +crlf+ #.(format nil "~C~C" #\Return #\Linefeed) + "A constant string consisting of the two ASCII characters CR and LF.") + +(def-http-return-code +http-continue+ 100 "Continue") +(def-http-return-code +http-switching-protocols+ 101 "Switching Protocols") +(def-http-return-code +http-ok+ 200 "OK") +(def-http-return-code +http-created+ 201 "Created") +(def-http-return-code +http-accepted+ 202 "Accepted") +(def-http-return-code +http-non-authoritative-information+ 203 "Non-Authoritative Information") +(def-http-return-code +http-no-content+ 204 "No Content") +(def-http-return-code +http-reset-content+ 205 "Reset Content") +(def-http-return-code +http-partial-content+ 206 "Partial Content") +(def-http-return-code +http-multi-status+ 207 "Multi-Status") +(def-http-return-code +http-multiple-choices+ 300 "Multiple Choices") +(def-http-return-code +http-moved-permanently+ 301 "Moved Permanently") +(def-http-return-code +http-moved-temporarily+ 302 "Moved Temporarily") +(def-http-return-code +http-see-other+ 303 "See Other") +(def-http-return-code +http-not-modified+ 304 "Not Modified") +(def-http-return-code +http-use-proxy+ 305 "Use Proxy") +(def-http-return-code +http-temporary-redirect+ 307 "Temporary Redirect") +(def-http-return-code +http-bad-request+ 400 "Bad Request") +(def-http-return-code +http-authorization-required+ 401 "Authorization Required") +(def-http-return-code +http-payment-required+ 402 "Payment Required") +(def-http-return-code +http-forbidden+ 403 "Forbidden") +(def-http-return-code +http-not-found+ 404 "Not Found") +(def-http-return-code +http-method-not-allowed+ 405 "Method Not Allowed") +(def-http-return-code +http-not-acceptable+ 406 "Not Acceptable") +(def-http-return-code +http-proxy-authentication-required+ 407 "Proxy Authentication Required") +(def-http-return-code +http-request-time-out+ 408 "Request Time-out") +(def-http-return-code +http-conflict+ 409 "Conflict") +(def-http-return-code +http-gone+ 410 "Gone") +(def-http-return-code +http-length-required+ 411 "Length Required") +(def-http-return-code +http-precondition-failed+ 412 "Precondition Failed") +(def-http-return-code +http-request-entity-too-large+ 413 "Request Entity Too Large") +(def-http-return-code +http-request-uri-too-large+ 414 "Request-URI Too Large") +(def-http-return-code +http-unsupported-media-type+ 415 "Unsupported Media Type") +(def-http-return-code +http-requested-range-not-satisfiable+ 416 "Requested range not satisfiable") +(def-http-return-code +http-expectation-failed+ 417 "Expectation Failed") +(def-http-return-code +http-failed-dependency+ 424 "Failed Dependency") +(def-http-return-code +http-internal-server-error+ 500 "Internal Server Error") +(def-http-return-code +http-not-implemented+ 501 "Not Implemented") +(def-http-return-code +http-bad-gateway+ 502 "Bad Gateway") +(def-http-return-code +http-service-unavailable+ 503 "Service Unavailable") +(def-http-return-code +http-gateway-time-out+ 504 "Gateway Time-out") +(def-http-return-code +http-version-not-supported+ 505 "Version not supported") + +(defvar *approved-return-codes* '(#.+http-ok+ #.+http-no-content+ + #.+http-multi-status+ + #.+http-not-modified+) + "A list of return codes the server should not treat as an error - +see *HANDLE-HTTP-ERRORS-P*.") + +(defconstant +day-names+ + #("Mon" "Tue" "Wed" "Thu" "Fri" "Sat" "Sun") + "The three-character names of the seven days of the week - needed +for cookie date format.") + +(defconstant +month-names+ + #("Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec") + "The three-character names of the twelve months - needed for cookie +date format.") + +(defvar *session-cookie-name* "hunchentoot-session" + "The name of the cookie (or the GET parameter) which is used to +store the session on the client side.") + +(defvar *rewrite-for-session-urls* t + "Whether HTML pages should possibly be rewritten for cookie-less +session-management.") + +(defvar *content-types-for-url-rewrite* + '("text/html" "application/xhtml+xml") + "The content types for which url-rewriting is OK. See +*REWRITE-FOR-SESSION-URLS*.") + +(defparameter *the-random-state* (make-random-state t) + "A fresh random state.") + +(defvar-unbound *session-secret* + "A random value that's used to encode the public session data.") + +(defvar-unbound *hunchentoot-stream* + "The stream representing the socket Hunchentoot is listening on.") + +(defvar *close-hunchentoot-stream* nil + "Will be set to T if the Hunchentoot socket stream has to be +closed at the end of the request.") + +(defvar *headers-sent* nil + "Used internally to check whether the reply headers have +already been sent for this request.") + +(defvar *file-upload-hook* nil + "If this is not NIL, it should be a unary function which will +be called with a pathname for each file which is uploaded to +Hunchentoot. The pathname denotes the temporary file to which +the uploaded file is written. The hook is called directly before +the file is created.") + +(defvar *session-data* nil + "All sessions of all users currently using Hunchentoot. An +alist where the car is the session's ID and the cdr is the +SESSION object itself.") + +(defvar *session-max-time* #.(* 30 60) + "The default time (in seconds) after which a session times out.") + +(defvar *session-gc-frequency* 50 + "A session GC (see function SESSION-GC) will happen every +*SESSION-GC-FREQUENCY* requests (counting only requests which +use a session) if this variable is not NIL.") + +(defvar *use-user-agent-for-sessions* t + "Whether the 'User-Agent' header should be encoded into the session +string. If this value is true, a session will cease to be accessible +if the client sends a different 'User-Agent' header.") + +(defvar *use-remote-addr-for-sessions* nil + "Whether the client's remote IP (as returned by REAL-REMOTE-ADDR) +should be encoded into the session string. If this value is true, a +session will cease to be accessible if the client's remote IP changes. + +This might for example be an issue if the client uses a proxy server +which doesn't send correct 'X_FORWARDED_FOR' headers.") + +(defvar *default-content-type* "text/html; charset=iso-8859-1" + "The default content-type header which is returned to the client.") + +(defvar *methods-for-post-parameters* '(:post) + "A list of the request method types (as keywords) for which +Hunchentoot will try to compute POST-PARAMETERS.") + +(defvar *header-stream* nil + "If this variable is not NIL, it should be bound to a stream to +which incoming and outgoing headers will be written for debugging +purposes.") + +(defvar *show-lisp-errors-p* nil + "Whether Lisp errors should be shown in HTML output.") + +(defvar *show-lisp-backtraces-p* nil + "Whether Lisp backtraces should be shown in HTML output when an +error occurs. Will only have an effect if *SHOW-LISP-ERRORS-P* is +also true.") + +(defvar *log-lisp-errors-p* t + "Whether Lisp errors should be logged.") + +(defvar *log-lisp-warnings-p* t + "Whether Lisp warnings should be logged.") + +(defvar *log-lisp-backtraces-p* nil + "Whether Lisp backtraces should be logged when an error or warning +occurs. Will only have an effect if *LOG-LISP-ERRORS-P* or +*LOG-LISP-BACKTRACES* are also true.") + +(defvar *lisp-errors-log-level* :error + "Log level for Lisp errors.") + +(defvar *lisp-warnings-log-level* :warning + "Log level for Lisp warnings.") + +(defvar *show-access-log-messages* t + "Whether routine messages about each request should be logged. This +will only be done if SERVER-USE-APACHE-LOG-P is NIL.") + +(defvar *log-file* + (load-time-value + (let ((tmp-dir + #+:allegro (system:temporary-directory) + #+:lispworks (pathname (or (lw:environment-variable "TEMP") + (lw:environment-variable "TMP") + #+:win32 "C:/" + #-:win32 "/tmp/")) + #-(or :allegro :lispworks) #p"/tmp/")) + (merge-pathnames "hunchentoot.log" tmp-dir))) + "The log file to use (unless the Apache log is used).") + +(defvar *log-file-stream* nil + "The stream corresponding to the log file.") + +(defvar *log-file-lock* (make-lock "log-file-lock") + "A lock to prevent two threads from writing to the log file at +same time.") + +(defvar-unbound *session* + "The current SESSION object.") + +(defvar-unbound *request* + "The current REQUEST object.") + +(defvar-unbound *reply* + "The current REPLY object.") + +(defvar *log-prefix* t + "The prefix which is printed in front of Apache log +messages. This should be a string or T (for "Hunchentoot", the +default) or NIL (meaning no prefix).") + +(defconstant +implementation-link+ + #+:cmu "http://www.cons.org/cmucl/" + #+:sbcl "http://www.sbcl.org/" + #+:allegro "http://www.franz.com/products/allegrocl/" + #+:lispworks "http://www.lispworks.com/" + #+:openmcl "http://openmcl.clozure.com/" + "A link to the website of the underlying Lisp implementation.") + +(defvar *dispatch-table* (list 'default-dispatcher) + "A list of dispatch functions - see *META-DISPATCHER*.") + +(defvar *default-handler* 'default-handler + "The name of the function which is always returned by +DEFAULT-DISPATCHER.") + +(defvar *easy-handler-alist* nil + "An alist of (URI server-names function) lists defined by +DEFINE-EASY-HANDLER.") + +(defvar *http-error-handler* nil + "Contains NIL (the default) or a function of one argument which is +called if the content handler has set a return code which is not in +*APPROVED-RETURN-CODES* and *HANDLE-HTTP-ERRORS* is true.") + +(defvar *handle-http-errors-p* t + "A generalized boolean that determines whether return codes which +are not in *APPROVED-HEADERS* are treated specially. When its value +is true (the default), either a default body for the return code or +the result of calling *HTTP-ERROR-HANDLER* is used. When the value is +NIL, no special action is taken and you are expected to supply your +own response body to describe the error.") + +(defvar *default-log-level* nil + "The default log level for LOG-MESSAGE*.") + +(defvar *session-data-lock* (make-lock "session-data-lock") + "A lock to prevent two threads from modifying *SESSION-DATA* at the +same time.") + +(defvar *session-removal-hook* (constantly nil) + "A function of one argument (a session object) which is called +whenever a session is garbage-collected.") + +(defvar *tmp-directory* + #+(or :win32 :mswindows) "c:\hunchentoot-temp\" + #-(or :win32 :mswindows) "/tmp/hunchentoot/" + "Directory for temporary files created by MAKE-TMP-FILE-NAME.") + +(defvar *tmp-files* nil + "A list of temporary files created while a request was handled.") + +(defconstant +latin-1+ + (make-external-format :latin1 :eol-style :lf) + "A FLEXI-STREAMS external format used for `faithful' input and +output of binary data.") + +(defconstant +utf-8+ + (make-external-format :utf8 :eol-style :lf) + "A FLEXI-STREAMS external format used internally for logging and to +encode cookie values.") + +(defvar *hunchentoot-default-external-format* +latin-1+ + "The external format used to compute the REQUEST object.") + +(defconstant +buffer-length+ 8192 + "Length of buffers used for internal purposes.") + +(defvar-unbound *server* + "During the execution of dispatchers and handlers this variable +is bound to the SERVER object which processes the request.") + +(defvar *meta-dispatcher* (lambda (server) + (declare (ignore server)) + *dispatch-table*) + "The value of this variable should be a function of one argument. +It is called with the current Hunchentoot server instance (unless the +server has its own dispatch table) and must return a suitable dispatch +table. The initial value is a function which always unconditionally +returns *DISPATCH-TABLE*.") + +(defvar *server-counter* 0 + "Internal counter used to generate meaningful names for +listener threads.") + +(defvar *worker-counter* 0 + "Internal counter used to generate meaningful names for worker +threads.") + +(defvar *default-read-timeout* 20 + "The default read-timeout used when a Hunchentoot server is +reading from a socket stream.") + +(defvar *default-write-timeout* 20 + "The default write-timeout used when a Hunchentoot server is +writing to a socket stream.") + +(defvar *force-output-timeout* 30 + "The maximal time Hunchentoot waits for FORCE-OUTPUT to +return.") + +(defvar *cleanup-interval* 100 + "Should be NIL or a positive integer. The system calls +*CLEANUP-FUNCTION* whenever *CLEANUP-INTERVAL* new worker threads have +been created unless the value is NIL.") + +(defvar *cleanup-function* 'cleanup-function + "The function which is called if *CLEANUP-INTERVAL* is not NIL.") + +(defvar-unbound *local-host* + "Bound to a string denoting the address at which the current +request arrived.") + +(defvar-unbound *remote-host* + "Bound to a string denoting the address the current request +originated from.") + +(defvar-unbound *remote-port* + "Bound to an integer denoting the port the current request +originated from.") + +(pushnew :hunchentoot *features*) + +;; stuff for Nikodemus Siivola's HYPERDOC +;; see http://common-lisp.net/project/hyperdoc/ +;; and http://www.cliki.net/hyperdoc + +(defvar *hyperdoc-base-uri* "http://weitz.de/hunchentoot/") + +(let ((exported-symbols-alist + (loop for symbol being the external-symbols of :hunchentoot + collect (cons symbol (concatenate 'string "#" (string-downcase symbol)))))) + (defun hyperdoc-lookup (symbol type) + (declare (ignore type)) + (cdr (assoc symbol exported-symbols-alist :test #'eq))))
Property changes on: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/specials.lisp ___________________________________________________________________ Name: svn:executable + *
Added: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/test/UTF-8-demo.html =================================================================== --- branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/test/UTF-8-demo.html 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/test/UTF-8-demo.html 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,213 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head><title>UTF-8 test file</title></head> + <body> + <p>Original by Markus Kuhn, adapted for HTML by Martin Dürst.</p> +<pre> +UTF-8 encoded sample plain-text file +‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ + +Markus Kuhn [ˈmaʳkʊs kuːn] <mkuhn@acm.org> — 1999-08-20 + + +The ASCII compatible UTF-8 encoding of ISO 10646 and Unicode +plain-text files is defined in RFC 2279 and in ISO 10646-1 Annex R. + + +Using Unicode/UTF-8, you can write in emails and source code things such as + +Mathematics and Sciences: + + ∮ E⋅da = Q, n → ∞, ∑ f(i) = ∏ g(i), ∀x∈ℝ: ⌈x⌉ = −⌊−x⌋, α ∧ ¬β = ¬(¬α ∨ β), + + ℕ ⊆ ℕ₀ ⊂ ℤ ⊂ ℚ ⊂ ℝ ⊂ ℂ, ⊥ < a ≠ b ≡ c ≤ d ≪ ⊤ ⇒ (A ⇔ B), + + 2H₂ + O₂ ⇌ 2H₂O, R = 4.7 kΩ, ⌀ 200 mm + +Linguistics and dictionaries: + + ði ıntəˈnæʃənəl fəˈnɛtık əsoʊsiˈeıʃn + Y [ˈʏpsilɔn], Yen [jɛn], Yoga [ˈjoːgɑ] + +APL: + + ((V⍳V)=⍳⍴V)/V←,V ⌷←⍳→⍴∆∇⊃‾⍎⍕⌈ + +Nicer typography in plain text files: + + ╔══════════════════════════════════════════╗ + ║ ║ + ║ • ‘single’ and “double” quotes ║ + ║ ║ + ║ • Curly apostrophes: “We’ve been here” ║ + ║ ║ + ║ • Latin-1 apostrophe and accents: '´` ║ + ║ ║ + ║ • ‚deutsche‘ „Anführungszeichen“ ║ + ║ ║ + ║ • †, ‡, ‰, •, 3–4, —, −5/+5, ™, … ║ + ║ ║ + ║ • ASCII safety test: 1lI|, 0OD, 8B ║ + ║ ╭─────────╮ ║ + ║ • the euro symbol: │ 14.95 € │ ║ + ║ ╰─────────╯ ║ + ╚══════════════════════════════════════════╝ + +Greek (in Polytonic): + + The Greek anthem: + + Σὲ γνωρίζω ἀπὸ τὴν κόψη + τοῦ σπαθιοῦ τὴν τρομερή, + σὲ γνωρίζω ἀπὸ τὴν ὄψη + ποὺ μὲ βία μετράει τὴ γῆ. + + ᾿Απ᾿ τὰ κόκκαλα βγαλμένη + τῶν ῾Ελλήνων τὰ ἱερά + καὶ σὰν πρῶτα ἀνδρειωμένη + χαῖρε, ὦ χαῖρε, ᾿Ελευθεριά! + + From a speech of Demosthenes in the 4th century BC: + + Οὐχὶ ταὐτὰ παρίσταταί μοι γιγνώσκειν, ὦ ἄνδρες ᾿Αθηναῖοι, + ὅταν τ᾿ εἰς τὰ πράγματα ἀποβλέψω καὶ ὅταν πρὸς τοὺς + λόγους οὓς ἀκούω· τοὺς μὲν γὰρ λόγους περὶ τοῦ + τιμωρήσασθαι Φίλιππον ὁρῶ γιγνομένους, τὰ δὲ πράγματ᾿ + εἰς τοῦτο προήκοντα, ὥσθ᾿ ὅπως μὴ πεισόμεθ᾿ αὐτοὶ + πρότερον κακῶς σκέψασθαι δέον. οὐδέν οὖν ἄλλο μοι δοκοῦσιν + οἱ τὰ τοιαῦτα λέγοντες ἢ τὴν ὑπόθεσιν, περὶ ἧς βουλεύεσθαι, + οὐχὶ τὴν οὖσαν παριστάντες ὑμῖν ἁμαρτάνειν. ἐγὼ δέ, ὅτι μέν + ποτ᾿ ἐξῆν τῇ πόλει καὶ τὰ αὑτῆς ἔχειν ἀσφαλῶς καὶ Φίλιππον + τιμωρήσασθαι, καὶ μάλ᾿ ἀκριβῶς οἶδα· ἐπ᾿ ἐμοῦ γάρ, οὐ πάλαι + γέγονεν ταῦτ᾿ ἀμφότερα· νῦν μέντοι πέπεισμαι τοῦθ᾿ ἱκανὸν + προλαβεῖν ἡμῖν εἶναι τὴν πρώτην, ὅπως τοὺς συμμάχους + σώσομεν. ἐὰν γὰρ τοῦτο βεβαίως ὑπάρξῃ, τότε καὶ περὶ τοῦ + τίνα τιμωρήσεταί τις καὶ ὃν τρόπον ἐξέσται σκοπεῖν· πρὶν δὲ + τὴν ἀρχὴν ὀρθῶς ὑποθέσθαι, μάταιον ἡγοῦμαι περὶ τῆς + τελευτῆς ὁντινοῦν ποιεῖσθαι λόγον. + + Δημοσθένους, Γ´ ᾿Ολυνθιακὸς + +Georgian: + + From a Unicode conference invitation: + + გთხოვთ ახლავე გაიაროთ რეგისტრაცია Unicode-ის მეათე საერთაშორისო + კონფერენციაზე დასასწრებად, რომელიც გაიმართება 10-12 მარტს, + ქ. მაინცში, გერმანიაში. კონფერენცია შეჰკრებს ერთად მსოფლიოს + ექსპერტებს ისეთ დარგებში როგორიცაა ინტერნეტი და Unicode-ი, + ინტერნაციონალიზაცია და ლოკალიზაცია, Unicode-ის გამოყენება + ოპერაციულ სისტემებსა, და გამოყენებით პროგრამებში, შრიფტებში, + ტექსტების დამუშავებასა და მრავალენოვან კომპიუტერულ სისტემებში. + +Russian: + + From a Unicode conference invitation: + + Зарегистрируйтесь сейчас на Десятую Международную Конференцию по + Unicode, которая состоится 10-12 марта 1997 года в Майнце в Германии. + Конференция соберет широкий круг экспертов по вопросам глобального + Интернета и Unicode, локализации и интернационализации, воплощению и + применению Unicode в различных операционных системах и программных + приложениях, шрифтах, верстке и многоязычных компьютерных системах. + +Thai (UCS Level 2): + + Excerpt from a poetry on The Romance of The Three Kingdoms (a Chinese + classic 'San Gua'): + + [----------------------------|------------------------] + ๏ แผ่นดินฮั่นเสื่อมโทรมแสนสังเวช พระปกเกศกองบู๊กู้ขึ้นใหม่ + สิบสองกษัตริย์ก่อนหน้าแลถัดไป สององค์ไซร้โง่เขลาเบาปัญญา + ทรงนับถือขันทีเป็นที่พึ่ง บ้านเมืองจึงวิปริตเป็นนักหนา + โฮจิ๋นเรียกทัพทั่วหัวเมืองมา หมายจะฆ่ามดชั่วตัวสำคัญ + เหมือนขับไสไล่เสือจากเคหา รับหมาป่าเข้ามาเลยอาสัญ + ฝ่ายอ้องอุ้นยุแยกให้แตกกัน ใช้สาวนั้นเป็นชนวนชื่นชวนใจ + พลันลิฉุยกุยกีกลับก่อเหตุ ช่างอาเพศจริงหนาฟ้าร้องไห้ + ต้องรบราฆ่าฟันจนบรรลัย ฤๅหาใครค้ำชูกู้บรรลังก์ ฯ + + (The above is a two-column text. If combining characters are handled + correctly, the lines of the second column should be aligned with the + | character above.) + +Ethiopian: + + Proverbs in the Amharic language: + + ሰማይ አይታረስ ንጉሥ አይከሰስ። + ብላ ካለኝ እንደአባቴ በቆመጠኝ። + ጌጥ ያለቤቱ ቁምጥና ነው። + ደሀ በሕልሙ ቅቤ ባይጠጣ ንጣት በገደለው። + የአፍ ወለምታ በቅቤ አይታሽም። + አይጥ በበላ ዳዋ ተመታ። + ሲተረጉሙ ይደረግሙ። + ቀስ በቀስ፥ ዕንቁላል በእግሩ ይሄዳል። + ድር ቢያብር አንበሳ ያስር። + ሰው እንደቤቱ እንጅ እንደ ጉረቤቱ አይተዳደርም። + እግዜር የከፈተውን ጉሮሮ ሳይዘጋው አይድርም። + የጎረቤት ሌባ፥ ቢያዩት ይስቅ ባያዩት ያጠልቅ። + ሥራ ከመፍታት ልጄን ላፋታት። + ዓባይ ማደሪያ የለው፥ ግንድ ይዞ ይዞራል። + የእስላም አገሩ መካ የአሞራ አገሩ ዋርካ። + ተንጋሎ ቢተፉ ተመልሶ ባፉ። + ወዳጅህ ማር ቢሆን ጨርስህ አትላሰው። + እግርህን በፍራሽህ ልክ ዘርጋ። + +Runes: + + ᚻᛖ ᚳᚹᚫᚦ ᚦᚫᛏ ᚻᛖ ᛒᚢᛞᛖ ᚩᚾ ᚦᚫᛗ ᛚᚪᚾᛞᛖ ᚾᚩᚱᚦᚹᛖᚪᚱᛞᚢᛗ ᚹᛁᚦ ᚦᚪ ᚹᛖᛥᚫ + + (Old English, which transcribed into Latin reads 'He cwaeth that he + bude thaem lande northweardum with tha Westsae.' and means 'He said + that he lived in the northern land near the Western Sea.') + +Braille: + + ⡌⠁⠧⠑ ⠼⠁⠒ ⡍⠜⠇⠑⠹⠰⠎ ⡣⠕⠌ + + ⡍⠜⠇⠑⠹ ⠺⠁⠎ ⠙⠑⠁⠙⠒ ⠞⠕ ⠃⠑⠛⠔ ⠺⠊⠹⠲ ⡹⠻⠑ ⠊⠎ ⠝⠕ ⠙⠳⠃⠞ + ⠱⠁⠞⠑⠧⠻ ⠁⠃⠳⠞ ⠹⠁⠞⠲ ⡹⠑ ⠗⠑⠛⠊⠌⠻ ⠕⠋ ⠙⠊⠎ ⠃⠥⠗⠊⠁⠇ ⠺⠁⠎ + ⠎⠊⠛⠝⠫ ⠃⠹ ⠹⠑ ⠊⠇⠻⠛⠹⠍⠁⠝⠂ ⠹⠑ ⠊⠇⠻⠅⠂ ⠹⠑ ⠥⠝⠙⠻⠞⠁⠅⠻⠂ + ⠁⠝⠙ ⠹⠑ ⠡⠊⠑⠋ ⠍⠳⠗⠝⠻⠲ ⡎⠊⠗⠕⠕⠛⠑ ⠎⠊⠛⠝⠫ ⠊⠞⠲ ⡁⠝⠙ + ⡎⠊⠗⠕⠕⠛⠑⠰⠎ ⠝⠁⠍⠑ ⠺⠁⠎ ⠛⠕⠕⠙ ⠥⠏⠕⠝ ⠰⡡⠁⠝⠛⠑⠂ ⠋⠕⠗ ⠁⠝⠹⠹⠔⠛ ⠙⠑ + ⠡⠕⠎⠑ ⠞⠕ ⠏⠥⠞ ⠙⠊⠎ ⠙⠁⠝⠙ ⠞⠕⠲ + + ⡕⠇⠙ ⡍⠜⠇⠑⠹ ⠺⠁⠎ ⠁⠎ ⠙⠑⠁⠙ ⠁⠎ ⠁ ⠙⠕⠕⠗⠤⠝⠁⠊⠇⠲ + + ⡍⠔⠙⠖ ⡊ ⠙⠕⠝⠰⠞ ⠍⠑⠁⠝ ⠞⠕ ⠎⠁⠹ ⠹⠁⠞ ⡊ ⠅⠝⠪⠂ ⠕⠋ ⠍⠹ + ⠪⠝ ⠅⠝⠪⠇⠫⠛⠑⠂ ⠱⠁⠞ ⠹⠻⠑ ⠊⠎ ⠏⠜⠞⠊⠊⠥⠇⠜⠇⠹ ⠙⠑⠁⠙ ⠁⠃⠳⠞ + ⠁ ⠙⠕⠕⠗⠤⠝⠁⠊⠇⠲ ⡊ ⠍⠊⠣⠞ ⠙⠁⠧⠑ ⠃⠑⠲ ⠔⠊⠇⠔⠫⠂ ⠍⠹⠎⠑⠇⠋⠂ ⠞⠕ + ⠗⠑⠛⠜⠙ ⠁ ⠊⠕⠋⠋⠔⠤⠝⠁⠊⠇ ⠁⠎ ⠹⠑ ⠙⠑⠁⠙⠑⠌ ⠏⠊⠑⠊⠑ ⠕⠋ ⠊⠗⠕⠝⠍⠕⠝⠛⠻⠹ + ⠔ ⠹⠑ ⠞⠗⠁⠙⠑⠲ ⡃⠥⠞ ⠹⠑ ⠺⠊⠎⠙⠕⠍ ⠕⠋ ⠳⠗ ⠁⠝⠊⠑⠌⠕⠗⠎ + ⠊⠎ ⠔ ⠹⠑ ⠎⠊⠍⠊⠇⠑⠆ ⠁⠝⠙ ⠍⠹ ⠥⠝⠙⠁⠇⠇⠪⠫ ⠙⠁⠝⠙⠎ + ⠩⠁⠇⠇ ⠝⠕⠞ ⠙⠊⠌⠥⠗⠃ ⠊⠞⠂ ⠕⠗ ⠹⠑ ⡊⠳⠝⠞⠗⠹⠰⠎ ⠙⠕⠝⠑ ⠋⠕⠗⠲ ⡹⠳ + ⠺⠊⠇⠇ ⠹⠻⠑⠋⠕⠗⠑ ⠏⠻⠍⠊⠞ ⠍⠑ ⠞⠕ ⠗⠑⠏⠑⠁⠞⠂ ⠑⠍⠏⠙⠁⠞⠊⠊⠁⠇⠇⠹⠂ ⠹⠁⠞ + ⡍⠜⠇⠑⠹ ⠺⠁⠎ ⠁⠎ ⠙⠑⠁⠙ ⠁⠎ ⠁ ⠙⠕⠕⠗⠤⠝⠁⠊⠇⠲ + + (The first couple of paragraphs of "A Christmas Carol" by Dickens) + +Compact font selection example text: + + ABCDEFGHIJKLMNOPQRSTUVWXYZ /0123456789 + abcdefghijklmnopqrstuvwxyz £©µÀÆÖÞßéöÿ + –—‘“”„†•…‰™œŠŸž€ ΑΒΓΔΩαβγδω АБВГДабвгд + ∀∂∈ℝ∧∪≡∞ ↑↗↨↻⇣ ┐┼╔╘░►☺♀ fi�⑀₂ἠḂӥẄɐː⍎אԱა + +Greetings in various languages: + + Hello world, Καλημέρα κόσμε, コンニチハ + +Box drawing alignment tests: █ + ▉ + ╔══╦══╗ ┌──┬──┐ ╭──┬──╮ ╭──┬──╮ ┏━━┳━━┓ ┎┒┏┑ ╷ ╻ ┏┯┓ ┌┰┐ ▊ ╱╲╱╲╳╳╳ + ║┌─╨─┐║ │╔═╧═╗│ │╒═╪═╕│ │╓─╁─╖│ ┃┌─╂─┐┃ ┗╃╄┙ ╶┼╴╺╋╸┠┼┨ ┝╋┥ ▋ ╲╱╲╱╳╳╳ + ║│╲ ╱│║ │║ ║│ ││ │ ││ │║ ┃ ║│ ┃│ ╿ │┃ ┍╅╆┓ ╵ ╹ ┗┷┛ └┸┘ ▌ ╱╲╱╲╳╳╳ + ╠╡ ╳ ╞╣ ├╢ ╟┤ ├┼─┼─┼┤ ├╫─╂─╫┤ ┣┿╾┼╼┿┫ ┕┛┖┚ ┌┄┄┐ ╎ ┏┅┅┓ ┋ ▍ ╲╱╲╱╳╳╳ + ║│╱ ╲│║ │║ ║│ ││ │ ││ │║ ┃ ║│ ┃│ ╽ │┃ ░░▒▒▓▓██ ┊ ┆ ╎ ╏ ┇ ┋ ▎ + ║└─╥─┘║ │╚═╤═╝│ │╘═╪═╛│ │╙─╀─╜│ ┃└─╂─┘┃ ░░▒▒▓▓██ ┊ ┆ ╎ ╏ ┇ ┋ ▏ + ╚══╩══╝ └──┴──┘ ╰──┴──╯ ╰──┴──╯ ┗━━┻━━┛ └╌╌┘ ╎ ┗╍╍┛ ┋ ▁▂▃▄▅▆▇█ + +</pre> +</body> +</html>
Added: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/test/favicon.ico =================================================================== (Binary files differ)
Property changes on: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/test/favicon.ico ___________________________________________________________________ Name: svn:executable + * Name: svn:mime-type + application/octet-stream
Added: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/test/fz.jpg =================================================================== (Binary files differ)
Property changes on: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/test/fz.jpg ___________________________________________________________________ Name: svn:mime-type + application/octet-stream
Added: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/test/packages.lisp =================================================================== --- branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/test/packages.lisp 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/test/packages.lisp 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,37 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-USER; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/hunchentoot/test/packages.lisp,v 1.4 2007/01/01 23:50:32 edi Exp $ + +;;; Copyright (c) 2004-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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-package :cl-user) + +(defpackage :hunchentoot-test + (:nicknames :tbnl-test) + (:use :cl :cl-who :hunchentoot)) + +(defpackage :hunchentoot-test-user + (:use :cl :hunchentoot)) \ No newline at end of file
Property changes on: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/test/packages.lisp ___________________________________________________________________ Name: svn:executable + *
Added: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/test/test.lisp =================================================================== --- branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/test/test.lisp 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/test/test.lisp 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,582 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: HUNCHENTOOT; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/hunchentoot/test/test.lisp,v 1.20 2007/09/18 14:24:01 edi Exp $ + +;;; Copyright (c) 2004-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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-package :hunchentoot-test) + +(defvar *this-file* (load-time-value + (or #.*compile-file-pathname* *load-pathname*))) + +(defmacro with-html (&body body) + `(with-html-output-to-string (*standard-output* nil :prologue t) + ,@body)) + +(defun hunchentoot-link () + (with-html-output (*standard-output*) + (:a :href "http://weitz.de/hunchentoot/" "Hunchentoot"))) + +(defun menu-link () + (with-html-output (*standard-output*) + (:p (:hr + (:a :href "/hunchentoot/test" "Back to menu"))))) + +(defmacro with-lisp-output ((var) &body body) + `(let ((*package* (find-package :hunchentoot-test-user))) + (with-output-to-string (,var #+:lispworks nil + #+:lispworks :element-type + #+:lispworks 'lw:simple-char) + ,@body))) + +(defmacro info-table (&rest forms) + (let ((=value= (gensym)) + (=first= (gensym))) + `(with-html-output (*standard-output*) + (:p (:table :border 1 :cellpadding 2 :cellspacing 0 + (:tr (:td :colspan 2 + "Some Information " + (hunchentoot-link) + " provides about this request:")) + ,@(loop for form in forms + collect `(:tr (:td :valign "top" + (:pre :style "padding: 0px" + (esc (with-lisp-output (s) (pprint ',form s))))) + (:td :valign "top" + (:pre :style "padding: 0px" + (esc (with-lisp-output (s) + (loop for ,=value= in (multiple-value-list ,form) + for ,=first= = t then nil + unless ,=first= + do (princ ", " s) + do (pprint ,=value= s)))))))))) + (menu-link)))) + +(defun authorization-page () + (multiple-value-bind (user password) + (authorization) + (cond ((and (equal user "nanook") + (equal password "igloo")) + (with-html + (:html + (:head (:title "Hunchentoot page with Basic Authentication")) + (:body + (:h2 (hunchentoot-link) + " page with Basic Authentication") + (info-table (header-in "Authorization") + (authorization)))))) + (t + (require-authorization))))) + +(defparameter *test-image* + (load-time-value + (with-open-file (in (make-pathname :name "fz" :type "jpg" :version nil + :defaults *this-file*) + :element-type '(unsigned-byte 8)) + (let ((image-data (make-array (file-length in) + :element-type '(unsigned-byte 8)))) + (read-sequence image-data in) + image-data)))) + +(defun image-ram-page () + (setf (content-type) + "image/jpeg") + *test-image*) + +(let ((count 0)) + (defun info () + (with-html + (:html + (:head (:title "Hunchentoot Information")) + (:body + (:h2 (hunchentoot-link) " Information Page") + (:p "This page has been called " + (:b + (fmt "~[~;once~;twice~:;~:*~R times~]" (incf count))) + " since its handler was compiled.") + (info-table (host) + (server-address *server*) + (server-addr) + (server-port) + (remote-addr) + (remote-port) + (real-remote-addr) + (request-method) + (script-name) + (query-string) + (get-parameters) + (headers-in) + (cookies-in) + (user-agent) + (referer) + (request-uri) + (server-protocol) + (mod-lisp-id) + (ssl-session-id))))))) + +(defun oops () + (with-html + (dotimes (i 3) + (log-message* "Oops (default) # ~a" i)) + (log-message :emerg "Oops emergency") + (log-message :alert "Oops alert") + (log-message :crit "Oops critical") + (log-message :error "Oops error") + (log-message :warning "Oops warning") + (log-message :notice "Oops notice") + (log-message :info "Oops info") + (log-message :debug "Oops debug") + (error "An error was triggered on purpose. Check your ~ +Apache error log. Up to 12 messages where logged depending on ~ +the Apache log level set in httpd.conf.") + (:html + (:body "You'll never see this sentence...")))) + +(defun redir () + (redirect "/hunchentoot/test/info.html?redirected=1")) + +(defun forbidden () + (setf (return-code *reply*) +http-forbidden+) + nil) + +(defun cookie-test () + (set-cookie "pumpkin" :value "barking") + (no-cache) + (with-html + (:html + (:head (:title "Hunchentoot cookie test")) + (:body + (:h2 (hunchentoot-link) + " cookie test") + (:p "You might have to reload this page to see the cookie value.") + (info-table (cookie-in "pumpkin") + (mapcar #'car (cookies-in))))))) + +(defun session-test () + (let ((new-foo-value (post-parameter "new-foo-value"))) + (when new-foo-value + (setf (session-value 'foo) new-foo-value))) + (let ((new-bar-value (post-parameter "new-bar-value"))) + (when new-bar-value + (setf (session-value 'bar) new-bar-value))) + (no-cache) + (with-html + (:html + (:head (:title "Hunchentoot session test")) + (:body + (:h2 (hunchentoot-link) + " session test") + (:p "Use the forms below to set new values for " + (:code "FOO") + " or " + (:code "BAR") + ". You can later return to this page to check if +they're still set. Also, try to use another browser at the same +time or try with cookies disabled.") + (:p (:form :method :post + "New value for " + (:code "FOO") + ": " + (:input :type :text + :name "new-foo-value" + :value (or (session-value 'foo) "")))) + (:p (:form :method :post + "New value for " + (:code "BAR") + ": " + (:input :type :text + :name "new-bar-value" + :value (or (session-value 'bar) "")))) + (info-table *session-cookie-name* + (cookie-in *session-cookie-name*) + (mapcar #'car (cookies-in)) + (session-value 'foo) + (session-value 'bar)))))) + +(defun parameter-test (&key (method :get) (charset :iso-8859-1)) + (no-cache) + (recompute-request-parameters :external-format + (flexi-streams:make-external-format charset :eol-style :lf)) + (setf (content-type) + (format nil "text/html; charset=~A" charset)) + (with-html + (:html + (:head (:title (fmt "Hunchentoot ~A parameter test" method))) + (:body + (:h2 (hunchentoot-link) + (fmt " ~A parameter test with charset ~A" method charset)) + (:p "Enter some non-ASCII characters in the input field below +and see what's happening.") + (:p (:form + :method method + "Enter a value: " + (:input :type :text + :name "foo"))) + (case method + (:get (info-table (query-string) + (map 'list #'char-code (get-parameter "foo")) + (get-parameter "foo"))) + (:post (info-table (raw-post-data) + (map 'list #'char-code (post-parameter "foo")) + (post-parameter "foo")))))))) + +(defun parameter-test-latin1-get () + (parameter-test :method :get :charset :iso-8859-1)) + +(defun parameter-test-latin1-post () + (parameter-test :method :post :charset :iso-8859-1)) + +(defun parameter-test-utf8-get () + (parameter-test :method :get :charset :utf-8)) + +(defun parameter-test-utf8-post () + (parameter-test :method :post :charset :utf-8)) + +;; this should not be the same directory as *TMP-DIRECTORY* and it +;; should be initially empty (or non-existent) +(defvar *tmp-test-directory* + #+(or :win32 :mswindows) #p"c:\hunchentoot-temp\test\" + #-(or :win32 :mswindows) #p"/tmp/hunchentoot/test/") + +(defvar *tmp-test-files* nil) + +(let ((counter 0)) + (defun handle-file (post-parameter) + (when (and post-parameter + (listp post-parameter)) + (destructuring-bind (path file-name content-type) + post-parameter + (let ((new-path (make-pathname :name (format nil "hunchentoot-test-~A" + (incf counter)) + :type nil + :defaults *tmp-test-directory*))) + ;; strip directory info sent by Windows browsers + (when (search "Windows" (user-agent) :test #'char-equal) + (setq file-name (cl-ppcre:regex-replace ".*\\" file-name ""))) + (rename-file path (ensure-directories-exist new-path)) + (push (list new-path file-name content-type) *tmp-test-files*)))))) + +(defun clean-tmp-dir () + (loop for (path . nil) in *tmp-test-files* + when (probe-file path) + do (ignore-errors (delete-file path))) + (setq *tmp-test-files* nil)) + +(defun upload-test () + (let (post-parameter-p) + (when (post-parameter "file1") + (handle-file (post-parameter "file1")) + (setq post-parameter-p t)) + (when (post-parameter "file2") + (handle-file (post-parameter "file2")) + (setq post-parameter-p t)) + (when (post-parameter "clean") + (clean-tmp-dir) + (setq post-parameter-p t)) + (when post-parameter-p + ;; redirect so user can safely use 'Back' button + (redirect (script-name)))) + (no-cache) + (with-html + (:html + (:head (:title "Hunchentoot file upload test")) + (:body + (:h2 (hunchentoot-link) + " file upload test") + (:form :method :post :enctype "multipart/form-data" + (:p "First file: " + (:input :type :file + :name "file1")) + (:p "Second file: " + (:input :type :file + :name "file2")) + (:p (:input :type :submit))) + (when *tmp-test-files* + (htm + (:p + (:table :border 1 :cellpadding 2 :cellspacing 0 + (:tr (:td :colspan 3 (:b "Uploaded files"))) + (loop for (path file-name nil) in *tmp-test-files* + for counter from 1 + do (htm + (:tr (:td :align "right" (str counter)) + (:td (:a :href (format nil "files/~A?path=~A" + (url-encode file-name) + (url-encode (namestring path))) + (esc file-name))) + (:td :align "right" + (str (ignore-errors + (with-open-file (in path) + (file-length in)))) + " Bytes")))))) + (:form :method :post + (:p (:input :type :submit :name "clean" :value "Delete uploaded files"))))) + (menu-link))))) + +(defun send-file () + (let* ((path (get-parameter "path")) + (file-info (and path + (find (pathname path) *tmp-test-files* + :key #'first :test #'equal)))) + (unless file-info + (setf (return-code *reply*) + +http-not-found+) + (return-from send-file)) + (handle-static-file path (third file-info)))) + +(defparameter *headline* + (load-time-value + (format nil "Hunchentoot test menu (see file <code>~A</code>)" + (merge-pathnames (make-pathname :type "lisp") *this-file*)))) + +(defvar *utf-8* (flex:make-external-format :utf-8 :eol-style :lf)) + +(defvar *utf-8-file* (merge-pathnames "UTF-8-demo.html" *this-file*) + "Demo file stolen from http://www.w3.org/2001/06/utf-8-test/.") + +(defun stream-direct () + (setf (content-type) "text/html; charset=utf-8") + (let ((stream (send-headers)) + (buffer (make-array 1024 :element-type '(unsigned-byte 8)))) + (with-open-file (in *utf-8-file* + :element-type '(unsigned-byte 8)) + (loop for pos = (read-sequence buffer in) + until (zerop pos) + do (write-sequence buffer stream :end pos))))) + +(defun stream-direct-utf-8 () + (setf (content-type) "text/html; charset=utf-8") + (let ((stream (send-headers))) + (setf (flex:flexi-stream-external-format stream) *utf-8*) + (with-open-file (in (merge-pathnames "UTF-8-demo.html" *this-file*) + :element-type '(unsigned-byte 8)) + (setq in (flex:make-flexi-stream in :external-format *utf-8*)) + (loop for line = (read-line in nil nil) + while line + do (write-line line stream))))) + +(defun stream-direct-utf-8-string () + (setf (content-type) "text/html; charset=utf-8" + (reply-external-format) *utf-8*) + (with-open-file (in (merge-pathnames "UTF-8-demo.html" *this-file*) + :element-type '(unsigned-byte 8)) + (let ((string (make-array (file-length in) + :element-type #-:lispworks 'character #+:lispworks 'lw:simple-char + :fill-pointer t))) + (setf in (flex:make-flexi-stream in :external-format *utf-8*) + (fill-pointer string) (read-sequence string in)) + string))) + +(define-easy-handler (easy-demo :uri "/hunchentoot/test/easy-demo.html" + :default-request-type :post) + (first-name last-name + (age :parameter-type 'integer) + (implementation :parameter-type 'keyword) + (meal :parameter-type '(hash-table boolean)) + (team :parameter-type 'list)) + (with-html + (:html + (:head (:title "Hunchentoot "easy" handler example")) + (:body + (:h2 (hunchentoot-link) + " "Easy" handler example") + (:p (:form :method :post + (:table :border 1 :cellpadding 2 :cellspacing 0 + (:tr + (:td "First Name:") + (:td (:input :type :text + :name "first-name" + :value (or first-name "Donald")))) + (:tr + (:td "Last name:") + (:td (:input :type :text + :name "last-name" + :value (or last-name "Duck")))) + (:tr + (:td "Age:") + (:td (:input :type :text + :name "age" + :value (or age 42)))) + (:tr + (:td "Implementation:") + (:td (:select :name "implementation" + (loop for (value option) in '((:lispworks "LispWorks") + (:allegro "AllegroCL") + (:cmu "CMUCL") + (:sbcl "SBCL") + (:openmcl "OpenMCL")) + do (htm + (:option :value value + :selected (eq value implementation) + (str option))))))) + (:tr + (:td :valign :top "Meal:") + (:td (loop for choice in '("Burnt weeny sandwich" + "Canard du jour" + "Easy meat" + "Muffin" + "Twenty small cigars" + "Yellow snow") + do (htm + (:input :type "checkbox" + :name (format nil "meal{~A}" choice) + :checked (gethash choice meal) + (esc choice)) + (:br))))) + (:tr + (:td :valign :top "Team:") + (:td (loop for player in '("Beckenbauer" + "Cruyff" + "Maradona" + ;; without accent (for SBCL) + "Pele" + "Zidane") + do (htm + (:input :type "checkbox" + :name "team" + :value player + :checked (member player team :test #'string=) + (esc player)) + (:br))))) + (:tr + (:td :colspan 2 + (:input :type "submit")))))) + (info-table first-name + last-name + age + implementation + (loop :for choice :being :the :hash-keys :of meal :collect choice) + (gethash "Yellow snow" meal) + team))))) + + +(defun menu () + (with-html + (:html + (:head + (:link :rel "shortcut icon" + :href "/hunchentoot/test/favicon.ico" :type "image/x-icon") + (:title "Hunchentoot test menu")) + (:body + (:h2 (str *headline*)) + (:table :border 0 :cellspacing 4 :cellpadding 4 + (:tr (:td (:a :href "/hunchentoot/test/info.html?foo=bar" + "Info provided by Hunchentoot"))) + (:tr (:td (:a :href "/hunchentoot/test/cookie.html" + "Cookie test"))) + (:tr (:td (:a :href "/hunchentoot/test/session.html" + "Session test"))) + (:tr (:td (:a :href "/hunchentoot/test/parameter_latin1_get.html" + "GET parameter handling with LATIN-1 charset"))) + (:tr (:td (:a :href "/hunchentoot/test/parameter_latin1_post.html" + "POST parameter handling with LATIN-1 charset"))) + (:tr (:td (:a :href "/hunchentoot/test/parameter_utf8_get.html" + "GET parameter handling with UTF-8 charset"))) + (:tr (:td (:a :href "/hunchentoot/test/parameter_utf8_post.html" + "POST parameter handling with UTF-8 charset"))) + (:tr (:td (:a :href "/hunchentoot/test/redir.html" + "Redirect (302) to info page above"))) + (:tr (:td (:a :href "/hunchentoot/test/authorization.html" + "Authorization") + " (user 'nanook', password 'igloo')")) + (:tr (:td (:a :href "/hunchentoot/code/test.lisp" + "The source code of this test"))) + (:tr (:td (:a :href "/hunchentoot/test/image.jpg" + "Binary data, delivered from file") + " (a picture)")) + (:tr (:td (:a :href "/hunchentoot/test/image-ram.jpg" + "Binary data, delivered from RAM") + " (same picture)")) + (:tr (:td (:a :href "/hunchentoot/test/easy-demo.html" + ""Easy" handler example"))) + (:tr (:td (:a :href "/hunchentoot/test/utf8-binary.txt" + "UTF-8 demo") + " (writing octets directly to the stream)")) + (:tr (:td (:a :href "/hunchentoot/test/utf8-character.txt" + "UTF-8 demo") + " (writing UTF-8 characters directly to the stream)")) + (:tr (:td (:a :href "/hunchentoot/test/utf8-string.txt" + "UTF-8 demo") + " (returning a string)")) + (:tr (:td (:a :href "/hunchentoot/test/upload.html" + "File uploads"))) + (:tr (:td (:a :href "/hunchentoot/test/forbidden.html" + "Forbidden (403) page"))) + (:tr (:td (:a :href "/hunchentoot/test/oops.html" + "Error handling") + " (output depends on settings like " + (:a :href "http://weitz.de/hunchentoot/#*show-lisp-errors-p*" + (:code "*SHOW-LISP-ERRORS-P*")) + (fmt " (currently ~S) and " *show-lisp-errors-p*) + (:a :href "http://weitz.de/hunchentoot/#*show-lisp-backtraces-p*" + (:code "*SHOW-LISP-BACKTRACES-P*")) + (fmt " (currently ~S)" *show-lisp-backtraces-p*) + ")")) + (:tr (:td (:a :href "/hunchentoot/foo" + "URI handled by") + " " + (:a :href "http://weitz.de/hunchentoot/#*default-handler*" + (:code "*DEFAULT-HANDLER*"))))))))) + +(setq *dispatch-table* + (nconc + (list 'dispatch-easy-handlers + (create-static-file-dispatcher-and-handler + "/hunchentoot/test/image.jpg" + (make-pathname :name "fz" :type "jpg" :version nil + :defaults *this-file*) + "image/jpeg") + (create-static-file-dispatcher-and-handler + "/hunchentoot/test/favicon.ico" + (make-pathname :name "favicon" :type "ico" :version nil + :defaults *this-file*)) + (create-folder-dispatcher-and-handler + "/hunchentoot/code/" + (make-pathname :name nil :type nil :version nil + :defaults *this-file*) + "text/plain")) + (mapcar (lambda (args) + (apply #'create-prefix-dispatcher args)) + '(("/hunchentoot/test/form-test.html" form-test) + ("/hunchentoot/test/forbidden.html" forbidden) + ("/hunchentoot/test/info.html" info) + ("/hunchentoot/test/authorization.html" authorization-page) + ("/hunchentoot/test/image-ram.jpg" image-ram-page) + ("/hunchentoot/test/cookie.html" cookie-test) + ("/hunchentoot/test/session.html" session-test) + ("/hunchentoot/test/parameter_latin1_get.html" parameter-test-latin1-get) + ("/hunchentoot/test/parameter_latin1_post.html" parameter-test-latin1-post) + ("/hunchentoot/test/parameter_utf8_get.html" parameter-test-utf8-get) + ("/hunchentoot/test/parameter_utf8_post.html" parameter-test-utf8-post) + ("/hunchentoot/test/upload.html" upload-test) + ("/hunchentoot/test/redir.html" redir) + ("/hunchentoot/test/oops.html" oops) + ("/hunchentoot/test/utf8-binary.txt" stream-direct) + ("/hunchentoot/test/utf8-character.txt" stream-direct-utf-8) + ("/hunchentoot/test/utf8-string.txt" stream-direct-utf-8-string) + ("/hunchentoot/test/files/" send-file) + ("/hunchentoot/test" menu))) + (list #'default-dispatcher)))
Added: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/unix-acl.lisp =================================================================== --- branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/unix-acl.lisp 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/unix-acl.lisp 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,53 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: HUNCHENTOOT; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/hunchentoot/unix-acl.lisp,v 1.5 2007/01/01 23:50:30 edi Exp $ + +;;; Copyright (c) 2004-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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-package :hunchentoot) + +(eval-when (:compile-toplevel :load-toplevel :execute) + (require "osi")) + +(defun setuid (uid) + "Sets the effective user ID of the current process to UID - see +setuid(2)." + (excl.osi:setuid uid)) + +(defun setgid (gid) + "Sets the effective group ID of the current process to GID - +see setgid(2)." + (excl.osi:setgid gid)) + +(defun get-uid-from-name (name) + "Returns the UID for the user named NAME." + (excl.osi:pwent-uid (or (excl.osi:getpwnam name) + (error "User ~S not found." name)))) + +(defun get-gid-from-name (name) + "Returns the GID for the group named NAME." + (excl.osi:grent-gid (or (excl.osi:getgrnam name) + (error "Group ~S not found." name))))
Added: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/unix-cmu.lisp =================================================================== --- branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/unix-cmu.lisp 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/unix-cmu.lisp 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,54 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: HUNCHENTOOT; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/hunchentoot/unix-cmu.lisp,v 1.5 2007/01/01 23:50:30 edi Exp $ + +;;; Copyright (c) 2004-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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-package :hunchentoot) + +(defun setuid (uid) + "Sets the effective user ID of the current process to UID - see +setuid(2)." + (multiple-value-bind (return-value errno) + (unix:unix-setuid uid) + (unless (and return-value (zerop return-value)) + (error "setuid failed: ~A" (unix:get-unix-error-msg errno))))) + +(defun setgid (gid) + "Sets the effective group ID of the current process to GID - +see setgid(2)." + (multiple-value-bind (return-value errno) + (unix:unix-setgid gid) + (unless (and return-value (zerop return-value)) + (error "setgid failed: ~A" (unix:get-unix-error-msg errno))))) + +(defun get-uid-from-name (name) + "Returns the UID for the user named NAME." + (unix:user-info-uid (unix:unix-getpwnam name))) + +(defun get-gid-from-name (name) + "Returns the GID for the group named NAME." + (unix:group-info-gid (unix:unix-getgrnam name)))
Added: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/unix-lw.lisp =================================================================== --- branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/unix-lw.lisp 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/unix-lw.lisp 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,93 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: HUNCHENTOOT; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/hunchentoot/unix-lw.lisp,v 1.4 2007/01/01 23:50:30 edi Exp $ + +;;; Copyright (c) 2004-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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-package :hunchentoot) + +(fli:define-foreign-function (%setuid "setuid") + ((uid :int)) + :result-type :int) + +(defun setuid (uid) + "Sets the effective user ID of the current process to UID - see +setuid(2)." + (unless (zerop (%setuid uid)) + (error "setuid failed: ~A" (lw:get-unix-error (lw:errno-value))))) + +(fli:define-foreign-function (%setgid "setgid") + ((gid :int)) + :result-type :int) + +(defun setgid (gid) + "Sets the effective group ID of the current process to GID - +see setgid(2)." + (unless (zerop (%setgid gid)) + (error "setgid failed: ~A" (lw:get-unix-error (lw:errno-value))))) + +(fli:define-c-struct passwd + (name (:pointer :char)) + (passwd (:pointer :char)) + (uid :int) + (gid :int) + (gecos (:pointer :char)) + (dir (:pointer :char)) + (shell (:pointer :char))) + +(fli:define-foreign-function (getpwnam "getpwnam") + ((name (:reference-pass :ef-mb-string))) + :result-type (:pointer passwd)) + +(defun get-uid-from-name (name) + "Returns the UID for the user named NAME." + (let ((passwd (getpwnam name))) + (when (fli:null-pointer-p passwd) + (let ((errno (lw:errno-value))) + (cond ((zerop errno) + (error "User ~S not found." name)) + (t (error "getpwnam failed: ~A" (lw:get-unix-error errno)))))) + (fli:foreign-slot-value passwd 'uid))) + +(fli:define-c-struct group + (name (:pointer :char)) + (passwd (:pointer :char)) + (gid :int) + (mem (:pointer (:pointer :char)))) + +(fli:define-foreign-function (getgrnam "getgrnam") + ((name (:reference-pass :ef-mb-string))) + :result-type (:pointer group)) + +(defun get-gid-from-name (name) + "Returns the GID for the group named NAME." + (let ((group (getgrnam name))) + (when (fli:null-pointer-p group) + (let ((errno (lw:errno-value))) + (cond ((zerop errno) + (error "Group ~S not found." name)) + (t (error "getgrnam failed: ~A" (lw:get-unix-error errno)))))) + (fli:foreign-slot-value group 'gid))) \ No newline at end of file
Property changes on: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/unix-lw.lisp ___________________________________________________________________ Name: svn:executable + *
Added: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/unix-mcl.lisp =================================================================== --- branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/unix-mcl.lisp 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/unix-mcl.lisp 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,54 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: HUNCHENTOOT; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/hunchentoot/unix-mcl.lisp,v 1.6 2007/01/01 23:50:30 edi Exp $ + +;;; Copyright (c) 2004-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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-package :hunchentoot) + +(defun setuid (uid) + "Sets the effective user ID of the current process to UID - see +setuid(2)." + (let ((errno (ccl::setuid uid))) + (unless (zerop errno) + (error "setuid failed with errno ~A." errno)))) + +(defun setgid (gid) + "Sets the effective group ID of the current process to GID - +see setgid(2)." + (let ((errno (ccl::setgid gid))) + (unless (zerop errno) + (error "setgid failed with errno ~A." errno)))) + +(defun get-uid-from-name (name) + "Returns the UID for the user named NAME." + (declare (ignore name)) + (error "GET-UID-FROM-NAME not yet implemented for OpenMCL. Please send patches...")) + +(defun get-gid-from-name (name) + "Returns the GID for the group named NAME." + (declare (ignore name)) + (error "GET-GID-FROM-NAME not yet implemented for OpenMCL. Please send patches..."))
Added: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/unix-sbcl.lisp =================================================================== --- branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/unix-sbcl.lisp 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/unix-sbcl.lisp 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,57 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: HUNCHENTOOT; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/hunchentoot/unix-sbcl.lisp,v 1.7 2007/10/06 22:44:06 edi Exp $ + +;;; Copyright (c) 2004-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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-package :hunchentoot) + +(eval-when (:compile-toplevel :load-toplevel :execute) + (when (and (eq (nth-value 1 (find-symbol "GETGRNAM" :sb-posix)) :external) + (eq (nth-value 1 (find-symbol "GROUP-GID" :sb-posix)) :external)) + (pushnew :sb-posix-has-getgrnam *features*))) + +(defun setuid (uid) + "Sets the effective user ID of the current process to UID - see +setuid(2)." + (sb-posix:setuid uid)) + +(defun setgid (gid) + "Sets the effective group ID of the current process to GID - +see setgid(2)." + (sb-posix:setgid gid)) + +(defun get-uid-from-name (name) + "Returns the UID for the user named NAME." + (sb-posix:passwd-uid (sb-posix:getpwnam name))) + +(defun get-gid-from-name (name) + "Returns the GID for the group named NAME." + (declare (ignorable name)) + #+:sb-posix-has-getgrnam + (sb-posix:group-gid (sb-posix:getgrnam name)) + #-:sb-posix-has-getgrnam + (error "You need a version of SBCL with SB-POSIX:GETGRNAM (1.0.10.31 or higher)."))
Added: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/util.lisp =================================================================== --- branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/util.lisp 2007-11-14 05:21:09 UTC (rev 2273) +++ branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/util.lisp 2007-11-14 05:24:08 UTC (rev 2274) @@ -0,0 +1,406 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: HUNCHENTOOT; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/hunchentoot/util.lisp,v 1.32 2007/11/08 20:07:58 edi Exp $ + +;;; Copyright (c) 2004-2007, Dr. Edmund Weitz. All rights reserved. + +;;; 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. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; 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 AUTHOR 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-package :hunchentoot) + +#-:lispworks +(defmacro when-let ((var form) &body body) + "Evaluates FORM and binds VAR to the result, then executes BODY +if VAR has a true value." + `(let ((,var ,form)) + (when ,var ,@body))) + +#-:lispworks +(defmacro with-unique-names ((&rest bindings) &body body) + "Syntax: WITH-UNIQUE-NAMES ( { var | (var x) }* ) declaration* form* + +Executes a series of forms with each VAR bound to a fresh, +uninterned symbol. The uninterned symbol is as if returned by a call +to GENSYM with the string denoted by X - or, if X is not supplied, the +string denoted by VAR - as argument. + +The variable bindings created are lexical unless special declarations +are specified. The scopes of the name bindings and declarations do not +include the Xs. + +The forms are evaluated in order, and the values of all but the last +are discarded (that is, the body is an implicit PROGN)." + ;; reference implementation posted to comp.lang.lisp as + ;; cy3bshuf30f.fsf@ljosa.com by Vebjorn Ljosa - see also + ;; http://www.cliki.net/Common%20Lisp%20Utilities + `(let ,(mapcar #'(lambda (binding) + (check-type binding (or cons symbol)) + (if (consp binding) + (destructuring-bind (var x) binding + (check-type var symbol) + `(,var (gensym ,(etypecase x + (symbol (symbol-name x)) + (character (string x)) + (string x))))) + `(,binding (gensym ,(symbol-name binding))))) + bindings) + ,@body)) + +#+:lispworks +(defmacro with-rebinding (bindings &body body) + "Renaming LW:REBINDING for better indentation." + `(lw:rebinding ,bindings ,@body)) + +#-:lispworks +(defmacro with-rebinding (bindings &body body) + "Syntax: WITH-REBINDING ( { var | (var prefix) }* ) form* + +Evaluates a series of forms in the lexical environment that is +formed by adding the binding of each VAR to a fresh, uninterned +symbol, and the binding of that fresh, uninterned symbol to VAR's +original value, i.e., its value in the current lexical environment. + +The uninterned symbol is created as if by a call to GENSYM with the +string denoted by PREFIX - or, if PREFIX is not supplied, the string +denoted by VAR - as argument. + +The forms are evaluated in order, and the values of all but the last +are discarded (that is, the body is an implicit PROGN)." + ;; reference implementation posted to comp.lang.lisp as + ;; cy3wv0fya0p.fsf@ljosa.com by Vebjorn Ljosa - see also + ;; http://www.cliki.net/Common%20Lisp%20Utilities + (loop for binding in bindings + for var = (if (consp binding) (car binding) binding) + for name = (gensym) + collect `(,name ,var) into renames + collect ``(,,var ,,name) into temps + finally (return `(let ,renames + (with-unique-names ,bindings + `(let (,,@temps) + ,,@body)))))) + +(defun starts-with-p (seq subseq &key (test 'eql)) + "Tests whether the sequence SEQ starts with the sequence +SUBSEQ. Individual elements are compared with TEST." + (let* ((length (length subseq)) + (mismatch (mismatch subseq seq + :test test))) + (or (null mismatch) + (<= length mismatch)))) + +(defun starts-with-one-of-p (seq subseq-list &key (test 'eql)) + "Tests whether the sequence SEQ starts with one of the +sequences in SUBSEQ-LIST. Individual elements are compared with +TEST." + (some (lambda (subseq) + (starts-with-p seq subseq :test test)) + subseq-list)) + +(defun create-random-string (&optional (n 10) (base 16)) + "Returns a random number (as a string) with base BASE and N +digits." + (with-output-to-string (s) + (dotimes (i n) + (format s "~VR" base + (random base *the-random-state*))))) + +(defun reset-session-secret () + "Sets *SESSION-SECRET* to a new random value. All old sessions will +cease to be valid." + (setq *session-secret* (create-random-string 10 36))) + +(defun reason-phrase (return-code) + "Returns a reason phrase for the HTTP return code RETURN-CODE +(which should be an integer) or NIL for return codes Hunchentoot +doesn't know." + (gethash return-code *http-reason-phrase-map*)) + +(defun make-keyword (string &key (destructivep t)) + "Interns the upcased version of STRING into the KEYWORD package. +Uses NSTRING-UPCASE if DESTRUCTIVEP is true. Returns NIL if STRING is +not a string." + (and (stringp string) + (intern (if destructivep + (nstring-upcase string) + (string-upcase string)) :keyword))) + +(defgeneric assoc (thing alist &key &allow-other-keys) + (:documentation "LIKE CL:ASSOC, but 'does the right thing' if +THING is a string or a symbol.")) + +(defmethod assoc ((thing symbol) alist &key &allow-other-keys) + "Version of ASSOC for symbols, always uses EQ as test function." + (cl:assoc thing alist :test #'eq)) + +(defmethod assoc ((thing string) alist &key (test #'string-equal)) + "Version of ASSOC for strings, uses STRING-EQUAL as default test +function." + (cl:assoc thing alist :test test)) + +(defmethod assoc (thing alist &key (test #'eql)) + "Default method - uses EQL as default test like CL:ASSOC." + (cl:assoc thing alist :test test)) + +(defun md5-hex (string) + "Calculates the md5 sum of the string STRING and returns it as a hex string." + (with-output-to-string (s) + (loop for code across (md5:md5sum-sequence string) + do (format s "~2,'0x" code)))) + +(defun escape-for-html (string) + "Escapes the characters #\<, #\>, #\', #\", and #\& for HTML output." + (with-output-to-string (out) + (with-input-from-string (in string) + (loop for char = (read-char in nil nil) + while char + do (case char + ((#<) (write-string "<" out)) + ((#>) (write-string ">" out)) + ((#") (write-string """ out)) + ((#') (write-string "'" out)) + ((#&) (write-string "&" out)) + (otherwise (write-char char out))))))) + +(defun http-token-p (token) + "Tests whether TOKEN is a string which is a valid 'token' +according to HTTP/1.1 (RFC 2068)." + (and (stringp token) + (plusp (length token)) + (every (lambda (char) + (and ;; CHAR is US-ASCII but not control character or ESC + (< 31 (char-code char) 127) + ;; CHAR is not 'tspecial' + (not (find char "()<>@,;:\"/[]?={} " :test #'char=)))) + token))) + + +(defun rfc-1123-date (&optional (time (get-universal-time))) + "Generates a time string according to RFC 1123. Default is current time." + (multiple-value-bind + (second minute hour date month year day-of-week) + (decode-universal-time time 0) + (format nil "~A, ~2,'0d ~A ~4d ~2,'0d:~2,'0d:~2,'0d GMT" + (svref +day-names+ day-of-week) + date + (svref +month-names+ (1- month)) + year + hour + minute + second))) + +(defun iso-time (&optional (time (get-universal-time))) + "Returns the universal time TIME as a string in full ISO format." + (multiple-value-bind (second minute hour date month year) + (decode-universal-time time) + (format nil "~4,'0d-~2,'0d-~2,'0d ~2,'0d:~2,'0d:~2,'0d" + year month date hour minute second))) + +(let ((counter 0)) + (declare (ignorable counter)) + (defun make-tmp-file-name (&optional (prefix "hunchentoot")) + "Generates a unique name for a temporary file. This function is +called from the RFC2388 library when a file is uploaded." + (let ((tmp-file-name + #+:allegro + (pathname (system:make-temp-file-name prefix *tmp-directory*)) + #-:allegro + (loop for pathname = (make-pathname :name (format nil "~A-~A" + prefix (incf counter)) + :type nil + :defaults *tmp-directory*) + unless (probe-file pathname) + return pathname))) + (push tmp-file-name *tmp-files*) + ;; maybe call hook for file uploads + (when *file-upload-hook* + (funcall *file-upload-hook* tmp-file-name)) + tmp-file-name))) + +(defun quote-string (string) + "Quotes string according to RFC 2616's definition of `quoted-string'." + (with-output-to-string (out) + (with-input-from-string (in string) + (loop for char = (read-char in nil nil) + while char + unless (or (char< char #\Space) + (char= char #\Rubout)) + do (case char + ((#\) (write-string "\\" out)) + ((#") (write-string "\"" out)) + (otherwise (write-char char out))))))) + +(defun url-decode (string &optional (external-format *hunchentoot-default-external-format*)) + "Decodes a URL-encoded STRING which is assumed to be encoded using +the external format EXTERNAL-FORMAT." + (let ((vector (make-array (length string) + :element-type '(unsigned-byte 8) + :fill-pointer 0))) + (loop with percent-p and buff + for char of-type character across string + for i from 0 + when buff do + (vector-push (parse-integer string + :start (1- i) + :end (1+ i) + :radix 16) + vector) + (setq buff nil) + else when percent-p + do (setq buff t + percent-p nil) + else when (char= char #%) + do (setq percent-p t) + else do (vector-push (char-code (case char + ((#+) #\Space) + (otherwise char))) + vector)) + (octets-to-string vector :external-format external-format))) + +(defun form-url-encoded-list-to-alist (form-url-encoded-list + &optional (external-format *hunchentoot-default-external-format*)) + "Converts a list FORM-URL-ENCODED-LIST of name/value pairs into an +alist. Both names and values are url-decoded while doing this." + (mapcar #'(lambda (entry) + (destructuring-bind (name &optional value) + (split "=" entry :limit 2) + (cons (string-trim " " (url-decode name external-format)) + (url-decode (or value "") external-format)))) + form-url-encoded-list)) + +(defun url-encode (string &optional (external-format *hunchentoot-default-external-format*)) + "URL-encodes a string using the external format EXTERNAL-FORMAT." + (with-output-to-string (s) + (loop for c across string + for index from 0 + do (cond ((or (char<= #\0 c #\9) + (char<= #\a c #\z) + (char<= #\A c #\Z) + ;; note that there's no comma in there - because of cookies + (find c "$-_.!*'()" :test #'char=)) + (write-char c s)) + (t (loop for octet across (string-to-octets string + :start index + :end (1+ index) + :external-format external-format) + do (format s "%~2,'0x" octet))))))) + +(defun force-output* (stream) + "Like FORCE-OUTPUT but aborts execution after +*FORCE-OUTPUT-TIMEOUT* seconds." + (with-timeout (*force-output-timeout* + (warn "FORCE-OUTPUT didn't return after ~A seconds." + *force-output-timeout*)) + (force-output stream))) + +(defun parse-content-type (content-type-header &optional want-external-format-p) + "Reads and parses a `Content-Type' header and returns it as three +values - the type, the subtype, and an external format corresponding +to the 'charset' parameter in the header (or +*HUNCHENTOOT-DEFAULT-EXTERNAL-FORMAT*), if there is one and if the +content type is "text" or WANT-EXTERNAL-FORMAT-P is true. +CONTENT-TYPE-HEADER is supposed to be the corresponding header value +as a string." + (with-input-from-string (stream content-type-header) + (let* ((*current-error-message* "Corrupted Content-Type header:") + (type (read-token stream)) + (subtype (and (or (ignore-errors (assert-char stream #/)) + (return-from parse-content-type + ;; try to return something meaningful + (values "application" "octet-stream" + (and want-external-format-p + *hunchentoot-default-external-format*)))) + (read-token stream))) + (parameters (read-name-value-pairs stream)) + (charset (cdr (assoc "charset" parameters))) + (external-format + (and (or want-external-format-p + (string-equal type "text")) + (or (when charset + (handler-case + (make-external-format (make-keyword charset) :eol-style :lf) + (error (condition) + (warn "Ignoring external format of name ~S~ +because of error:~%~A" + charset condition)))) + *hunchentoot-default-external-format*)))) + (values type subtype external-format)))) + +(defun get-token-and-parameters (header) + (with-input-from-string (stream header) + (let* ((*current-error-message* (format nil "Corrupted header ~S:" header)) + (token (read-token stream)) + (parameters (read-name-value-pairs stream))) + (values token parameters)))) + +(defun keep-alive-p () + "Returns a true value unless the incoming request obviates a +keep-alive reply. The second return value denotes whether the client +has explicitly asked for a persistent connection." + (let ((connection-values + ;; the header might consist of different values separated by commas + (when-let (connection-header (header-in :connection)) + (split "\s*,\s*" connection-header)))) + (flet ((connection-value-p (value) + "Checks whether the string VALUE is one of the +values of the `Connection' header." + (member value connection-values :test #'string-equal))) + (let ((keep-alive-requested-p (connection-value-p "keep-alive"))) + (values (and (or (and (eq (server-protocol) :http/1.1) + (not (connection-value-p "close"))) + (and (eq (server-protocol) :http/1.0) + keep-alive-requested-p))) + keep-alive-requested-p))))) + +(defun address-string () + "Returns a string with information about Hunchentoot suitable for +inclusion in HTML output." + (format nil "<address>~:[~3*~;<a href='http://httpd.apache.org/'>~A</a> / <a href='http://www.fractalconcept.com/asp/html/mod_lisp.html'>mod_lisp~A~@[/~A~]</a> / ~]<a href='http://weitz.de/hunchentoot/'>Hunchentoot ~A</a> <a href='~A'>(~A ~A)</a>~@[ at ~A~:[ (port ~D)~;~]~]</address>" + (server-mod-lisp-p *server*) + (or (header-in :server-baseversion) "Apache") + (or (header-in :modlisp-major-version) "") + (header-in :modlisp-version) + *hunchentoot-version* + +implementation-link+ + (escape-for-html (lisp-implementation-type)) + (escape-for-html (lisp-implementation-version)) + (or (host *request*) (server-address *server*)) + (scan ":\d+$" (or (host *request*) "")) + (server-port))) + +(defun server-name-header () + "Returns a string which can be used for 'Server' headers." + (format nil "Hunchentoot ~A" *hunchentoot-version*)) + +(defun input-chunking-p () + "Whether input chunking is currently switched on for (the socket +stream underlying) *HUNCHENTOOT-STREAM* - note that this will return +NIL if the underlying stream of the flexi stream is not a chunked +stream." + (chunked-stream-input-chunking-p (flexi-stream-stream *hunchentoot-stream*))) + +(defun cleanup-function () + "The default for *CLEANUP-FUNCTION*. Invokes a GC on 32-bit +LispWorks and does nothing on other Lisps." + #+(and :lispworks (not :lispworks-64bit)) + (hcl:mark-and-sweep 2))
Property changes on: branches/trunk-reorg/thirdparty/hunchentoot-0.14.6/util.lisp ___________________________________________________________________ Name: svn:executable + *