mud/fluffos-2.23-ds03/packages/pcre.c
2020-09-06 05:43:07 -07:00

1011 lines
22 KiB
C

/* FILES
* - pcre.c
* - pcre_spec.c
* - pcre.h
*
* PCRE (Perl Compatible Regular Expressions)
* Efuns using system library of PCRE (http://www.pcre.org/)
* The PCRE library was created by Philip Hazel at the
* University of Cambridge
*
* For regular expressions syntactics:
* http://perldoc.perl.org/perlre.html
*
*
* AUTHOR
* Volothamp @ Final Realms
* nfa106 [a] gmail.com
*
* HISTORY
* June-July 2009:
* Package created
*
*
* DESCRIPTION
*
* This package introduces the following efuns:
*
* string pcre_version();
* - returns the version of the compiled PCRE library used
*
* mixed pcre_match(string | string *, string, void | int);
* - analog with regexp(string | string *, string, void | int);
* for backwards compatibility reasons but utilizing the PCRE
* library.
*
* mixed *pcre_assoc(string, string *, mixed *, mixed | void);
* - analog with reg_assoc(string, string *, mixed *, mixed | void);
* for backwards compatibility reasons but utilizing the PCRE
* library.
*
* string *pcre_extract(string subject, string pattern);
* - returns an array of captured groups specified in pattern
*
* string pcre_replace(string subject, string pattern, string *replacement);
* - returns a string where all captured groups have been replaced by the
* elements of the replacement array. Number of subgroups and the size of
* the replacement array must match.
*
* string pcre_replace_callback(string subject, string pattern, function | string fun, object ob);
* - returns a string where all captured groups have been replaced by the
* return value of function pointe fun or function fun in object ob.
*/
//TODO
// study pattern
// extra options when matching, greedy, lazy, possesive, etc.
// match_all ? see previous
// store reg->error & reg->erroffset before error(..)
#include "lpc_incl.h"
#include <pcre.h>
#include "pcre.h"
#include "macros.h"
#include "mapping.h"
// Prototype declarations
static void pcre_free_memory(pcre_t *p);
static pcre *pcre_local_compile(pcre_t *p);
static int pcre_local_exec(pcre_t *p);
static int pcre_magic(pcre_t *p);
static int pcre_query_match(pcre_t *p);
static int pcre_match_single(svalue_t *str, svalue_t *pattern);
static array_t *pcre_match(array_t *v, svalue_t *pattern, int flag);
static array_t *pcre_assoc(svalue_t *str, array_t *pat, array_t *tok, svalue_t *def);
static char *pcre_get_replace(pcre_t *run, array_t *replacements);
static array_t *pcre_get_substrings(pcre_t *run);
//Caching functions
static int pcre_cache_pattern(struct pcre_cache_t *table, pcre *cpat, svalue_t *pattern);
static pcre *pcre_get_cached_pattern(struct pcre_cache_t *table, svalue_t *pattern);
static mapping_t *pcre_get_cache();
int pcrecachesize = 0;
// Globals
struct pcre_cache_t pcre_cache = {{ 0 }};
// efuns
void f_pcre_version(void)
{
char *version;
version = (char *)pcre_version();
push_constant_string(version);
}
void f_pcre_match(void)
{
array_t *v;
int flag = 0;
if (st_num_arg > 2)
{
if (sp->type != T_NUMBER)
error("Bad argument 3 to pcre_match()\n");
if ((sp - 2)->type == T_STRING)
error("3rd argument illegal for pcre_match(string, string)\n");
flag = (sp--)->u.number;
}
if ((sp - 1)->type == T_STRING )
{
flag = pcre_match_single((sp-1), sp);
free_string_svalue(sp--);
free_string_svalue(sp);
put_number(flag);
}
else
{
v = pcre_match((sp - 1)->u.arr, sp, flag);
free_string_svalue(sp--);
free_array(sp->u.arr);
sp->u.arr = v;
}
}
void f_pcre_assoc(void)
{
svalue_t *arg;
array_t *vec;
arg = sp - st_num_arg + 1;
if ((arg + 2)->type != T_ARRAY)
error("Bad argument 3 to pcre_assoc()\n");
vec = pcre_assoc(arg, (arg+1)->u.arr, (arg+2)->u.arr,
st_num_arg > 3 ? (arg+3) : &const0);
if (st_num_arg == 4)
pop_3_elems();
else
pop_2_elems();
free_string_svalue(sp);
sp->type = T_ARRAY;
sp->u.arr = vec;
}
void f_pcre_extract(void)
{
pcre_t *run;
array_t *ret;
run = CALLOCATE(1, pcre_t, TAG_TEMPORARY, "f_pcre_extract : run");
assign_svalue_no_free(&run->pattern, sp);
run->subject = (sp - 1)->u.string;
run->s_length = SVALUE_STRLEN(sp - 1);
run->ovector = NULL;
run->ovecsize = 0;
if(pcre_magic(run) < 0)
{
error("PCRE compilation failed at offset %d: %s\n", run->erroffset,
run->error);
pop_2_elems();
pcre_free_memory(run);
return;
}
/* Pop the 2 arguments from the stack */
if (run->rc < 0) /* No match. could do handling of matching errors if wanted */
{
pop_2_elems();
pcre_free_memory(run);
push_refed_array(&the_null_array);
return;
}
else if (run->rc > (run->ovecsize/3 - 1))
{
pop_2_elems();
pcre_free_memory(run);
error("Too many substrings.\n");
return;
}
ret = pcre_get_substrings(run);
pop_2_elems();
push_refed_array(ret);
pcre_free_memory(run);
return;
}
void f_pcre_replace(void)
{
pcre_t *run;
array_t *replacements;
unsigned int i;
char *ret;
run = CALLOCATE(1, pcre_t, TAG_TEMPORARY, "f_pcre_replace: run");
run->ovector = NULL;
run->ovecsize = 0;
assign_svalue_no_free(&run->pattern, (sp - 1));
run->subject = (sp - 2)->u.string;
replacements = sp->u.arr;
run->s_length = SVALUE_STRLEN(sp - 2);
if(pcre_magic(run) < 0)
{
pcre_free_memory(run);
error("PCRE compilation failed at offset %d: %s\n", run->erroffset,
run->error);
}
if (run->rc < 0) /* No match. could do handling of matching errors if wanted */
{
pcre_free_memory(run);
pop_2_elems();
return;
}
if (run->rc > (run->ovecsize/3-1))
{
pcre_free_memory(run);
error("Too many substrings.\n");
}
if ( (run->rc - 1) != replacements->size )
{
int tmp = run->rc-1;
pcre_free_memory(run);
error("Number of captured substrings and replacements do not match, "
"%d vs %d.\n", tmp, replacements->size);
}
if (run->rc == 1)
{
/* No captured substrings, return subject */
pcre_free_memory(run);
pop_2_elems();
return;
//push_malloced_string(run->subject);
}
ret = pcre_get_replace(run, replacements);
pop_3_elems();
push_malloced_string(ret);
pcre_free_memory(run);
return;
}
//string pcre_replace_callback(string, string, function)
void f_pcre_replace_callback(void)
{
int num_arg = st_num_arg, i;
char *ret;
pcre_t *run;
svalue_t *arg;
array_t *arr, *r;
function_to_call_t ftc;
arg = sp - num_arg + 1;
run = CALLOCATE(1, pcre_t, TAG_TEMPORARY, "f_pcre_replace: run");
run->ovector = NULL;
run->ovecsize = 0;
run->subject = arg->u.string;
assign_svalue_no_free(&run->pattern, (arg + 1));
run->s_length = SVALUE_STRLEN(arg);
if(pcre_magic(run) < 0)
{
pcre_free_memory(run);
error("PCRE compilation failed at offset %d: %s\n", run->erroffset,
run->error);
}
if (run->rc < 0) /* No match. could do handling of matching errors if wanted */
{
pop_n_elems(num_arg-1);
pcre_free_memory(run);
return;
}
if (run->rc > (run->ovecsize/3-1))
{
pcre_free_memory(run);
error("Too many substrings.\n");
}
arr = pcre_get_substrings(run);
if(arg[2].type == T_FUNCTION || arg[2].type == T_STRING)
process_efun_callback(2, &ftc, F_PCRE_REPLACE_CALLBACK);
else {// 0
pcre_free_memory(run);
error("Illegal third argument (0) to pcre_replace_callback");
}
r = allocate_array(run->rc - 1); //can't use the empty variant in case we error below
push_refed_array(r);
push_refed_array(arr);
error_context_t econ;
if (!save_context(&econ)){
pcre_free_memory(run);
error("context stack full!\n");
}
if (SETJMP(econ.context)) {
restore_context(&econ);
/* condition was restored to where it was when we came in */
pcre_free_memory(run);
pop_context(&econ);
error("error in callback!\n");
}
for (i = 0; i < run->rc - 1; i++)
{
svalue_t *v;
push_svalue(arr->item + i);
push_number(i);
v = call_efun_callback(&ftc, 2);
/* Mimic behaviour of map(string, function) when function pointer returns null,
ie return the input. */
if (v && v->type == T_STRING && v->u.string != NULL)
assign_svalue_no_free(&r->item[i], v);
else
assign_svalue_no_free(&r->item[i], &arr->item[i]);
}
pop_context(&econ);
ret = pcre_get_replace(run, r);
pop_n_elems(num_arg+2); //refed arrays
push_malloced_string(ret);
pcre_free_memory(run);
return;
}
void f_pcre_cache(void)
{
mapping_t *m=NULL;
m = pcre_get_cache();
if (!m)
push_number(0);
else
push_refed_mapping(m);
}
// Internal functions utilized by the efuns
static pcre *pcre_local_compile(pcre_t *p)
{
p->re = pcre_compile(
p->pattern.u.string,
0,
&p->error,
&p->erroffset,
NULL);
return p->re;
}
static int pcre_local_exec(pcre_t *p)
{
int size;
pcre_fullinfo(p->re, NULL, PCRE_INFO_CAPTURECOUNT, &size);
size+=2;
size *=3;
if(p->ovector)
FREE(p->ovector);
p->ovector = CALLOCATE(size+1, int, TAG_TEMPORARY, "pcre_local_exec"); //too much, but who cares
p->ovecsize = size;
p->rc = pcre_exec(
p->re,
NULL,
p->subject,
p->s_length,
0,
#ifndef USE_ICONV
PCRE_NO_UTF8_CHECK,
#else
0,
#endif
p->ovector,
size);
return p->rc;
}
static int pcre_magic(pcre_t *p)
{
p->re = pcre_get_cached_pattern(&pcre_cache, &p->pattern);
if (p->re == NULL)
{
pcre_local_compile(p);
pcre_cache_pattern(&pcre_cache, p->re, &p->pattern);
}
if (p->re == NULL)
return -1;
/* Add support for studied patterns here */
//if(p->study && !found)
// {
// }
pcre_local_exec(p);
return 1;
}
static int pcre_query_match(pcre_t *p)
{
return p->rc < 0 ? 0 : 1;
}
static int pcre_match_single(svalue_t *str, svalue_t *pattern)
{
pcre_t *run;
int ret;
run = CALLOCATE(1, pcre_t, TAG_TEMPORARY, "pcre_match_single : run");
run->ovector = NULL;
run->ovecsize = 0;
assign_svalue_no_free(&run->pattern, pattern);
run->subject = str->u.string;
run->s_length = SVALUE_STRLEN(str);
if(pcre_magic(run) < 0)
{
error("PCRE compilation failed at offset %d: %s\n", run->erroffset,
run->error);
pcre_free_memory(run);
return 0;
}
ret = pcre_query_match(run);
/* Free memory */
pcre_free_memory(run);
return ret;
}
static array_t *pcre_match(array_t *v, svalue_t *pattern, int flag)
{
pcre_t *run;
array_t *ret;
svalue_t *sv1, *sv2;
char *res;
int num_match, size, match = !(flag & 2);
if (!(size = v->size))
return &the_null_array;
run = CALLOCATE(1, pcre_t, TAG_TEMPORARY, "pcre_match : run");
run->ovector = NULL;
run->ovecsize = 0;
assign_svalue_no_free(&run->pattern, pattern);
run->re = pcre_get_cached_pattern(&pcre_cache, &run->pattern);
if (run->re == NULL)
{
if (pcre_local_compile(run) == NULL)
{
const char *rerror = run->error;
int offset = run->erroffset;
pcre_free_memory(run);
error("PCRE compilation failed at offset %d: %s\n", offset, rerror);
}
else
pcre_cache_pattern(&pcre_cache, run->re, &run->pattern);
}
res = (char*)DMALLOC(size, TAG_TEMPORARY, "prcre_match: res");
sv1 = v->item + size;
num_match = 0;
while (size--)
{
if ((--sv1)->type != T_STRING)
{
res[size] = 0;
continue;
}
run->subject = sv1->u.string;
run->s_length = SVALUE_STRLEN(sv1);
pcre_local_exec(run);
if (!pcre_query_match(run))
{
res[size] = 0;
continue;
}
res[size] = 1;
num_match++;
}
flag &= 1;
ret = allocate_empty_array(num_match << flag);
sv2 = ret->item + (num_match << flag);
size = v->size;
while (size--)
{
if (res[size])
{
if (flag)
{
(--sv2)->type = T_NUMBER;
sv2->u.number = size + 1;
}
(--sv2)->type = T_STRING;
sv1 = v->item + size;
*sv2 = *sv1;
if (sv1->subtype & STRING_COUNTED)
{
INC_COUNTED_REF(sv1->u.string);
ADD_STRING(MSTR_SIZE(sv1->u.string));
}
if (!--num_match)
break;
}
}
FREE(res);
pcre_free_memory(run);
return ret;
}
/* This is mostly copy/paste from reg_assoc, some parts are changed
* TODO: rewrite with new logic
*/
static array_t *pcre_assoc(svalue_t *str, array_t *pat, array_t *tok, svalue_t *def)
{
int i, size;
const char *tmp;
array_t *ret;
if ((size = pat->size) != tok->size)
error("Pattern and token array size must be identical.\n");
for (i = 0; i < size; i++)
if (pat->item[i].type != T_STRING)
error("Non-string found in pattern array.\n");
ret = allocate_empty_array(2);
if (size)
{
pcre_t **rgpp;
struct reg_match {
int tok_i;
const char *begin, *end;
struct reg_match *next;
} *rmp = (struct reg_match *) 0, *rmph = (struct reg_match *) 0;
int num_match = 0, length;
svalue_t *sv1, *sv2, *sv;
int regindex;
pcre_t *tmpreg;
int laststart;
rgpp = CALLOCATE(size, pcre_t *, TAG_TEMPORARY, "pcre_assoc : rgpp");
for (i = 0; i < size; i++)
{
rgpp[i] = CALLOCATE(1, pcre_t, TAG_TEMPORARY, "pcre_assoc : rgpp[i]");
rgpp[i]->ovector = NULL;
rgpp[i]->ovecsize = 0;
assign_svalue_no_free(&rgpp[i]->pattern, &pat->item[i]);
rgpp[i]->re = pcre_get_cached_pattern(&pcre_cache, &rgpp[i]->pattern);
if (rgpp[i]->re == NULL)
{
if (pcre_local_compile(rgpp[i]) == NULL)
{
const char *rerror = rgpp[i]->error;
int offset = rgpp[i]->erroffset;
while (i--)
pcre_free_memory(rgpp[i]);
FREE(rgpp);
free_empty_array(ret);
error("PCRE compilation failed at offset %d: %s\n", offset, rerror);
}
else
pcre_cache_pattern(&pcre_cache, rgpp[i]->re, &rgpp[i]->pattern);
}
}
tmp = str->u.string;
int totalsize = SVALUE_STRLEN(str);
int used = 0;
while (*tmp)
{
laststart = 0;
regindex = -1;
for (i = 0; i < size; i++)
{
rgpp[i]->subject = tmp;
rgpp[i]->s_length = totalsize-used;
pcre_local_exec(tmpreg = rgpp[i]);
if (pcre_query_match(tmpreg))
{
char *curr_temp;
size_t curr_temp_sz;
curr_temp_sz = totalsize - used - tmpreg->ovector[0];
if(!tmpreg->ovector[0]){
regindex = i;
break;
}
if (laststart < curr_temp_sz)
{
laststart = curr_temp_sz;
regindex = i;
}
}
}
if (regindex >= 0)
{
const char *rmpb_tmp, *rmpe_tmp;
size_t rmpb_tmp_sz, rmpe_tmp_sz;
num_match++;
if (rmp)
{
rmp->next = ALLOCATE(struct reg_match,
TAG_TEMPORARY, "pcre_assoc : rmp->next");
rmp = rmp->next;
}
else
rmph = rmp = ALLOCATE(struct reg_match,
TAG_TEMPORARY, "pcre_assoc : rmp");
tmpreg = rgpp[regindex];
rmpb_tmp = tmp + tmpreg->ovector[0];
rmpe_tmp = tmp + tmpreg->ovector[1];
rmp->begin = rmpb_tmp;
rmp->end = tmp = rmpe_tmp;
used+=tmpreg->ovector[1];
rmp->tok_i = regindex;
rmp->next = (struct reg_match *) 0;
}
else
break;
if (rmp->begin == tmp && (!*++tmp))
break;
}
sv = ret->item;
sv->type = T_ARRAY;
sv1 = (sv->u.arr = allocate_empty_array(2*num_match + 1))->item;
sv++;
sv->type = T_ARRAY;
sv2 = (sv->u.arr = allocate_empty_array(2*num_match + 1))->item;
rmp = rmph;
tmp = str->u.string;
while (num_match--){
char *svtmp;
length = rmp->begin - tmp;
sv1->type = T_STRING;
sv1->subtype = STRING_MALLOC;
sv1->u.string = svtmp = new_string(length, "pcre_assoc : sv1");
strncpy(svtmp, tmp, length);
svtmp[length] = 0;
sv1++;
assign_svalue_no_free(sv2++, def);
tmp += length;
length = rmp->end - rmp->begin;
sv1->type = T_STRING;
sv1->subtype = STRING_MALLOC;
sv1->u.string = svtmp = new_string(length, "pcre_assoc : sv1");
strncpy(svtmp, tmp, length);
svtmp[length] = 0;
sv1++;
assign_svalue_no_free(sv2++, &tok->item[rmp->tok_i]);
tmp += length;
rmp = rmp->next;
}
sv1->type = T_STRING;
sv1->subtype = STRING_MALLOC;
sv1->u.string = string_copy(tmp, "pcre_assoc");
assign_svalue_no_free(sv2, def);
for (i = 0; i < size; i++)
pcre_free_memory(rgpp[i]);
FREE(rgpp);
while (rmp = rmph){
rmph = rmp->next;
FREE((char *) rmp);
}
return ret;
}
else {
svalue_t *temp;
svalue_t *sv;
(sv = ret->item)->type = T_ARRAY;
temp = (sv->u.arr = allocate_empty_array(1))->item;
assign_svalue_no_free(temp, str);
sv = &ret->item[1];
sv->type = T_ARRAY;
assign_svalue_no_free((sv->u.arr = allocate_empty_array(1))->item, def);
return ret;
}
}
static array_t *pcre_get_substrings(pcre_t *run)
{
array_t *ret;
unsigned int i;
char **matches;
ret = allocate_empty_array(run->rc - 1);
if (run->rc != 1)
{
for (i = 1; i<= (run->rc-1); i++)
{
unsigned int start, length;
/* Allocate enough for the match */
length = run->ovector[2*i + 1] - run->ovector[2*i];
start = run->ovector[2*i];
char *match = new_string(length, "pcre get substrings");
sprintf(match, "%.*s", length, run->subject + start);
ret->item[i-1].type = T_STRING;
ret->item[i-1].subtype = STRING_MALLOC;
ret->item[i-1].u.string = match;
}
}
return ret;
}
static char *pcre_get_replace(pcre_t *run, array_t *replacements)
{
unsigned int ret_pos = 0, i;
size_t ret_sz;
char *ret;
/* Set size of return string to subject length */
ret_sz = run->s_length;
/* Subtract total size of all substrings */
int prev = run->ovector[2];
for (i = 1; i <= (run->rc - 1); i++){
//printf("%d %d %d\n", ret_sz, run->ovector[2*i],run->ovector[2*i+1] );
if(run->ovector[2*i] >= prev){
ret_sz -= (size_t)(run->ovector[2*i + 1] - run->ovector[2*i]);
prev = run->ovector[2*i + 1];
/* Add total size of all replacements */
ret_sz += SVALUE_STRLEN(&replacements->item[i-1]);
}
}
/* Allocate space for the return string */
ret = new_string((ret_sz), "pcre get replace");
//printf("ret_sz:%d\n", ret_sz);
/* Copy start of subject up until first match */
if(run->rc > 1){
strncpy(ret, run->subject, run->ovector[2]);
ret_pos = run->ovector[2];
}
else
strncpy(ret, run->subject, ret_sz);
for (i = 1; i <= (run->rc - 1); i++)
{
unsigned int start, end, len_nxt;
const char *rep;
size_t rep_sz;
start = run->ovector[2*i];
end = run->ovector[2*i + 1];
if ( i == (run->rc - 1))
len_nxt = run->s_length - end;
else
len_nxt = run->ovector[2*i + 2] - end;
if(len_nxt > MAX_STRING_LENGTH)
continue; //nested ()s
rep = replacements->item[i - 1].u.string;
rep_sz = SVALUE_STRLEN(&replacements->item[i - 1]);
/* Copy first substring into return variable */
strncpy(ret + ret_pos, rep, rep_sz);
/* increment position in return variable by replacement size */
ret_pos += rep_sz;
strncpy(ret + ret_pos, run->subject + end, len_nxt);
ret_pos += len_nxt;
}
*(ret+ret_sz) = '\0';
return ret;
}
static void pcre_free_memory(pcre_t *p)
{
free_svalue(&p->pattern, "pcre_free_memory");
if(p->ovector)
FREE(p->ovector);
FREE(p);
}
//Caching functions, add new ones at the front of the bucket so we find them faster
static int pcre_cache_pattern(struct pcre_cache_t *table, pcre *cpat, svalue_t *pattern) //don't keep pointers to strings that will get freed elsewhere!
{
unsigned int bucket = svalue_to_int(pattern) % PCRE_CACHE_SIZE;
int sz;
struct pcre_cache_bucket_t *tmp;
struct pcre_cache_bucket_t *node;
int full;
tmp = table->buckets[bucket];
// Calculate size of compiled pattern
pcre_fullinfo(cpat, NULL, PCRE_INFO_SIZE, &sz);
full = (pcrecachesize > 2 * PCRE_CACHE_SIZE);
while (tmp)
{
if (pattern->u.string == tmp->pattern.u.string)
break;
tmp = tmp->next;
}
if (tmp)
{
//does this even make sense? same pattern will always compile the same way?
pcre_free(tmp->compiled_pattern);
node = tmp;
}
else
{
node = CALLOCATE(1, struct pcre_cache_bucket_t, TAG_TEMPORARY, "pcre_cache_pattern : node");
node->pattern.type = T_NUMBER; //so we don't free invalids
if (node == NULL)
return -1;
if(!full)
pcrecachesize++;
else{
if((tmp = table->buckets[bucket])){
while(tmp->next)
tmp = tmp->next;
if(tmp == table->buckets[bucket]){//if the hash version works, most of the time
pcre_free(tmp->compiled_pattern);
FREE(tmp);
table->buckets[bucket] = NULL;
} else {
struct pcre_cache_bucket_t *tmp2;
tmp2 = table->buckets[bucket];
while(tmp2->next != tmp)
tmp2 = tmp2->next; //shouldn't get here often
pcre_free(tmp->compiled_pattern);
FREE(tmp);
tmp2->next = NULL;
}
}
}
node->next = table->buckets[bucket];
table->buckets[bucket] = node;
}
assign_svalue(&node->pattern, pattern);
node->compiled_pattern = cpat;
node->size = sz;
return 0;
}
static pcre *pcre_get_cached_pattern(struct pcre_cache_t *table, svalue_t *pattern)
{
unsigned int bucket = svalue_to_int(pattern) % PCRE_CACHE_SIZE;
struct pcre_cache_bucket_t *node;
struct pcre_cache_bucket_t *lnode = NULL;
node = table->buckets[bucket];
while (node)
{
if (pattern->u.string == node->pattern.u.string){
if(node != table->buckets[bucket]){
//not at the front, move it there, so the most used pattern is fastest
lnode->next = node->next;
node->next = table->buckets[bucket];
table->buckets[bucket] = node;
}
return node->compiled_pattern;
}
lnode = node;
node = node->next;
}
return NULL;
}
static mapping_t *pcre_get_cache()
{
int size = 0, i;
mapping_t *ret;
struct pcre_cache_bucket_t *node;
// Calculate size for mapping
for (i = 0; i < PCRE_CACHE_SIZE; i++)
{
if (pcre_cache.buckets[i] != NULL)
{
node = pcre_cache.buckets[i];
while (node)
{
node = node->next;
size++;
}
}
}
ret = allocate_mapping(size);
for (i = 0; i< PCRE_CACHE_SIZE; i++)
{
if (pcre_cache.buckets[i] != NULL)
{
node = pcre_cache.buckets[i];
while (node)
{
add_mapping_pair(ret, node->pattern.u.string, node->size);
node = node->next;
}
}
}
return ret;
}