Home modules.gotpike.org
Username: Password: [Create Account]
[Forgot Password?]

Modules

ADT
Database
GTK2
GUI
IP
PiJAX
Public
Sql
Stdio
Subversion
System
Tools
Xosd
lua
v4l2
wx

Recent Changes

Public.Parser.XML2 1.50
Public.ZeroMQ 1.1
Public.Template.Mustache 1.0
Public.Protocols.XMPP 1.4
Sql.Provider.jdbc 1.0

Popular Downloads

Public.Parser.JSON2 1.0
Public.Parser.JSON 0.2
GTK2 2.23
Public.Web.FCGI 1.8
Public.Parser.XML2 1.48


Module Information
Public.Regexp.PCRE
Viewing contents of Public_Regexp_PCRE-1.2/PCRE.cmod

/*
 * Copyright (c) 2006 Adam Montague 
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include "util.h"
#include 

EXTRA
{
	add_string_constant("__version", "1.2", 0);
	add_string_constant("__author", "Adam Montague ", 0);

	add_integer_constant("CASELESS", PCRE_CASELESS, 0);
	add_integer_constant("MULTILINE", PCRE_MULTILINE, 0);
	add_integer_constant("DOTALL", PCRE_DOTALL, 0);
	add_integer_constant("EXTENDED", PCRE_EXTENDED, 0);
	add_integer_constant("ANCHORED", PCRE_ANCHORED, 0);
	add_integer_constant("DOLLAR_ENDONLY", PCRE_DOLLAR_ENDONLY, 0);
	add_integer_constant("EXTRA", PCRE_EXTRA, 0);
	add_integer_constant("NOTBOL", PCRE_NOTBOL, 0);
	add_integer_constant("NOTEOL", PCRE_NOTEOL, 0);
	add_integer_constant("UNGREEDY", PCRE_UNGREEDY, 0);
	add_integer_constant("NOTEMPTY", PCRE_NOTEMPTY, 0);
	add_integer_constant("UTF8", PCRE_UTF8, 0);
	add_integer_constant("NO_AUTO_CAPTURE", PCRE_NO_AUTO_CAPTURE, 0);
	add_integer_constant("NO_UTF8_CHECK", PCRE_NO_UTF8_CHECK, 0);
#ifdef PCRE_PARTIAL
	add_integer_constant("PARTIAL", PCRE_PARTIAL, 0);
#endif
#ifdef PCRE_FIRSTLINE
	add_integer_constant("FIRSTLINE", PCRE_FIRSTLINE, 0);
#endif
}
/*
	add_integer_constant("NOTBOL", PCRE_NOTBOL, 0);
	add_integer_constant("NOTEOL", PCRE_NOTEOL, 0);
	add_integer_constant("NOTEMPTY", PCRE_NOTEMPTY, 0);
	add_integer_constant("NO_UTF8_CHECK", PCRE_NO_UTF8_CHECK, 0);
	add_integer_constant("PARTIAL", PCRE_PARTIAL, 0);
	add_integer_constant("FIRSTLINE", PCRE_FIRSTLINE, 0);
*/

static char err_msgs[14][50] = {
	"Passed a NULL pointer\n",
	"Invalid option bit set\n",
	"Bad magic number\n",
	"Unknown node in pattern\n",
	"Failed to allocate memory\n",
	"No such substring\n",
	"Match limit exceeded\n",
	"Callout error\n",
	"Invalid UTF-8 character\n",
	"Invalid offset into UTF-8 string\n",
	"Partial match\n",
	"Pattern cannot be partially matched\n",
	"Internal pcre error\n",
	"Invalid ovec size\n"
};

static void realloc_array(struct array *arr, size_t size)
{
	struct svalue *tmp;
	tmp = realloc(arr->item, sizeof(struct svalue) * size);
	if (tmp == NULL) {
		sub_ref(arr);
		really_free_array(arr);
		Pike_error("Memory allocation failed!\n");
	}
	arr->item = tmp;
	arr->malloced_size = size;
}

/*! @module Public
 */

/*! @module Regexp
 */

/*! @module PCRE
 */

/*! @class Plain
 *!   The basic class for perl compatible regular expressions.
 */
