From 55f0596fabfe9613d535adcb19caa820b2104e51 Mon Sep 17 00:00:00 2001 From: Marcus Boerger Date: Sun, 16 Jul 2006 21:12:32 +0000 Subject: [PATCH] - MFH: . Upgrade RegexIterator capabilities, see docu . Update docu . Add test (which fails right now: iterator_049.phpt) . Add tests for new functionality --- ext/spl/internal/filteriterator.inc | 10 +- ext/spl/internal/recursiveregexiterator.inc | 55 ++++ ext/spl/internal/regexiterator.inc | 90 +++++++ ext/spl/spl.php | 263 +++++++++++++------- ext/spl/spl_iterators.c | 84 +++++-- ext/spl/spl_iterators.h | 10 + ext/spl/tests/iterator_049.phpt | 24 ++ ext/spl/tests/iterator_050.phpt | 93 +++++++ ext/spl/tests/iterator_051.phpt | 159 ++++++++++++ ext/spl/tests/iterator_052.phpt | 129 ++++++++++ ext/spl/tests/iterator_053.phpt | 237 ++++++++++++++++++ ext/spl/tests/iterator_054.phpt | 84 +++++++ ext/spl/tests/iterator_055.phpt | 93 +++++++ 13 files changed, 1220 insertions(+), 111 deletions(-) create mode 100755 ext/spl/internal/recursiveregexiterator.inc create mode 100755 ext/spl/internal/regexiterator.inc create mode 100755 ext/spl/tests/iterator_049.phpt create mode 100755 ext/spl/tests/iterator_050.phpt create mode 100755 ext/spl/tests/iterator_051.phpt create mode 100755 ext/spl/tests/iterator_052.phpt create mode 100755 ext/spl/tests/iterator_053.phpt create mode 100755 ext/spl/tests/iterator_054.phpt create mode 100755 ext/spl/tests/iterator_055.phpt diff --git a/ext/spl/internal/filteriterator.inc b/ext/spl/internal/filteriterator.inc index cc9c999a40..9820d48318 100755 --- a/ext/spl/internal/filteriterator.inc +++ b/ext/spl/internal/filteriterator.inc @@ -4,13 +4,13 @@ * @ingroup SPL * @brief class FilterIterator * @author Marcus Boerger - * @date 2003 - 2005 + * @date 2003 - 2006 * * SPL - Standard PHP Library */ /** - * @brief Regular expression filter for string iterators + * @brief Abstract filter for iterators * @author Marcus Boerger * @version 1.1 * @since PHP 5.0 @@ -28,11 +28,9 @@ abstract class FilterIterator implements OuterIterator private $it; /** - * Constructs a filter around an iterator whose elemnts are strings. - * If the given iterator is of type spl_sequence then its rewind() - * method is called. + * Constructs a filter around another iterator. * - * @param it Object that implements at least spl_forward + * @param it Iterator to filter */ function __construct(Iterator $it) { $this->it = $it; diff --git a/ext/spl/internal/recursiveregexiterator.inc b/ext/spl/internal/recursiveregexiterator.inc new file mode 100755 index 0000000000..caaee97b54 --- /dev/null +++ b/ext/spl/internal/recursiveregexiterator.inc @@ -0,0 +1,55 @@ +getInnerIterator()->hasChildren(); + } + + /** @return an iterator for the current elements children + * + * @note the returned iterator will be of the same class as $this + */ + function getChildren() + { + if (empty($this->ref)) + { + $this->ref = new ReflectionClass($this); + } + return $this->ref->newInstance($this->getInnerIterator()->getChildren()); + } + + private $ref; +} + +?> \ No newline at end of file diff --git a/ext/spl/internal/regexiterator.inc b/ext/spl/internal/regexiterator.inc new file mode 100755 index 0000000000..84ebf986d2 --- /dev/null +++ b/ext/spl/internal/regexiterator.inc @@ -0,0 +1,90 @@ +regex = $regex; + $this->flags = $flags; + $this->mode = $mode; + $this->preg_flags = $preg_flags; + } + + /** + * Match current or key against regular expression using mode, flags and + * preg_flags. + * + * @return whether this is a match + * + * @warning never call this twice for the same state + */ + function accept() + { + $matches = array(); + $this->current = parent::current(); + /* note that we use $this->current, rather than calling parent::current() */ + $subject = ($this->flags & self::USE_KEY) ? parent::key() : $this->current; + switch($this->mode) + { + case self::MATCH: + return preg_match($this->regex, $subject, $matches, $this->preg_flags); + + case self::GET_MATCH: + $this->current = array(); + return preg_match($this->regex, $subject, $this->current, $this->preg_flags) > 0; + + case self::ALL_MATCHES: + $this->current = array(); + return preg_match_all($this->regex, $subject, $this->current, $this->preg_flags) > 0; + + case self::SPLIT: + $this->current = array(); + preg_split($this->regex, $subject, $this->current, $this->preg_flags) > 1; + } + } + + /** @return the current value after accept has been called + */ + function current() + { + return $this->current; + } +} + +?> \ No newline at end of file diff --git a/ext/spl/spl.php b/ext/spl/spl.php index f704e044ba..625042f72d 100755 --- a/ext/spl/spl.php +++ b/ext/spl/spl.php @@ -6,7 +6,7 @@ * * SPL - Standard PHP Library * - * (c) Marcus Boerger, 2003 - 2005 + * (c) Marcus Boerger, 2003 - 2006 */ /** @mainpage SPL - Standard PHP Library @@ -46,6 +46,8 @@ * - class EmptyIterator implements Iterator * - class InfiniteIterator extends IteratorIterator * - class AppendIterator implements OuterIterator + * - class RegexIterator extends FilterIterator + * - class RegursiveRegexIterator extends RegexIterator implements RecursiveIterator * * 2) Directories and Files * @@ -66,8 +68,8 @@ * * SPL offers advanced Array overloading: * - * - class ArrayObject implements IteratorAggregate - * - class ArrayIterator implements Iterator + * - class ArrayObject implements IteratorAggregate, ArrayAccess, Countable + * - class ArrayIterator implements Iterator, ArrayAccess, Countable, SeekableIterator * - class RecursiveArrayIterator extends ArrayIterator implements RecursiveIterator * * As the above suggest an ArrayObject creates an ArrayIterator when it comes to @@ -128,7 +130,7 @@ * You can download this documentation as a chm file * here. * - * (c) Marcus Boerger, 2003 - 2005 + * (c) Marcus Boerger, 2003 - 2006 */ /** @defgroup ZendEngine Zend engine classes @@ -157,7 +159,7 @@ * @param class_name name of class to load * @param file_extensions file extensions (use defaults if NULL) */ -function spl_autoload(string $class_name, string $file_extensions = NULL); +function spl_autoload(string $class_name, string $file_extensions = NULL) {/**/}; /** @ingroup SPL * @brief Manual invocation of all registerd autoload functions @@ -165,7 +167,7 @@ function spl_autoload(string $class_name, string $file_extensions = NULL); * * @param class_name name of class to load */ -function spl_autoload_call(string $class_name); +function spl_autoload_call(string $class_name) {/**/}; /** @ingroup SPL * @brief Register and return default file extensions for spl_autoload @@ -176,7 +178,7 @@ function spl_autoload_call(string $class_name); * @return comma separated list of file extensions to use in default autoload * function. */ -function spl_autoload_extensions($file_extensions); +function spl_autoload_extensions($file_extensions) {/**/}; /** @ingroup SPL * @brief Return all registered autoload functionns @@ -184,7 +186,7 @@ function spl_autoload_extensions($file_extensions); * * @return array of all registered autoload functions or false */ -function spl_autoload_functions(); +function spl_autoload_functions() {/**/}; /** @ingroup SPL * @brief Register given function as autoload implementation @@ -194,7 +196,7 @@ function spl_autoload_functions(); * function name to register as autoload function. * @param throw whether to throw or issue an error on failure. */ -function spl_autoload_register(string $autoload_function = "spl_autoload", $throw = true); +function spl_autoload_register(string $autoload_function = "spl_autoload", $throw = true) {/**/}; /** @ingroup SPL * @brief Unregister given function as autoload implementation @@ -203,7 +205,7 @@ function spl_autoload_register(string $autoload_function = "spl_autoload", $thro * @param autoload_function name of function or array of object/class and * function name to unregister as autoload function. */ -function spl_autoload_unregister(string $autoload_function = "spl_autoload"); +function spl_autoload_unregister(string $autoload_function = "spl_autoload") {/**/}; /** @ingroup SPL * @brief Return an array of classes and interfaces in SPL @@ -211,7 +213,7 @@ function spl_autoload_unregister(string $autoload_function = "spl_autoload"); * @return array containing the names of all clsses and interfaces defined in * extension SPL */ -function spl_classes(); +function spl_classes() {/**/}; /** @ingroup SPL * @brief Count the elements in an iterator @@ -219,7 +221,7 @@ function spl_classes(); * * @return number of elements in an iterator */ -function iterator_count(Traversable $it); +function iterator_count(Traversable $it) {/**/}; /** @ingroup SPL * @brief Copy iterator elements into an array @@ -228,7 +230,7 @@ function iterator_count(Traversable $it); * @param it iterator to copy * @return array with elements copied from the iterator */ -function iterator_to_array(Traversable $it); +function iterator_to_array(Traversable $it) {/**/}; /** @ingroup ZendEngine * @brief Basic Exception class. @@ -611,7 +613,7 @@ class ArrayObject implements IteratorAggregate, ArrayAccess, Countable * @param $flags see setFlags(). * @param $iterator_class class used in getIterator() */ - function __construct($array, $flags = 0, $iterator_class = "ArrayIterator"); + function __construct($array, $flags = 0, $iterator_class = "ArrayIterator") {/**/} /** Set behavior flags. * @@ -620,72 +622,94 @@ class ArrayObject implements IteratorAggregate, ArrayAccess, Countable * when accessed as list (var_dump, foreach, etc.) * 1 set: array indices can be accessed as properties in read/write */ - function setFlags($flags); + function setFlags($flags) {/**/} - /** - * @ return current flags + /** @return current flags */ - function getFlags(); + function getFlags() {/**/} - /** - * @param $array new array or object + /** Sort the entries by values. + */ + function asort() {/**/} + + /** Sort the entries by key. */ - function exchangeArray($array); + function ksort() {/**/} + + /** Sort the entries by values using user defined function. + */ + function uasort(mixed cmp_function) {/**/} + + /** Sort the entries by key using user defined function. + */ + function uksort(mixed cmp_function) {/**/} + + /** Sort the entries by values using "natural order" algorithm. + */ + function natsort() {/**/} + + /** Sort the entries by values using case insensitive "natural order" algorithm. + */ + function natcasesort() {/**/} + + /** @param $array new array or object + */ + function exchangeArray($array) {/**/} /** @return the iterator which is an ArrayIterator object connected to * this object. */ - function getIterator(); + function getIterator() {/**/} /** @param $index offset to inspect * @return whetehr offset $index esists */ - function offsetExists($index); + function offsetExists($index) {/**/} /** @param $index offset to return value for * @return value at offset $index */ - function offsetGet($index); + function offsetGet($index) {/**/} /** @param $index index to set * @param $newval new value to store at offset $index */ - function offsetSet($index, $newval); + function offsetSet($index, $newval) {/**/} /** @param $index offset to unset */ - function offsetUnset($index); + function offsetUnset($index) {/**/} /** @param $value is appended as last element * @warning this method cannot be called when the ArrayObject refers to * an object. */ - function append($value); + function append($value) {/**/} /** @return a \b copy of the array * @note when the ArrayObject refers to an object then this method * returns an array of the public properties. */ - function getArrayCopy(); + function getArrayCopy() {/**/} /** @return the number of elements in the array or the number of public * properties in the object. */ - function count(); + function count() {/**/} /* @param $iterator_class new class used in getIterator() */ - function setIteratorClass($itertor_class); + function setIteratorClass($itertor_class) {/**/} /* @return class used in getIterator() */ - function getIteratorClass(); + function getIteratorClass() {/**/} } /** @ingroup SPL * @brief An Array iterator * @since PHP 5.0 - * @version 1.1 + * @version 1.2 * * This iterator allows to unset and modify values and keys while iterating * over Arrays and Objects. @@ -709,7 +733,7 @@ class ArrayIterator implements SeekableIterator, ArrayAccess, Countable * @param $array the array to use. * @param $flags see setFlags(). */ - function __construct($array, $flags = 0); + function __construct($array, $flags = 0) {/**/} /** Set behavior flags. * @@ -718,53 +742,92 @@ class ArrayIterator implements SeekableIterator, ArrayAccess, Countable * when accessed as list (var_dump, foreach, etc.) * 1 set: array indices can be accessed as properties in read/write */ - function setFlags($flags); + function setFlags($flags) {/**/} /** - * @ return current flags + * @return current flags */ - function getFlags(); + function getFlags() {/**/} + /** Sort the entries by values. + */ + function asort() {/**/} + + /** Sort the entries by key. + */ + function ksort() {/**/} + + /** Sort the entries by values using user defined function. + */ + function uasort(mixed cmp_function) {/**/} + + /** Sort the entries by key using user defined function. + */ + function uksort(mixed cmp_function) {/**/} + + /** Sort the entries by values using "natural order" algorithm. + */ + function natsort() {/**/} + + /** Sort the entries by values using case insensitive "natural order" algorithm. + */ + function natcasesort() {/**/} + /** @param $index offset to inspect * @return whetehr offset $index esists */ - function offsetExists($index); + function offsetExists($index) {/**/} /** @param $index offset to return value for * @return value at offset $index */ - function offsetGet($index); + function offsetGet($index) {/**/} /** @param $index index to set * @param $newval new value to store at offset $index */ - function offsetSet($index, $newval); + function offsetSet($index, $newval) {/**/} /** @param $index offset to unset */ - function offsetUnset($index); + function offsetUnset($index) {/**/} /** @param $value is appended as last element * @warning this method cannot be called when the ArrayIterator refers to * an object. */ - function append($value); + function append($value) {/**/} /** @return a \b copy of the array * @note when the ArrayIterator refers to an object then this method * returns an array of the public properties. */ - function getArrayCopy(); + function getArrayCopy() {/**/} /** @param $position offset to seek to * @throw OutOfBoundsException if $position is invalid */ - function seek($position); + function seek($position) {/**/} /** @return the number of elements in the array or the number of public * properties in the object. */ - function count(); + function count() {/**/} + + /** @copydoc Iterator::rewind */ + function rewind() {/**/} + + /** @copydoc Iterator::valid */ + function valid() {/**/} + + /** @copydoc Iterator::current */ + function current() {/**/} + + /** @copydoc Iterator::key */ + function key() {/**/} + + /** @copydoc Iterator::next */ + function next() {/**/} } /** @ingroup SPL @@ -777,95 +840,95 @@ class SplFileInfo * * @param $file_name path or file name */ - function __construct($file_name); + function __construct($file_name) {/**/} /** @return the path part only. */ - function getPath(); + function getPath() {/**/} /** @return the filename only. */ - function getFilename(); + function getFilename() {/**/} /** @return SplFileInfo created for the file * @param class_name name of class to instantiate * @see SplFileInfo::setInfoClass() */ - function getFileInfo(string class_name = NULL); + function getFileInfo(string class_name = NULL) {/**/} /** @return The current entries path and file name. */ - function getPathname(); + function getPathname() {/**/} /** @return SplFileInfo created for the path * @param class_name name of class to instantiate * @see SplFileInfo::setInfoClass() */ - function getPathInfo(string class_name = NULL); + function getPathInfo(string class_name = NULL) {/**/} /** @return The current entry's permissions. */ - function getPerms(); + function getPerms() {/**/} /** @return The current entry's inode. */ - function getInode(); + function getInode() {/**/} /** @return The current entry's size in bytes . */ - function getSize(); + function getSize() {/**/} /** @return The current entry's owner name. */ - function getOwner(); + function getOwner() {/**/} /** @return The current entry's group name. */ - function getGroup(); + function getGroup() {/**/} /** @return The current entry's last access time. */ - function getATime(); + function getATime() {/**/} /** @return The current entry's last modification time. */ - function getMTime(); + function getMTime() {/**/} /** @return The current entry's last change time. */ - function getCTime(); + function getCTime() {/**/} /** @return The current entry's size in bytes . */ - function getType(); + function getType() {/**/} /** @return Whether the current entry is writeable. */ - function isWritable(); + function isWritable() {/**/} /** @return Whether the current entry is readable. */ - function isReadable(); + function isReadable() {/**/} /** @return Whether the current entry is executable. */ - function isExecutable(); + function isExecutable() {/**/} /** @return Whether the current entry is . */ - function isFile(); + function isFile() {/**/} /** @return Whether the current entry is a directory. */ - function isDir(); + function isDir() {/**/} /** @return whether the current entry is a link. */ - function isLink(); + function isLink() {/**/} /** @return getPathname() */ - function __toString(); + function __toString() {/**/} /** Open the current file as a SplFileObject instance * @@ -880,17 +943,17 @@ class SplFileInfo * @see SplFileInfo::setFileClass() * @see file() */ - function openFile($mode = 'r', $use_include_path = false, $context = NULL); + function openFile($mode = 'r', $use_include_path = false, $context = NULL) {/**/} /** @param class_name name of class used with openFile(). Must be derived * from SPLFileObject. */ - function setFileClass(string class_name = "SplFileObject"); + function setFileClass(string class_name = "SplFileObject") {/**/} /** @param class_name name of class used with getFileInfo(), getPathInfo(). - * Must be derived from SplFileInfo. + * Must be derived from SplFileInfo. */ - function setInfoClass(string class_name = "SplFileInfo"); + function setInfoClass(string class_name = "SplFileInfo") {/**/} } /** @ingroup SPL @@ -904,27 +967,36 @@ class DirectoryIterator extends SplFileInfo implements Iterator * * @param $path directory to iterate. */ - function __construct($path); + function __construct($path) {/**/} + /** @copydoc Iterator::rewind */ + function rewind() {/**/} + + /** @copydoc Iterator::valid */ + function valid() {/**/} + /** @return index of entry */ - function key(); + function key() {/**/} /** @return $this */ - function current(); + function current() {/**/} + + /** @copydoc Iterator::next */ + function next() {/**/} /** @return Whether the current entry is either '.' or '..'. */ - function isDot(); + function isDot() {/**/} /** @return whether the current entry is a link. */ - function isLink(); + function isLink() {/**/} /** @return getFilename() */ - function __toString(); + function __toString() {/**/} } /** @ingroup SPL @@ -946,31 +1018,31 @@ class RecursiveDirectoryIterator extends DirectoryIterator implements RecursiveI * - KEY_AS_FILENAME * - NEW_CURRENT_AND_KEY */ - function __construct($path, $flags = 0); + function __construct($path, $flags = 0) {/**/} /** @return getPathname() or getFilename() depending on flags */ - function key(); + function key() {/**/} /** @return getFilename() or getFileInfo() depending on flags */ - function current(); + function current() {/**/} /** @return whether the current is a directory (not '.' or '..'). */ - function hasChildren(); + function hasChildren() {/**/} /** @return a RecursiveDirectoryIterator for the current entry. */ - function getChildren(); + function getChildren() {/**/} /** @return sub path only (without main path) */ - function getSubPath(); + function getSubPath() {/**/} /** @return the current sub path */ - function getSubPathname(); + function getSubPathname() {/**/} } /** @ingroup SPL @@ -984,15 +1056,34 @@ class RecursiveDirectoryIterator extends DirectoryIterator implements RecursiveI * has subelements, hasChildren() returns true. This will trigger a call to * getChildren() which returns the iterator for that sub element. */ -class SimpleXMLIterator extends SimpleXMLElement implements RecursiveIterator +class SimpleXMLIterator extends SimpleXMLElement implements RecursiveIterator, Countable { /** @return whether the current node has sub nodes. */ - function hasChildren(); + function hasChildren() {/**/} /** @return a SimpleXMLIterator for the current node. */ - function getChildren(); + function getChildren() {/**/} + + /** @return number of elements/attributes seen with foreach() + */ + function count() {/**/} + + /** @copydoc Iterator::rewind */ + function rewind() {/**/} + + /** @copydoc Iterator::valid */ + function valid() {/**/} + + /** @copydoc Iterator::current */ + function current() {/**/} + + /** @copydoc Iterator::key */ + function key() {/**/} + + /** @copydoc Iterator::next */ + function next() {/**/} } /** @ingroup SPL diff --git a/ext/spl/spl_iterators.c b/ext/spl/spl_iterators.c index 294bc12126..b62e404f3a 100755 --- a/ext/spl/spl_iterators.c +++ b/ext/spl/spl_iterators.c @@ -996,12 +996,20 @@ static spl_dual_it_object* spl_dual_it_construct(INTERNAL_FUNCTION_PARAMETERS, z char *regex; int len, poptions, coptions; pcre_extra *extra = NULL; + long mode = REGIT_MODE_MATCH; intern->u.regex.flags = 0; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Os|l", &zobject, ce_inner, ®ex, &len, &intern->u.regex.flags) == FAILURE) { + intern->u.regex.preg_flags = 0; + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Os|lll", &zobject, ce_inner, ®ex, &len, &intern->u.regex.flags, &mode, &intern->u.regex.preg_flags) == FAILURE) { php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC); return NULL; } + if (mode < 0 || mode >= REGIT_MODE_MAX) { + zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "Illegal mode %ld", mode); + php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC); + return NULL; + } + intern->u.regex.mode = mode; intern->u.regex.regex = estrndup(regex, len); intern->u.regex.pce = pcre_get_compiled_regex_cache(regex, len, &extra, &poptions, &coptions TSRMLS_CC); intern->u.regex.pce->refcount++; @@ -1357,7 +1365,7 @@ SPL_METHOD(ParentIterator, getChildren) } /* }}} */ #if HAVE_PCRE || HAVE_BUNDLED_PCRE -/* {{{ proto void RegexIterator::__construct(Iterator it, string $regex [, int $flags]) +/* {{{ proto void RegexIterator::__construct(Iterator it, string regex [, int flags [, int mode [, int preg_flags]]]) Create an RegexIterator from another iterator and a regular expression */ SPL_METHOD(RegexIterator, __construct) { @@ -1368,22 +1376,22 @@ SPL_METHOD(RegexIterator, __construct) Match (string)current() against regular expression */ SPL_METHOD(RegexIterator, accept) { - spl_dual_it_object *intern; - int count; - char *subject, tmp[32]; - int subject_len, use_copy = 0; - zval subject_copy; - pcre_extra *extra; + spl_dual_it_object *intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + char *subject, tmp[32]; + int subject_len, use_copy, count; + zval subject_copy, zcount; + pcre *regex = intern->u.regex.pce->re; + pcre_extra *extra = intern->u.regex.pce->extra; - intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); - if (intern->u.regex.flags & REGIT_USE_KEY) { if (intern->current.key_type == HASH_KEY_IS_LONG) { subject_len = snprintf(tmp, sizeof(tmp), "%ld", intern->current.int_key); subject = &tmp[0]; + use_copy = 0; } else { - subject_len = intern->current.str_key_len; - subject = intern->current.str_key; + subject_len = intern->current.str_key_len - 1; + subject = estrndup(intern->current.str_key, subject_len); + use_copy = 1; } } else { zend_make_printable_zval(intern->current.data, &subject_copy, &use_copy); @@ -1396,17 +1404,49 @@ SPL_METHOD(RegexIterator, accept) } } - extra = intern->u.regex.pce->extra; - count = pcre_exec(intern->u.regex.pce->re, extra, subject, subject_len, 0, 0, NULL, 0); + switch (intern->u.regex.mode) + { + case REGIT_MODE_MAX: /* won't happen but makes compiler happy */ + case REGIT_MODE_MATCH: + count = pcre_exec(regex, extra, subject, subject_len, 0, 0, NULL, 0); + RETVAL_BOOL(count >= 0); + break; - if (use_copy) { - zval_dtor(&subject_copy); + case REGIT_MODE_ALL_MATCHES: + case REGIT_MODE_GET_MATCH: + if (!use_copy) { + subject = estrndup(subject, subject_len); + use_copy = 1; + } + zval_ptr_dtor(&intern->current.data); + MAKE_STD_ZVAL(intern->current.data); + array_init(intern->current.data); + php_pcre_match(regex, extra, subject, subject_len, &zcount, + intern->current.data, intern->u.regex.mode == REGIT_MODE_ALL_MATCHES, 0, 0, 0, 0 TSRMLS_CC); + count = zend_hash_num_elements(Z_ARRVAL_P(intern->current.data)); + RETVAL_BOOL(count > 0); + break; + + case REGIT_MODE_SPLIT: + if (!use_copy) { + subject = estrndup(subject, subject_len); + use_copy = 1; + } + zval_ptr_dtor(&intern->current.data); + MAKE_STD_ZVAL(intern->current.data); + array_init(intern->current.data); + php_pcre_split(regex, extra, subject, subject_len, intern->current.data, 0, -1, 0, 0, 0 TSRMLS_CC); + count = zend_hash_num_elements(Z_ARRVAL_P(intern->current.data)); + RETVAL_BOOL(count > 1); + break; } - RETURN_BOOL(count >= 0); + if (use_copy) { + efree(subject); + } } /* }}} */ -/* {{{ proto void RecursiveRegexIterator::__construct(RecursiveIterator it, string $regex [, int $flags]) +/* {{{ proto void RecursiveRegexIterator::__construct(RecursiveIterator it, string regex [, int flags [, int mode [, int preg_flags]]]) Create an RecursiveRegexIterator from another recursive iterator and a regular expression */ SPL_METHOD(RecursiveRegexIterator, __construct) { @@ -1547,6 +1587,8 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_regex_it___construct, 0, 0, 2) ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0) ZEND_ARG_INFO(0, regex) ZEND_ARG_INFO(0, flags) + ZEND_ARG_INFO(0, mode) + ZEND_ARG_INFO(0, preg_flags) ZEND_END_ARG_INFO(); static zend_function_entry spl_funcs_RegexIterator[] = { @@ -2734,7 +2776,11 @@ PHP_MINIT_FUNCTION(spl_iterators) REGISTER_SPL_SUB_CLASS_EX(InfiniteIterator, IteratorIterator, spl_dual_it_new, spl_funcs_InfiniteIterator); #if HAVE_PCRE || HAVE_BUNDLED_PCRE REGISTER_SPL_SUB_CLASS_EX(RegexIterator, FilterIterator, spl_dual_it_new, spl_funcs_RegexIterator); - REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "USE_KEY", REGIT_USE_KEY); + REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "USE_KEY", REGIT_USE_KEY); + REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "MATCH", REGIT_MODE_MATCH); + REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "GET_MATCH", REGIT_MODE_GET_MATCH); + REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "ALL_MATCHES", REGIT_MODE_ALL_MATCHES); + REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "SPLIT", REGIT_MODE_SPLIT); REGISTER_SPL_SUB_CLASS_EX(RecursiveRegexIterator, RegexIterator, spl_dual_it_new, spl_funcs_RecursiveRegexIterator); REGISTER_SPL_IMPLEMENTS(RecursiveRegexIterator, RecursiveIterator); #else diff --git a/ext/spl/spl_iterators.h b/ext/spl/spl_iterators.h index af4eccd8ff..c2ee24949c 100755 --- a/ext/spl/spl_iterators.h +++ b/ext/spl/spl_iterators.h @@ -95,6 +95,14 @@ enum { REGIT_USE_KEY = 0x00000001, }; +typedef enum { + REGIT_MODE_MATCH, + REGIT_MODE_GET_MATCH, + REGIT_MODE_ALL_MATCHES, + REGIT_MODE_SPLIT, + REGIT_MODE_MAX, +} regex_mode; + typedef struct _spl_dual_it_object { zend_object std; struct { @@ -130,6 +138,8 @@ typedef struct _spl_dual_it_object { #if HAVE_PCRE || HAVE_BUNDLED_PCRE struct { int flags; + regex_mode mode; + long preg_flags; pcre_cache_entry *pce; char *regex; } regex; diff --git a/ext/spl/tests/iterator_049.phpt b/ext/spl/tests/iterator_049.phpt new file mode 100755 index 0000000000..9a5d4029f8 --- /dev/null +++ b/ext/spl/tests/iterator_049.phpt @@ -0,0 +1,24 @@ +--TEST-- +SPL: ArrayIterator with NULL key +--SKIPIF-- + +--FILE-- +NULL)); +var_dump($ar); +var_dump($ar->getArrayCopy()); + +?> +===DONE=== + +--EXPECTF-- +object(ArrayIterator)#1 (1) { + [""]=> + NULL +} +array(1) { + [""]=> + NULL +} +===DONE=== diff --git a/ext/spl/tests/iterator_050.phpt b/ext/spl/tests/iterator_050.phpt new file mode 100755 index 0000000000..983dfa4573 --- /dev/null +++ b/ext/spl/tests/iterator_050.phpt @@ -0,0 +1,93 @@ +--TEST-- +SPL: RegexIterator::GET_MATCH +--SKIPIF-- + +--FILE-- + $v) + { + var_dump($k); + var_dump($v); + } + } +} + +$ar = new ArrayIterator(array('1','1,2','1,2,3','',NULL,array(),'FooBar',',',',,')); +$it = new MyRegexIterator($ar, '/(\d),(\d)/', 0, RegexIterator::GET_MATCH); +$it->show(); + +$it = new MyRegexIterator($ar, '/(\d)/', 0, RegexIterator::GET_MATCH); +$it->show(); + +var_dump($ar); + +?> +===DONE=== + +--EXPECTF-- +int(1) +array(3) { + [0]=> + string(3) "1,2" + [1]=> + string(1) "1" + [2]=> + string(1) "2" +} +int(2) +array(3) { + [0]=> + string(3) "1,2" + [1]=> + string(1) "1" + [2]=> + string(1) "2" +} +int(0) +array(2) { + [0]=> + string(1) "1" + [1]=> + string(1) "1" +} +int(1) +array(2) { + [0]=> + string(1) "1" + [1]=> + string(1) "1" +} +int(2) +array(2) { + [0]=> + string(1) "1" + [1]=> + string(1) "1" +} +object(ArrayIterator)#%d (9) { + [0]=> + %s(1) "1" + [1]=> + %s(3) "1,2" + [2]=> + %s(5) "1,2,3" + [3]=> + %s(0) "" + [4]=> + NULL + [5]=> + array(0) { + } + [6]=> + %s(6) "FooBar" + [7]=> + %s(1) "," + [8]=> + %s(2) ",," +} +===DONE=== diff --git a/ext/spl/tests/iterator_051.phpt b/ext/spl/tests/iterator_051.phpt new file mode 100755 index 0000000000..d396612ca6 --- /dev/null +++ b/ext/spl/tests/iterator_051.phpt @@ -0,0 +1,159 @@ +--TEST-- +SPL: RegexIterator::GET_MATCH, USE_KEY +--SKIPIF-- + +--FILE-- + $v) + { + var_dump($k); + var_dump($v); + } + } +} + +$ar = new ArrayIterator(array('1'=>0,'1,2'=>1,'1,2,3'=>2,0=>3,'FooBar'=>4,','=>5,',,'=>6)); +$it = new MyRegexIterator($ar, '/(\d),(\d)/', RegexIterator::USE_KEY, RegexIterator::GET_MATCH); +$it->show(); + +$it = new MyRegexIterator($ar, '/(\d)/', RegexIterator::USE_KEY, RegexIterator::GET_MATCH); +$it->show(); + +var_dump($ar); + +?> +===DONE=== + +--EXPECTF-- +string(3) "1,2" +array(3) { + [0]=> + string(3) "1,2" + [1]=> + string(1) "1" + [2]=> + string(1) "2" +} +string(5) "1,2,3" +array(3) { + [0]=> + string(3) "1,2" + [1]=> + string(1) "1" + [2]=> + string(1) "2" +} +int(1) +array(2) { + [0]=> + string(1) "1" + [1]=> + string(1) "1" +} +string(3) "1,2" +array(2) { + [0]=> + string(1) "1" + [1]=> + string(1) "1" +} +string(5) "1,2,3" +array(2) { + [0]=> + string(1) "1" + [1]=> + string(1) "1" +} +int(0) +array(2) { + [0]=> + string(1) "0" + [1]=> + string(1) "0" +} +object(ArrayIterator)#%d (7) { + [1]=> + int(0) + ["1,2"]=> + int(1) + ["1,2,3"]=> + int(2) + [0]=> + int(3) + ["FooBar"]=> + int(4) + [","]=> + int(5) + [",,"]=> + int(6) +} +===DONE=== +--UEXPECTF-- +unicode(3) "1,2" +array(3) { + [0]=> + string(3) "1,2" + [1]=> + string(1) "1" + [2]=> + string(1) "2" +} +unicode(5) "1,2,3" +array(3) { + [0]=> + string(3) "1,2" + [1]=> + string(1) "1" + [2]=> + string(1) "2" +} +int(1) +array(2) { + [0]=> + string(1) "1" + [1]=> + string(1) "1" +} +unicode(3) "1,2" +array(2) { + [0]=> + string(1) "1" + [1]=> + string(1) "1" +} +unicode(5) "1,2,3" +array(2) { + [0]=> + string(1) "1" + [1]=> + string(1) "1" +} +int(0) +array(2) { + [0]=> + string(1) "0" + [1]=> + string(1) "0" +} +object(ArrayIterator)#%d (7) { + [1]=> + int(0) + [u"1,2"]=> + int(1) + [u"1,2,3"]=> + int(2) + [0]=> + int(3) + [u"FooBar"]=> + int(4) + [u","]=> + int(5) + [u",,"]=> + int(6) +} +===DONE=== diff --git a/ext/spl/tests/iterator_052.phpt b/ext/spl/tests/iterator_052.phpt new file mode 100755 index 0000000000..574868bd65 --- /dev/null +++ b/ext/spl/tests/iterator_052.phpt @@ -0,0 +1,129 @@ +--TEST-- +SPL: RegexIterator::ALL_MATCHES +--SKIPIF-- + +--FILE-- + $v) + { + var_dump($k); + var_dump($v); + } + } +} + +$ar = new ArrayIterator(array('1','1,2','1,2,3','',NULL,array(),'FooBar',',',',,')); +$it = new MyRegexIterator($ar, '/(\d),(\d)/', 0, RegexIterator::ALL_MATCHES); +$it->show(); + +$it = new MyRegexIterator($ar, '/(\d)/', 0, RegexIterator::ALL_MATCHES); +$it->show(); + +var_dump($ar); + +?> +===DONE=== + +--EXPECTF-- +int(1) +array(1) { + [0]=> + array(3) { + [0]=> + string(3) "1,2" + [1]=> + string(1) "1" + [2]=> + string(1) "2" + } +} +int(2) +array(1) { + [0]=> + array(3) { + [0]=> + string(3) "1,2" + [1]=> + string(1) "1" + [2]=> + string(1) "2" + } +} +int(0) +array(1) { + [0]=> + array(2) { + [0]=> + string(1) "1" + [1]=> + string(1) "1" + } +} +int(1) +array(2) { + [0]=> + array(2) { + [0]=> + string(1) "1" + [1]=> + string(1) "1" + } + [1]=> + array(2) { + [0]=> + string(1) "2" + [1]=> + string(1) "2" + } +} +int(2) +array(3) { + [0]=> + array(2) { + [0]=> + string(1) "1" + [1]=> + string(1) "1" + } + [1]=> + array(2) { + [0]=> + string(1) "2" + [1]=> + string(1) "2" + } + [2]=> + array(2) { + [0]=> + string(1) "3" + [1]=> + string(1) "3" + } +} +object(ArrayIterator)#%d (9) { + [0]=> + %s(1) "1" + [1]=> + %s(3) "1,2" + [2]=> + %s(5) "1,2,3" + [3]=> + %s(0) "" + [4]=> + NULL + [5]=> + array(0) { + } + [6]=> + %s(6) "FooBar" + [7]=> + %s(1) "," + [8]=> + %s(2) ",," +} +===DONE=== diff --git a/ext/spl/tests/iterator_053.phpt b/ext/spl/tests/iterator_053.phpt new file mode 100755 index 0000000000..bc4b1440d6 --- /dev/null +++ b/ext/spl/tests/iterator_053.phpt @@ -0,0 +1,237 @@ +--TEST-- +SPL: RegexIterator::ALL_MATCHES, USE_KEY +--SKIPIF-- + +--FILE-- + $v) + { + var_dump($k); + var_dump($v); + } + } +} + +$ar = new ArrayIterator(array('1'=>0,'1,2'=>1,'1,2,3'=>2,0=>3,'FooBar'=>4,','=>5,',,'=>6)); +$it = new MyRegexIterator($ar, '/(\d),(\d)/', RegexIterator::USE_KEY, RegexIterator::ALL_MATCHES); +$it->show(); + +$it = new MyRegexIterator($ar, '/(\d)/', RegexIterator::USE_KEY, RegexIterator::ALL_MATCHES); +$it->show(); + +var_dump($ar); + +?> +===DONE=== + +--EXPECTF-- +string(3) "1,2" +array(1) { + [0]=> + array(3) { + [0]=> + string(3) "1,2" + [1]=> + string(1) "1" + [2]=> + string(1) "2" + } +} +string(5) "1,2,3" +array(1) { + [0]=> + array(3) { + [0]=> + string(3) "1,2" + [1]=> + string(1) "1" + [2]=> + string(1) "2" + } +} +int(1) +array(1) { + [0]=> + array(2) { + [0]=> + string(1) "1" + [1]=> + string(1) "1" + } +} +string(3) "1,2" +array(2) { + [0]=> + array(2) { + [0]=> + string(1) "1" + [1]=> + string(1) "1" + } + [1]=> + array(2) { + [0]=> + string(1) "2" + [1]=> + string(1) "2" + } +} +string(5) "1,2,3" +array(3) { + [0]=> + array(2) { + [0]=> + string(1) "1" + [1]=> + string(1) "1" + } + [1]=> + array(2) { + [0]=> + string(1) "2" + [1]=> + string(1) "2" + } + [2]=> + array(2) { + [0]=> + string(1) "3" + [1]=> + string(1) "3" + } +} +int(0) +array(1) { + [0]=> + array(2) { + [0]=> + string(1) "0" + [1]=> + string(1) "0" + } +} +object(ArrayIterator)#%d (7) { + [1]=> + int(0) + ["1,2"]=> + int(1) + ["1,2,3"]=> + int(2) + [0]=> + int(3) + ["FooBar"]=> + int(4) + [","]=> + int(5) + [",,"]=> + int(6) +} +===DONE=== +--UEXPECTF-- +unicode(3) "1,2" +array(1) { + [0]=> + array(3) { + [0]=> + string(3) "1,2" + [1]=> + string(1) "1" + [2]=> + string(1) "2" + } +} +unicode(5) "1,2,3" +array(1) { + [0]=> + array(3) { + [0]=> + string(3) "1,2" + [1]=> + string(1) "1" + [2]=> + string(1) "2" + } +} +int(1) +array(1) { + [0]=> + array(2) { + [0]=> + string(1) "1" + [1]=> + string(1) "1" + } +} +unicode(3) "1,2" +array(2) { + [0]=> + array(2) { + [0]=> + string(1) "1" + [1]=> + string(1) "1" + } + [1]=> + array(2) { + [0]=> + string(1) "2" + [1]=> + string(1) "2" + } +} +unicode(5) "1,2,3" +array(3) { + [0]=> + array(2) { + [0]=> + string(1) "1" + [1]=> + string(1) "1" + } + [1]=> + array(2) { + [0]=> + string(1) "2" + [1]=> + string(1) "2" + } + [2]=> + array(2) { + [0]=> + string(1) "3" + [1]=> + string(1) "3" + } +} +int(0) +array(1) { + [0]=> + array(2) { + [0]=> + string(1) "0" + [1]=> + string(1) "0" + } +} +object(ArrayIterator)#%d (7) { + [1]=> + int(0) + [u"1,2"]=> + int(1) + [u"1,2,3"]=> + int(2) + [0]=> + int(3) + [u"FooBar"]=> + int(4) + [u","]=> + int(5) + [u",,"]=> + int(6) +} +===DONE=== diff --git a/ext/spl/tests/iterator_054.phpt b/ext/spl/tests/iterator_054.phpt new file mode 100755 index 0000000000..b3aaf4f45f --- /dev/null +++ b/ext/spl/tests/iterator_054.phpt @@ -0,0 +1,84 @@ +--TEST-- +SPL: RegexIterator::SPLIT +--SKIPIF-- + +--FILE-- + $v) + { + var_dump($k); + var_dump($v); + } + } +} + +$ar = new ArrayIterator(array('1','1,2','1,2,3','',NULL,array(),'FooBar',',',',,')); +$it = new MyRegexIterator($ar, '/,/', 0, RegexIterator::SPLIT); + +$it->show(); + +var_dump($ar); + +?> +===DONE=== + +--EXPECTF-- +int(1) +array(2) { + [0]=> + string(1) "1" + [1]=> + string(1) "2" +} +int(2) +array(3) { + [0]=> + string(1) "1" + [1]=> + string(1) "2" + [2]=> + string(1) "3" +} +int(7) +array(2) { + [0]=> + string(0) "" + [1]=> + string(0) "" +} +int(8) +array(3) { + [0]=> + string(0) "" + [1]=> + string(0) "" + [2]=> + string(0) "" +} +object(ArrayIterator)#%d (9) { + [0]=> + %s(1) "1" + [1]=> + %s(3) "1,2" + [2]=> + %s(5) "1,2,3" + [3]=> + %s(0) "" + [4]=> + NULL + [5]=> + array(0) { + } + [6]=> + %s(6) "FooBar" + [7]=> + %s(1) "," + [8]=> + %s(2) ",," +} +===DONE=== diff --git a/ext/spl/tests/iterator_055.phpt b/ext/spl/tests/iterator_055.phpt new file mode 100755 index 0000000000..9d881a1129 --- /dev/null +++ b/ext/spl/tests/iterator_055.phpt @@ -0,0 +1,93 @@ +--TEST-- +SPL: RegexIterator::SPLIT, USE_KEY +--SKIPIF-- + +--FILE-- + $v) + { + var_dump($k); + var_dump($v); + } + } +} + +$ar = new ArrayIterator(array('1'=>0,'1,2'=>1,'1,2,3'=>2,0=>3,'FooBar'=>4,','=>5,',,'=>6)); +$it = new MyRegexIterator($ar, '/(\d),(\d)/', RegexIterator::USE_KEY, RegexIterator::SPLIT); + +$it->show(); + +var_dump($ar); + +?> +===DONE=== + +--EXPECTF-- +string(3) "1,2" +array(2) { + [0]=> + string(0) "" + [1]=> + string(0) "" +} +string(5) "1,2,3" +array(2) { + [0]=> + string(0) "" + [1]=> + string(2) ",3" +} +object(ArrayIterator)#%d (7) { + [1]=> + int(0) + ["1,2"]=> + int(1) + ["1,2,3"]=> + int(2) + [0]=> + int(3) + ["FooBar"]=> + int(4) + [","]=> + int(5) + [",,"]=> + int(6) +} +===DONE=== +--UEXPECTF-- +unicode(3) "1,2" +array(2) { + [0]=> + string(0) "" + [1]=> + string(0) "" +} +unicode(5) "1,2,3" +array(2) { + [0]=> + string(0) "" + [1]=> + string(2) ",3" +} +object(ArrayIterator)#%d (7) { + [1]=> + int(0) + [u"1,2"]=> + int(1) + [u"1,2,3"]=> + int(2) + [0]=> + int(3) + [u"FooBar"]=> + int(4) + [u","]=> + int(5) + [u",,"]=> + int(6) +} +===DONE=== -- 2.40.0