changed awk to handle IGNORECASE with a regular expression engine that doesn't have a run-time option but has a compile-time option
This commit is contained in:
parent
47677ca566
commit
d841c9f62f
@ -110,21 +110,21 @@ typedef struct qse_awk_loc_t qse_awk_loc_t;
|
||||
* Three common fields are:
|
||||
* - type - type of a value from #qse_awk_val_type_t
|
||||
* - ref - reference count
|
||||
* - nstr - numeric string marker
|
||||
* - stat - static value
|
||||
* - nstr - numeric string marker, 1 -> long, 2 -> real
|
||||
*/
|
||||
#if QSE_SIZEOF_INT == 2
|
||||
# define QSE_AWK_VAL_HDR \
|
||||
unsigned int type: 3; \
|
||||
unsigned int ref: 10; \
|
||||
unsigned int stat: 1; \
|
||||
unsigned int nstr: 2
|
||||
#else
|
||||
# define QSE_AWK_VAL_HDR \
|
||||
/*
|
||||
#define QSE_AWK_VAL_HDR \
|
||||
unsigned int type: 3; \
|
||||
unsigned int ref: 26; \
|
||||
unsigned int stat: 1; \
|
||||
unsigned int nstr: 2
|
||||
#endif
|
||||
unsigned int nstr: 2;
|
||||
*/
|
||||
#define QSE_AWK_VAL_HDR \
|
||||
qse_uintptr_t type: 3; \
|
||||
qse_uintptr_t ref: ((QSE_SIZEOF_UINTPTR_T * 8) - 6); \
|
||||
qse_uintptr_t stat: 1; \
|
||||
qse_uintptr_t nstr: 2;
|
||||
|
||||
/**
|
||||
* The qse_awk_val_t type is an abstract value type. A value commonly contains:
|
||||
@ -191,7 +191,7 @@ struct qse_awk_val_rex_t
|
||||
{
|
||||
QSE_AWK_VAL_HDR;
|
||||
qse_xstr_t str;
|
||||
void* code;
|
||||
void* code[2];
|
||||
};
|
||||
typedef struct qse_awk_val_rex_t qse_awk_val_rex_t;
|
||||
|
||||
@ -2388,7 +2388,7 @@ QSE_EXPORT qse_awk_val_t* qse_awk_rtx_makenstrvalwithcstr (
|
||||
QSE_EXPORT qse_awk_val_t* qse_awk_rtx_makerexval (
|
||||
qse_awk_rtx_t* rtx,
|
||||
const qse_cstr_t* str,
|
||||
void* code
|
||||
void* code[2]
|
||||
);
|
||||
|
||||
/**
|
||||
|
@ -99,15 +99,6 @@ enum qse_tre_eflag_t
|
||||
QSE_TRE_NOTEOL = (1 << 2)
|
||||
};
|
||||
|
||||
typedef struct qse_tre_strsrc_t qse_tre_strsrc_t;
|
||||
struct qse_tre_strsrc_t
|
||||
{
|
||||
int (*get_next_char) (qse_char_t *c, unsigned int* pos_add, void* context);
|
||||
void (*rewind)(qse_size_t pos, void *context);
|
||||
int (*compare)(qse_size_t pos1, qse_size_t pos2, qse_size_t len, void* context);
|
||||
void* context;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
@ -307,8 +307,8 @@ struct qse_awk_rtx_t
|
||||
|
||||
struct
|
||||
{
|
||||
void* rs;
|
||||
void* fs;
|
||||
void* rs[2];
|
||||
void* fs[2];
|
||||
int ignorecase;
|
||||
|
||||
qse_long_t nr;
|
||||
|
@ -624,7 +624,7 @@ static int fnc_substr (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fnc_split (qse_awk_rtx_t* run, const qse_awk_fnc_info_t* fi)
|
||||
static int fnc_split (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
|
||||
{
|
||||
qse_size_t nargs;
|
||||
qse_awk_val_t* a0, * a1, * a2, * t1, * t2;
|
||||
@ -642,12 +642,12 @@ static int fnc_split (qse_awk_rtx_t* run, const qse_awk_fnc_info_t* fi)
|
||||
qse_awk_errnum_t errnum;
|
||||
int x;
|
||||
|
||||
nargs = qse_awk_rtx_getnargs (run);
|
||||
nargs = qse_awk_rtx_getnargs (rtx);
|
||||
QSE_ASSERT (nargs >= 2 && nargs <= 3);
|
||||
|
||||
a0 = qse_awk_rtx_getarg (run, 0);
|
||||
a1 = qse_awk_rtx_getarg (run, 1);
|
||||
a2 = (nargs >= 3)? qse_awk_rtx_getarg (run, 2): QSE_NULL;
|
||||
a0 = qse_awk_rtx_getarg (rtx, 0);
|
||||
a1 = qse_awk_rtx_getarg (rtx, 1);
|
||||
a2 = (nargs >= 3)? qse_awk_rtx_getarg (rtx, 2): QSE_NULL;
|
||||
|
||||
QSE_ASSERT (a1->type == QSE_AWK_VAL_REF);
|
||||
|
||||
@ -658,7 +658,7 @@ static int fnc_split (qse_awk_rtx_t* run, const qse_awk_fnc_info_t* fi)
|
||||
}
|
||||
else
|
||||
{
|
||||
str.ptr = qse_awk_rtx_valtostrdup (run, a0, &str.len);
|
||||
str.ptr = qse_awk_rtx_valtostrdup (rtx, a0, &str.len);
|
||||
if (str.ptr == QSE_NULL) return -1;
|
||||
str_free = (qse_char_t*)str.ptr;
|
||||
}
|
||||
@ -666,7 +666,7 @@ static int fnc_split (qse_awk_rtx_t* run, const qse_awk_fnc_info_t* fi)
|
||||
if (a2 == QSE_NULL)
|
||||
{
|
||||
/* get the value from FS */
|
||||
t1 = qse_awk_rtx_getgbl (run, QSE_AWK_GBL_FS);
|
||||
t1 = qse_awk_rtx_getgbl (rtx, QSE_AWK_GBL_FS);
|
||||
if (t1->type == QSE_AWK_VAL_NIL)
|
||||
{
|
||||
fs.ptr = QSE_T(" ");
|
||||
@ -679,17 +679,17 @@ static int fnc_split (qse_awk_rtx_t* run, const qse_awk_fnc_info_t* fi)
|
||||
}
|
||||
else
|
||||
{
|
||||
fs.ptr = qse_awk_rtx_valtostrdup (run, t1, &fs.len);
|
||||
fs.ptr = qse_awk_rtx_valtostrdup (rtx, t1, &fs.len);
|
||||
if (fs.ptr == QSE_NULL) goto oops;
|
||||
fs_free = (qse_char_t*)fs.ptr;
|
||||
}
|
||||
|
||||
if (fs.len > 1) fs_rex = run->gbl.fs;
|
||||
if (fs.len > 1) fs_rex = rtx->gbl.fs[rtx->gbl.ignorecase];
|
||||
}
|
||||
else if (a2->type == QSE_AWK_VAL_REX)
|
||||
{
|
||||
/* the third parameter is a regular expression */
|
||||
fs_rex = ((qse_awk_val_rex_t*)a2)->code;
|
||||
fs_rex = ((qse_awk_val_rex_t*)a2)->code[rtx->gbl.ignorecase];
|
||||
|
||||
/* make the loop below to take fs_rex by
|
||||
* setting fs_len greater than 1*/
|
||||
@ -705,30 +705,36 @@ static int fnc_split (qse_awk_rtx_t* run, const qse_awk_fnc_info_t* fi)
|
||||
}
|
||||
else
|
||||
{
|
||||
fs.ptr = qse_awk_rtx_valtostrdup (run, a2, &fs.len);
|
||||
fs.ptr = qse_awk_rtx_valtostrdup (rtx, a2, &fs.len);
|
||||
if (fs.ptr == QSE_NULL) goto oops;
|
||||
fs_free = (qse_char_t*)fs.ptr;
|
||||
}
|
||||
|
||||
if (fs.len > 1)
|
||||
{
|
||||
fs_rex = qse_awk_buildrex (
|
||||
run->awk, fs.ptr, fs.len, &errnum);
|
||||
if (fs_rex == QSE_NULL)
|
||||
int x;
|
||||
|
||||
if (rtx->gbl.ignorecase)
|
||||
x = qse_awk_buildrex (rtx->awk, fs.ptr, fs.len, &errnum, QSE_NULL, &fs_rex);
|
||||
else
|
||||
x = qse_awk_buildrex (rtx->awk, fs.ptr, fs.len, &errnum, &fs_rex, QSE_NULL);
|
||||
|
||||
if (x <= -1)
|
||||
{
|
||||
qse_awk_rtx_seterrnum (run, errnum, QSE_NULL);
|
||||
qse_awk_rtx_seterrnum (rtx, errnum, QSE_NULL);
|
||||
goto oops;
|
||||
}
|
||||
|
||||
fs_rex_free = fs_rex;
|
||||
}
|
||||
}
|
||||
|
||||
t1 = qse_awk_rtx_makemapval (run);
|
||||
t1 = qse_awk_rtx_makemapval (rtx);
|
||||
if (t1 == QSE_NULL) goto oops;
|
||||
|
||||
qse_awk_rtx_refupval (run, t1);
|
||||
x = qse_awk_rtx_setrefval (run, a1, t1);
|
||||
qse_awk_rtx_refdownval (run, t1);
|
||||
qse_awk_rtx_refupval (rtx, t1);
|
||||
x = qse_awk_rtx_setrefval (rtx, (qse_awk_val_ref_t*)a1, t1);
|
||||
qse_awk_rtx_refdownval (rtx, t1);
|
||||
if (x <= -1) goto oops;
|
||||
|
||||
/* fill the map with actual values */
|
||||
@ -742,18 +748,18 @@ static int fnc_split (qse_awk_rtx_t* run, const qse_awk_fnc_info_t* fi)
|
||||
|
||||
if (fs.len <= 1)
|
||||
{
|
||||
p = qse_awk_rtx_strxntok (run,
|
||||
p = qse_awk_rtx_strxntok (rtx,
|
||||
p, str.len, fs.ptr, fs.len, &tok);
|
||||
}
|
||||
else
|
||||
{
|
||||
p = qse_awk_rtx_strxntokbyrex (
|
||||
run, str.ptr, org_len, p, str.len,
|
||||
rtx, str.ptr, org_len, p, str.len,
|
||||
fs_rex, &tok, &errnum
|
||||
);
|
||||
if (p == QSE_NULL && errnum != QSE_AWK_ENOERR)
|
||||
{
|
||||
qse_awk_rtx_seterrnum (run, errnum, QSE_NULL);
|
||||
qse_awk_rtx_seterrnum (rtx, errnum, QSE_NULL);
|
||||
goto oops;
|
||||
}
|
||||
}
|
||||
@ -768,42 +774,54 @@ static int fnc_split (qse_awk_rtx_t* run, const qse_awk_fnc_info_t* fi)
|
||||
|
||||
/* create the field string - however, the split function must
|
||||
* create a numeric string if the string is a number */
|
||||
/*t2 = qse_awk_rtx_makestrvalwithcstr (run, &tok);*/
|
||||
t2 = qse_awk_rtx_makenstrvalwithcstr (run, &tok);
|
||||
/*t2 = qse_awk_rtx_makestrvalwithcstr (rtx, &tok);*/
|
||||
t2 = qse_awk_rtx_makenstrvalwithcstr (rtx, &tok);
|
||||
if (t2 == QSE_NULL) goto oops;
|
||||
|
||||
/* put it into the map */
|
||||
key_len = qse_awk_longtostr (
|
||||
run->awk, ++nflds, 10, QSE_NULL, key_buf, QSE_COUNTOF(key_buf));
|
||||
rtx->awk, ++nflds, 10, QSE_NULL, key_buf, QSE_COUNTOF(key_buf));
|
||||
QSE_ASSERT (key_len != (qse_size_t)-1);
|
||||
|
||||
if (qse_awk_rtx_setmapvalfld (
|
||||
run, t1, key_buf, key_len, t2) == QSE_NULL)
|
||||
rtx, t1, key_buf, key_len, t2) == QSE_NULL)
|
||||
{
|
||||
qse_awk_rtx_refupval (run, t2);
|
||||
qse_awk_rtx_refdownval (run, t2);
|
||||
qse_awk_rtx_refupval (rtx, t2);
|
||||
qse_awk_rtx_refdownval (rtx, t2);
|
||||
goto oops;
|
||||
}
|
||||
|
||||
str.len = str_left - (p - str.ptr);
|
||||
}
|
||||
|
||||
if (str_free) QSE_AWK_FREE (run->awk, str_free);
|
||||
if (fs_free) QSE_AWK_FREE (run->awk, fs_free);
|
||||
if (fs_rex_free) qse_awk_freerex (run->awk, fs_rex_free);
|
||||
if (str_free) QSE_AWK_FREE (rtx->awk, str_free);
|
||||
if (fs_free) QSE_AWK_FREE (rtx->awk, fs_free);
|
||||
if (fs_rex_free)
|
||||
{
|
||||
if (rtx->gbl.ignorecase)
|
||||
qse_awk_freerex (rtx->awk, QSE_NULL, fs_rex_free);
|
||||
else
|
||||
qse_awk_freerex (rtx->awk, fs_rex_free, QSE_NULL);
|
||||
}
|
||||
|
||||
/*nflds--;*/
|
||||
|
||||
t1 = qse_awk_rtx_makeintval (run, nflds);
|
||||
t1 = qse_awk_rtx_makeintval (rtx, nflds);
|
||||
if (t1 == QSE_NULL) return -1;
|
||||
|
||||
qse_awk_rtx_setretval (run, t1);
|
||||
qse_awk_rtx_setretval (rtx, t1);
|
||||
return 0;
|
||||
|
||||
oops:
|
||||
if (str_free) QSE_AWK_FREE (run->awk, str_free);
|
||||
if (fs_free) QSE_AWK_FREE (run->awk, fs_free);
|
||||
if (fs_rex_free) qse_awk_freerex (run->awk, fs_rex_free);
|
||||
if (str_free) QSE_AWK_FREE (rtx->awk, str_free);
|
||||
if (fs_free) QSE_AWK_FREE (rtx->awk, fs_free);
|
||||
if (fs_rex_free)
|
||||
{
|
||||
if (rtx->gbl.ignorecase)
|
||||
qse_awk_freerex (rtx->awk, QSE_NULL, fs_rex_free);
|
||||
else
|
||||
qse_awk_freerex (rtx->awk, fs_rex_free, QSE_NULL);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -832,7 +850,7 @@ static int fnc_tolower (qse_awk_rtx_t* run, const qse_awk_fnc_info_t* fi)
|
||||
|
||||
for (i = 0; i < str.len; i++) str.ptr[i] = QSE_AWK_TOLOWER (run->awk, str.ptr[i]);
|
||||
|
||||
r = qse_awk_rtx_makestrvalwithcstr (run, &str);
|
||||
r = qse_awk_rtx_makestrvalwithcstr (run, (qse_cstr_t*)&str);
|
||||
if (r == QSE_NULL)
|
||||
{
|
||||
if (a0->type != QSE_AWK_VAL_STR) QSE_AWK_FREE (run->awk, str.ptr);
|
||||
@ -869,7 +887,7 @@ static int fnc_toupper (qse_awk_rtx_t* run, const qse_awk_fnc_info_t* fi)
|
||||
|
||||
for (i = 0; i < str.len; i++) str.ptr[i] = QSE_AWK_TOUPPER (run->awk, str.ptr[i]);
|
||||
|
||||
r = qse_awk_rtx_makestrvalwithcstr (run, &str);
|
||||
r = qse_awk_rtx_makestrvalwithcstr (run, (qse_cstr_t*)&str);
|
||||
if (r == QSE_NULL)
|
||||
{
|
||||
if (a0->type != QSE_AWK_VAL_STR) QSE_AWK_FREE (run->awk, str.ptr);
|
||||
@ -881,11 +899,10 @@ static int fnc_toupper (qse_awk_rtx_t* run, const qse_awk_fnc_info_t* fi)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int __substitute (qse_awk_rtx_t* run, qse_long_t max_count)
|
||||
{
|
||||
qse_size_t nargs;
|
||||
qse_awk_val_t* a0, * a1, * a2, ** a2_ref, * v;
|
||||
qse_awk_val_t* a0, * a1, * a2, * v;
|
||||
|
||||
qse_cstr_t s0, s1, s2;
|
||||
const qse_char_t* s2_end;
|
||||
@ -898,7 +915,7 @@ static int __substitute (qse_awk_rtx_t* run, qse_long_t max_count)
|
||||
void* rex_free = QSE_NULL;
|
||||
|
||||
qse_str_t new;
|
||||
int new_inited = 0, opt;
|
||||
int new_inited = 0;
|
||||
|
||||
qse_cstr_t mat, pmat, cur;
|
||||
|
||||
@ -915,7 +932,7 @@ static int __substitute (qse_awk_rtx_t* run, qse_long_t max_count)
|
||||
|
||||
if (a0->type == QSE_AWK_VAL_REX)
|
||||
{
|
||||
rex = ((qse_awk_val_rex_t*)a0)->code;
|
||||
rex = ((qse_awk_val_rex_t*)a0)->code[run->gbl.ignorecase];
|
||||
}
|
||||
else if (a0->type == QSE_AWK_VAL_STR)
|
||||
{
|
||||
@ -964,10 +981,14 @@ static int __substitute (qse_awk_rtx_t* run, qse_long_t max_count)
|
||||
if (a0->type != QSE_AWK_VAL_REX)
|
||||
{
|
||||
qse_awk_errnum_t errnum;
|
||||
int x;
|
||||
|
||||
rex = qse_awk_buildrex (
|
||||
run->awk, s0.ptr, s0.len, &errnum);
|
||||
if (rex == QSE_NULL)
|
||||
if (run->gbl.ignorecase)
|
||||
x = qse_awk_buildrex (run->awk, s0.ptr, s0.len, &errnum, QSE_NULL, &rex);
|
||||
else
|
||||
x = qse_awk_buildrex (run->awk, s0.ptr, s0.len, &errnum, &rex, QSE_NULL);
|
||||
|
||||
if (x <= -1)
|
||||
{
|
||||
qse_awk_rtx_seterrnum (run, errnum, QSE_NULL);
|
||||
goto oops;
|
||||
@ -976,8 +997,6 @@ static int __substitute (qse_awk_rtx_t* run, qse_long_t max_count)
|
||||
rex_free = rex;
|
||||
}
|
||||
|
||||
opt = (run->gbl.ignorecase)? QSE_REX_IGNORECASE: 0;
|
||||
|
||||
s2_end = s2.ptr + s2.len;
|
||||
cur.ptr = s2.ptr;
|
||||
cur.len = s2.len;
|
||||
@ -997,7 +1016,8 @@ static int __substitute (qse_awk_rtx_t* run, qse_long_t max_count)
|
||||
if (max_count == 0 || sub_count < max_count)
|
||||
{
|
||||
n = qse_awk_matchrex (
|
||||
run->awk, rex, opt, &s2, &cur, &mat, &errnum
|
||||
run->awk, rex, run->gbl.ignorecase,
|
||||
&s2, &cur, &mat, &errnum
|
||||
);
|
||||
}
|
||||
else n = 0;
|
||||
@ -1085,7 +1105,10 @@ static int __substitute (qse_awk_rtx_t* run, qse_long_t max_count)
|
||||
|
||||
if (rex_free)
|
||||
{
|
||||
qse_awk_freerex (run->awk, rex_free);
|
||||
if (run->gbl.ignorecase)
|
||||
qse_awk_freerex (run->awk, QSE_NULL, rex_free);
|
||||
else
|
||||
qse_awk_freerex (run->awk, rex_free, QSE_NULL);
|
||||
rex_free = QSE_NULL;
|
||||
}
|
||||
|
||||
@ -1104,7 +1127,7 @@ static int __substitute (qse_awk_rtx_t* run, qse_long_t max_count)
|
||||
v = qse_awk_rtx_makestrvalwithcstr (run, QSE_STR_CSTR(&new));
|
||||
if (v == QSE_NULL) goto oops;
|
||||
qse_awk_rtx_refupval (run, v);
|
||||
n = qse_awk_rtx_setrefval (run, a2, v);
|
||||
n = qse_awk_rtx_setrefval (run, (qse_awk_val_ref_t*)a2, v);
|
||||
qse_awk_rtx_refdownval (run, v);
|
||||
if (n <= -1) goto oops;
|
||||
}
|
||||
@ -1123,7 +1146,13 @@ static int __substitute (qse_awk_rtx_t* run, qse_long_t max_count)
|
||||
return 0;
|
||||
|
||||
oops:
|
||||
if (rex_free) qse_awk_freerex (run->awk, rex_free);
|
||||
if (rex_free)
|
||||
{
|
||||
if (run->gbl.ignorecase)
|
||||
qse_awk_freerex (run->awk, QSE_NULL, rex_free);
|
||||
else
|
||||
qse_awk_freerex (run->awk, rex_free, QSE_NULL);
|
||||
}
|
||||
if (new_inited) qse_str_fini (&new);
|
||||
if (s2_free) QSE_AWK_FREE (run->awk, s2_free);
|
||||
if (s1_free) QSE_AWK_FREE (run->awk, s1_free);
|
||||
@ -1145,13 +1174,11 @@ static int fnc_match (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
|
||||
{
|
||||
qse_size_t nargs;
|
||||
qse_awk_val_t* a0, * a1;
|
||||
qse_char_t* str0, * str1;
|
||||
qse_size_t len0, len1;
|
||||
qse_char_t* str0;
|
||||
qse_size_t len0;
|
||||
qse_long_t idx, start = 1;
|
||||
void* rex;
|
||||
int n;
|
||||
qse_cstr_t mat;
|
||||
qse_awk_errnum_t errnum;
|
||||
|
||||
nargs = qse_awk_rtx_getnargs (rtx);
|
||||
QSE_ASSERT (nargs >= 2 && nargs <= 3);
|
||||
@ -1195,42 +1222,6 @@ static int fnc_match (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
|
||||
if (str0 == QSE_NULL) return -1;
|
||||
}
|
||||
|
||||
if (a1->type == QSE_AWK_VAL_REX)
|
||||
{
|
||||
rex = ((qse_awk_val_rex_t*)a1)->code;
|
||||
}
|
||||
else
|
||||
{
|
||||
qse_awk_errnum_t errnum;
|
||||
|
||||
if (a1->type == QSE_AWK_VAL_STR)
|
||||
{
|
||||
str1 = ((qse_awk_val_str_t*)a1)->val.ptr;
|
||||
len1 = ((qse_awk_val_str_t*)a1)->val.len;
|
||||
}
|
||||
else
|
||||
{
|
||||
str1 = qse_awk_rtx_valtostrdup (rtx, a1, &len1);
|
||||
if (str1 == QSE_NULL)
|
||||
{
|
||||
if (a0->type != QSE_AWK_VAL_STR)
|
||||
QSE_AWK_FREE (rtx->awk, str0);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
rex = qse_awk_buildrex (rtx->awk, str1, len1, &errnum);
|
||||
if (rex == QSE_NULL)
|
||||
{
|
||||
if (a0->type != QSE_AWK_VAL_STR)
|
||||
QSE_AWK_FREE (rtx->awk, str0);
|
||||
qse_awk_rtx_seterrnum (rtx, errnum, QSE_NULL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (a1->type != QSE_AWK_VAL_STR) QSE_AWK_FREE (rtx->awk, str1);
|
||||
}
|
||||
|
||||
if (start == 0) start = 1;
|
||||
else if (start < 0) start = len0 + start + 1;
|
||||
|
||||
@ -1239,24 +1230,15 @@ static int fnc_match (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
|
||||
{
|
||||
qse_cstr_t tmp;
|
||||
|
||||
/*TODO: must use str0,len0?*/
|
||||
/*TODO: must use str0,len0? */
|
||||
tmp.ptr = str0 + start - 1;
|
||||
tmp.len = len0 - start + 1;
|
||||
n = qse_awk_matchrex (
|
||||
rtx->awk, rex,
|
||||
(rtx->gbl.ignorecase? QSE_REX_IGNORECASE: 0),
|
||||
&tmp, &tmp, &mat, &errnum
|
||||
);
|
||||
|
||||
n = qse_awk_rtx_matchrex (rtx, a1, &tmp, &tmp, &mat);
|
||||
if (n <= -1) return -1;
|
||||
}
|
||||
|
||||
if (a0->type != QSE_AWK_VAL_STR) QSE_AWK_FREE (rtx->awk, str0);
|
||||
if (a1->type != QSE_AWK_VAL_REX) qse_awk_freerex (rtx->awk, rex);
|
||||
|
||||
if (n <= -1)
|
||||
{
|
||||
qse_awk_rtx_seterrnum (rtx, errnum, QSE_NULL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
idx = (n == 0)? 0: ((qse_long_t)(mat.ptr-str0) + 1);
|
||||
|
||||
@ -1338,7 +1320,7 @@ static int fnc_sprintf (qse_awk_rtx_t* run, const qse_awk_fnc_info_t* fi)
|
||||
if (a0->type != QSE_AWK_VAL_STR) QSE_AWK_FREE (run->awk, cs0.ptr);
|
||||
if (x.ptr == QSE_NULL) goto oops;
|
||||
|
||||
a0 = qse_awk_rtx_makestrvalwithcstr (run, &x);
|
||||
a0 = qse_awk_rtx_makestrvalwithcstr (run, (qse_cstr_t*)&x);
|
||||
if (a0 == QSE_NULL) goto oops;
|
||||
|
||||
qse_str_fini (&fbu);
|
||||
|
@ -20,7 +20,7 @@
|
||||
|
||||
#include "awk.h"
|
||||
|
||||
#define USE_REX
|
||||
/*#define USE_REX */
|
||||
|
||||
#if defined(USE_REX)
|
||||
# include <qse/cmn/rex.h>
|
||||
@ -892,8 +892,7 @@ qse_char_t* qse_awk_rtx_strxntokbyrex (
|
||||
while (cursub.len > 0)
|
||||
{
|
||||
n = qse_awk_matchrex (
|
||||
rtx->awk, rex,
|
||||
((rtx->gbl.ignorecase)? QSE_REX_IGNORECASE: 0),
|
||||
rtx->awk, rex, rtx->gbl.ignorecase,
|
||||
&s, &cursub, &match, errnum);
|
||||
if (n == -1) return QSE_NULL;
|
||||
if (n == 0)
|
||||
@ -1090,36 +1089,46 @@ static QSE_INLINE int rexerr_to_errnum (int err)
|
||||
}
|
||||
}
|
||||
|
||||
void* qse_awk_buildrex (
|
||||
qse_awk_t* awk, const qse_char_t* ptn,
|
||||
qse_size_t len, qse_awk_errnum_t* errnum)
|
||||
int qse_awk_buildrex (
|
||||
qse_awk_t* awk, const qse_char_t* ptn, qse_size_t len,
|
||||
qse_awk_errnum_t* errnum, void** code, void** icode)
|
||||
{
|
||||
#if defined(USE_REX)
|
||||
qse_rex_errnum_t err;
|
||||
void* p;
|
||||
|
||||
if (code || icode)
|
||||
{
|
||||
p = qse_buildrex (
|
||||
awk->mmgr, awk->opt.depth.s.rex_build,
|
||||
((awk->opt.trait & QSE_AWK_REXBOUND)? 0: QSE_REX_NOBOUND),
|
||||
ptn, len, &err
|
||||
);
|
||||
if (p == QSE_NULL) *errnum = rexerr_to_errnum(err);
|
||||
return p;
|
||||
if (p == QSE_NULL)
|
||||
{
|
||||
*errnum = rexerr_to_errnum(err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (code) *code = p;
|
||||
if (icode) *icode = p;
|
||||
}
|
||||
|
||||
return 0;
|
||||
#else
|
||||
qse_tre_t* tre;
|
||||
qse_tre_t* tre = QSE_NULL;
|
||||
qse_tre_t* itre = QSE_NULL;
|
||||
int opt = QSE_TRE_EXTENDED;
|
||||
|
||||
if (code)
|
||||
{
|
||||
tre = qse_tre_open (awk->mmgr, 0);
|
||||
if (tre == QSE_NULL)
|
||||
{
|
||||
*errnum = QSE_AWK_ENOMEM;
|
||||
return QSE_NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* ignorecase is a compile option for TRE */
|
||||
#if 0 /* TODO */
|
||||
if (ignorecase) opt |= QSE_TRE_IGNORECASE;
|
||||
#endif
|
||||
if (!(awk->opt.trait & QSE_AWK_REXBOUND)) opt |= QSE_TRE_NOBOUND;
|
||||
|
||||
if (qse_tre_compx (tre, ptn, len, QSE_NULL, opt) <= -1)
|
||||
@ -1133,13 +1142,44 @@ void* qse_awk_buildrex (
|
||||
*errnum = (QSE_TRE_ERRNUM(tre) == QSE_TRE_ENOMEM)?
|
||||
QSE_AWK_ENOMEM: QSE_AWK_EREXBL;
|
||||
qse_tre_close (tre);
|
||||
return QSE_NULL;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return tre;
|
||||
if (icode)
|
||||
{
|
||||
itre = qse_tre_open (awk->mmgr, 0);
|
||||
if (itre == QSE_NULL)
|
||||
{
|
||||
if (tre) qse_tre_close (tre);
|
||||
*errnum = QSE_AWK_ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* ignorecase is a compile option for TRE */
|
||||
if (qse_tre_compx (itre, ptn, len, QSE_NULL, opt | QSE_TRE_IGNORECASE) <= -1)
|
||||
{
|
||||
#if 0 /* TODO */
|
||||
|
||||
if (QSE_TRE_ERRNUM(tre) == QSE_TRE_ENOMEM) *errnum = QSE_AWK_ENOMEM;
|
||||
else
|
||||
SETERR1 (awk, QSE_AWK_EREXBL, str->ptr, str->len, loc);
|
||||
#endif
|
||||
*errnum = (QSE_TRE_ERRNUM(tre) == QSE_TRE_ENOMEM)?
|
||||
QSE_AWK_ENOMEM: QSE_AWK_EREXBL;
|
||||
qse_tre_close (itre);
|
||||
if (tre) qse_tre_close (tre);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (code) *code = tre;
|
||||
if (icode) *icode = itre;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if !defined(USE_REX)
|
||||
|
||||
static int matchtre (
|
||||
@ -1192,7 +1232,7 @@ static int matchtre (
|
||||
#endif
|
||||
|
||||
int qse_awk_matchrex (
|
||||
qse_awk_t* awk, void* code, int option,
|
||||
qse_awk_t* awk, void* code, int icase,
|
||||
const qse_cstr_t* str, const qse_cstr_t* substr,
|
||||
qse_cstr_t* match, qse_awk_errnum_t* errnum)
|
||||
{
|
||||
@ -1201,8 +1241,8 @@ int qse_awk_matchrex (
|
||||
qse_rex_errnum_t err;
|
||||
|
||||
x = qse_matchrex (
|
||||
awk->mmgr, awk->opt.depth.s.rex_match,
|
||||
code, option, str, substr, match, &err);
|
||||
awk->mmgr, awk->opt.depth.s.rex_match, code,
|
||||
(icase? QSE_REX_IGNORECASE: 0), str, substr, match, &err);
|
||||
if (x <= -1) *errnum = rexerr_to_errnum(err);
|
||||
return x;
|
||||
#else
|
||||
@ -1218,13 +1258,102 @@ int qse_awk_matchrex (
|
||||
#endif
|
||||
}
|
||||
|
||||
void qse_awk_freerex (qse_awk_t* awk, void* code)
|
||||
void qse_awk_freerex (qse_awk_t* awk, void* code, void* icode)
|
||||
{
|
||||
if (code)
|
||||
{
|
||||
#if defined(USE_REX)
|
||||
qse_freerex((awk)->mmgr,code);
|
||||
qse_freerex ((awk)->mmgr, code);
|
||||
#else
|
||||
qse_tre_close (code);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (icode && icode != code)
|
||||
{
|
||||
#if defined(USE_REX)
|
||||
qse_freerex ((awk)->mmgr, icode);
|
||||
#else
|
||||
qse_tre_close (icode);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
int qse_awk_rtx_matchrex (
|
||||
qse_awk_rtx_t* rtx, qse_awk_val_t* val,
|
||||
const qse_cstr_t* str, const qse_cstr_t* substr, qse_cstr_t* match)
|
||||
{
|
||||
void* code;
|
||||
int icase, x;
|
||||
qse_awk_errnum_t awkerr;
|
||||
#if defined(USE_REX)
|
||||
qse_rex_errnum_t rexerr;
|
||||
#endif
|
||||
|
||||
icase = rtx->gbl.ignorecase;
|
||||
|
||||
if (val->type == QSE_AWK_VAL_REX)
|
||||
{
|
||||
code = ((qse_awk_val_rex_t*)val)->code[icase];
|
||||
}
|
||||
else if (val->type == QSE_AWK_VAL_STR)
|
||||
{
|
||||
/* build a regular expression */
|
||||
qse_awk_val_str_t* strv = (qse_awk_val_str_t*)val;
|
||||
x = icase? qse_awk_buildrex (rtx->awk, strv->val.ptr, strv->val.len, &awkerr, QSE_NULL, &code):
|
||||
qse_awk_buildrex (rtx->awk, strv->val.ptr, strv->val.len, &awkerr, &code, QSE_NULL);
|
||||
if (x <= -1)
|
||||
{
|
||||
qse_awk_rtx_seterrnum (rtx, awkerr, QSE_NULL);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* convert to a string and build a regular expression */
|
||||
|
||||
qse_xstr_t tmp;
|
||||
tmp.ptr = qse_awk_rtx_valtostrdup (rtx, val, &tmp.len);
|
||||
if (tmp.ptr == QSE_NULL) return -1;
|
||||
|
||||
x = icase? qse_awk_buildrex (rtx->awk, tmp.ptr, tmp.len, &awkerr, QSE_NULL, &code):
|
||||
qse_awk_buildrex (rtx->awk, tmp.ptr, tmp.len, &awkerr, &code, QSE_NULL);
|
||||
qse_awk_rtx_freemem (rtx, tmp.ptr);
|
||||
if (x <= -1)
|
||||
{
|
||||
qse_awk_rtx_seterrnum (rtx, awkerr, QSE_NULL);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(USE_REX)
|
||||
x = qse_matchrex (
|
||||
rtx->awk->mmgr, rtx->awk->opt.depth.s.rex_match,
|
||||
code, (icase? QSE_REX_IGNORECASE: 0),
|
||||
str, substr, match, &rexerr);
|
||||
if (x <= -1) qse_awk_rtx_seterrnum (rtx, rexerr_to_errnum(rexerr), QSE_NULL);
|
||||
#else
|
||||
x = matchtre (
|
||||
rtx->awk, code,
|
||||
((str->ptr == substr->ptr)? QSE_TRE_BACKTRACKING: (QSE_TRE_BACKTRACKING | QSE_TRE_NOTBOL)),
|
||||
substr, match, QSE_NULL, &awkerr
|
||||
);
|
||||
if (x <= -1) qse_awk_rtx_seterrnum (rtx, awkerr, QSE_NULL);
|
||||
#endif
|
||||
|
||||
if (val->type == QSE_AWK_VAL_REX)
|
||||
{
|
||||
/* nothing to free */
|
||||
}
|
||||
else
|
||||
{
|
||||
if (icase)
|
||||
qse_awk_freerex (rtx->awk, QSE_NULL, code);
|
||||
else
|
||||
qse_awk_freerex (rtx->awk, code, QSE_NULL);
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
void* qse_awk_rtx_allocmem (qse_awk_rtx_t* rtx, qse_size_t size)
|
||||
|
@ -63,20 +63,28 @@ qse_char_t* qse_awk_rtx_strxnfld (
|
||||
qse_cstr_t* tok
|
||||
);
|
||||
|
||||
void* qse_awk_buildrex (
|
||||
int qse_awk_buildrex (
|
||||
qse_awk_t* awk,
|
||||
const qse_char_t* ptn,
|
||||
qse_size_t len,
|
||||
qse_awk_errnum_t* errnum
|
||||
qse_awk_errnum_t* errnum,
|
||||
void** code,
|
||||
void** icode
|
||||
);
|
||||
|
||||
int qse_awk_matchrex (
|
||||
qse_awk_t* awk, void* code, int option,
|
||||
qse_awk_t* awk, void* code, int icase,
|
||||
const qse_cstr_t* str, const qse_cstr_t* substr,
|
||||
qse_cstr_t* match, qse_awk_errnum_t* errnum
|
||||
);
|
||||
|
||||
void qse_awk_freerex (qse_awk_t* awk, void* code);
|
||||
void qse_awk_freerex (qse_awk_t* awk, void* code, void* icode);
|
||||
|
||||
int qse_awk_rtx_matchrex (
|
||||
qse_awk_rtx_t* rtx, qse_awk_val_t* val,
|
||||
const qse_cstr_t* str, const qse_cstr_t* substr,
|
||||
qse_cstr_t* match
|
||||
);
|
||||
|
||||
int qse_awk_sprintflt (
|
||||
qse_awk_t* awk,
|
||||
|
@ -4351,9 +4351,7 @@ static qse_awk_nde_t* parse_primary_rex (qse_awk_t* awk, const qse_awk_loc_t* x
|
||||
nde->str.ptr = qse_awk_cstrdup (awk, QSE_STR_CSTR(awk->tok.name));
|
||||
if (nde->str.ptr == QSE_NULL) goto oops;
|
||||
|
||||
nde->code = qse_awk_buildrex (
|
||||
awk, QSE_STR_PTR(awk->tok.name), QSE_STR_LEN(awk->tok.name), &errnum);
|
||||
if (nde->code == QSE_NULL)
|
||||
if (qse_awk_buildrex (awk, QSE_STR_PTR(awk->tok.name), QSE_STR_LEN(awk->tok.name), &errnum, &nde->code[0], &nde->code[1]) <= -1)
|
||||
{
|
||||
SETERR_LOC (awk, errnum, xloc);
|
||||
goto oops;
|
||||
@ -4365,7 +4363,7 @@ static qse_awk_nde_t* parse_primary_rex (qse_awk_t* awk, const qse_awk_loc_t* x
|
||||
|
||||
oops:
|
||||
QSE_ASSERT (nde != QSE_NULL);
|
||||
if (nde->code) qse_awk_freerex (awk, nde->code);
|
||||
if (nde->code[0]) qse_awk_freerex (awk, nde->code[0], nde->code[1]);
|
||||
if (nde->str.ptr) QSE_AWK_FREE (awk, nde->str.ptr);
|
||||
QSE_AWK_FREE (awk, nde);
|
||||
return QSE_NULL;
|
||||
|
@ -122,13 +122,8 @@ static int split_record (qse_awk_rtx_t* rtx)
|
||||
}
|
||||
else
|
||||
{
|
||||
qse_awk_rtx_valtostr_out_t out;
|
||||
|
||||
out.type = QSE_AWK_RTX_VALTOSTR_CPLDUP;
|
||||
if (qse_awk_rtx_valtostr (rtx, fs, &out) <= -1) return -1;
|
||||
|
||||
fs_ptr = out.u.cpldup.ptr;
|
||||
fs_len = out.u.cpldup.len;
|
||||
fs_ptr = qse_awk_rtx_valtostrdup (rtx, fs, &fs_len);
|
||||
if (fs_ptr == QSE_NULL) return -1;
|
||||
fs_free = fs_ptr;
|
||||
}
|
||||
|
||||
@ -178,7 +173,7 @@ static int split_record (qse_awk_rtx_t* rtx)
|
||||
QSE_STR_PTR(&rtx->inrec.line),
|
||||
QSE_STR_LEN(&rtx->inrec.line),
|
||||
p, len,
|
||||
rtx->gbl.fs, &tok, &errnum
|
||||
rtx->gbl.fs[rtx->gbl.ignorecase], &tok, &errnum
|
||||
);
|
||||
if (p == QSE_NULL && errnum != QSE_AWK_ENOERR)
|
||||
{
|
||||
@ -268,7 +263,7 @@ static int split_record (qse_awk_rtx_t* rtx)
|
||||
QSE_STR_PTR(&rtx->inrec.line),
|
||||
QSE_STR_LEN(&rtx->inrec.line),
|
||||
p, len,
|
||||
rtx->gbl.fs, &tok, &errnum
|
||||
rtx->gbl.fs[rtx->gbl.ignorecase], &tok, &errnum
|
||||
);
|
||||
if (p == QSE_NULL && errnum != QSE_AWK_ENOERR)
|
||||
{
|
||||
|
@ -223,12 +223,12 @@ static QSE_INLINE int match_long_rs (
|
||||
qse_awk_errnum_t errnum;
|
||||
int ret;
|
||||
|
||||
QSE_ASSERT (run->gbl.rs != QSE_NULL);
|
||||
QSE_ASSERT (run->gbl.rs[0] != QSE_NULL);
|
||||
QSE_ASSERT (run->gbl.rs[1] != QSE_NULL);
|
||||
|
||||
ret = qse_awk_matchrex (
|
||||
run->awk, run->gbl.rs,
|
||||
((run->gbl.ignorecase)? QSE_REX_IGNORECASE: 0),
|
||||
QSE_STR_CSTR(buf), QSE_STR_CSTR(buf),
|
||||
run->awk, run->gbl.rs[run->gbl.ignorecase],
|
||||
run->gbl.ignorecase, QSE_STR_CSTR(buf), QSE_STR_CSTR(buf),
|
||||
&match, &errnum);
|
||||
if (ret <= -1)
|
||||
{
|
||||
|
@ -464,12 +464,11 @@ static int set_global (
|
||||
|
||||
if (fs_len > 1 && !(fs_len == 5 && fs_ptr[0] == QSE_T('?')))
|
||||
{
|
||||
void* rex;
|
||||
void* rex, * irex;
|
||||
|
||||
qse_awk_errnum_t errnum;
|
||||
|
||||
rex = qse_awk_buildrex (
|
||||
rtx->awk, fs_ptr, fs_len, &errnum);
|
||||
if (rex == QSE_NULL)
|
||||
if (qse_awk_buildrex (rtx->awk, fs_ptr, fs_len, &errnum, &rex, &irex) <= -1)
|
||||
{
|
||||
SETERR_COD (rtx, errnum);
|
||||
if (val->type != QSE_AWK_VAL_STR)
|
||||
@ -477,14 +476,14 @@ static int set_global (
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rtx->gbl.fs != QSE_NULL)
|
||||
qse_awk_freerex (rtx->awk, rtx->gbl.fs);
|
||||
if (rtx->gbl.fs[0])
|
||||
qse_awk_freerex (rtx->awk, rtx->gbl.fs[0], rtx->gbl.fs[1]);
|
||||
|
||||
rtx->gbl.fs = rex;
|
||||
rtx->gbl.fs[0] = rex;
|
||||
rtx->gbl.fs[1] = irex;
|
||||
}
|
||||
|
||||
if (val->type != QSE_AWK_VAL_STR)
|
||||
QSE_AWK_FREE (rtx->awk, fs_ptr);
|
||||
if (val->type != QSE_AWK_VAL_STR) QSE_AWK_FREE (rtx->awk, fs_ptr);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -613,33 +612,31 @@ static int set_global (
|
||||
rss = out.u.cpldup;
|
||||
}
|
||||
|
||||
if (rtx->gbl.rs)
|
||||
if (rtx->gbl.rs[0])
|
||||
{
|
||||
qse_awk_freerex (rtx->awk, rtx->gbl.rs);
|
||||
rtx->gbl.rs = QSE_NULL;
|
||||
qse_awk_freerex (rtx->awk, rtx->gbl.rs[0], rtx->gbl.rs[1]);
|
||||
rtx->gbl.rs[0] = QSE_NULL;
|
||||
rtx->gbl.rs[1] = QSE_NULL;
|
||||
}
|
||||
|
||||
if (rss.len > 1)
|
||||
{
|
||||
void* rex;
|
||||
void* rex, * irex;
|
||||
qse_awk_errnum_t errnum;
|
||||
|
||||
/* compile the regular expression */
|
||||
rex = qse_awk_buildrex (
|
||||
rtx->awk, rss.ptr, rss.len, &errnum);
|
||||
if (rex == QSE_NULL)
|
||||
if (qse_awk_buildrex (rtx->awk, rss.ptr, rss.len, &errnum, &rex, &irex) <= -1)
|
||||
{
|
||||
SETERR_COD (rtx, errnum);
|
||||
if (val->type != QSE_AWK_VAL_STR)
|
||||
QSE_AWK_FREE (rtx->awk, rss.ptr);
|
||||
if (val->type != QSE_AWK_VAL_STR) QSE_AWK_FREE (rtx->awk, rss.ptr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rtx->gbl.rs = rex;
|
||||
rtx->gbl.rs[0] = rex;
|
||||
rtx->gbl.rs[1] = irex;
|
||||
}
|
||||
|
||||
if (val->type != QSE_AWK_VAL_STR)
|
||||
QSE_AWK_FREE (rtx->awk, rss.ptr);
|
||||
if (val->type != QSE_AWK_VAL_STR) QSE_AWK_FREE (rtx->awk, rss.ptr);
|
||||
|
||||
break;
|
||||
}
|
||||
@ -1016,8 +1013,10 @@ static int init_rtx (qse_awk_rtx_t* rtx, qse_awk_t* awk, qse_awk_rio_t* rio)
|
||||
rtx->rio.chain = QSE_NULL;
|
||||
}
|
||||
|
||||
rtx->gbl.rs = QSE_NULL;
|
||||
rtx->gbl.fs = QSE_NULL;
|
||||
rtx->gbl.rs[0] = QSE_NULL;
|
||||
rtx->gbl.rs[1] = QSE_NULL;
|
||||
rtx->gbl.fs[0] = QSE_NULL;
|
||||
rtx->gbl.fs[1] = QSE_NULL;
|
||||
rtx->gbl.ignorecase = 0;
|
||||
|
||||
return 0;
|
||||
@ -1051,15 +1050,17 @@ static void fini_rtx (qse_awk_rtx_t* rtx, int fini_globals)
|
||||
qse_awk_rtx_cleario (rtx);
|
||||
QSE_ASSERT (rtx->rio.chain == QSE_NULL);
|
||||
|
||||
if (rtx->gbl.rs)
|
||||
if (rtx->gbl.rs[0])
|
||||
{
|
||||
qse_awk_freerex (rtx->awk, rtx->gbl.rs);
|
||||
rtx->gbl.rs = QSE_NULL;
|
||||
qse_awk_freerex (rtx->awk, rtx->gbl.rs[0], rtx->gbl.rs[1]);
|
||||
rtx->gbl.rs[0] = QSE_NULL;
|
||||
rtx->gbl.rs[1] = QSE_NULL;
|
||||
}
|
||||
if (rtx->gbl.fs)
|
||||
if (rtx->gbl.fs[0])
|
||||
{
|
||||
qse_awk_freerex (rtx->awk, rtx->gbl.fs);
|
||||
rtx->gbl.fs = QSE_NULL;
|
||||
qse_awk_freerex (rtx->awk, rtx->gbl.fs[0], rtx->gbl.fs[1]);
|
||||
rtx->gbl.fs[0] = QSE_NULL;
|
||||
rtx->gbl.fs[1] = QSE_NULL;
|
||||
}
|
||||
|
||||
if (rtx->gbl.convfmt.ptr != QSE_NULL &&
|
||||
@ -3208,7 +3209,6 @@ static qse_awk_val_t* eval_expression (qse_awk_rtx_t* rtx, qse_awk_nde_t* nde)
|
||||
{
|
||||
qse_awk_val_t* v;
|
||||
int n;
|
||||
qse_awk_errnum_t errnum;
|
||||
|
||||
#if 0
|
||||
if (rtx->exit_level >= EXIT_GLOBAL)
|
||||
@ -3230,9 +3230,11 @@ static qse_awk_val_t* eval_expression (qse_awk_rtx_t* rtx, qse_awk_nde_t* nde)
|
||||
qse_cstr_t vs;
|
||||
int opt = 0;
|
||||
|
||||
if (((qse_awk_rtx_t*)rtx)->gbl.ignorecase)
|
||||
opt = QSE_REX_IGNORECASE;
|
||||
|
||||
/* special case where a regular expression is used in
|
||||
* without any match operators:
|
||||
* print /abc/;
|
||||
* perform match against $0.
|
||||
*/
|
||||
qse_awk_rtx_refupval (rtx, v);
|
||||
|
||||
if (rtx->inrec.d0->type == QSE_AWK_VAL_NIL)
|
||||
@ -3253,23 +3255,13 @@ static qse_awk_val_t* eval_expression (qse_awk_rtx_t* rtx, qse_awk_nde_t* nde)
|
||||
vs.len = ((qse_awk_val_str_t*)rtx->inrec.d0)->val.len;
|
||||
}
|
||||
|
||||
n = qse_awk_matchrex (
|
||||
((qse_awk_rtx_t*)rtx)->awk,
|
||||
((qse_awk_val_rex_t*)v)->code,
|
||||
opt, &vs, &vs, QSE_NULL, &errnum
|
||||
);
|
||||
n = qse_awk_rtx_matchrex (rtx, v, &vs, &vs, QSE_NULL);
|
||||
if (n <= -1)
|
||||
{
|
||||
ADJERR_LOC (rtx, &nde->loc);
|
||||
qse_awk_rtx_refdownval (rtx, v);
|
||||
|
||||
/* matchrex should never set the error number
|
||||
* whose message contains a formatting
|
||||
* character. otherwise, the following way of
|
||||
* setting the error information may not work */
|
||||
SETERR_LOC (rtx, errnum, &nde->loc);
|
||||
return QSE_NULL;
|
||||
}
|
||||
|
||||
qse_awk_rtx_refdownval (rtx, v);
|
||||
|
||||
v = qse_awk_rtx_makeintval (rtx, (n != 0));
|
||||
@ -4974,115 +4966,50 @@ static qse_awk_val_t* eval_binop_match0 (
|
||||
{
|
||||
qse_awk_val_t* res;
|
||||
int n;
|
||||
qse_awk_errnum_t errnum;
|
||||
void* rex_code;
|
||||
|
||||
if (right->type == QSE_AWK_VAL_REX)
|
||||
{
|
||||
rex_code = ((qse_awk_val_rex_t*)right)->code;
|
||||
}
|
||||
else if (right->type == QSE_AWK_VAL_STR)
|
||||
{
|
||||
rex_code = qse_awk_buildrex (
|
||||
rtx->awk,
|
||||
((qse_awk_val_str_t*)right)->val.ptr,
|
||||
((qse_awk_val_str_t*)right)->val.len, &errnum);
|
||||
if (rex_code == QSE_NULL)
|
||||
{
|
||||
SETERR_LOC (rtx, errnum, rloc);
|
||||
return QSE_NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
qse_awk_rtx_valtostr_out_t out;
|
||||
|
||||
out.type = QSE_AWK_RTX_VALTOSTR_CPLDUP;
|
||||
if (qse_awk_rtx_valtostr (rtx, right, &out) <= -1) return QSE_NULL;
|
||||
|
||||
rex_code = qse_awk_buildrex (
|
||||
rtx->awk, out.u.cpldup.ptr, out.u.cpldup.len, &errnum);
|
||||
if (rex_code == QSE_NULL)
|
||||
{
|
||||
QSE_AWK_FREE (rtx->awk, out.u.cpldup.ptr);
|
||||
SETERR_LOC (rtx, errnum, rloc);
|
||||
return QSE_NULL;
|
||||
}
|
||||
|
||||
QSE_AWK_FREE (rtx->awk, out.u.cpldup.ptr);
|
||||
}
|
||||
|
||||
if (left->type == QSE_AWK_VAL_STR)
|
||||
{
|
||||
n = qse_awk_matchrex (
|
||||
rtx->awk, rex_code,
|
||||
((rtx->gbl.ignorecase)? QSE_REX_IGNORECASE: 0),
|
||||
n = qse_awk_rtx_matchrex (
|
||||
rtx, right,
|
||||
xstr_to_cstr(&((qse_awk_val_str_t*)left)->val),
|
||||
xstr_to_cstr(&((qse_awk_val_str_t*)left)->val),
|
||||
QSE_NULL, &errnum);
|
||||
if (n == -1)
|
||||
xstr_to_cstr(&((qse_awk_val_str_t*)left)->val), QSE_NULL);
|
||||
if (n <= -1)
|
||||
{
|
||||
if (right->type != QSE_AWK_VAL_REX)
|
||||
qse_awk_freerex (rtx->awk, rex_code);
|
||||
|
||||
SETERR_LOC (rtx, errnum, lloc);
|
||||
ADJERR_LOC (rtx, lloc);
|
||||
return QSE_NULL;
|
||||
}
|
||||
|
||||
res = qse_awk_rtx_makeintval (rtx, (n == ret));
|
||||
if (res == QSE_NULL)
|
||||
{
|
||||
if (right->type != QSE_AWK_VAL_REX)
|
||||
qse_awk_freerex (rtx->awk, rex_code);
|
||||
|
||||
ADJERR_LOC (rtx, lloc);
|
||||
return QSE_NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
qse_awk_rtx_valtostr_out_t out;
|
||||
qse_xstr_t out;
|
||||
|
||||
out.type = QSE_AWK_RTX_VALTOSTR_CPLDUP;
|
||||
if (qse_awk_rtx_valtostr (rtx, left, &out) <= -1)
|
||||
out.ptr = qse_awk_rtx_valtostrdup (rtx, left, &out.len);
|
||||
if (out.ptr == QSE_NULL) return QSE_NULL;
|
||||
|
||||
n = qse_awk_rtx_matchrex (rtx, right, &out, &out, QSE_NULL);
|
||||
QSE_AWK_FREE (rtx->awk, out.ptr);
|
||||
|
||||
if (n <= -1)
|
||||
{
|
||||
if (right->type != QSE_AWK_VAL_REX)
|
||||
qse_awk_freerex (rtx->awk, rex_code);
|
||||
return QSE_NULL;
|
||||
}
|
||||
|
||||
n = qse_awk_matchrex (
|
||||
rtx->awk, rex_code,
|
||||
((rtx->gbl.ignorecase)? QSE_REX_IGNORECASE: 0),
|
||||
xstr_to_cstr(&out.u.cpldup),
|
||||
xstr_to_cstr(&out.u.cpldup),
|
||||
QSE_NULL, &errnum
|
||||
);
|
||||
if (n == -1)
|
||||
{
|
||||
QSE_AWK_FREE (rtx->awk, out.u.cpldup.ptr);
|
||||
if (right->type != QSE_AWK_VAL_REX)
|
||||
qse_awk_freerex (rtx->awk, rex_code);
|
||||
|
||||
SETERR_LOC (rtx, errnum, lloc);
|
||||
ADJERR_LOC (rtx, lloc);
|
||||
return QSE_NULL;
|
||||
}
|
||||
|
||||
res = qse_awk_rtx_makeintval (rtx, (n == ret));
|
||||
if (res == QSE_NULL)
|
||||
{
|
||||
QSE_AWK_FREE (rtx->awk, out.u.cpldup.ptr);
|
||||
if (right->type != QSE_AWK_VAL_REX)
|
||||
qse_awk_freerex (rtx->awk, rex_code);
|
||||
|
||||
ADJERR_LOC (rtx, lloc);
|
||||
return QSE_NULL;
|
||||
}
|
||||
|
||||
QSE_AWK_FREE (rtx->awk, out.u.cpldup.ptr);
|
||||
}
|
||||
|
||||
if (right->type != QSE_AWK_VAL_REX) qse_awk_freerex (rtx->awk, rex_code);
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -6307,7 +6234,8 @@ static qse_awk_val_t* eval_rex (qse_awk_rtx_t* run, qse_awk_nde_t* nde)
|
||||
|
||||
val = qse_awk_rtx_makerexval (run,
|
||||
&((qse_awk_nde_rex_t*)nde)->str,
|
||||
((qse_awk_nde_rex_t*)nde)->code);
|
||||
((qse_awk_nde_rex_t*)nde)->code
|
||||
);
|
||||
if (val == QSE_NULL) ADJERR_LOC (run, &nde->loc);
|
||||
|
||||
return val;
|
||||
|
@ -1305,7 +1305,8 @@ void qse_awk_clrpt (qse_awk_t* awk, qse_awk_nde_t* tree)
|
||||
|
||||
case QSE_AWK_NDE_REX:
|
||||
{
|
||||
qse_awk_freerex (awk, ((qse_awk_nde_rex_t*)p)->code);
|
||||
qse_awk_nde_rex_t* rex = (qse_awk_nde_rex_t*)p;
|
||||
qse_awk_freerex (awk, rex->code[0], rex->code[1]);
|
||||
QSE_AWK_FREE (awk, ((qse_awk_nde_rex_t*)p)->str.ptr);
|
||||
QSE_AWK_FREE (awk, p);
|
||||
break;
|
||||
@ -1318,8 +1319,7 @@ void qse_awk_clrpt (qse_awk_t* awk, qse_awk_nde_t* tree)
|
||||
{
|
||||
qse_awk_nde_var_t* px = (qse_awk_nde_var_t*)p;
|
||||
QSE_ASSERT (px->idx == QSE_NULL);
|
||||
if (px->id.name.ptr != QSE_NULL)
|
||||
QSE_AWK_FREE (awk, px->id.name.ptr);
|
||||
if (px->id.name.ptr) QSE_AWK_FREE (awk, px->id.name.ptr);
|
||||
QSE_AWK_FREE (awk, p);
|
||||
break;
|
||||
}
|
||||
|
@ -155,7 +155,7 @@ struct qse_awk_nde_rex_t
|
||||
{
|
||||
QSE_AWK_NDE_HDR;
|
||||
qse_xstr_t str;
|
||||
void* code;
|
||||
void* code[2]; /* [0]: case sensitive, [1]: case insensitive */
|
||||
};
|
||||
|
||||
/* QSE_AWK_NDE_NAMED, QSE_AWK_NDE_GBL,
|
||||
|
@ -35,6 +35,7 @@ qse_awk_val_t* qse_awk_val_zls = (qse_awk_val_t*)&awk_zls;
|
||||
|
||||
static qse_awk_val_int_t awk_int[] =
|
||||
{
|
||||
/* type ref stat nstr val nde */
|
||||
{ QSE_AWK_VAL_INT, 0, 1, 0, -1, QSE_NULL },
|
||||
{ QSE_AWK_VAL_INT, 0, 1, 0, 0, QSE_NULL },
|
||||
{ QSE_AWK_VAL_INT, 0, 1, 0, 1, QSE_NULL },
|
||||
@ -216,7 +217,7 @@ qse_awk_val_t* qse_awk_rtx_makestrvalwithmbs (
|
||||
return QSE_NULL;
|
||||
}
|
||||
|
||||
v = qse_awk_rtx_makestrvalwithcstr (rtx, &tmp);
|
||||
v = qse_awk_rtx_makestrvalwithcstr (rtx, (qse_cstr_t*)&tmp);
|
||||
QSE_AWK_FREE (rtx->awk, tmp.ptr);
|
||||
return v;
|
||||
#endif
|
||||
@ -268,7 +269,7 @@ qse_awk_val_t* qse_awk_rtx_makestrvalwithmcstr (
|
||||
return QSE_NULL;
|
||||
}
|
||||
|
||||
v = qse_awk_rtx_makestrvalwithcstr (rtx, &tmp);
|
||||
v = qse_awk_rtx_makestrvalwithcstr (rtx, (qse_cstr_t*)&tmp);
|
||||
QSE_AWK_FREE (rtx->awk, tmp.ptr);
|
||||
return v;
|
||||
#endif
|
||||
@ -438,7 +439,7 @@ qse_awk_val_t* qse_awk_rtx_makenstrvalwithcstr (qse_awk_rtx_t* rtx, const qse_cs
|
||||
}
|
||||
|
||||
qse_awk_val_t* qse_awk_rtx_makerexval (
|
||||
qse_awk_rtx_t* rtx, const qse_cstr_t* str, void* code)
|
||||
qse_awk_rtx_t* rtx, const qse_cstr_t* str, void* code[2])
|
||||
{
|
||||
qse_awk_val_rex_t* val;
|
||||
qse_size_t totsz;
|
||||
@ -465,7 +466,8 @@ qse_awk_val_t* qse_awk_rtx_makerexval (
|
||||
val->str.ptr = (qse_char_t*)(val + 1);
|
||||
qse_strncpy (val->str.ptr, str->ptr, str->len);
|
||||
|
||||
val->code = code;
|
||||
val->code[0] = code[0];
|
||||
val->code[1] = code[1];
|
||||
|
||||
return (qse_awk_val_t*)val;
|
||||
}
|
||||
@ -824,7 +826,7 @@ void qse_awk_rtx_freeval (
|
||||
|
||||
/* code is just a pointer to a regular expression stored
|
||||
* in parse tree nodes. so don't free it.
|
||||
qse_awk_freerex (rtx->awk, ((qse_awk_val_rex_t*)val)->code);
|
||||
qse_awk_freerex (rtx->awk, ((qse_awk_val_rex_t*)val)->code[0], ((qse_awk_val_rex_t*)val)->code[1]);
|
||||
*/
|
||||
|
||||
QSE_AWK_FREE (rtx->awk, val);
|
||||
@ -1717,7 +1719,7 @@ int qse_awk_rtx_setrefval (qse_awk_rtx_t* rtx, qse_awk_val_ref_t* ref, qse_awk_v
|
||||
qse_awk_rtx_refupval (rtx, val);
|
||||
x = qse_awk_rtx_setrec (
|
||||
rtx, (qse_size_t)ref->adr,
|
||||
&((qse_awk_val_str_t*)val)->val
|
||||
(qse_cstr_t*)&((qse_awk_val_str_t*)val)->val
|
||||
);
|
||||
qse_awk_rtx_refdownval (rtx, val);
|
||||
return x;
|
||||
@ -1730,7 +1732,7 @@ int qse_awk_rtx_setrefval (qse_awk_rtx_t* rtx, qse_awk_val_ref_t* ref, qse_awk_v
|
||||
|
||||
str.ptr = qse_awk_rtx_valtostrdup (rtx, val, &str.len);
|
||||
qse_awk_rtx_refupval (rtx, val);
|
||||
x = qse_awk_rtx_setrec (rtx, (qse_size_t)ref->adr, &str);
|
||||
x = qse_awk_rtx_setrec (rtx, (qse_size_t)ref->adr, (qse_cstr_t*)&str);
|
||||
qse_awk_rtx_refdownval (rtx, val);
|
||||
QSE_AWK_FREE (rtx->awk, str.ptr);
|
||||
return x;
|
||||
|
@ -60,11 +60,9 @@ tre_ast_new_node(tre_mem_t mem, tre_ast_type_t type, size_t size)
|
||||
tre_ast_node_t *node;
|
||||
|
||||
node = tre_mem_calloc(mem, sizeof(*node));
|
||||
if (!node)
|
||||
return NULL;
|
||||
if (!node) return NULL;
|
||||
node->obj = tre_mem_calloc(mem, size);
|
||||
if (!node->obj)
|
||||
return NULL;
|
||||
if (!node->obj) return NULL;
|
||||
node->type = type;
|
||||
node->nullable = -1;
|
||||
node->submatch_id = -1;
|
||||
@ -72,15 +70,13 @@ tre_ast_new_node(tre_mem_t mem, tre_ast_type_t type, size_t size)
|
||||
return node;
|
||||
}
|
||||
|
||||
tre_ast_node_t *
|
||||
tre_ast_new_literal(tre_mem_t mem, int code_min, int code_max, int position)
|
||||
tre_ast_node_t * tre_ast_new_literal(tre_mem_t mem, int code_min, int code_max, int position)
|
||||
{
|
||||
tre_ast_node_t *node;
|
||||
tre_literal_t *lit;
|
||||
|
||||
node = tre_ast_new_node(mem, LITERAL, sizeof(tre_literal_t));
|
||||
if (!node)
|
||||
return NULL;
|
||||
if (!node) return NULL;
|
||||
lit = node->obj;
|
||||
lit->code_min = code_min;
|
||||
lit->code_max = code_max;
|
||||
@ -97,8 +93,7 @@ tre_ast_new_iter(tre_mem_t mem, tre_ast_node_t *arg, int min, int max,
|
||||
tre_iteration_t *iter;
|
||||
|
||||
node = tre_ast_new_node(mem, ITERATION, sizeof(tre_iteration_t));
|
||||
if (!node)
|
||||
return NULL;
|
||||
if (!node) return NULL;
|
||||
iter = node->obj;
|
||||
iter->arg = arg;
|
||||
iter->min = min;
|
||||
@ -115,8 +110,7 @@ tre_ast_new_union(tre_mem_t mem, tre_ast_node_t *left, tre_ast_node_t *right)
|
||||
tre_ast_node_t *node;
|
||||
|
||||
node = tre_ast_new_node(mem, UNION, sizeof(tre_union_t));
|
||||
if (node == NULL)
|
||||
return NULL;
|
||||
if (node == NULL) return NULL;
|
||||
((tre_union_t *)node->obj)->left = left;
|
||||
((tre_union_t *)node->obj)->right = right;
|
||||
node->num_submatches = left->num_submatches + right->num_submatches;
|
||||
@ -131,8 +125,7 @@ tre_ast_new_catenation(tre_mem_t mem, tre_ast_node_t *left,
|
||||
tre_ast_node_t *node;
|
||||
|
||||
node = tre_ast_new_node(mem, CATENATION, sizeof(tre_catenation_t));
|
||||
if (node == NULL)
|
||||
return NULL;
|
||||
if (node == NULL) return NULL;
|
||||
((tre_catenation_t *)node->obj)->left = left;
|
||||
((tre_catenation_t *)node->obj)->right = right;
|
||||
node->num_submatches = left->num_submatches + right->num_submatches;
|
||||
|
@ -88,14 +88,11 @@ tre_add_tag_left(tre_mem_t mem, tre_ast_node_t *node, int tag_id)
|
||||
DPRINT(("add_tag_left: tag %d\n", tag_id));
|
||||
|
||||
c = tre_mem_alloc(mem, sizeof(*c));
|
||||
if (c == NULL)
|
||||
return REG_ESPACE;
|
||||
if (c == NULL) return REG_ESPACE;
|
||||
c->left = tre_ast_new_literal(mem, TAG, tag_id, -1);
|
||||
if (c->left == NULL)
|
||||
return REG_ESPACE;
|
||||
if (c->left == NULL) return REG_ESPACE;
|
||||
c->right = tre_mem_alloc(mem, sizeof(tre_ast_node_t));
|
||||
if (c->right == NULL)
|
||||
return REG_ESPACE;
|
||||
if (c->right == NULL) return REG_ESPACE;
|
||||
|
||||
c->right->obj = node->obj;
|
||||
c->right->type = node->type;
|
||||
@ -152,7 +149,6 @@ typedef enum
|
||||
ADDTAGS_SET_SUBMATCH_END
|
||||
} tre_addtags_symbol_t;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int tag;
|
||||
@ -763,8 +759,7 @@ tre_copy_ast(tre_mem_t mem, tre_stack_t *stack, tre_ast_node_t *ast,
|
||||
first_tag = 0;
|
||||
}
|
||||
*result = tre_ast_new_literal(mem, min, max, pos);
|
||||
if (*result == NULL)
|
||||
status = REG_ESPACE;
|
||||
if (*result == NULL) status = REG_ESPACE;
|
||||
|
||||
if (pos > *max_pos)
|
||||
*max_pos = pos;
|
||||
@ -1121,8 +1116,7 @@ tre_set_one(tre_mem_t mem, int position, int code_min, int code_max,
|
||||
tre_pos_and_tags_t *new_set;
|
||||
|
||||
new_set = tre_mem_calloc(mem, sizeof(*new_set) * 2);
|
||||
if (new_set == NULL)
|
||||
return NULL;
|
||||
if (new_set == NULL) return NULL;
|
||||
|
||||
new_set[0].position = position;
|
||||
new_set[0].code_min = code_min;
|
||||
@ -1150,8 +1144,7 @@ tre_set_union(tre_mem_t mem, tre_pos_and_tags_t *set1, tre_pos_and_tags_t *set2,
|
||||
for (s1 = 0; set1[s1].position >= 0; s1++);
|
||||
for (s2 = 0; set2[s2].position >= 0; s2++);
|
||||
new_set = tre_mem_calloc(mem, sizeof(*new_set) * (s1 + s2 + 1));
|
||||
if (!new_set )
|
||||
return NULL;
|
||||
if (!new_set) return NULL;
|
||||
|
||||
for (s1 = 0; set1[s1].position >= 0; s1++)
|
||||
{
|
||||
@ -1395,15 +1388,10 @@ tre_compute_nfl(tre_mem_t mem, tre_stack_t *stack, tre_ast_node_t *tree)
|
||||
/* Back references: nullable = false, firstpos = {i},
|
||||
lastpos = {i}. */
|
||||
node->nullable = 0;
|
||||
node->firstpos = tre_set_one(mem, lit->position, 0,
|
||||
TRE_CHAR_MAX, 0, NULL, -1);
|
||||
if (!node->firstpos)
|
||||
return REG_ESPACE;
|
||||
node->lastpos = tre_set_one(mem, lit->position, 0,
|
||||
TRE_CHAR_MAX, 0, NULL,
|
||||
(int)lit->code_max);
|
||||
if (!node->lastpos)
|
||||
return REG_ESPACE;
|
||||
node->firstpos = tre_set_one(mem, lit->position, 0, TRE_CHAR_MAX, 0, NULL, -1);
|
||||
if (!node->firstpos) return REG_ESPACE;
|
||||
node->lastpos = tre_set_one(mem, lit->position, 0, TRE_CHAR_MAX, 0, NULL, (int)lit->code_max);
|
||||
if (!node->lastpos) return REG_ESPACE;
|
||||
}
|
||||
else if (lit->code_min < 0)
|
||||
{
|
||||
@ -1422,18 +1410,10 @@ tre_compute_nfl(tre_mem_t mem, tre_stack_t *stack, tre_ast_node_t *tree)
|
||||
/* Literal at position i: nullable = false, firstpos = {i},
|
||||
lastpos = {i}. */
|
||||
node->nullable = 0;
|
||||
node->firstpos =
|
||||
tre_set_one(mem, lit->position, (int)lit->code_min,
|
||||
(int)lit->code_max, 0, NULL, -1);
|
||||
if (!node->firstpos)
|
||||
return REG_ESPACE;
|
||||
node->lastpos = tre_set_one(mem, lit->position,
|
||||
(int)lit->code_min,
|
||||
(int)lit->code_max,
|
||||
lit->u.class, lit->neg_classes,
|
||||
-1);
|
||||
if (!node->lastpos)
|
||||
return REG_ESPACE;
|
||||
node->firstpos = tre_set_one(mem, lit->position, (int)lit->code_min, (int)lit->code_max, 0, NULL, -1);
|
||||
if (!node->firstpos) return REG_ESPACE;
|
||||
node->lastpos = tre_set_one(mem, lit->position, (int)lit->code_min, (int)lit->code_max, lit->u.class, lit->neg_classes, -1);
|
||||
if (!node->lastpos) return REG_ESPACE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1628,6 +1608,7 @@ tre_make_trans(qse_mmgr_t* mmgr, tre_pos_and_tags_t *p1, tre_pos_and_tags_t *p2,
|
||||
int i, j, k, l, dup, prev_p2_pos;
|
||||
|
||||
if (transitions != NULL)
|
||||
{
|
||||
while (p1->position >= 0)
|
||||
{
|
||||
p2 = orig_p2;
|
||||
@ -1814,7 +1795,9 @@ tre_make_trans(qse_mmgr_t* mmgr, tre_pos_and_tags_t *p1, tre_pos_and_tags_t *p2,
|
||||
}
|
||||
p1++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Compute a maximum limit for the number of transitions leaving
|
||||
from each state. */
|
||||
while (p1->position >= 0)
|
||||
@ -1827,6 +1810,7 @@ tre_make_trans(qse_mmgr_t* mmgr, tre_pos_and_tags_t *p1, tre_pos_and_tags_t *p2,
|
||||
}
|
||||
p1++;
|
||||
}
|
||||
}
|
||||
return REG_OK;
|
||||
}
|
||||
|
||||
|
@ -168,23 +168,18 @@ typedef struct tre_backtrack_struct
|
||||
while (/*CONSTCOND*/0)
|
||||
|
||||
#define BT_STACK_POP() \
|
||||
do \
|
||||
{ \
|
||||
do { \
|
||||
int i; \
|
||||
assert(stack->prev); \
|
||||
pos = stack->item.pos; \
|
||||
if (type == STR_USER) \
|
||||
str_source->rewind(pos + pos_add_next, str_source->context); \
|
||||
str_byte = stack->item.str_byte; \
|
||||
BT_STACK_WIDE_OUT; \
|
||||
state = stack->item.state; \
|
||||
next_c = stack->item.next_c; \
|
||||
for (i = 0; i < tnfa->num_tags; i++) \
|
||||
tags[i] = stack->item.tags[i]; \
|
||||
for (i = 0; i < tnfa->num_tags; i++) tags[i] = stack->item.tags[i]; \
|
||||
BT_STACK_MBSTATE_OUT; \
|
||||
stack = stack->prev; \
|
||||
} \
|
||||
while (/*CONSTCOND*/0)
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#undef MIN
|
||||
#define MIN(a, b) ((a) <= (b) ? (a) : (b))
|
||||
@ -208,7 +203,6 @@ tre_tnfa_run_backtrack(qse_mmgr_t* mmgr, const tre_tnfa_t *tnfa, const void *str
|
||||
int reg_notbol = eflags & REG_NOTBOL;
|
||||
int reg_noteol = eflags & REG_NOTEOL;
|
||||
int reg_newline = tnfa->cflags & REG_NEWLINE;
|
||||
int str_user_end = 0;
|
||||
|
||||
/* These are used to remember the necessary values of the above
|
||||
variables to return to the position where the current search
|
||||
@ -302,8 +296,6 @@ retry:
|
||||
|
||||
state = NULL;
|
||||
pos = pos_start;
|
||||
if (type == STR_USER)
|
||||
str_source->rewind(pos + pos_add_next, str_source->context);
|
||||
GET_NEXT_WCHAR();
|
||||
pos_start = pos;
|
||||
next_c_start = next_c;
|
||||
@ -446,15 +438,11 @@ retry:
|
||||
|
||||
if (len < 0)
|
||||
{
|
||||
if (type == STR_USER)
|
||||
result = str_source->compare((unsigned)so, (unsigned)pos,
|
||||
(unsigned)bt_len,
|
||||
str_source->context);
|
||||
#ifdef TRE_WCHAR
|
||||
else if (type == STR_WIDE)
|
||||
if (type == STR_WIDE)
|
||||
result = qse_wcszcmp((const qse_wchar_t*)string + so, str_wide - 1, (size_t)bt_len);
|
||||
#endif /* TRE_WCHAR */
|
||||
else
|
||||
#endif /* TRE_WCHAR */
|
||||
result = qse_mbszcmp((const char*)string + so, str_byte - 1, (size_t)bt_len);
|
||||
}
|
||||
else if (len - pos < bt_len)
|
||||
@ -508,12 +496,7 @@ retry:
|
||||
/* Check for end of string. */
|
||||
if (len < 0)
|
||||
{
|
||||
if (type == STR_USER)
|
||||
{
|
||||
if (str_user_end)
|
||||
goto backtrack;
|
||||
}
|
||||
else if (next_c == QSE_T('\0'))
|
||||
if (next_c == QSE_T('\0'))
|
||||
goto backtrack;
|
||||
}
|
||||
else
|
||||
@ -533,8 +516,8 @@ retry:
|
||||
trans_i->code_min, trans_i->code_max,
|
||||
trans_i->code_min, trans_i->code_max,
|
||||
trans_i->assertions, trans_i->state_id));
|
||||
if (trans_i->code_min <= (tre_cint_t)prev_c &&
|
||||
trans_i->code_max >= (tre_cint_t)prev_c)
|
||||
|
||||
if (trans_i->code_min <= (tre_cint_t)prev_c && trans_i->code_max >= (tre_cint_t)prev_c)
|
||||
{
|
||||
if (trans_i->assertions
|
||||
&& (CHECK_ASSERTIONS(trans_i->assertions)
|
||||
|
@ -325,12 +325,7 @@ tre_tnfa_run_parallel(qse_mmgr_t* mmgr, const tre_tnfa_t *tnfa, const void *stri
|
||||
/* Check for end of string. */
|
||||
if (len < 0)
|
||||
{
|
||||
if (type == STR_USER)
|
||||
{
|
||||
if (str_user_end)
|
||||
break;
|
||||
}
|
||||
else if (next_c == QSE_T('\0'))
|
||||
if (next_c == QSE_T('\0'))
|
||||
break;
|
||||
}
|
||||
else
|
||||
@ -408,28 +403,28 @@ tre_tnfa_run_parallel(qse_mmgr_t* mmgr, const tre_tnfa_t *tnfa, const void *stri
|
||||
for (trans_i = reach_i->state; trans_i->state; trans_i++)
|
||||
{
|
||||
/* Does this transition match the input symbol? */
|
||||
if (trans_i->code_min <= (tre_cint_t)prev_c &&
|
||||
trans_i->code_max >= (tre_cint_t)prev_c)
|
||||
if (trans_i->code_min <= (tre_cint_t)prev_c && trans_i->code_max >= (tre_cint_t)prev_c)
|
||||
{
|
||||
if (trans_i->assertions
|
||||
&& (CHECK_ASSERTIONS(trans_i->assertions)
|
||||
|| CHECK_CHAR_CLASSES(trans_i, tnfa, eflags)))
|
||||
if (trans_i->assertions &&
|
||||
(CHECK_ASSERTIONS(trans_i->assertions) ||
|
||||
CHECK_CHAR_CLASSES(trans_i, tnfa, eflags)))
|
||||
{
|
||||
DPRINT(("assertion failed\n"));
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Compute the tags after this transition. */
|
||||
for (i = 0; i < num_tags; i++)
|
||||
tmp_tags[i] = reach_i->tags[i];
|
||||
for (i = 0; i < num_tags; i++) tmp_tags[i] = reach_i->tags[i];
|
||||
tag_i = trans_i->tags;
|
||||
if (tag_i != NULL)
|
||||
{
|
||||
while (*tag_i >= 0)
|
||||
{
|
||||
if (*tag_i < num_tags)
|
||||
tmp_tags[*tag_i] = pos;
|
||||
tag_i++;
|
||||
}
|
||||
}
|
||||
|
||||
if (reach_pos[trans_i->state_id].pos < pos)
|
||||
{
|
||||
@ -442,15 +437,12 @@ tre_tnfa_run_parallel(qse_mmgr_t* mmgr, const tre_tnfa_t *tnfa, const void *stri
|
||||
reach_pos[trans_i->state_id].tags = &reach_next_i->tags;
|
||||
|
||||
if (reach_next_i->state == tnfa->final
|
||||
&& (match_eo == -1
|
||||
|| (num_tags > 0
|
||||
&& reach_next_i->tags[0] <= match_tags[0])))
|
||||
&& (match_eo == -1 || (num_tags > 0 && reach_next_i->tags[0] <= match_tags[0])))
|
||||
{
|
||||
DPRINT((" found match %p\n", trans_i->state));
|
||||
match_eo = pos;
|
||||
new_match = 1;
|
||||
for (i = 0; i < num_tags; i++)
|
||||
match_tags[i] = reach_next_i->tags[i];
|
||||
for (i = 0; i < num_tags; i++) match_tags[i] = reach_next_i->tags[i];
|
||||
}
|
||||
reach_next_i++;
|
||||
|
||||
|
@ -52,8 +52,6 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#define str_source ((const tre_str_source*)string)
|
||||
|
||||
#ifdef TRE_WCHAR
|
||||
|
||||
#ifdef TRE_MULTIBYTE
|
||||
@ -116,12 +114,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
else if (type == STR_USER) \
|
||||
{ \
|
||||
pos += pos_add_next; \
|
||||
str_user_end = str_source->get_next_char(&next_c, &pos_add_next, \
|
||||
str_source->context); \
|
||||
} \
|
||||
} while(/*CONSTCOND*/0)
|
||||
|
||||
#else /* !TRE_MULTIBYTE */
|
||||
@ -143,11 +135,6 @@ do { \
|
||||
if (len >= 0 && pos >= len) next_c = QSE_T('\0'); \
|
||||
else next_c = *str_wide++; \
|
||||
} \
|
||||
else if (type == STR_USER) \
|
||||
{ \
|
||||
pos += pos_add_next; \
|
||||
str_user_end = str_source->get_next_char(&next_c, &pos_add_next, str_source->context); \
|
||||
} \
|
||||
} while(/*CONSTCOND*/0)
|
||||
|
||||
#endif /* !TRE_MULTIBYTE */
|
||||
@ -162,16 +149,8 @@ do { \
|
||||
if (type == STR_BYTE) \
|
||||
{ \
|
||||
pos++; \
|
||||
if (len >= 0 && pos >= len) \
|
||||
next_c = '\0'; \
|
||||
else \
|
||||
next_c = (unsigned char)(*str_byte++); \
|
||||
} \
|
||||
else if (type == STR_USER) \
|
||||
{ \
|
||||
pos += pos_add_next; \
|
||||
str_user_end = str_source->get_next_char(&next_c, &pos_add_next, \
|
||||
str_source->context); \
|
||||
if (len >= 0 && pos >= len) next_c = '\0'; \
|
||||
else next_c = (unsigned char)(*str_byte++); \
|
||||
} \
|
||||
} while(/*CONSTCOND*/0)
|
||||
|
||||
|
@ -138,8 +138,7 @@ tre_expand_macro(const tre_char_t *regex, const tre_char_t *regex_end,
|
||||
}
|
||||
|
||||
static reg_errcode_t
|
||||
tre_new_item(tre_mem_t mem, int min, int max, int *i, int *max_i,
|
||||
tre_ast_node_t ***items)
|
||||
tre_new_item(tre_mem_t mem, int min, int max, int *i, int *max_i, tre_ast_node_t ***items)
|
||||
{
|
||||
reg_errcode_t status;
|
||||
tre_ast_node_t **array = *items;
|
||||
@ -306,8 +305,7 @@ tre_parse_bracket_items(tre_parse_ctx_t *ctx, int negate,
|
||||
/* END QSE */
|
||||
if (status == REG_OK)
|
||||
{
|
||||
status = tre_expand_ctype(ctx->mem, class, items,
|
||||
&i, &max_i, ctx->cflags);
|
||||
status = tre_expand_ctype(ctx->mem, class, items, &i, &max_i, ctx->cflags);
|
||||
class = (tre_ctype_t)0;
|
||||
skip = 1;
|
||||
}
|
||||
@ -328,25 +326,25 @@ tre_parse_bracket_items(tre_parse_ctx_t *ctx, int negate,
|
||||
min = max = *re++;
|
||||
}
|
||||
|
||||
if (status != REG_OK)
|
||||
break;
|
||||
if (status != REG_OK) break;
|
||||
|
||||
if (class && negate)
|
||||
{
|
||||
if (*num_neg_classes >= MAX_NEG_CLASSES)
|
||||
status = REG_ESPACE;
|
||||
else
|
||||
neg_classes[(*num_neg_classes)++] = class;
|
||||
}
|
||||
else if (!skip)
|
||||
{
|
||||
status = tre_new_item(ctx->mem, min, max, &i, &max_i, items);
|
||||
if (status != REG_OK)
|
||||
break;
|
||||
if (status != REG_OK) break;
|
||||
((tre_literal_t*)((*items)[i-1])->obj)->u.class = class;
|
||||
}
|
||||
|
||||
/* Add opposite-case counterpoints if REG_ICASE is present.
|
||||
This is broken if there are more than two "same" characters. */
|
||||
if (ctx->cflags & REG_ICASE && !class && status == REG_OK && !skip)
|
||||
if ((ctx->cflags & REG_ICASE) && !class && status == REG_OK && !skip)
|
||||
{
|
||||
tre_cint_t cmin, ccurr;
|
||||
|
||||
@ -356,27 +354,21 @@ tre_parse_bracket_items(tre_parse_ctx_t *ctx, int negate,
|
||||
if (tre_islower(min))
|
||||
{
|
||||
cmin = ccurr = tre_toupper(min++);
|
||||
while (tre_islower(min) && tre_toupper(min) == ccurr + 1
|
||||
&& min <= max)
|
||||
while (tre_islower(min) && tre_toupper(min) == ccurr + 1 && min <= max)
|
||||
ccurr = tre_toupper(min++);
|
||||
status = tre_new_item(ctx->mem, cmin, ccurr,
|
||||
&i, &max_i, items);
|
||||
status = tre_new_item(ctx->mem, cmin, ccurr, &i, &max_i, items);
|
||||
}
|
||||
else if (tre_isupper(min))
|
||||
{
|
||||
cmin = ccurr = tre_tolower(min++);
|
||||
while (tre_isupper(min) && tre_tolower(min) == ccurr + 1
|
||||
&& min <= max)
|
||||
while (tre_isupper(min) && tre_tolower(min) == ccurr + 1 && min <= max)
|
||||
ccurr = tre_tolower(min++);
|
||||
status = tre_new_item(ctx->mem, cmin, ccurr,
|
||||
&i, &max_i, items);
|
||||
status = tre_new_item(ctx->mem, cmin, ccurr, &i, &max_i, items);
|
||||
}
|
||||
else min++;
|
||||
if (status != REG_OK)
|
||||
break;
|
||||
if (status != REG_OK) break;
|
||||
}
|
||||
if (status != REG_OK)
|
||||
break;
|
||||
if (status != REG_OK) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -399,8 +391,7 @@ tre_parse_bracket(tre_parse_ctx_t *ctx, tre_ast_node_t **result)
|
||||
|
||||
/* Start off with an array of `max_i' elements. */
|
||||
items = xmalloc(ctx->mem->mmgr, sizeof(*items) * max_i);
|
||||
if (items == NULL)
|
||||
return REG_ESPACE;
|
||||
if (items == NULL) return REG_ESPACE;
|
||||
|
||||
if (*ctx->re == CHAR_CARET)
|
||||
{
|
||||
@ -409,15 +400,11 @@ tre_parse_bracket(tre_parse_ctx_t *ctx, tre_ast_node_t **result)
|
||||
ctx->re++;
|
||||
}
|
||||
|
||||
status = tre_parse_bracket_items(ctx, negate, neg_classes, &num_neg_classes,
|
||||
&items, &i, &max_i);
|
||||
|
||||
if (status != REG_OK)
|
||||
goto parse_bracket_done;
|
||||
status = tre_parse_bracket_items(ctx, negate, neg_classes, &num_neg_classes, &items, &i, &max_i);
|
||||
if (status != REG_OK) goto parse_bracket_done;
|
||||
|
||||
/* Sort the array if we need to negate it. */
|
||||
if (negate)
|
||||
qse_qsort(items, (unsigned)i, sizeof(*items), tre_compare_items, QSE_NULL);
|
||||
if (negate) qse_qsort(items, (unsigned)i, sizeof(*items), tre_compare_items, QSE_NULL);
|
||||
|
||||
curr_max = curr_min = 0;
|
||||
/* Build a union of the items in the array, negated if necessary. */
|
||||
@ -466,22 +453,23 @@ tre_parse_bracket(tre_parse_ctx_t *ctx, tre_ast_node_t **result)
|
||||
l->position = ctx->position;
|
||||
if (num_neg_classes > 0)
|
||||
{
|
||||
l->neg_classes = tre_mem_alloc(ctx->mem,
|
||||
(sizeof(l->neg_classes)
|
||||
* (num_neg_classes + 1)));
|
||||
l->neg_classes = tre_mem_alloc(ctx->mem, (sizeof(l->neg_classes) * (num_neg_classes + 1)));
|
||||
if (l->neg_classes == NULL)
|
||||
{
|
||||
status = REG_ESPACE;
|
||||
break;
|
||||
}
|
||||
for (k = 0; k < num_neg_classes; k++)
|
||||
l->neg_classes[k] = neg_classes[k];
|
||||
for (k = 0; k < num_neg_classes; k++) l->neg_classes[k] = neg_classes[k];
|
||||
l->neg_classes[k] = (tre_ctype_t)0;
|
||||
}
|
||||
else
|
||||
{
|
||||
l->neg_classes = NULL;
|
||||
}
|
||||
if (node == NULL)
|
||||
{
|
||||
node = items[j];
|
||||
}
|
||||
else
|
||||
{
|
||||
u = tre_ast_new_union(ctx->mem, node, items[j]);
|
||||
@ -492,8 +480,7 @@ tre_parse_bracket(tre_parse_ctx_t *ctx, tre_ast_node_t **result)
|
||||
}
|
||||
}
|
||||
|
||||
if (status != REG_OK)
|
||||
goto parse_bracket_done;
|
||||
if (status != REG_OK) goto parse_bracket_done;
|
||||
|
||||
if (negate)
|
||||
{
|
||||
@ -501,7 +488,9 @@ tre_parse_bracket(tre_parse_ctx_t *ctx, tre_ast_node_t **result)
|
||||
DPRINT(("final: creating %d - %d\n", curr_min, (int)TRE_CHAR_MAX));
|
||||
n = tre_ast_new_literal(ctx->mem, curr_min, TRE_CHAR_MAX, ctx->position);
|
||||
if (n == NULL)
|
||||
{
|
||||
status = REG_ESPACE;
|
||||
}
|
||||
else
|
||||
{
|
||||
tre_literal_t *l = n->obj;
|
||||
@ -520,21 +509,23 @@ tre_parse_bracket(tre_parse_ctx_t *ctx, tre_ast_node_t **result)
|
||||
l->neg_classes[k] = (tre_ctype_t)0;
|
||||
}
|
||||
else
|
||||
{
|
||||
l->neg_classes = NULL;
|
||||
}
|
||||
if (node == NULL)
|
||||
{
|
||||
node = n;
|
||||
}
|
||||
else
|
||||
{
|
||||
u = tre_ast_new_union(ctx->mem, node, n);
|
||||
if (u == NULL)
|
||||
status = REG_ESPACE;
|
||||
if (u == NULL) status = REG_ESPACE;
|
||||
node = u;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (status != REG_OK)
|
||||
goto parse_bracket_done;
|
||||
if (status != REG_OK) goto parse_bracket_done;
|
||||
|
||||
#ifdef TRE_DEBUG
|
||||
tre_ast_print(node);
|
||||
@ -814,8 +805,7 @@ tre_parse_bound(tre_parse_ctx_t *ctx, tre_ast_node_t **result)
|
||||
if (min == 0 && max == 0)
|
||||
{
|
||||
*result = tre_ast_new_literal(ctx->mem, EMPTY, -1, -1);
|
||||
if (*result == NULL)
|
||||
return REG_ESPACE;
|
||||
if (*result == NULL) return REG_ESPACE;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -909,9 +899,7 @@ typedef enum
|
||||
PARSE_RESTORE_CFLAGS
|
||||
} tre_parse_re_stack_symbol_t;
|
||||
|
||||
|
||||
reg_errcode_t
|
||||
tre_parse(tre_parse_ctx_t *ctx)
|
||||
reg_errcode_t tre_parse(tre_parse_ctx_t *ctx)
|
||||
{
|
||||
tre_ast_node_t *result = NULL;
|
||||
tre_parse_re_stack_symbol_t symbol;
|
||||
@ -941,8 +929,8 @@ tre_parse(tre_parse_ctx_t *ctx)
|
||||
call stack, and efficiency (both in lines of code and speed). */
|
||||
while (tre_stack_num_objects(stack) > bottom && status == REG_OK)
|
||||
{
|
||||
if (status != REG_OK)
|
||||
break;
|
||||
if (status != REG_OK) break;
|
||||
|
||||
symbol = tre_stack_pop_int(stack);
|
||||
switch (symbol)
|
||||
{
|
||||
@ -978,8 +966,8 @@ tre_parse(tre_parse_ctx_t *ctx)
|
||||
/* If the expression has not ended, parse another piece. */
|
||||
{
|
||||
tre_char_t c;
|
||||
if (ctx->re >= ctx->re_end)
|
||||
break;
|
||||
|
||||
if (ctx->re >= ctx->re_end) break;
|
||||
c = *ctx->re;
|
||||
#ifdef REG_LITERAL
|
||||
if (!(ctx->cflags & REG_LITERAL))
|
||||
@ -1039,12 +1027,10 @@ tre_parse(tre_parse_ctx_t *ctx)
|
||||
}
|
||||
|
||||
case PARSE_UNION:
|
||||
if (ctx->re >= ctx->re_end)
|
||||
break;
|
||||
#ifdef REG_LITERAL
|
||||
if (ctx->cflags & REG_LITERAL)
|
||||
break;
|
||||
#endif /* REG_LITERAL */
|
||||
if (ctx->re >= ctx->re_end) break;
|
||||
#ifdef REG_LITERAL
|
||||
if (ctx->cflags & REG_LITERAL) break;
|
||||
#endif /* REG_LITERAL */
|
||||
switch (*ctx->re)
|
||||
{
|
||||
case CHAR_PIPE:
|
||||
@ -1081,37 +1067,36 @@ tre_parse(tre_parse_ctx_t *ctx)
|
||||
/* Parse postfix operators. */
|
||||
if (ctx->re >= ctx->re_end)
|
||||
break;
|
||||
#ifdef REG_LITERAL
|
||||
#ifdef REG_LITERAL
|
||||
if (ctx->cflags & REG_LITERAL)
|
||||
break;
|
||||
#endif /* REG_LITERAL */
|
||||
#endif /* REG_LITERAL */
|
||||
switch (*ctx->re)
|
||||
{
|
||||
case CHAR_PLUS:
|
||||
case CHAR_QUESTIONMARK:
|
||||
if (!(ctx->cflags & REG_EXTENDED))
|
||||
break;
|
||||
if (!(ctx->cflags & REG_EXTENDED)) break;
|
||||
/*FALLTHROUGH*/
|
||||
case CHAR_STAR:
|
||||
/* QSE - added this label */
|
||||
parse_star:
|
||||
/* END QSE */
|
||||
/* QSE - added this label */
|
||||
parse_star:
|
||||
/* END QSE */
|
||||
{
|
||||
tre_ast_node_t *tmp_node;
|
||||
int minimal = (ctx->cflags & REG_UNGREEDY) ? 1 : 0;
|
||||
int rep_min = 0;
|
||||
int rep_max = -1;
|
||||
#ifdef TRE_DEBUG
|
||||
#ifdef TRE_DEBUG
|
||||
const tre_char_t *tmp_re;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (*ctx->re == CHAR_PLUS) /* QSE: case CHAR_PLUS fell through down here */
|
||||
rep_min = 1;
|
||||
if (*ctx->re == CHAR_QUESTIONMARK) /* QSE: case CHAR_QUESTIONMARK fell though down here */
|
||||
rep_max = 1;
|
||||
#ifdef TRE_DEBUG
|
||||
#ifdef TRE_DEBUG
|
||||
tmp_re = ctx->re;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (ctx->re + 1 < ctx->re_end)
|
||||
{
|
||||
@ -1120,18 +1105,18 @@ parse_star:
|
||||
minimal = !(ctx->cflags & REG_UNGREEDY);
|
||||
ctx->re++;
|
||||
}
|
||||
/* QSE - TRE has provisions for ** or *+ as a special repetition operator.
|
||||
/* QSE - TRE has provisions for ** or *+ as a special repetition operator.
|
||||
* however, that seems to break backward compatibility.
|
||||
* '+' in 'a*+' is not treated as a normal character with the
|
||||
* following block enabled. So let me comment it out */
|
||||
#if 0
|
||||
#if 0
|
||||
else if (*(ctx->re + 1) == CHAR_STAR
|
||||
|| *(ctx->re + 1) == CHAR_PLUS)
|
||||
{
|
||||
/* These are reserved for future extensions. */
|
||||
return REG_BADRPT;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
DPRINT(("tre_parse: %s star: '%.*" STRF "'\n",
|
||||
@ -1143,8 +1128,9 @@ parse_star:
|
||||
return REG_ESPACE;
|
||||
result = tmp_node;
|
||||
STACK_PUSHX(stack, int, PARSE_POSTFIX);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case CHAR_BACKSLASH:
|
||||
/* "\{" is special without REG_EXTENDED */
|
||||
@ -1185,7 +1171,7 @@ parse_star:
|
||||
if (ctx->cflags & REG_NOBOUND) break;
|
||||
/* END QSE */
|
||||
|
||||
parse_brace:
|
||||
parse_brace:
|
||||
DPRINT(("tre_parse: bound: '%.*" STRF "'\n",
|
||||
REST(ctx->re)));
|
||||
ctx->re++;
|
||||
@ -1200,18 +1186,17 @@ parse_brace:
|
||||
break;
|
||||
|
||||
case PARSE_ATOM:
|
||||
|
||||
/* Parse an atom. An atom is a regular expression enclosed in `()',
|
||||
an empty set of `()', a bracket expression, `.', `^', `$',
|
||||
a `\' followed by a character, or a single character. */
|
||||
|
||||
/* End of regexp? (empty string). */
|
||||
if (ctx->re >= ctx->re_end)
|
||||
goto parse_literal;
|
||||
if (ctx->re >= ctx->re_end) goto parse_literal;
|
||||
|
||||
#ifdef REG_LITERAL
|
||||
if (ctx->cflags & REG_LITERAL)
|
||||
goto parse_literal;
|
||||
#endif /* REG_LITERAL */
|
||||
#ifdef REG_LITERAL
|
||||
if (ctx->cflags & REG_LITERAL) goto parse_literal;
|
||||
#endif /* REG_LITERAL */
|
||||
|
||||
switch (*ctx->re)
|
||||
{
|
||||
@ -1226,15 +1211,13 @@ parse_brace:
|
||||
{
|
||||
int new_cflags = ctx->cflags;
|
||||
int bit = 1;
|
||||
DPRINT(("tre_parse: extension: '%.*" STRF "\n",
|
||||
REST(ctx->re)));
|
||||
DPRINT(("tre_parse: extension: '%.*" STRF "\n", REST(ctx->re)));
|
||||
ctx->re += 2;
|
||||
while (/*CONSTCOND*/1)
|
||||
{
|
||||
if (*ctx->re == QSE_T('i'))
|
||||
{
|
||||
DPRINT(("tre_parse: icase: '%.*" STRF "\n",
|
||||
REST(ctx->re)));
|
||||
DPRINT(("tre_parse: icase: '%.*" STRF "\n", REST(ctx->re)));
|
||||
if (bit)
|
||||
new_cflags |= REG_ICASE;
|
||||
else
|
||||
@ -1243,38 +1226,35 @@ parse_brace:
|
||||
}
|
||||
else if (*ctx->re == QSE_T('n'))
|
||||
{
|
||||
DPRINT(("tre_parse: newline: '%.*" STRF "\n",
|
||||
REST(ctx->re)));
|
||||
DPRINT(("tre_parse: newline: '%.*" STRF "\n", REST(ctx->re)));
|
||||
if (bit)
|
||||
new_cflags |= REG_NEWLINE;
|
||||
else
|
||||
new_cflags &= ~REG_NEWLINE;
|
||||
ctx->re++;
|
||||
}
|
||||
#ifdef REG_RIGHT_ASSOC
|
||||
#ifdef REG_RIGHT_ASSOC
|
||||
else if (*ctx->re == QSE_T('r'))
|
||||
{
|
||||
DPRINT(("tre_parse: right assoc: '%.*" STRF "\n",
|
||||
REST(ctx->re)));
|
||||
DPRINT(("tre_parse: right assoc: '%.*" STRF "\n", REST(ctx->re)));
|
||||
if (bit)
|
||||
new_cflags |= REG_RIGHT_ASSOC;
|
||||
else
|
||||
new_cflags &= ~REG_RIGHT_ASSOC;
|
||||
ctx->re++;
|
||||
}
|
||||
#endif /* REG_RIGHT_ASSOC */
|
||||
#ifdef REG_UNGREEDY
|
||||
#endif /* REG_RIGHT_ASSOC */
|
||||
#ifdef REG_UNGREEDY
|
||||
else if (*ctx->re == QSE_T('U'))
|
||||
{
|
||||
DPRINT(("tre_parse: ungreedy: '%.*" STRF "\n",
|
||||
REST(ctx->re)));
|
||||
DPRINT(("tre_parse: ungreedy: '%.*" STRF "\n", REST(ctx->re)));
|
||||
if (bit)
|
||||
new_cflags |= REG_UNGREEDY;
|
||||
else
|
||||
new_cflags &= ~REG_UNGREEDY;
|
||||
ctx->re++;
|
||||
}
|
||||
#endif /* REG_UNGREEDY */
|
||||
#endif /* REG_UNGREEDY */
|
||||
else if (*ctx->re == CHAR_MINUS)
|
||||
{
|
||||
DPRINT(("tre_parse: turn off: '%.*" STRF "\n",
|
||||
@ -1366,29 +1346,24 @@ parse_brace:
|
||||
|| (ctx->re > ctx->re_start
|
||||
&& *(ctx->re - 1) == CHAR_BACKSLASH))
|
||||
{
|
||||
DPRINT(("tre_parse: empty: '%.*" STRF "'\n",
|
||||
REST(ctx->re)));
|
||||
DPRINT(("tre_parse: empty: '%.*" STRF "'\n", REST(ctx->re)));
|
||||
/* We were expecting an atom, but instead the current
|
||||
subexpression was closed. POSIX leaves the meaning of
|
||||
this to be implementation-defined. We interpret this as
|
||||
an empty expression (which matches an empty string). */
|
||||
result = tre_ast_new_literal(ctx->mem, EMPTY, -1, -1);
|
||||
if (result == NULL)
|
||||
return REG_ESPACE;
|
||||
if (!(ctx->cflags & REG_EXTENDED))
|
||||
ctx->re--;
|
||||
if (result == NULL) return REG_ESPACE;
|
||||
if (!(ctx->cflags & REG_EXTENDED)) ctx->re--;
|
||||
}
|
||||
else
|
||||
goto parse_literal;
|
||||
break;
|
||||
|
||||
case CHAR_LBRACKET: /* bracket expression */
|
||||
DPRINT(("tre_parse: bracket: '%.*" STRF "'\n",
|
||||
REST(ctx->re)));
|
||||
DPRINT(("tre_parse: bracket: '%.*" STRF "'\n", REST(ctx->re)));
|
||||
ctx->re++;
|
||||
status = tre_parse_bracket(ctx, &result);
|
||||
if (status != REG_OK)
|
||||
return status;
|
||||
if (status != REG_OK) return status;
|
||||
break;
|
||||
|
||||
case CHAR_BACKSLASH:
|
||||
@ -1407,8 +1382,7 @@ parse_brace:
|
||||
/* If a macro is used, parse the expanded macro recursively. */
|
||||
{
|
||||
tre_char_t buf[64];
|
||||
tre_expand_macro(ctx->re + 1, ctx->re_end,
|
||||
buf, QSE_COUNTOF(buf));
|
||||
tre_expand_macro(ctx->re + 1, ctx->re_end, buf, QSE_COUNTOF(buf));
|
||||
if (buf[0] != 0)
|
||||
{
|
||||
tre_parse_ctx_t subctx;
|
||||
@ -1426,10 +1400,12 @@ parse_brace:
|
||||
}
|
||||
|
||||
if (ctx->re + 1 >= ctx->re_end)
|
||||
{
|
||||
/* Trailing backslash. */
|
||||
return REG_EESCAPE;
|
||||
}
|
||||
|
||||
#ifdef REG_LITERAL
|
||||
#ifdef REG_LITERAL
|
||||
if (*(ctx->re + 1) == QSE_T('Q'))
|
||||
{
|
||||
DPRINT(("tre_parse: tmp literal: '%.*" STRF "'\n",
|
||||
@ -1440,30 +1416,26 @@ parse_brace:
|
||||
STACK_PUSHX(stack, int, PARSE_ATOM);
|
||||
break;
|
||||
}
|
||||
#endif /* REG_LITERAL */
|
||||
#endif /* REG_LITERAL */
|
||||
|
||||
DPRINT(("tre_parse: bleep: '%.*" STRF "'\n", REST(ctx->re)));
|
||||
ctx->re++;
|
||||
switch (*ctx->re)
|
||||
{
|
||||
case QSE_T('b'):
|
||||
result = tre_ast_new_literal(ctx->mem, ASSERTION,
|
||||
ASSERT_AT_WB, -1);
|
||||
result = tre_ast_new_literal(ctx->mem, ASSERTION, ASSERT_AT_WB, -1);
|
||||
ctx->re++;
|
||||
break;
|
||||
case QSE_T('B'):
|
||||
result = tre_ast_new_literal(ctx->mem, ASSERTION,
|
||||
ASSERT_AT_WB_NEG, -1);
|
||||
result = tre_ast_new_literal(ctx->mem, ASSERTION, ASSERT_AT_WB_NEG, -1);
|
||||
ctx->re++;
|
||||
break;
|
||||
case QSE_T('<'):
|
||||
result = tre_ast_new_literal(ctx->mem, ASSERTION,
|
||||
ASSERT_AT_BOW, -1);
|
||||
result = tre_ast_new_literal(ctx->mem, ASSERTION, ASSERT_AT_BOW, -1);
|
||||
ctx->re++;
|
||||
break;
|
||||
case QSE_T('>'):
|
||||
result = tre_ast_new_literal(ctx->mem, ASSERTION,
|
||||
ASSERT_AT_EOW, -1);
|
||||
result = tre_ast_new_literal(ctx->mem, ASSERTION, ASSERT_AT_EOW, -1);
|
||||
ctx->re++;
|
||||
break;
|
||||
case QSE_T('x'):
|
||||
@ -1503,8 +1475,7 @@ parse_brace:
|
||||
ctx->re++;
|
||||
}
|
||||
|
||||
result = tre_ast_new_literal(ctx->mem, (int)val,
|
||||
(int)val, ctx->position);
|
||||
result = tre_ast_new_literal(ctx->mem, (int)val, (int)val, ctx->position);
|
||||
ctx->position++;
|
||||
break;
|
||||
}
|
||||
@ -1552,8 +1523,7 @@ parse_brace:
|
||||
return REG_EBRACE;
|
||||
}
|
||||
|
||||
result = tre_ast_new_literal(ctx->mem, (int)val, (int)val,
|
||||
ctx->position);
|
||||
result = tre_ast_new_literal(ctx->mem, (int)val, (int)val, ctx->position);
|
||||
ctx->position++;
|
||||
break;
|
||||
}
|
||||
@ -1564,12 +1534,9 @@ parse_brace:
|
||||
{
|
||||
/* Back reference. */
|
||||
int val = *ctx->re - QSE_T('0');
|
||||
DPRINT(("tre_parse: backref: '%.*" STRF "'\n",
|
||||
REST(ctx->re - 1)));
|
||||
result = tre_ast_new_literal(ctx->mem, BACKREF, val,
|
||||
ctx->position);
|
||||
if (result == NULL)
|
||||
return REG_ESPACE;
|
||||
DPRINT(("tre_parse: backref: '%.*" STRF "'\n", REST(ctx->re - 1)));
|
||||
result = tre_ast_new_literal(ctx->mem, BACKREF, val, ctx->position);
|
||||
if (result == NULL) return REG_ESPACE;
|
||||
ctx->position++;
|
||||
ctx->max_backref = MAX(val, ctx->max_backref);
|
||||
ctx->re++;
|
||||
@ -1577,8 +1544,7 @@ parse_brace:
|
||||
else
|
||||
{
|
||||
/* Escaped character. */
|
||||
DPRINT(("tre_parse: escaped: '%.*" STRF "'\n",
|
||||
REST(ctx->re - 1)));
|
||||
DPRINT(("tre_parse: escaped: '%.*" STRF "'\n", REST(ctx->re - 1)));
|
||||
result = tre_ast_new_literal(ctx->mem, *ctx->re, *ctx->re, ctx->position);
|
||||
ctx->position++;
|
||||
ctx->re++;
|
||||
@ -1596,25 +1562,20 @@ parse_brace:
|
||||
{
|
||||
tre_ast_node_t *tmp1;
|
||||
tre_ast_node_t *tmp2;
|
||||
tmp1 = tre_ast_new_literal(ctx->mem, 0, QSE_T('\n') - 1,
|
||||
ctx->position);
|
||||
if (!tmp1)
|
||||
return REG_ESPACE;
|
||||
tmp2 = tre_ast_new_literal(ctx->mem, QSE_T('\n') + 1, TRE_CHAR_MAX,
|
||||
ctx->position + 1);
|
||||
if (!tmp2)
|
||||
return REG_ESPACE;
|
||||
/* exclude new line */
|
||||
tmp1 = tre_ast_new_literal(ctx->mem, 0, QSE_T('\n') - 1, ctx->position);
|
||||
if (!tmp1) return REG_ESPACE;
|
||||
tmp2 = tre_ast_new_literal(ctx->mem, QSE_T('\n') + 1, TRE_CHAR_MAX, ctx->position + 1);
|
||||
if (!tmp2) return REG_ESPACE;
|
||||
result = tre_ast_new_union(ctx->mem, tmp1, tmp2);
|
||||
if (!result)
|
||||
return REG_ESPACE;
|
||||
if (!result) return REG_ESPACE;
|
||||
ctx->position += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = tre_ast_new_literal(ctx->mem, 0, TRE_CHAR_MAX,
|
||||
ctx->position);
|
||||
if (!result)
|
||||
return REG_ESPACE;
|
||||
/* all characters */
|
||||
result = tre_ast_new_literal(ctx->mem, 0, TRE_CHAR_MAX, ctx->position);
|
||||
if (!result) return REG_ESPACE;
|
||||
ctx->position++;
|
||||
}
|
||||
ctx->re++;
|
||||
@ -1631,10 +1592,8 @@ parse_brace:
|
||||
{
|
||||
DPRINT(("tre_parse: BOL: '%.*" STRF "'\n",
|
||||
REST(ctx->re)));
|
||||
result = tre_ast_new_literal(ctx->mem, ASSERTION,
|
||||
ASSERT_AT_BOL, -1);
|
||||
if (result == NULL)
|
||||
return REG_ESPACE;
|
||||
result = tre_ast_new_literal(ctx->mem, ASSERTION, ASSERT_AT_BOL, -1);
|
||||
if (result == NULL) return REG_ESPACE;
|
||||
ctx->re++;
|
||||
}
|
||||
else
|
||||
@ -1652,8 +1611,7 @@ parse_brace:
|
||||
{
|
||||
DPRINT(("tre_parse: EOL: '%.*" STRF "'\n",
|
||||
REST(ctx->re)));
|
||||
result = tre_ast_new_literal(ctx->mem, ASSERTION,
|
||||
ASSERT_AT_EOL, -1);
|
||||
result = tre_ast_new_literal(ctx->mem, ASSERTION, ASSERT_AT_EOL, -1);
|
||||
if (result == NULL)
|
||||
return REG_ESPACE;
|
||||
ctx->re++;
|
||||
@ -1663,13 +1621,12 @@ parse_brace:
|
||||
break;
|
||||
|
||||
default:
|
||||
parse_literal:
|
||||
parse_literal:
|
||||
|
||||
if (temporary_cflags && ctx->re + 1 < ctx->re_end
|
||||
&& *ctx->re == CHAR_BACKSLASH && *(ctx->re + 1) == QSE_T('E'))
|
||||
{
|
||||
DPRINT(("tre_parse: end tmps: '%.*" STRF "'\n",
|
||||
REST(ctx->re)));
|
||||
DPRINT(("tre_parse: end tmps: '%.*" STRF "'\n", REST(ctx->re)));
|
||||
ctx->cflags &= ~temporary_cflags;
|
||||
temporary_cflags = 0;
|
||||
ctx->re += 2;
|
||||
@ -1682,9 +1639,9 @@ parse_literal:
|
||||
regexp ends here, we interpret it as an empty expression
|
||||
(which matches an empty string). */
|
||||
if (
|
||||
#ifdef REG_LITERAL
|
||||
#ifdef REG_LITERAL
|
||||
!(ctx->cflags & REG_LITERAL) &&
|
||||
#endif /* REG_LITERAL */
|
||||
#endif /* REG_LITERAL */
|
||||
(ctx->re >= ctx->re_end
|
||||
|| *ctx->re == CHAR_STAR
|
||||
|| (ctx->cflags & REG_EXTENDED
|
||||
@ -1701,11 +1658,9 @@ parse_literal:
|
||||
&& *ctx->re == CHAR_BACKSLASH
|
||||
&& *(ctx->re + 1) == CHAR_LBRACE)))
|
||||
{
|
||||
DPRINT(("tre_parse: empty: '%.*" STRF "'\n",
|
||||
REST(ctx->re)));
|
||||
DPRINT(("tre_parse: empty: '%.*" STRF "'\n", REST(ctx->re)));
|
||||
result = tre_ast_new_literal(ctx->mem, EMPTY, -1, -1);
|
||||
if (!result)
|
||||
return REG_ESPACE;
|
||||
if (!result) return REG_ESPACE;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1714,8 +1669,7 @@ parse_literal:
|
||||
/* Note that we can't use an tre_isalpha() test here, since there
|
||||
may be characters which are alphabetic but neither upper or
|
||||
lower case. */
|
||||
if (ctx->cflags & REG_ICASE
|
||||
&& (tre_isupper(*ctx->re) || tre_islower(*ctx->re)))
|
||||
if (ctx->cflags & REG_ICASE && (tre_isupper(*ctx->re) || tre_islower(*ctx->re)))
|
||||
{
|
||||
tre_ast_node_t *tmp1;
|
||||
tre_ast_node_t *tmp2;
|
||||
@ -1728,26 +1682,17 @@ parse_literal:
|
||||
that at least for multi-character collating elements there
|
||||
could be several opposite-case counterpoints, but they
|
||||
cannot be supported portably anyway. */
|
||||
tmp1 = tre_ast_new_literal(ctx->mem, tre_toupper(*ctx->re),
|
||||
tre_toupper(*ctx->re),
|
||||
ctx->position);
|
||||
if (!tmp1)
|
||||
return REG_ESPACE;
|
||||
tmp2 = tre_ast_new_literal(ctx->mem, tre_tolower(*ctx->re),
|
||||
tre_tolower(*ctx->re),
|
||||
ctx->position);
|
||||
if (!tmp2)
|
||||
return REG_ESPACE;
|
||||
tmp1 = tre_ast_new_literal(ctx->mem, tre_toupper(*ctx->re), tre_toupper(*ctx->re), ctx->position);
|
||||
if (!tmp1) return REG_ESPACE;
|
||||
tmp2 = tre_ast_new_literal(ctx->mem, tre_tolower(*ctx->re), tre_tolower(*ctx->re), ctx->position);
|
||||
if (!tmp2) return REG_ESPACE;
|
||||
result = tre_ast_new_union(ctx->mem, tmp1, tmp2);
|
||||
if (!result)
|
||||
return REG_ESPACE;
|
||||
if (!result) return REG_ESPACE;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = tre_ast_new_literal(ctx->mem, *ctx->re, *ctx->re,
|
||||
ctx->position);
|
||||
if (!result)
|
||||
return REG_ESPACE;
|
||||
result = tre_ast_new_literal(ctx->mem, *ctx->re, *ctx->re, ctx->position);
|
||||
if (!result) return REG_ESPACE;
|
||||
}
|
||||
ctx->position++;
|
||||
ctx->re++;
|
||||
@ -1763,11 +1708,9 @@ parse_literal:
|
||||
{
|
||||
tre_ast_node_t *n, *tmp_node;
|
||||
n = tre_ast_new_literal(ctx->mem, EMPTY, -1, -1);
|
||||
if (n == NULL)
|
||||
return REG_ESPACE;
|
||||
if (n == NULL) return REG_ESPACE;
|
||||
tmp_node = tre_ast_new_catenation(ctx->mem, n, result);
|
||||
if (tmp_node == NULL)
|
||||
return REG_ESPACE;
|
||||
if (tmp_node == NULL) return REG_ESPACE;
|
||||
tmp_node->num_submatches = result->num_submatches;
|
||||
result = tmp_node;
|
||||
}
|
||||
@ -1784,16 +1727,16 @@ parse_literal:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for missing closing parentheses. */
|
||||
if (depth > 0)
|
||||
/* Check for missing closing parentheses. */
|
||||
if (depth > 0)
|
||||
return REG_EPAREN;
|
||||
|
||||
if (status == REG_OK)
|
||||
if (status == REG_OK)
|
||||
ctx->result = result;
|
||||
|
||||
return status;
|
||||
return status;
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
|
@ -205,15 +205,6 @@ static int tre_match(
|
||||
if (tnfa->have_backrefs || (eflags & REG_BACKTRACKING_MATCHER))
|
||||
{
|
||||
/* The regex has back references, use the backtracking matcher. */
|
||||
if (type == STR_USER)
|
||||
{
|
||||
const tre_str_source *source = string;
|
||||
if (source->rewind == QSE_NULL || source->compare == QSE_NULL)
|
||||
/* The backtracking matcher requires rewind and compare
|
||||
capabilities from the input stream. */
|
||||
return REG_BADPAT;
|
||||
}
|
||||
|
||||
status = tre_tnfa_run_backtrack (
|
||||
preg->mmgr, tnfa, string, (int)len, type,
|
||||
tags, eflags, &eo);
|
||||
@ -266,15 +257,6 @@ int qse_tre_exec (
|
||||
return qse_tre_execx (tre, str, (qse_size_t)-1, pmatch, nmatch, eflags);
|
||||
}
|
||||
|
||||
#if 0
|
||||
int qse_tre_execsrc (
|
||||
const regex_t *preg, const tre_str_source *str,
|
||||
qse_size_t nmatch, regmatch_t pmatch[], int eflags)
|
||||
{
|
||||
return tre_match (preg, str, (unsigned)-1, STR_USER, nmatch, pmatch, eflags);
|
||||
}
|
||||
#endif
|
||||
|
||||
qse_tre_errnum_t qse_tre_geterrnum (qse_tre_t* tre)
|
||||
{
|
||||
return tre->errnum;
|
||||
|
@ -177,7 +177,6 @@ typedef qse_cint_t tre_cint_t;
|
||||
#define regex_t qse_tre_t
|
||||
#define regmatch_t qse_tre_match_t
|
||||
#define reg_errcode_t qse_tre_errnum_t
|
||||
#define tre_str_source qse_tre_strsrc_t
|
||||
|
||||
|
||||
#define REG_OK QSE_TRE_ENOERR
|
||||
@ -278,7 +277,7 @@ typedef qse_pma_t* tre_mem_t;
|
||||
typedef qse_ctype_t tre_ctype_t;
|
||||
#define tre_isctype(c,t) QSE_ISCTYPE(c,t)
|
||||
|
||||
typedef enum { STR_WIDE, STR_BYTE, STR_MBS, STR_USER } tre_str_type_t;
|
||||
typedef enum { STR_WIDE, STR_BYTE, STR_MBS } tre_str_type_t;
|
||||
|
||||
/* Returns number of bytes to add to (char *)ptr to make it
|
||||
properly aligned for the type. */
|
||||
@ -305,6 +304,9 @@ typedef struct tnfa_transition tre_tnfa_transition_t;
|
||||
struct tnfa_transition
|
||||
{
|
||||
/* Range of accepted characters. */
|
||||
/* QSE indicate that code_min .. code_max is not yet negated for ^ in a bracket */
|
||||
int negate_range;
|
||||
/* END QSE */
|
||||
tre_cint_t code_min;
|
||||
tre_cint_t code_max;
|
||||
/* Pointer to the destination state. */
|
||||
|
Loading…
x
Reference in New Issue
Block a user