summaryrefslogtreecommitdiff
path: root/src/map
diff options
context:
space:
mode:
authorHaru <haru@dotalux.com>2013-09-20 04:28:50 +0200
committerHaru <haru@dotalux.com>2014-03-17 17:15:02 +0100
commit42da97d7979f5db56d50072dfd7787ebf549ab1b (patch)
tree8946b2b7e5319512b01c0116b20099d263d00196 /src/map
parent1cf8ea92f8e8e992617addc371272c78e60df219 (diff)
downloadhercules-42da97d7979f5db56d50072dfd7787ebf549ab1b.tar.gz
hercules-42da97d7979f5db56d50072dfd7787ebf549ab1b.tar.bz2
hercules-42da97d7979f5db56d50072dfd7787ebf549ab1b.tar.xz
hercules-42da97d7979f5db56d50072dfd7787ebf549ab1b.zip
Added regular expression matching script commands and operators
- The script command pcre_match and the operator ~= will return the number of regular expression matches in a given string (roughly equivalent to the php function preg_match or the perl operator =~) - The operator ~! is the opposite of ~= (roughly equivalent to the perl operator !~) - See script_commands and npc/custom/test.txt for more information. Signed-off-by: Haru <haru@dotalux.com>
Diffstat (limited to 'src/map')
-rw-r--r--src/map/script.c97
-rw-r--r--src/map/script.h4
2 files changed, 97 insertions, 4 deletions
diff --git a/src/map/script.c b/src/map/script.c
index 17eba6b21..41453e366 100644
--- a/src/map/script.c
+++ b/src/map/script.c
@@ -112,6 +112,10 @@ const char* script_op2name(int op) {
RETURN_OP_NAME(C_SUB_POST);
RETURN_OP_NAME(C_ADD_PRE);
RETURN_OP_NAME(C_SUB_PRE);
+#ifdef PCRE_SUPPORT
+ RETURN_OP_NAME(C_RE_EQ);
+ RETURN_OP_NAME(C_RE_NE);
+#endif // PCRE_SUPPORT
default:
ShowDebug("script_op2name: unexpected op=%d\n", op);
@@ -1224,6 +1228,10 @@ const char* script_parse_subexpr(const char* p,int limit) {
|| (op=C_XOR, opl=4, len=1,*p=='^') // ^
|| (op=C_EQ, opl=6, len=2,*p=='=' && p[1]=='=') // ==
|| (op=C_NE, opl=6, len=2,*p=='!' && p[1]=='=') // !=
+#ifdef PCRE_SUPPORT
+ || (op=C_RE_EQ, opl=6, len=2,*p=='~' && p[1]=='=') // ~=
+ || (op=C_RE_NE, opl=6, len=2,*p=='~' && p[1]=='!') // ~!
+#endif // PCRE_SUPPORT
|| (op=C_R_SHIFT,opl=8, len=2,*p=='>' && p[1]=='>') // >>
|| (op=C_GE, opl=7, len=2,*p=='>' && p[1]=='=') // >=
|| (op=C_GT, opl=7, len=1,*p=='>') // >
@@ -3405,6 +3413,8 @@ void op_3(struct script_state* st, int op)
/// s1 GE s2 -> i
/// s1 LT s2 -> i
/// s1 LE s2 -> i
+/// s1 RE_EQ s2 -> i
+/// s1 RE_NE s2 -> i
/// s1 ADD s2 -> s
void op_2str(struct script_state* st, int op, const char* s1, const char* s2)
{
@@ -3417,6 +3427,72 @@ void op_2str(struct script_state* st, int op, const char* s1, const char* s2)
case C_GE: a = (strcmp(s1,s2) >= 0); break;
case C_LT: a = (strcmp(s1,s2) < 0); break;
case C_LE: a = (strcmp(s1,s2) <= 0); break;
+#ifdef PCRE_SUPPORT
+ case C_RE_EQ:
+ case C_RE_NE:
+ {
+ int inputlen = (int)strlen(s1);
+ pcre *compiled_regex;
+ pcre_extra *extra_regex;
+ const char *pcre_error, *pcre_match;
+ int pcre_erroroffset, offsetcount, i;
+ int offsets[256*3]; // (max_capturing_groups+1)*3
+
+ compiled_regex = libpcre->compile(s2, 0, &pcre_error, &pcre_erroroffset, NULL);
+
+ if( compiled_regex == NULL ) {
+ ShowError("script:op2_str: Invalid regex '%s'.\n", s2);
+ script->reportsrc(st);
+ script_pushnil(st);
+ st->state = END;
+ return;
+ }
+
+ extra_regex = libpcre->study(compiled_regex, 0, &pcre_error);
+
+ if( pcre_error != NULL ) {
+ libpcre->free(compiled_regex);
+ ShowError("script:op2_str: Unable to optimize the regex '%s': %s\n", s2, pcre_error);
+ script->reportsrc(st);
+ script_pushnil(st);
+ st->state = END;
+ return;
+ }
+
+ offsetcount = libpcre->exec(compiled_regex, extra_regex, s1, inputlen, 0, 0, offsets, 256*3);
+
+ if( offsetcount == 0 ) {
+ offsetcount = 256;
+ } else if( offsetcount == PCRE_ERROR_NOMATCH ) {
+ offsetcount = 0;
+ } else if( offsetcount < 0 ) {
+ libpcre->free(compiled_regex);
+ if( extra_regex != NULL )
+ libpcre->free(extra_regex);
+ ShowWarning("script:op2_str: Unable to process the regex '%s'.\n", s2);
+ script->reportsrc(st);
+ script_pushnil(st);
+ st->state = END;
+ return;
+ }
+
+ if( op == C_RE_EQ ) {
+ for( i = 0; i < offsetcount; i++ ) {
+ libpcre->get_substring(s1, offsets, offsetcount, i, &pcre_match);
+ mapreg->setregstr(reference_uid(script->add_str("$@regexmatch$"), i), pcre_match);
+ libpcre->free_substring(pcre_match);
+ }
+ mapreg->setreg(script->add_str("$@regexmatchcount"), i);
+ a = offsetcount;
+ } else { // C_RE_NE
+ a = (offsetcount == 0);
+ }
+ libpcre->free(compiled_regex);
+ if( extra_regex != NULL )
+ libpcre->free(extra_regex);
+ }
+ break;
+#endif // PCRE_SUPPORT
case C_ADD:
{
char* buf = (char *)aMalloc((strlen(s1)+strlen(s2)+1)*sizeof(char));
@@ -3988,6 +4064,10 @@ void run_script_main(struct script_state *st) {
case C_LOR:
case C_R_SHIFT:
case C_L_SHIFT:
+#ifdef PCRE_SUPPORT
+ case C_RE_EQ:
+ case C_RE_NE:
+#endif // PCRE_SUPPORT
script->op_2(st, c);
break;
@@ -18500,10 +18580,18 @@ BUILDIN(shopcount) {
// declarations that were supposed to be exported from npc_chat.c
#ifdef PCRE_SUPPORT
- BUILDIN(defpattern);
- BUILDIN(activatepset);
- BUILDIN(deactivatepset);
- BUILDIN(deletepset);
+BUILDIN(defpattern);
+BUILDIN(activatepset);
+BUILDIN(deactivatepset);
+BUILDIN(deletepset);
+
+BUILDIN(pcre_match) {
+ const char *input = script_getstr(st, 2);
+ const char *regex = script_getstr(st, 3);
+
+ script->op_2str(st, C_RE_EQ, input, regex);
+ return true;
+}
#endif
/**
@@ -18867,6 +18955,7 @@ void script_parse_builtin(void) {
BUILDIN_DEF(activatepset,"i"), // Activate a pattern set [MouseJstr]
BUILDIN_DEF(deactivatepset,"i"), // Deactive a pattern set [MouseJstr]
BUILDIN_DEF(deletepset,"i"), // Delete a pattern set [MouseJstr]
+ BUILDIN_DEF(pcre_match,"ss"),
#endif
BUILDIN_DEF(dispbottom,"s"), //added from jA [Lupus]
BUILDIN_DEF(getusersname,""),
diff --git a/src/map/script.h b/src/map/script.h
index cf7f22aa9..eed0dbf1d 100644
--- a/src/map/script.h
+++ b/src/map/script.h
@@ -213,6 +213,10 @@ typedef enum c_op {
C_SUB_POST, // a--
C_ADD_PRE, // ++a
C_SUB_PRE, // --a
+#ifdef PCRE_SUPPORT
+ C_RE_EQ, // ~=
+ C_RE_NE, // ~!
+#endif // PCRE_SUPPORT
} c_op;
enum hQueueOpt {