PIKECLASS Plain
{
	CVAR pcre *regex;
	CVAR pcre_extra *extra;		// for studied regexps
	CVAR int ovec_size;
	PIKEVAR string pattern
	    flags ID_STATIC;

	INIT
	{
		THIS->regex = NULL;
		THIS->extra = NULL;
	}

	EXIT
	{
		if (THIS->regex != NULL) {
			free(THIS->regex);
		}
		if (THIS->extra != NULL) {
			free(THIS->extra);
		}
	}

/*! @decl void create(string pattern, int|void options)
 *!   Creates a regex object.
 *!
 *! @param pattern
 *!   The pattern to be used for matching.
 *!
 *! @param options
 *!   Any of the following options ORed together.
 *! @int
 *!   @value CASELESS
 *!     Case insensitive matching
 *!   @value MULTILINE
 *!     The ^ and $ special characters match based on \n characters within the string
 *!   @value DOTALL
 *!     The . special character will match anything, including \n
 *!   @value EXTENDED
 *!     Allow comments using # and ignore unescaped whitespace within the pattern
 *!   @value ANCHORED
 *!     Force the pattern to only match at the first matching point in the string
 *!   @value DOLLAR_ENDONLY
 *!     The $ special character will not match a final \n at the end of the string
 *!   @value EXTRA
 *!     Throw an error when the pattern contains a backslash followed by a letter which has
 *!     no special meaning
 *!   @value UNGREEDY
 *!     Invert the greediness of matching.
 *!   @value UTF8
 *!     Treat the pattern and subject strings as UTF8 strings.  Will throw an error if used
 *!     when pcre was not compiled with utf8 support
 *!   @value NO_AUTO_CAPTURE
 *!     Disable automatic substring capturing.  Named substrings may still be used.
 *! @endint
 */
	PIKEFUN void create(string pattern, int|void options)
	    flags ID_STATIC;
	{
		int err_offset;
		const char *err_msg;
		int opts;

		if (pattern->len == 0) {
			Pike_error("You can't use an empty string as a regex!\n");
		}
		if (THIS->regex != NULL || THIS->extra != NULL) {
			Pike_error("Constructor has already been called!\n");
		}

		if (options != NULL) {
			opts = options->u.integer;
		} else {
			opts = 0;
		}

		copy_shared_string(THIS->pattern, pattern);
		if ((THIS->regex = pcre_compile(pattern->str, opts, &err_msg, &err_offset, NULL)) == NULL) {
			Pike_error("Compile failed at character %d: %s\n", err_offset, err_msg);
		}
		THIS->ovec_size = (pcre_info(THIS->regex, NULL, NULL) + 1) * 3;
		pop_n_elems(args);
	}


/*! @decl array(int) exec(string subject, int|void offset)
 *!   Low level method that returns an array containing the locations of the
 *!   matched string and captured substrings as integer offsets.
 *!   The matched string is subject[ret[0]..ret[1] - 1]
 *!
 *! @param subject
 *!   The string to search.
 *!
 *! @param offset
 *!   The offset into the subject to begin searching.
 */
	PIKEFUN array(int) exec(string subject, int|void offset)
	{
		int ovec[THIS->ovec_size];
		int off, size, i;
		struct array *ret;

		if (offset != NULL) {
			off = offset->u.integer;
		} else {
			off = 0;
		}

		size = pcre_exec(THIS->regex, THIS->extra, subject->str, subject->len, off, 0, ovec, THIS->ovec_size);

		if (size < -1) {
			Pike_error(err_msgs[-size - 2]);
		}
		if (size == -1) {
			add_ref(&empty_array);
			RETURN(&empty_array);
		}
		ret = allocate_array_no_init(size * 2, 0);
		for (i = 0; i < ret->size; i++) {
			ITEM(ret)[i].type = T_INT;
			ITEM(ret)[i].u.integer = ovec[i];
		}
		RETURN(ret);
	}

/*! @decl int(0..1) match(string subject, int|void offset)
 *!   Returns 1 if subject matches the pattern, or 0 if it does not.
 *!
 *! @param subject
 *!   The string to search.
 *!
 *! @param offset
 *!   The offset into the subject to begin searching.
 */
	PIKEFUN int(0..1) match(string subject, int|void offset)
	{
		int ovec[THIS->ovec_size];
		int ret, off;

		if (offset != NULL) {
			off = offset->u.integer;
		} else {
			off = 0;
		}

		ret = pcre_exec(THIS->regex, THIS->extra, subject->str, subject->len, off, 0, ovec, THIS->ovec_size);
		if (ret == -1) {
			RETURN(0);
		}
		if (ret < -1) {
			Pike_error(err_msgs[-ret - 2]);
		}
		RETURN(1);
	}

/*! @decl int|array(int|array(array(string))) matchall(string subject, int|void offset, int|void limit, int|void substrings)
 *!   Returns the number of times the pattern matches subject, or an array with the first element
 *!   the number of matches, and the second element an array of the matched substrings if substrings is not 0.
 *!
 *! @param subject
 *!   The string to search.
 *!
 *! @param offset
 *!   The offset into the subject to begin searching.
 *!
 *! @param limit
 *!   Stop searching for more matches once this many matches have been found.
 *!
 *! @param substrings
 *!   In addition to the number of matches, also return an array containing the matches that were found.
 *!   Each element in this array is another array, where element 0 is the entire match, and each element
 *!   after that is a captured substring.
 */
	PIKEFUN int|array(int|array(array(string))) matchall(string subject, int|void offset, int|void limit, int|void substrings)
	{
		int ovec[THIS->ovec_size];
		int ret, off, lim, count, i;
		struct array *arr;

		if (offset != NULL) {
			off = offset->u.integer;
		} else {
			off = 0;
		}
		if (limit != NULL) {
			lim = limit->u.integer;
		} else {
			lim = -1;
		}
		ret = count = 0;

		if (substrings != NULL && substrings->u.integer != 0) {
			arr = allocate_array_no_init(0, 10);
			arr->type_field = BIT_ARRAY;
		}

		while ((ret = pcre_exec(THIS->regex, THIS->extra, subject->str, subject->len, off, 0, ovec, THIS->ovec_size)) > 0) {
			off = ovec[1];
			count++;

			if (substrings != NULL && substrings->u.integer != 0) {
				if (arr->size == arr->malloced_size) {
					realloc_array(arr, arr->malloced_size * 2);
				}
				ITEM(arr)[arr->size].type = T_ARRAY;
				ITEM(arr)[arr->size].subtype = 0;
				ITEM(arr)[arr->size].u.array = allocate_array_no_init(ret, 0);
				ITEM(arr)[arr->size].u.array->type_field = BIT_STRING;
				for (i = 0; i < ret; i++) {
					ITEM(ITEM(arr)[arr->size].u.array)[i].type = T_STRING;
					ITEM(ITEM(arr)[arr->size].u.array)[i].u.string = make_shared_binary_string(subject->str + ovec[i * 2], ovec[i * 2 + 1] - ovec[i * 2]);
				}
				arr->size++;
			}

			if (lim != -1) {
				if (--lim == 0) {
					break;
				}
			}
		}
		if (ret < -1) {
			Pike_error(err_msgs[-ret - 1]);
		}

		if (substrings != NULL && substrings->u.integer != 0) {
			struct array *tmp;
			tmp = allocate_array_no_init(2, 0);
			tmp->type_field = BIT_INT | BIT_ARRAY;
			ITEM(tmp)[0].type = T_INT;
			ITEM(tmp)[0].u.integer = count;
			ITEM(tmp)[1].type = T_ARRAY;
			ITEM(tmp)[1].u.array = arr;
			pop_n_elems(args);
			push_array(tmp);
			return;
		}

		pop_n_elems(args);
		push_int(count);
	}

/*! @decl string|array(string|array(array(string))) replace(string subject, string|function(array(string):string) replacement, int|void offset, int|void limit, int|void substrings)
 *!   Returns the subject with any matches replaced, or an array with the first element the replaced subject,
 *!   and the second element an array of the matched substrings if substrings is not 0.
 *!
 *! @param subject
 *!   The string to search and replace in.
 *!
 *! @param replacement
 *!   If replacement is a string, each match in subject will be replaced with this string.
 *!   If replacement is a function, it will be called for each match, and the matching part of
 *!   subject will be replaced with the string returned.  This function is passed an array of
 *!   strings, where element 0 is the entire match, and each element after that is a captured
 *!   substring.
 *!
 *! @param offset
 *!   The offset into the subject to begin searching.
 *!
 *! @param limit
 *!   Stop searching for more matches once this many replacments have been done.
 *!
 *! @param substrings
 *!   In addition to the replaced subject, also return an array containing the matches that were found.
 *!   Each element in this array is another array, where element 0 is the entire match, and each element
 *!   after that is a captured substring.
 */
	PIKEFUN string|array(string|array(array(string))) replace(string subject, string|function(array(string):string) replacement, int|void offset, int|void limit, int|void substrings)
	{
		int ovec[THIS->ovec_size];
		int off, pos, i, matches, lim, memcpy_size;
		struct pike_string *ret;
		struct array *substrs, *arr;

		if (offset != NULL) {
			off = offset->u.integer;
		} else {
			off = 0;
		}
		if (limit != NULL) {
			lim = limit->u.integer;
		} else {
			lim = -1;
		}
		pos = 0;
		ret = begin_shared_string(1024);

		if (substrings != NULL && substrings->u.integer != 0) {
			arr = allocate_array_no_init(0, 10);
			arr->type_field = BIT_ARRAY;
		}

		if (off > 0) {
			while (off > ret->len) {
				ret = realloc_unlinked_string(ret, ret->len * 2);
			}
			memcpy(ret->str, subject->str, off);
			pos = off;
		}

#define SLASH 1
#define DOLLAR 2
#define BRACE 3
		while ((matches = pcre_exec(THIS->regex, THIS->extra, subject->str, subject->len, off, 0, ovec, THIS->ovec_size)) > 0) {
			int flag, reference, j;
			flag = 0;
			reference = -1;

			if (substrings != NULL && substrings->u.integer != 0) {
				if (arr->size == arr->malloced_size) {
					realloc_array(arr, arr->malloced_size * 2);
				}
				ITEM(arr)[arr->size].type = T_ARRAY;
				ITEM(arr)[arr->size].subtype = 0;
				ITEM(arr)[arr->size].u.array = allocate_array_no_init(matches, 0);
				ITEM(arr)[arr->size].u.array->type_field = BIT_STRING;
				for (i = 0; i < matches; i++) {
					ITEM(ITEM(arr)[arr->size].u.array)[i].type = T_STRING;
					ITEM(ITEM(arr)[arr->size].u.array)[i].u.string = make_shared_binary_string(subject->str + ovec[i * 2], ovec[i * 2 + 1] - ovec[i * 2]);
				}
				arr->size++;
			}

			/* copy the existing string up until the beginning of the first match */
			memcpy_size = ovec[0] - off;
			while (pos + memcpy_size > ret->len) {
				ret = realloc_unlinked_string(ret, ret->len * 2);
			}
			memcpy(ret->str + pos, subject->str + off, memcpy_size);
			pos += memcpy_size;

			if (replacement->type == PIKE_T_STRING) {
				/* copy the replacement text */
				for (i = 0; i < replacement->u.string->len; i++) {
					switch (flag) {
					case 0:
						if (replacement->u.string->str[i] == '\\') {
							flag = SLASH;
						} else if (replacement->u.string->str[i] == '$') {
							flag = DOLLAR;
						}
						ret->str[pos] = replacement->u.string->str[i];
						pos++;
						break;
					case SLASH:
						if (replacement->u.string->str[i] == '$') {
							ret->str[pos - 1] = '$';
							flag = 0;
						} else {
							ret->str[pos] = replacement->u.string->str[i];
							pos++;
							flag = 0;
						}
						break;
					case DOLLAR:
						if (replacement->u.string->str[i] == '{') {
							flag = BRACE;
						} else if (isdigit(replacement->u.string->str[i])) {
							reference = (reference == -1) ? replacement->u.string->str[i] -
							    48 : reference * 10 + (replacement->u.string->str[i] - 48);
						} else {
							/* reference is too high, back up over the $ and start over */
							if (reference >= matches) {
								pos--;
							} else if (reference != -1) {
								/* copy the referenced string */
								pos--;	/* we need to back up over the '$' */
								memcpy_size = ovec[reference * 2 + 1] - ovec[reference * 2];
								while (pos + memcpy_size > ret->len) {
									ret = realloc_unlinked_string(ret, ret->len * 2);
								}
								memcpy(ret->str + pos, subject->str + ovec[reference * 2], memcpy_size);
								pos += memcpy_size;
							}
							flag = 0;
							reference = -1;
							i--;
						}
						break;
					case BRACE:
						if (replacement->u.string->str[i] == '}') {
							if (reference == -1) {
								Pike_error("Invalid reference at character %d\n", i);
							}
							if (reference >= matches) {
								pos--;
								flag = 0;
								reference = -1;
								break;
							}
							/* copy the referenced string */
							pos--;	/* we need to back up over the '$' */
							memcpy_size = ovec[reference * 2 + 1] - ovec[reference * 2];
							while (pos + memcpy_size > ret->len) {
								ret = realloc_unlinked_string(ret, ret->len * 2);
							}
							memcpy(ret->str + pos, subject->str + ovec[reference * 2], memcpy_size);
							pos += memcpy_size;
							flag = 0;
							reference = -1;
						} else if (isdigit(replacement->u.string->str[i])) {
							reference = reference == -1 ? replacement->u.string->str[i] -
							    48 : reference * 10 + (replacement->u.string->str[1] - 48);
						} else {
							Pike_error("Unclosed reference at character %d\n", i);
						}
						break;
					}
					if (pos == ret->len) {
						ret = realloc_unlinked_string(ret, ret->len * 2);
					}
				}
				if (flag == BRACE) {
					Pike_error("Unclosed reference at character %d\n", i);
				}
				if (flag == DOLLAR && reference != -1) {
					if (reference >= matches) {
						pos--;
					} else {
						/* copy the referenced string */
						pos--;	/* we need to back up over the '$' */
						memcpy_size = ovec[reference * 2 + 1] - ovec[reference * 2];
						while (pos + memcpy_size > ret->len) {
							ret = realloc_unlinked_string(ret, ret->len * 2);
						}
						memcpy(ret->str + pos, subject->str + ovec[reference * 2], memcpy_size);
						pos += memcpy_size;
					}
				}
			} else {	/* get the replacement string from the callback */
				if (substrings != NULL && substrings->u.integer != 0) {
					substrs = ITEM(arr)[arr->size - 1].u.array;
				} else {
					substrs = allocate_array_no_init(matches, 0);
					substrs->type_field = BIT_STRING;
					for (i = 0; i < substrs->size; i++) {
						ITEM(substrs)[i].type = T_STRING;
						ITEM(substrs)[i].u.string = make_shared_binary_string(subject->str + ovec[i * 2], ovec[i * 2 + 1] - ovec[i * 2]);
					}
				}
				push_array(substrs);
				apply_svalue(replacement, 1);
				if (Pike_sp[-1].type != T_STRING) {
					Pike_error("Callback did not return string\n");
				}
				while (pos + Pike_sp[-1].u.string->len > ret->len) {
					ret = realloc_unlinked_string(ret, ret->len * 2);
				}
				memcpy(ret->str + pos, Pike_sp[-1].u.string->str, Pike_sp[-1].u.string->len);
				pos += Pike_sp[-1].u.string->len;
				pop_stack();
			}
			off = ovec[1];
			if (lim != -1) {
				if (--lim == 0) {
					break;
				}
			}
		}

		if (matches < -1) {
			Pike_error(err_msgs[-matches - 1]);
		}

		/* copy any left over original string after there's no more matches */
		memcpy_size = subject->len - off;
		while (pos + memcpy_size > ret->len) {
			ret = realloc_unlinked_string(ret, ret->len * 2);
		}
		memcpy(ret->str + pos, subject->str + off, memcpy_size);
		pos += memcpy_size;

		if (substrings != NULL && substrings->u.integer != 0) {
			struct array *tmp;
			tmp = allocate_array_no_init(2, 0);
			tmp->type_field = BIT_STRING | BIT_ARRAY;
			ITEM(tmp)[0].type = T_STRING;
			ITEM(tmp)[0].u.string = end_and_resize_shared_string(ret, pos);
			ITEM(tmp)[1].type = T_ARRAY;
			ITEM(tmp)[1].u.array = arr;
			pop_n_elems(args);
			push_array(tmp);
			return;
		}
		pop_n_elems(args);
		push_string(end_and_resize_shared_string(ret, pos));
	}

/*! @decl array(string)|array(array(string)|array(array(string))) split(string subject, int|void offset, int|void limit, int|void substrings)
 *!   Returns an array of strings containing the parts of the subject split on the pattern,
 *!   or an array with the first element the array of the split subject,
 *!   and the second element an array of the matched substrings if substrings is not 0.
 *!
 *! @param subject
 *!   The string to split.
 *!
 *! @param offset
 *!   The offset into the subject to begin searching.
 *!
 *! @param limit
 *!   Stop searching for more matches to split on once this many matches have been found.
 *!
 *! @param substrings
 *!   In addition to the split subject, also return an array containing the matches that were found.
 *!   Each element in this array is another array, where element 0 is the entire match, and each element
 *!   after that is a captured substring.
 */
	PIKEFUN array(string)|array(array(string)|array(array(string))) split(string subject, int|void offset, int|void limit, int|void substrings)
	{
		int ovec[THIS->ovec_size];
		int i, off, pos, matches, len, r, lim;
		char split_string[subject->len];
		struct array *ret, *arr;

		if (offset != NULL) {
			off = offset->u.integer;
		} else {
			off = 0;
		}
		if (limit != NULL) {
			lim = limit->u.integer;
		} else {
			lim = -1;
		}

		if (substrings != NULL && substrings->u.integer != 0) {
			arr = allocate_array_no_init(0, 10);
			arr->type_field = BIT_ARRAY;
		}

		pos = matches = 0;
		if (off > 0) {
			memcpy(split_string, subject->str, off);
			pos = off;
		}

		while ((r = pcre_exec(THIS->regex, THIS->extra, subject->str, subject->len, off, 0, ovec, THIS->ovec_size)) > 0) {
			if (substrings != NULL && substrings->u.integer != 0) {
				if (arr->size == arr->malloced_size) {
					realloc_array(arr, arr->malloced_size * 2);
				}
				ITEM(arr)[arr->size].type = T_ARRAY;
				ITEM(arr)[arr->size].subtype = 0;
				ITEM(arr)[arr->size].u.array = allocate_array_no_init(r, 0);
				ITEM(arr)[arr->size].u.array->type_field = BIT_STRING;
				for (i = 0; i < r; i++) {
					ITEM(ITEM(arr)[arr->size].u.array)[i].type = T_STRING;
					ITEM(ITEM(arr)[arr->size].u.array)[i].u.string = make_shared_binary_string(subject->str + ovec[i * 2], ovec[i * 2 + 1] - ovec[i * 2]);
				}
				arr->size++;
			}

			memcpy(split_string + pos, subject->str + off, ovec[0] - off);
			pos += ovec[0] - off;
			split_string[pos] = '\0';
			pos++;
			off = ovec[1];
			matches++;
			if (lim != -1) {
				if (--lim == 0) {
					break;
				}
			}
		}

		if (r < -1) {
			Pike_error(err_msgs[-r - 1]);
		}

		/* copy what's left after the last match */
		memcpy(split_string + pos, subject->str + off, subject->len - off);
		pos += subject->len - off;
		split_string[pos] = '\0';

		ret = allocate_array_no_init(matches + 1, 0);
		for (pos = i = 0; i < ret->size; i++) {
			ITEM(ret)[i].type = T_STRING;
			len = strlen(split_string + pos);
			ITEM(ret)[i].u.string = make_shared_binary_string(split_string + pos, len);
			pos += len + 1;
		}

		if (substrings != NULL && substrings->u.integer != 0) {
			struct array *tmp;
			tmp = allocate_array_no_init(2, 0);
			tmp->type_field = BIT_ARRAY;
			ITEM(tmp)[0].type = T_ARRAY;
			ITEM(tmp)[0].u.array = ret;
			ITEM(tmp)[1].type = T_ARRAY;
			ITEM(tmp)[1].u.array = arr;
			pop_n_elems(args);
			push_array(tmp);
			return;
		}
		pop_n_elems(args);
		push_array(ret);
	}
}
/*! @endclass
 */

/*! @class Studied
 *! @inherit Plain
 *!   The Studied class spends extra time on object creation studying the
 *!   regular expression in order to speed up later matching.  Use this class
 *!   if you will be matching against the same pattern many times.
 */
PIKECLASS Studied
{
	static int inherited_Plain_create_num;
	INHERIT Plain;

	EXTRA
	{
		inherited_Plain_create_num = really_low_reference_inherited_identifier(NULL, 1, f_Plain_create_fun_num);
	}

	PIKEFUN void create(string pattern, int|void options)
	    flags ID_STATIC;
	{
		const char *err_msg;
		apply_current(inherited_Plain_create_num, args);
		THIS->extra = pcre_study(THIS->regex, 0, &err_msg);
		if (err_msg != NULL) {
			Pike_error("Studying compiled regex failed: %s\n", err_msg);
		}
	}
}
/*! @endclass
 */

/*! @endmodule
 */

/*! @endmodule
 */

/*! @endmodule
 */


gotpike.org | Copyright © 2004 - 2019 | Pike is a trademark of Department of Computer and Information Science, Linköping University