/**********************************************************************
regparse.c - Oniguruma (regular expression library)
**********************************************************************/
/*-
* Copyright (c) 2002-2007 K.Kosako <sndgk393 AT ybb DOT ne DOT jp>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "regparse.h"
#define WARN_BUFSIZE 256
#define CASE_FOLD_IS_APPLIED_INSIDE_NEGATIVE_CCLASS
const OnigSyntaxType OnigSyntaxRuby = {
(( SYN_GNU_REGEX_OP | ONIG_SYN_OP_QMARK_NON_GREEDY |
ONIG_SYN_OP_ESC_OCTAL3 | ONIG_SYN_OP_ESC_X_HEX2 |
ONIG_SYN_OP_ESC_X_BRACE_HEX8 | ONIG_SYN_OP_ESC_CONTROL_CHARS |
ONIG_SYN_OP_ESC_C_CONTROL )
& ~ONIG_SYN_OP_ESC_LTGT_WORD_BEGIN_END )
, ( ONIG_SYN_OP2_QMARK_GROUP_EFFECT |
ONIG_SYN_OP2_OPTION_RUBY |
ONIG_SYN_OP2_QMARK_LT_NAMED_GROUP | ONIG_SYN_OP2_ESC_K_NAMED_BACKREF |
ONIG_SYN_OP2_ESC_G_SUBEXP_CALL |
ONIG_SYN_OP2_ESC_P_BRACE_CHAR_PROPERTY |
ONIG_SYN_OP2_ESC_P_BRACE_CIRCUMFLEX_NOT |
ONIG_SYN_OP2_PLUS_POSSESSIVE_REPEAT |
ONIG_SYN_OP2_CCLASS_SET_OP | ONIG_SYN_OP2_ESC_CAPITAL_C_BAR_CONTROL |
ONIG_SYN_OP2_ESC_CAPITAL_M_BAR_META | ONIG_SYN_OP2_ESC_V_VTAB |
ONIG_SYN_OP2_ESC_H_XDIGIT )
, ( SYN_GNU_REGEX_BV |
ONIG_SYN_ALLOW_INTERVAL_LOW_ABBREV |
ONIG_SYN_DIFFERENT_LEN_ALT_LOOK_BEHIND |
ONIG_SYN_CAPTURE_ONLY_NAMED_GROUP |
ONIG_SYN_ALLOW_MULTIPLEX_DEFINITION_NAME |
ONIG_SYN_FIXED_INTERVAL_IS_GREEDY_ONLY |
ONIG_SYN_WARN_CC_OP_NOT_ESCAPED |
ONIG_SYN_WARN_REDUNDANT_NESTED_REPEAT )
, ONIG_OPTION_NONE
,
{
(OnigCodePoint )'\\' /* esc */
, (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* anychar '.' */
, (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* anytime '*' */
, (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* zero or one time '?' */
, (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* one or more time '+' */
, (OnigCodePoint )ONIG_INEFFECTIVE_META_CHAR /* anychar anytime */
}
};
const OnigSyntaxType* OnigDefaultSyntax = ONIG_SYNTAX_RUBY;
extern void onig_null_warn(const char* s ARG_UNUSED) { }
#ifdef DEFAULT_WARN_FUNCTION
static OnigWarnFunc onig_warn = (OnigWarnFunc )DEFAULT_WARN_FUNCTION;
#else
static OnigWarnFunc onig_warn = onig_null_warn;
#endif
#ifdef DEFAULT_VERB_WARN_FUNCTION
static OnigWarnFunc onig_verb_warn = (OnigWarnFunc )DEFAULT_VERB_WARN_FUNCTION;
#else
static OnigWarnFunc onig_verb_warn = onig_null_warn;
#endif
extern void onig_set_warn_func(OnigWarnFunc f)
{
onig_warn = f;
}
extern void onig_set_verb_warn_func(OnigWarnFunc f)
{
onig_verb_warn = f;
}
static void
bbuf_free(BBuf* bbuf)
{
if (IS_NOT_NULL(bbuf)) {
if (IS_NOT_NULL(bbuf->p)) xfree(bbuf->p);
xfree(bbuf);
}
}
static int
bbuf_clone(BBuf** rto, BBuf* from)
{
int r;
BBuf *to;
*rto = to = (BBuf* )xmalloc(sizeof(BBuf));
CHECK_NULL_RETURN_MEMERR(to);
r = BBUF_INIT(to, from->alloc);
if (r != 0) return r;
to->used = from->used;
xmemcpy(to->p, from->p, from->used);
return 0;
}
#define BACKREF_REL_TO_ABS(rel_no, env) \
((env)->num_mem + 1 + (rel_no))
#define ONOFF(v,f,negative) (negative) ? ((v) &= ~(f)) : ((v) |= (f))
#define MBCODE_START_POS(enc) \
(OnigCodePoint )(ONIGENC_MBC_MINLEN(enc) > 1 ? 0 : 0x80)
#define SET_ALL_MULTI_BYTE_RANGE(enc, pbuf) \
add_code_range_to_buf(pbuf, MBCODE_START_POS(enc), ~((OnigCodePoint )0))
#define ADD_ALL_MULTI_BYTE_RANGE(enc, mbuf) do {\
if (! ONIGENC_IS_SINGLEBYTE(enc)) {\
r = SET_ALL_MULTI_BYTE_RANGE(enc, &(mbuf));\
if (r) return r;\
}\
} while (0)
#define BITSET_IS_EMPTY(bs,empty) do {\
int i;\
empty = 1;\
for (i = 0; i < (int )BITSET_SIZE; i++) {\
if ((bs)[i] != 0) {\
empty = 0; break;\
}\
}\
} while (0)
static void
bitset_set_range(BitSetRef bs, int from, int to)
{
int i;
for (i = from; i <= to && i < SINGLE_BYTE_SIZE; i++) {
BITSET_SET_BIT(bs, i);
}
}
#if 0
static void
bitset_set_all(BitSetRef bs)
{
int i;
for (i = 0; i < BITSET_SIZE; i++) { bs[i] = ~((Bits )0); }
}
#endif
static void
bitset_invert(BitSetRef bs)
{
int i;
for (i = 0; i < (int )BITSET_SIZE; i++) { bs[i] = ~(bs[i]); }
}
static void
bitset_invert_to(BitSetRef from, BitSetRef to)
{
int i;
for (i = 0; i < (int )BITSET_SIZE; i++) { to[i] = ~(from[i]); }
}
static void
bitset_and(BitSetRef dest, BitSetRef bs)
{
int i;
for (i = 0; i < (int )BITSET_SIZE; i++) { dest[i] &= bs[i]; }
}
static void
bitset_or(BitSetRef dest, BitSetRef bs)
{
int i;
for (i = 0; i < (int )BITSET_SIZE; i++) { dest[i] |= bs[i]; }
}
static void
bitset_copy(BitSetRef dest, BitSetRef bs)
{
int i;
for (i = 0; i < (int )BITSET_SIZE; i++) { dest[i] = bs[i]; }
}
extern int
onig_strncmp(const UChar* s1, const UChar* s2, int n)
{
int x;
while (n-- > 0) {
x = *s2++ - *s1++;
if (x) return x;
}
return 0;
}
extern void
onig_strcpy(UChar* dest, const UChar* src, const UChar* end)
{
int len = end - src;
if (len > 0) {
xmemcpy(dest, src, len);
dest[len] = (UChar )0;
}
}
#ifdef USE_NAMED_GROUP
static UChar*
strdup_with_null(OnigEncoding enc, UChar* s, UChar* end)
{
int slen, term_len, i;
UChar *r;
slen = end - s;
term_len = ONIGENC_MBC_MINLEN(enc);
r = (UChar* )xmalloc(slen + term_len);
CHECK_NULL_RETURN(r);
xmemcpy(r, s, slen);
for (i = 0; i < term_len; i++)
r[slen + i] = (UChar )0;
return r;
}
#endif
/* scan pattern methods */
#define PEND_VALUE 0
#define PFETCH_READY UChar* pfetch_prev
#define PEND (p < end ? 0 : 1)
#define PUNFETCH p = pfetch_prev
#define PINC do { \
pfetch_prev = p; \
p += enclen(enc, p, end); \
} while (0)
#define PFETCH(c) do { \
c = ((enc->max_enc_len == 1) ? *p : ONIGENC_MBC_TO_CODE(enc, p, end)); \
pfetch_prev = p; \
p += enclen(enc, p, end); \
} while (0)
#define PPEEK (p < end ? ONIGENC_MBC_TO_CODE(enc, p, end) : PEND_VALUE)
#define PPEEK_IS(c) (PPEEK == (OnigCodePoint )c)
static UChar*
strcat_capa(UChar* dest, UChar* dest_end, const UChar* src, const UChar* src_end,
int capa)
{
UChar* r;
if (dest)
r = (UChar* )xrealloc(dest, capa + 1);
else
r = (UChar* )xmalloc(capa + 1);
CHECK_NULL_RETURN(r);
onig_strcpy(r + (dest_end - dest), src, src_end);
return r;
}
/* dest on static area */
static UChar*
strcat_capa_from_static(UChar* dest, UChar* dest_end,
const UChar* src, const UChar* src_end, int capa)
{
UChar* r;
r = (UChar* )xmalloc(capa + 1);
CHECK_NULL_RETURN(r);
onig_strcpy(r, dest, dest_end);
onig_strcpy(r + (dest_end - dest), src, src_end);
return r;
}
#ifdef USE_ST_LIBRARY
#include "ruby/st.h"
typedef struct {
UChar* s;
UChar* end;
} st_str_end_key;
static int
str_end_cmp(st_str_end_key* x, st_str_end_key* y)
{
UChar *p, *q;
int c;
if ((x->end - x->s) != (y->end - y->s))
return 1;
p = x->s;
q = y->s;
while (p < x->end) {
c = (int )*p - (int )*q;
if (c != 0) return c;
p++; q++;
}
return 0;
}
static int
str_end_hash(st_str_end_key* x)
{
UChar *p;
int val = 0;
p = x->s;
while (p < x->end) {
val = val * 997 + (int )*p++;
}
return val + (val >> 5);
}
extern hash_table_type*
onig_st_init_strend_table_with_size(int size)
{
static const struct st_hash_type hashType = {
str_end_cmp,
str_end_hash,
};
return (hash_table_type* )
onig_st_init_table_with_size(&hashType, size);
}
extern int
onig_st_lookup_strend(hash_table_type* table, const UChar* str_key,
const UChar* end_key, hash_data_type *value)
{
st_str_end_key key;
key.s = (UChar* )str_key;
key.end = (UChar* )end_key;
return onig_st_lookup(table, (st_data_t )(&key), value);
}
extern int
onig_st_insert_strend(hash_table_type* table, const UChar* str_key,
const UChar* end_key, hash_data_type value)
{
st_str_end_key* key;
int result;
key = (st_str_end_key* )xmalloc(sizeof(st_str_end_key));
key->s = (UChar* )str_key;
key->end = (UChar* )end_key;
result = onig_st_insert(table, (st_data_t )key, value);
if (result) {
xfree(key);
}
return result;
}
#endif /* USE_ST_LIBRARY */
#ifdef USE_NAMED_GROUP
#define INIT_NAME_BACKREFS_ALLOC_NUM 8
typedef struct {
UChar* name;
int name_len; /* byte length */
int back_num; /* number of backrefs */
int back_alloc;
int back_ref1;
int* back_refs;
} NameEntry;
#ifdef USE_ST_LIBRARY
typedef st_table NameTable;
typedef st_data_t HashDataType; /* 1.6 st.h doesn't define st_data_t type */
#define NAMEBUF_SIZE 24
#define NAMEBUF_SIZE_1 25
#ifdef ONIG_DEBUG
static int
i_print_name_entry(UChar* key, NameEntry* e, void* arg)
{
int i;
FILE* fp = (FILE* )arg;
fprintf(fp, "%s: ", e->name);
if (e->back_num == 0)
fputs("-", fp);
else if (e->back_num == 1)
fprintf(fp, "%d", e->back_ref1);
else {
for (i = 0; i < e->back_num; i++) {
if (i > 0) fprintf(fp, ", ");
fprintf(fp, "%d", e->back_refs[i]);
}
}
fputs("\n", fp);
return ST_CONTINUE;
}
extern int
onig_print_names(FILE* fp, regex_t* reg)
{
NameTable* t = (NameTable* )reg->name_table;
if (IS_NOT_NULL(t)) {
fprintf(fp, "name table\n");
onig_st_foreach(t, i_print_name_entry, (HashDataType )fp);
fputs("\n", fp);
}
return 0;
}
#endif /* ONIG_DEBUG */
static int
i_free_name_entry(UChar* key, NameEntry* e, void* arg ARG_UNUSED)
{
xfree(e->name);
if (IS_NOT_NULL(e->back_refs)) xfree(e->back_refs);
xfree(key);
xfree(e);
return ST_DELETE;
}
static int
names_clear(regex_t* reg)
{
NameTable* t = (NameTable* )reg->name_table;
if (IS_NOT_NULL(t)) {
onig_st_foreach(t, i_free_name_entry, 0);
}
return 0;
}
extern int
onig_names_free(regex_t* reg)
{
int r;
NameTable* t;
r = names_clear(reg);
if (r) return r;
t = (NameTable* )reg->name_table;
if (IS_NOT_NULL(t)) onig_st_free_table(t);
reg->name_table = (void* )NULL;
return 0;
}
static NameEntry*
name_find(regex_t* reg, const UChar* name, const UChar* name_end)
{
NameEntry* e;
NameTable* t = (NameTable* )reg->name_table;
e = (NameEntry* )NULL;
if (IS_NOT_NULL(t)) {
onig_st_lookup_strend(t, name, name_end, (HashDataType* )((void* )(&e)));
}
return e;
}
typedef struct {
int (*func)(const UChar*, const UChar*,int,int*,regex_t*,void*);
regex_t* reg;
void* arg;
int ret;
OnigEncoding enc;
} INamesArg;
static int
i_names(UChar* key ARG_UNUSED, NameEntry* e, INamesArg* arg)
{
int r = (*(arg->func))(e->name,
e->name + e->name_len,
e->back_num,
(e->back_num > 1 ? e->back_refs : &(e->back_ref1)),
arg->reg, arg->arg);
if (r != 0) {
arg->ret = r;
return ST_STOP;
}
return ST_CONTINUE;
}
extern int
onig_foreach_name(regex_t* reg,
int (*func)(const UChar*, const UChar*,int,int*,regex_t*,void*), void* arg)
{
INamesArg narg;
NameTable* t = (NameTable* )reg->name_table;
narg.ret = 0;
if (IS_NOT_NULL(t)) {
narg.func = func;
narg.reg = reg;
narg.arg = arg;
narg.enc = reg->enc; /* should be pattern encoding. */
onig_st_foreach(t, i_names, (HashDataType )&narg);
}
return narg.ret;
}
static int
i_renumber_name(UChar* key ARG_UNUSED, NameEntry* e, GroupNumRemap* map)
{
int i;
if (e->back_num > 1) {
for (i = 0; i < e->back_num; i++) {
e->back_refs[i] = map[e->back_refs[i]].new_val;
}
}
else if (e->back_num == 1) {
e->back_ref1 = map[e->back_ref1].new_val;
}
return ST_CONTINUE;
}
extern int
onig_renumber_name_table(regex_t* reg, GroupNumRemap* map)
{
NameTable* t = (NameTable* )reg->name_table;
if (IS_NOT_NULL(t)) {
onig_st_foreach(t, i_renumber_name, (HashDataType )map);
}
return 0;
}
extern int
onig_number_of_names(regex_t* reg)
{
NameTable* t = (NameTable* )reg->name_table;
if (IS_NOT_NULL(t))
return t->num_entries;
else
return 0;
}
#else /* USE_ST_LIBRARY */
#define INIT_NAMES_ALLOC_NUM 8
typedef struct {
NameEntry* e;
int num;
int alloc;
} NameTable;
#ifdef ONIG_DEBUG
extern int
onig_print_names(FILE* fp, regex_t* reg)
{
int i, j;
NameEntry* e;
NameTable* t = (NameTable* )reg->name_table;
if (IS_NOT_NULL(t) && t->num > 0) {
fprintf(fp, "name table\n");
for (i = 0; i < t->num; i++) {
e = &(t->e[i]);
fprintf(fp, "%s: ", e->name);
if (e->back_num == 0) {
fputs("-", fp);
}
else if (e->back_num == 1) {
fprintf(fp, "%d", e->back_ref1);
}
else {
for (j = 0; j < e->back_num; j++) {
if (j > 0) fprintf(fp, ", ");
fprintf(fp, "%d", e->back_refs[j]);
}
}
fputs("\n", fp);
}
fputs("\n", fp);
}
return 0;
}
#endif
static int
names_clear(regex_t* reg)
{
int i;
NameEntry* e;
NameTable* t = (NameTable* )reg->name_table;
if (IS_NOT_NULL(t)) {
for (i = 0; i < t->num; i++) {
e = &(t->e[i]);
if (IS_NOT_NULL(e->name)) {
xfree(e->name);
e->name = NULL;
e->name_len = 0;
e->back_num = 0;
e->back_alloc = 0;
if (IS_NOT_NULL(e->back_refs)) xfree(e->back_refs);
e->back_refs = (int* )NULL;
}
}
if (IS_NOT_NULL(t->e)) {
xfree(t->e);
t->e = NULL;
}
t->num = 0;
}
return 0;
}
extern int
onig_names_free(regex_t* reg)
{
int r;
NameTable* t;
r = names_clear(reg);
if (r) return r;
t = (NameTable* )reg->name_table;
if (IS_NOT_NULL(t)) xfree(t);
reg->name_table = NULL;
return 0;
}
static NameEntry*
name_find(regex_t* reg, UChar* name, UChar* name_end)
{
int i, len;
NameEntry* e;
NameTable* t = (NameTable* )reg->name_table;
if (IS_NOT_NULL(t)) {
len = name_end - name;
for (i = 0; i < t->num; i++) {
e = &(t->e[i]);
if (len == e->name_len && onig_strncmp(name, e->name, len) == 0)
return e;
}
}
return (NameEntry* )NULL;
}
extern int
onig_foreach_name(regex_t* reg,
int (*func)(const UChar*, const UChar*,int,int*,regex_t*,void*), void* arg)
{
int i, r;
NameEntry* e;
NameTable* t = (NameTable* )reg->name_table;
if (IS_NOT_NULL(t)) {
for (i = 0; i < t->num; i++) {
e = &(t->e[i]);
r = (*func)(e->name, e->name + e->name_len, e->back_num,
(e->back_num > 1 ? e->back_refs : &(e->back_ref1)),
reg, arg);
if (r != 0) return r;
}
}
return 0;
}
extern int
onig_number_of_names(regex_t* reg)
{
NameTable* t = (NameTable* )reg->name_table;
if (IS_NOT_NULL(t))
return t->num;
else
return 0;
}
#endif /* else USE_ST_LIBRARY */
static int
name_add(regex_t* reg, UChar* name, UChar* name_end, int backref, ScanEnv* env)
{
int alloc;
NameEntry* e;
NameTable* t = (NameTable* )reg->name_table;
if (name_end - name <= 0)
return ONIGERR_EMPTY_GROUP_NAME;
e = name_find(reg, name, name_end);
if (IS_NULL(e)) {
#ifdef USE_ST_LIBRARY
if (IS_NULL(t)) {
t = onig_st_init_strend_table_with_size(5);
reg->name_table = (void* )t;
}
e = (NameEntry* )xmalloc(sizeof(NameEntry));
CHECK_NULL_RETURN_MEMERR(e);
e->name = strdup_with_null(reg->enc, name, name_end);
if (IS_NULL(e->name)) {
xfree(e);
return ONIGERR_MEMORY;
}
onig_st_insert_strend(t, e->name, (e->name + (name_end - name)),
(HashDataType )e);
e->name_len = name_end - name;
e->back_num = 0;
e->back_alloc = 0;
e->back_refs = (int* )NULL;
#else
if (IS_NULL(t)) {
alloc = INIT_NAMES_ALLOC_NUM;
t = (NameTable* )xmalloc(sizeof(NameTable));
CHECK_NULL_RETURN_MEMERR(t);
t->e = NULL;
t->alloc = 0;
t->num = 0;
t->e = (NameEntry* )xmalloc(sizeof(NameEntry) * alloc);
if (IS_NULL(t->e)) {
xfree(t);
return ONIGERR_MEMORY;
}
t->alloc = alloc;
reg->name_table = t;
goto clear;
}
else if (t->num == t->alloc) {
int i;
alloc = t->alloc * 2;
t->e = (NameEntry* )xrealloc(t->e, sizeof(NameEntry) * alloc);
CHECK_NULL_RETURN_MEMERR(t->e);
t->alloc = alloc;
clear:
for (i = t->num; i < t->alloc; i++) {
t->e[i].name = NULL;
t->e[i].name_len = 0;
t->e[i].back_num = 0;
t->e[i].back_alloc = 0;
t->e[i].back_refs = (int* )NULL;
}
}
e = &(t->e[t->num]);
t->num++;
e->name = strdup_with_null(reg->enc, name, name_end);
e->name_len = name_end - name;
#endif
}
if (e->back_num >= 1 &&
! IS_SYNTAX_BV(env->syntax, ONIG_SYN_ALLOW_MULTIPLEX_DEFINITION_NAME)) {
onig_scan_env_set_error_string(env, ONIGERR_MULTIPLEX_DEFINED_NAME,
name, name_end);
return ONIGERR_MULTIPLEX_DEFINED_NAME;
}
e->back_num++;
if (e->back_num == 1) {
e->back_ref1 = backref;
}
else {
if (e->back_num == 2) {
alloc = INIT_NAME_BACKREFS_ALLOC_NUM;
e->back_refs = (int* )xmalloc(sizeof(int) * alloc);
CHECK_NULL_RETURN_MEMERR(e->back_refs);
e->back_alloc = alloc;
e->back_refs[0] = e->back_ref1;
e->back_refs[1] = backref;
}
else {
if (e->back_num > e->back_alloc) {
alloc = e->back_alloc * 2;
e->back_refs = (int* )xrealloc(e->back_refs, sizeof(int) * alloc);
CHECK_NULL_RETURN_MEMERR(e->back_refs);
e->back_alloc = alloc;
}
e->back_refs[e->back_num - 1] = backref;
}
}
return 0;
}
extern int
onig_name_to_group_numbers(regex_t* reg, const UChar* name,
const UChar* name_end, int** nums)
{
NameEntry* e = name_find(reg, name, name_end);
if (IS_NULL(e)) return ONIGERR_UNDEFINED_NAME_REFERENCE;
switch (e->back_num) {
case 0:
*nums = 0;
break;
case 1:
*nums = &(e->back_ref1);
break;
default:
*nums = e->back_refs;
break;
}
return e->back_num;
}
extern int
onig_name_to_backref_number(regex_t* reg, const UChar* name,
const UChar* name_end, OnigRegion *region)
{
int i, n, *nums;
n = onig_name_to_group_numbers(reg, name, name_end, &nums);
if (n < 0)
return n;
else if (n == 0)
return ONIGERR_PARSER_BUG;
else if (n == 1)
return nums[0];
else {
if (IS_NOT_NULL(region)) {
for (i = n - 1; i >= 0; i--) {
if (region->beg[nums[i]] != ONIG_REGION_NOTPOS)
return nums[i];
}
}
return nums[n - 1];
}
}
#else /* USE_NAMED_GROUP */
extern int
onig_name_to_group_numbers(regex_t* reg, const UChar* name,
const UChar* name_end, int** nums)
{
return ONIG_NO_SUPPORT_CONFIG;
}
extern int
onig_name_to_backref_number(regex_t* reg, const UChar* name,
const UChar* name_end, OnigRegion* region)
{
return ONIG_NO_SUPPORT_CONFIG;
}
extern int
onig_foreach_name(regex_t* reg,
int (*func)(const UChar*, const UChar*,int,int*,regex_t*,void*), void* arg)
{
return ONIG_NO_SUPPORT_CONFIG;
}
extern int
onig_number_of_names(regex_t* reg)
{
return 0;
}
#endif /* else USE_NAMED_GROUP */
extern int
onig_noname_group_capture_is_active(regex_t* reg)
{
if (ONIG_IS_OPTION_ON(reg->options, ONIG_OPTION_DONT_CAPTURE_GROUP))
return 0;
#ifdef USE_NAMED_GROUP
if (onig_number_of_names(reg) > 0 &&
IS_SYNTAX_BV(reg->syntax, ONIG_SYN_CAPTURE_ONLY_NAMED_GROUP) &&
!ONIG_IS_OPTION_ON(reg->options, ONIG_OPTION_CAPTURE_GROUP)) {
return 0;
}
#endif
return 1;
}
#define INIT_SCANENV_MEMNODES_ALLOC_SIZE 16
static void
scan_env_clear(ScanEnv* env)
{
int i;
BIT_STATUS_CLEAR(env->capture_history);
BIT_STATUS_CLEAR(env->bt_mem_start);
BIT_STATUS_CLEAR(env->bt_mem_end);
BIT_STATUS_CLEAR(env->backrefed_mem);
env->error = (UChar* )NULL;
env->error_end = (UChar* )NULL;
env->num_call = 0;
env->num_mem = 0;
#ifdef USE_NAMED_GROUP
env->num_named = 0;
#endif
env->mem_alloc = 0;
env->mem_nodes_dynamic = (Node** )NULL;
for (i = 0; i < SCANENV_MEMNODES_SIZE; i++)
env->mem_nodes_static[i] = NULL_NODE;
#ifdef USE_COMBINATION_EXPLOSION_CHECK
env->num_comb_exp_check = 0;
env->comb_exp_max_regnum = 0;
env->curr_max_regnum = 0;
env->has_recursion = 0;
#endif
}
static int
scan_env_add_mem_entry(ScanEnv* env)
{
int i, need, alloc;
Node** p;
need = env->num_mem + 1;
if (need >= SCANENV_MEMNODES_SIZE) {
if (env->mem_alloc <= need) {
if (IS_NULL(env->mem_nodes_dynamic)) {
alloc = INIT_SCANENV_MEMNODES_ALLOC_SIZE;
p = (Node** )xmalloc(sizeof(Node*) * alloc);
xmemcpy(p, env->mem_nodes_static,
sizeof(Node*) * SCANENV_MEMNODES_SIZE);
}
else {
alloc = env->mem_alloc * 2;
p = (Node** )xrealloc(env->mem_nodes_dynamic, sizeof(Node*) * alloc);
}
CHECK_NULL_RETURN_MEMERR(p);
for (i = env->num_mem + 1; i < alloc; i++)
p[i] = NULL_NODE;
env->mem_nodes_dynamic = p;
env->mem_alloc = alloc;
}
}
env->num_mem++;
return env->num_mem;
}
static int
scan_env_set_mem_node(ScanEnv* env, int num, Node* node)
{
if (env->num_mem >= num)
SCANENV_MEM_NODES(env)[num] = node;
else
return ONIGERR_PARSER_BUG;
return 0;
}
#ifdef USE_PARSE_TREE_NODE_RECYCLE
typedef struct _FreeNode {
struct _FreeNode* next;
} FreeNode;
static FreeNode* FreeNodeList = (FreeNode* )NULL;
#endif
extern void
onig_node_free(Node* node)
{
start:
if (IS_NULL(node)) return ;
switch (NTYPE(node)) {
case NT_STR:
if (NSTR(node)->capa != 0 &&
IS_NOT_NULL(NSTR(node)->s) && NSTR(node)->s != NSTR(node)->buf) {
xfree(NSTR(node)->s);
}
break;
case NT_LIST:
case NT_ALT:
onig_node_free(NCAR(node));
{
Node* next_node = NCDR(node);
#ifdef USE_PARSE_TREE_NODE_RECYCLE
{
FreeNode* n = (FreeNode* )node;
THREAD_ATOMIC_START;
n->next = FreeNodeList;
FreeNodeList = n;
THREAD_ATOMIC_END;
}
#else
xfree(node);
#endif
node = next_node;
goto start;
}
break;
case NT_CCLASS:
{
CClassNode* cc = NCCLASS(node);
if (IS_NCCLASS_SHARE(cc)) return ;
if (cc->mbuf)
bbuf_free(cc->mbuf);
}
break;
case NT_QTFR:
if (NQTFR(node)->target)
onig_node_free(NQTFR(node)->target);
break;
case NT_ENCLOSE:
if (NENCLOSE(node)->target)
onig_node_free(NENCLOSE(node)->target);
break;
case NT_BREF:
if (IS_NOT_NULL(NBREF(node)->back_dynamic))
xfree(NBREF(node)->back_dynamic);
break;
case NT_ANCHOR:
if (NANCHOR(node)->target)
onig_node_free(NANCHOR(node)->target);
break;
}
#ifdef USE_PARSE_TREE_NODE_RECYCLE
{
FreeNode* n = (FreeNode* )node;
THREAD_ATOMIC_START;
n->next = FreeNodeList;
FreeNodeList = n;
THREAD_ATOMIC_END;
}
#else
xfree(node);
#endif
}
#ifdef USE_PARSE_TREE_NODE_RECYCLE
extern int
onig_free_node_list(void)
{
FreeNode* n;
/* THREAD_ATOMIC_START; */
while (IS_NOT_NULL(FreeNodeList)) {
n = FreeNodeList;
FreeNodeList = FreeNodeList->next;
xfree(n);
}
/* THREAD_ATOMIC_END; */
return 0;
}
#endif
static Node*
node_new(void)
{
Node* node;
#ifdef USE_PARSE_TREE_NODE_RECYCLE
THREAD_ATOMIC_START;
if (IS_NOT_NULL(FreeNodeList)) {
node = (Node* )FreeNodeList;
FreeNodeList = FreeNodeList->next;
THREAD_ATOMIC_END;
return node;
}
THREAD_ATOMIC_END;
#endif
node = (Node* )xmalloc(sizeof(Node));
/* xmemset(node, 0, sizeof(Node)); */
return node;
}
static void
initialize_cclass(CClassNode* cc)
{
BITSET_CLEAR(cc->bs);
/* cc->base.flags = 0; */
cc->flags = 0;
cc->mbuf = NULL;
}
static Node*
node_new_cclass(void)
{
Node* node = node_new();
CHECK_NULL_RETURN(node);
SET_NTYPE(node, NT_CCLASS);
initialize_cclass(NCCLASS(node));
return node;
}
static Node*
node_new_cclass_by_codepoint_range(int not, OnigCodePoint sb_out,
const OnigCodePoint ranges[])
{
int n, i;
CClassNode* cc;
OnigCodePoint j;
Node* node = node_new_cclass();
CHECK_NULL_RETURN(node);
cc = NCCLASS(node);
if (not != 0) NCCLASS_SET_NOT(cc);
BITSET_CLEAR(cc->bs);
if (sb_out > 0 && IS_NOT_NULL(ranges)) {
n = ONIGENC_CODE_RANGE_NUM(ranges);
for (i = 0; i < n; i++) {
for (j = ONIGENC_CODE_RANGE_FROM(ranges, i);
j <= (OnigCodePoint )ONIGENC_CODE_RANGE_TO(ranges, i); j++) {
if (j >= sb_out) goto sb_end;
BITSET_SET_BIT(cc->bs, j);
}
}
}
sb_end:
if (IS_NULL(ranges)) {
is_null:
cc->mbuf = NULL;
}
else {
BBuf* bbuf;
n = ONIGENC_CODE_RANGE_NUM(ranges);
if (n == 0) goto is_null;
bbuf = (BBuf* )xmalloc(sizeof(BBuf));
CHECK_NULL_RETURN(bbuf);
bbuf->alloc = n + 1;
bbuf->used = n + 1;
bbuf->p = (UChar* )((void* )ranges);
cc->mbuf = bbuf;
}
return node;
}
static Node*
node_new_ctype(int type, int not)
{
Node* node = node_new();
CHECK_NULL_RETURN(node);
SET_NTYPE(node, NT_CTYPE);
NCTYPE(node)->ctype = type;
NCTYPE(node)->not = not;
return node;
}
static Node*
node_new_anychar(void)
{
Node* node = node_new();
CHECK_NULL_RETURN(node);
SET_NTYPE(node, NT_CANY);
return node;
}
static Node*
node_new_list(Node* left, Node* right)
{
Node* node = node_new();
CHECK_NULL_RETURN(node);
SET_NTYPE(node, NT_LIST);
NCAR(node) = left;
NCDR(node) = right;
return node;
}
extern Node*
onig_node_new_list(Node* left, Node* right)
{
return node_new_list(left, right);
}
extern Node*
onig_node_list_add(Node* list, Node* x)
{
Node *n;
n = onig_node_new_list(x, NULL);
if (IS_NULL(n)) return NULL_NODE;
if (IS_NOT_NULL(list)) {
while (IS_NOT_NULL(NCDR(list)))
list = NCDR(list);
NCDR(list) = n;
}
return n;
}
extern Node*
onig_node_new_alt(Node* left, Node* right)
{
Node* node = node_new();
CHECK_NULL_RETURN(node);
SET_NTYPE(node, NT_ALT);
NCAR(node) = left;
NCDR(node) = right;
return node;
}
extern Node*
onig_node_new_anchor(int type)
{
Node* node = node_new();
CHECK_NULL_RETURN(node);
SET_NTYPE(node, NT_ANCHOR);
NANCHOR(node)->type = type;
NANCHOR(node)->target = NULL;
NANCHOR(node)->char_len = -1;
return node;
}
static Node*
node_new_backref(int back_num, int* backrefs, int by_name,
#ifdef USE_BACKREF_WITH_LEVEL
int exist_level, int nest_level,
#endif
ScanEnv* env)
{
int i;
Node* node = node_new();
CHECK_NULL_RETURN(node);
SET_NTYPE(node, NT_BREF);
NBREF(node)->state = 0;
NBREF(node)->back_num = back_num;
NBREF(node)->back_dynamic = (int* )NULL;
if (by_name != 0)
NBREF(node)->state |= NST_NAME_REF;
#ifdef USE_BACKREF_WITH_LEVEL
if (exist_level != 0) {
NBREF(node)->state |= NST_NEST_LEVEL;
NBREF(node)->nest_level = nest_level;
}
#endif
for (i = 0; i < back_num; i++) {
if (backrefs[i] <= env->num_mem &&
IS_NULL(SCANENV_MEM_NODES(env)[backrefs[i]])) {
NBREF(node)->state |= NST_RECURSION; /* /...(\1).../ */
break;
}
}
if (back_num <= NODE_BACKREFS_SIZE) {
for (i = 0; i < back_num; i++)
NBREF(node)->back_static[i] = backrefs[i];
}
else {
int* p = (int* )xmalloc(sizeof(int) * back_num);
if (IS_NULL(p)) {
onig_node_free(node);
return NULL;
}
NBREF(node)->back_dynamic = p;
for (i = 0; i < back_num; i++)
p[i] = backrefs[i];
}
return node;
}
#ifdef USE_SUBEXP_CALL
static Node*
node_new_call(UChar* name, UChar* name_end, int gnum)
{
Node* node = node_new();
CHECK_NULL_RETURN(node);
SET_NTYPE(node, NT_CALL);
NCALL(node)->state = 0;
NCALL(node)->target = NULL_NODE;
NCALL(node)->name = name;
NCALL(node)->name_end = name_end;
NCALL(node)->group_num = gnum; /* call by number if gnum != 0 */
return node;
}
#endif
static Node*
node_new_quantifier(int lower, int upper, int by_number)
{
Node* node = node_new();
CHECK_NULL_RETURN(node);
SET_NTYPE(node, NT_QTFR);
NQTFR(node)->state = 0;
NQTFR(node)->target = NULL;
NQTFR(node)->lower = lower;
NQTFR(node)->upper = upper;
NQTFR(node)->greedy = 1;
NQTFR(node)->target_empty_info = NQ_TARGET_ISNOT_EMPTY;
NQTFR(node)->head_exact = NULL_NODE;
NQTFR(node)->next_head_exact = NULL_NODE;
NQTFR(node)->is_refered = 0;
if (by_number != 0)
NQTFR(node)->state |= NST_BY_NUMBER;
#ifdef USE_COMBINATION_EXPLOSION_CHECK
NQTFR(node)->comb_exp_check_num = 0;
#endif
return node;
}
static Node*
node_new_enclose(int type)
{
Node* node = node_new();
CHECK_NULL_RETURN(node);
SET_NTYPE(node, NT_ENCLOSE);
NENCLOSE(node)->type = type;
NENCLOSE(node)->state = 0;
NENCLOSE(node)->regnum = 0;
NENCLOSE(node)->option = 0;
NENCLOSE(node)->target = NULL;
NENCLOSE(node)->call_addr = -1;
NENCLOSE(node)->opt_count = 0;
return node;
}
extern Node*
onig_node_new_enclose(int type)
{
return node_new_enclose(type);
}
static Node*
node_new_enclose_memory(OnigOptionType option, int is_named)
{
Node* node = node_new_enclose(ENCLOSE_MEMORY);
CHECK_NULL_RETURN(node);
if (is_named != 0)
SET_ENCLOSE_STATUS(node, NST_NAMED_GROUP);
#ifdef USE_SUBEXP_CALL
NENCLOSE(node)->option = option;
#endif
return node;
}
static Node*
node_new_option(OnigOptionType option)
{
Node* node = node_new_enclose(ENCLOSE_OPTION);
CHECK_NULL_RETURN(node);
NENCLOSE(node)->option = option;
return node;
}
extern int
onig_node_str_cat(Node* node, const UChar* s, const UChar* end)
{
int addlen = end - s;
if (addlen > 0) {
int len = NSTR(node)->end - NSTR(node)->s;
if (NSTR(node)->capa > 0 || (len + addlen > NODE_STR_BUF_SIZE - 1)) {
UChar* p;
int capa = len + addlen + NODE_STR_MARGIN;
if (capa <= NSTR(node)->capa) {
onig_strcpy(NSTR(node)->s + len, s, end);
}
else {
if (NSTR(node)->s == NSTR(node)->buf)
p = strcat_capa_from_static(NSTR(node)->s, NSTR(node)->end,
s, end, capa);
else
p = strcat_capa(NSTR(node)->s, NSTR(node)->end, s, end, capa);
CHECK_NULL_RETURN_MEMERR(p);
NSTR(node)->s = p;
NSTR(node)->capa = capa;
}
}
else {
onig_strcpy(NSTR(node)->s + len, s, end);
}
NSTR(node)->end = NSTR(node)->s + len + addlen;
}
return 0;
}
extern int
onig_node_str_set(Node* node, const UChar* s, const UChar* end)
{
onig_node_str_clear(node);
return onig_node_str_cat(node, s, end);
}
static int
node_str_cat_char(Node* node, UChar c)
{
UChar s[1];
s[0] = c;
return onig_node_str_cat(node, s, s + 1);
}
extern void
onig_node_conv_to_str_node(Node* node, int flag)
{
SET_NTYPE(node, NT_STR);
NSTR(node)->flag = flag;
NSTR(node)->capa = 0;
NSTR(node)->s = NSTR(node)->buf;
NSTR(node)->end = NSTR(node)->buf;
}
extern void
onig_node_str_clear(Node* node)
{
if (NSTR(node)->capa != 0 &&
IS_NOT_NULL(NSTR(node)->s) && NSTR(node)->s != NSTR(node)->buf) {
xfree(NSTR(node)->s);
}
NSTR(node)->capa = 0;
NSTR(node)->flag = 0;
NSTR(node)->s = NSTR(node)->buf;
NSTR(node)->end = NSTR(node)->buf;
}
static Node*
node_new_str(const UChar* s, const UChar* end)
{
Node* node = node_new();
CHECK_NULL_RETURN(node);
SET_NTYPE(node, NT_STR);
NSTR(node)->capa = 0;
NSTR(node)->flag = 0;
NSTR(node)->s = NSTR(node)->buf;
NSTR(node)->end = NSTR(node)->buf;
if (onig_node_str_cat(node, s, end)) {
onig_node_free(node);
return NULL;
}
return node;
}
extern Node*
onig_node_new_str(const UChar* s, const UChar* end)
{
return node_new_str(s, end);
}
static Node*
node_new_str_raw(UChar* s, UChar* end)
{
Node* node = node_new_str(s, end);
NSTRING_SET_RAW(node);
return node;
}
static Node*
node_new_empty(void)
{
return node_new_str(NULL, NULL);
}
static Node*
node_new_str_raw_char(UChar c)
{
UChar p[1];
p[0] = c;
return node_new_str_raw(p, p + 1);
}
static Node*
str_node_split_last_char(StrNode* sn, OnigEncoding enc)
{
const UChar *p;
Node* n = NULL_NODE;
if (sn->end > sn->s) {
p = onigenc_get_prev_char_head(enc, sn->s, sn->end, sn->end);
if (p && p > sn->s) { /* can be splitted. */
n = node_new_str(p, sn->end);
if ((sn->flag & NSTR_RAW) != 0)
NSTRING_SET_RAW(n);
sn->end = (UChar* )p;
}
}
return n;
}
static int
str_node_can_be_split(StrNode* sn, OnigEncoding enc)
{
if (sn->end > sn->s) {
|