summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorshennetsind <ind@henn.et>2014-03-18 15:00:16 -0300
committershennetsind <ind@henn.et>2014-03-18 15:00:16 -0300
commit7b71f22331c805a406c57f5a8eff93b464b57018 (patch)
treeed65b87c241aa123d46ed32f13257d487e3dfe71
parent4cc9d5f91cf6276e28cc02bb75fc4158d28d553b (diff)
parent21aeb5aa1d5fee9702aba476a94b800c94b29859 (diff)
downloadhercules-7b71f22331c805a406c57f5a8eff93b464b57018.tar.gz
hercules-7b71f22331c805a406c57f5a8eff93b464b57018.tar.bz2
hercules-7b71f22331c805a406c57f5a8eff93b464b57018.tar.xz
hercules-7b71f22331c805a406c57f5a8eff93b464b57018.zip
Merge branch 'master' of https://github.com/HerculesWS/Hercules
-rw-r--r--doc/script_commands.txt66
-rw-r--r--npc/dev/test.txt (renamed from npc/custom/test.txt)17
-rw-r--r--npc/pre-re/scripts_main.conf3
-rw-r--r--npc/re/scripts_main.conf3
-rw-r--r--npc/scripts_custom.conf4
-rw-r--r--npc/scripts_dev.conf8
-rwxr-xr-xscript-checker19
-rw-r--r--script-checker.bat2
-rw-r--r--src/char/char.c2
-rw-r--r--src/common/HPM.c9
-rw-r--r--src/common/HPM.h2
-rw-r--r--src/login/login.c2
-rw-r--r--src/map/atcommand.c2
-rw-r--r--src/map/map.c62
-rw-r--r--src/map/map.h2
-rw-r--r--src/map/script.c97
-rw-r--r--src/map/script.h4
-rw-r--r--src/plugins/HPMHooking/HPMHooking.Hooks.inc12
-rwxr-xr-xtools/HPMHookGen/HPMHookGen.pl4
19 files changed, 266 insertions, 54 deletions
diff --git a/doc/script_commands.txt b/doc/script_commands.txt
index dc09256c5..5e3f62a69 100644
--- a/doc/script_commands.txt
+++ b/doc/script_commands.txt
@@ -725,6 +725,12 @@ other, but you can not compare numbers to strings.
> - True if the first value greater than the second value.
< - True if the first value is less than the second value.
!= - True if the first value IS NOT equal to the second one.
+ ~= - True if the second value (as regular expression) matches the first
+ value. Both values must be strings. See the script function pcre_match
+ for more details and advanced features.
+ ~! - True if the second value (as regular expression) DOES NOT match the
+ first value. Both values must be strings. See script function pcre_match
+ for more details and advanced features.
Examples:
@@ -732,9 +738,9 @@ Examples:
1<2 is True while 1>2 is False.
@x>2 is True if @x is equal to 3. But it isn't true if @x is 2.
-Only '==' and '!=' have been tested for comparing strings. Since there's
-no way to code a seriously complex data structure in this language, trying
-to sort strings by alphabet would be pointless anyway.
+Only '==', '!=', '~=' and '~!' have been tested for comparing strings. Since
+there's no way to code a seriously complex data structure in this language,
+trying to sort strings by alphabet would be pointless anyway.
Comparisons can be stacked in the same condition:
@@ -910,6 +916,8 @@ Precedence | Description | Associativity
---------------------------------------------------------------------------
7 | == Equal to | Left to right
| != Not equal to |
+ | ~= Regexp match |
+ | ~! Regexp non-match |
---------------------------------------------------------------------------
8 | & Bitwise AND | Left to right
---------------------------------------------------------------------------
@@ -7234,15 +7242,54 @@ script is used.
---------------------------------------
+*pcre_match("<string>","<regex>");
+
+This command is only available if the server is compiled with regular
+expressions library enabled.
+
+The string <string> will be searched for a match to the regular expression
+<regex>, and the number of matches will be returned.
+
+An alternative way to invoke this command is to use the operators '~=' or '~!'.
+The operator '~=' is exactly the same as pcre_match, while the operator '~!'
+will return 1 if no matches were found, or 0 if at least a match was found.
+
+ if (pcre_match("string", "regex")) mes "There was a match.";
+ if ("string" ~= "regex") mes "There was a match.";
+ if ("string" ~! "regex") mes "There were no matches.";
+
+You can find more usage examples in the test script npc/custom/test.txt.
+
+Using regular expressions is high wizardry. But with this high wizardry
+comes unparalleled power of text manipulation. For an explanation of what
+a regular expression pattern is, see a few web pages:
+
+http://www.regular-expressions.info/
+http://www.weitz.de/regex-coach/
+
+Additionally, the following temporary variables will be filled (unless the
+command is invoked as '~!'):
+
+- $@regexmatchcount: The number of matches detected, including any
+ parenthesized capture-groups.
+- $@regexmatch$[0]: The part of <string> That matched the full <regex> pattern.
+- $@regexmatch$[1 .. $@regexmatchcount]: The parts of <string> that matched
+ each of the parenthesized capture-groups in <pattern>.
+
+A capture group is a part of a regex enclosed in (parentheses) in order to
+store in a variable the part of the expression that was matched by that part of
+the regex. For more details, see the links above, as this is not intended to be
+a regex tutorial.
+
+---------------------------------------
+
*defpattern <set number>,"<regular expression pattern>","<event label>";
*activatepset <set number>;
*deactivatepset <set number>;
*deletepset <set number>;
This set of commands is only available if the server is compiled with
-regular expressions library enabled. Default compilation and most binary
-distributions aren't, which is probably bad, since these, while complex to
-use, are quite fascinating.
+regular expressions library enabled.
They will make the NPC object listen for text spoken publicly by players
and match it against regular expression patterns, then trigger labels
@@ -7266,13 +7313,6 @@ pattern set number in this case will deactivate all pattern sets defined.
'deletepset' will delete a pattern set from memory, so you can create a
new pattern set in its place.
-Using regular expressions is high wizardry. But with this high wizardry
-comes unparalleled power of text manipulation. For an explanation of what
-a regular expression pattern is, see a few web pages:
-
-http://www.regular-expressions.info/
-http://www.weitz.de/regex-coach/
-
For an example of this in use, see doc/sample/npc_test_pcre.txt
With this you could, for example, automatically punish players for asking
diff --git a/npc/custom/test.txt b/npc/dev/test.txt
index 00f9c376e..6d1c6b49f 100644
--- a/npc/custom/test.txt
+++ b/npc/dev/test.txt
@@ -335,7 +335,7 @@ OnInit:
callsub(OnCheck, "Order of < and <<", .@x);
- // ==, != operators
+ // ==, !=, ~=, ~! operators
.@x = (0 == 0); // true
.@y = (1 == 0); // false
callsub(OnCheck, "== operator", .@x);
@@ -344,6 +344,21 @@ OnInit:
.@y = (1 != 1); // false
callsub(OnCheck, "!= operator", .@x);
callsub(OnCheck, "!= operator", .@y, 0);
+ .@x$ = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. "
+ "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. "
+ "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. "
+ "Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
+ .@y = (.@x$ ~= "^Lorem.*, ([a-z]*).*(Duis).* ([a-z.]*)$");
+ callsub(OnCheck, "~= operator", .@y, 4);
+ callsub(OnCheck, "~= operator", $@regexmatchcount, 4);
+ if( $@regexmatchcount == 4 ) {
+ callsub(OnCheck, "~= operator", $@regexmatch$[0], .@x$);
+ callsub(OnCheck, "~= operator", $@regexmatch$[1], "quis");
+ callsub(OnCheck, "~= operator", $@regexmatch$[2], "Duis");
+ callsub(OnCheck, "~= operator", $@regexmatch$[3], "laborum.");
+ }
+ .@y = (.@x$ ~! "^Not Lorem.*, ([a-z]*).*(Duis).* ([a-z.]*)$");
+ callsub(OnCheck, "~! operator", .@y);
// Associativity of ==, !=
.@x = (1 == 0 == 0); // (1 == 0) == 0 --> 0 == 0 --> 1
diff --git a/npc/pre-re/scripts_main.conf b/npc/pre-re/scripts_main.conf
index 8c53b586b..a2c1fcc1c 100644
--- a/npc/pre-re/scripts_main.conf
+++ b/npc/pre-re/scripts_main.conf
@@ -39,6 +39,9 @@ import: npc/pre-re/scripts_jobs.conf
import: npc/pre-re/scripts_monsters.conf
import: npc/pre-re/scripts_warps.conf
+// ----------- Development / Testing Script Files ---------------
+import: npc/scripts_dev.conf
+
// ------------------- Custom Script Files ----------------------
// - Your NPCs go in this file!
import: npc/scripts_custom.conf
diff --git a/npc/re/scripts_main.conf b/npc/re/scripts_main.conf
index 082fb81f4..8ee3c45e5 100644
--- a/npc/re/scripts_main.conf
+++ b/npc/re/scripts_main.conf
@@ -40,6 +40,9 @@ import: npc/re/scripts_jobs.conf
import: npc/re/scripts_monsters.conf
import: npc/re/scripts_warps.conf
+// ----------- Development / Testing Script Files ---------------
+import: npc/scripts_dev.conf
+
// ------------------- Custom Script Files ----------------------
// - Your NPCs go in this file!
import: npc/scripts_custom.conf
diff --git a/npc/scripts_custom.conf b/npc/scripts_custom.conf
index b4283502c..aeae9e22f 100644
--- a/npc/scripts_custom.conf
+++ b/npc/scripts_custom.conf
@@ -104,7 +104,3 @@
//npc: npc/custom/battleground/bg_kvm01.txt
//npc: npc/custom/battleground/bg_kvm02.txt
//npc: npc/custom/battleground/bg_kvm03.txt
-
-// ----------------------- Misc Scripts -----------------------------
-// Self-test script (for development use only)
-//npc: npc/custom/test.txt
diff --git a/npc/scripts_dev.conf b/npc/scripts_dev.conf
new file mode 100644
index 000000000..ee9bcfc26
--- /dev/null
+++ b/npc/scripts_dev.conf
@@ -0,0 +1,8 @@
+// --------------------------------------------------------------
+// - Development and Testing Scripts -
+// --------------------------------------------------------------
+// The scripts listed here are for development or testing purpose.
+// There's little to no reason to enable them in a production server.
+
+// Script engine self-test.
+//npc: npc/dev/test.txt
diff --git a/script-checker b/script-checker
index 521cf9025..f4a277e2d 100755
--- a/script-checker
+++ b/script-checker
@@ -14,12 +14,21 @@ if [ -z "$1" ]; then
echo "Usage: $0 <path to the script>"
echo " (you may use a relative or absolute path)"
exit -1
-elif [[ "$1" =~ ^\/ ]]; then
- FILE="$1"
-else
- FILE="${ORIG_CWD}/$1"
fi
if [ ! -x "$EXECUTABLE" ]; then
exit -1
fi
-"$EXECUTABLE" --script-check "${FILE}" 2>&1
+
+while [ -n "$1" ]; do
+ [ -n "$FILES" ] && FILES="${FILES}!"
+ if [[ "$1" =~ ^\/ ]]; then
+ FILES="${FILES}--load-script!$1"
+ else
+ FILES="${FILES}--load-script!${ORIG_CWD}/$1"
+ fi
+ shift
+done
+
+# We assume that filenames don't contain exclamation marks.
+IFS=!
+"$EXECUTABLE" --script-check $FILES 2>&1
diff --git a/script-checker.bat b/script-checker.bat
index e05eda64e..d81277971 100644
--- a/script-checker.bat
+++ b/script-checker.bat
@@ -24,6 +24,6 @@ ECHO.
:LOOP
SET /P SCRIPT="Enter path/to/your/script.txt: " %=%
- map-server.exe --script-check %SCRIPT%
+ map-server.exe --script-check --load-script %SCRIPT%
ECHO.
GOTO LOOP
diff --git a/src/char/char.c b/src/char/char.c
index a42524444..bf19a0012 100644
--- a/src/char/char.c
+++ b/src/char/char.c
@@ -5393,7 +5393,7 @@ int do_init(int argc, char **argv) {
online_char_db = idb_alloc(DB_OPT_RELEASE_DATA);
HPM->share(sql_handle,"sql_handle");
- HPM->config_read();
+ HPM->config_read(NULL, 0);
HPM->event(HPET_INIT);
mmo_char_sql_init();
diff --git a/src/common/HPM.c b/src/common/HPM.c
index a25a17782..971eb83bd 100644
--- a/src/common/HPM.c
+++ b/src/common/HPM.c
@@ -269,11 +269,12 @@ void hplugin_unload(struct hplugin* plugin) {
}
}
-void hplugins_config_read(void) {
+void hplugins_config_read(const char * const *extra_plugins, int extra_plugins_count) {
config_t plugins_conf;
config_setting_t *plist = NULL;
const char *config_filename = "conf/plugins.conf"; // FIXME hardcoded name
FILE *fp;
+ int i;
// uncomment once login/char support is wrapped up
// if( !HPM->DataCheck ) {
@@ -294,9 +295,13 @@ void hplugins_config_read(void) {
HPM->symbol_defaults_sub();
plist = libconfig->lookup(&plugins_conf, "plugins_list");
+ for (i = 0; i < extra_plugins_count; i++) {
+ config_setting_t *entry = libconfig->setting_add(plist, NULL, CONFIG_TYPE_STRING);
+ config_setting_set_string(entry, extra_plugins[i]);
+ }
if (plist != NULL) {
- int length = libconfig->setting_length(plist), i;
+ int length = libconfig->setting_length(plist);
char filename[60];
for(i = 0; i < length; i++) {
if( !strcmpi(libconfig->setting_get_string_elem(plist,i),"HPMHooking") ) {//must load it first
diff --git a/src/common/HPM.h b/src/common/HPM.h
index 52ad24a03..b466cb4f3 100644
--- a/src/common/HPM.h
+++ b/src/common/HPM.h
@@ -131,7 +131,7 @@ struct HPM_interface {
void *(*import_symbol) (char *name, unsigned int pID);
void (*share) (void *, char *);
void (*symbol_defaults) (void);
- void (*config_read) (void);
+ void (*config_read) (const char * const *extra_plugins, int extra_plugins_count);
bool (*populate) (struct hplugin *plugin,const char *filename);
void (*symbol_defaults_sub) (void);//TODO drop
char *(*pid2name) (unsigned int pid);
diff --git a/src/login/login.c b/src/login/login.c
index 252031bb8..cb30de2f3 100644
--- a/src/login/login.c
+++ b/src/login/login.c
@@ -1821,7 +1821,7 @@ int do_init(int argc, char** argv)
}
HPM->share(account_db_sql_up(accounts),"sql_handle");
- HPM->config_read();
+ HPM->config_read(NULL, 0);
HPM->event(HPET_INIT);
// server port open & binding
diff --git a/src/map/atcommand.c b/src/map/atcommand.c
index 50ec913c4..4c35999d6 100644
--- a/src/map/atcommand.c
+++ b/src/map/atcommand.c
@@ -3666,7 +3666,7 @@ ACMD(reloadscript) {
mapit->free(iter);
flush_fifos();
- map->reloadnpc(true); // reload config files seeking for npcs
+ map->reloadnpc(true, NULL, 0); // reload config files seeking for npcs
script->reload();
npc->reload();
diff --git a/src/map/map.c b/src/map/map.c
index 51b717a16..9e41bdca3 100644
--- a/src/map/map.c
+++ b/src/map/map.c
@@ -3559,8 +3559,8 @@ void map_reloadnpc_sub(char *cfgName)
fclose(fp);
}
-void map_reloadnpc(bool clear)
-{
+void map_reloadnpc(bool clear, const char * const *extra_scripts, int extra_scripts_count) {
+ int i;
if (clear)
npc->addsrcfile("clear"); // this will clear the current script list
@@ -3569,6 +3569,11 @@ void map_reloadnpc(bool clear)
#else
map->reloadnpc_sub("npc/pre-re/scripts_main.conf");
#endif
+
+ // Append extra scripts
+ for( i = 0; i < extra_scripts_count; i++ ) {
+ npc->addsrcfile(extra_scripts[i]);
+ }
}
int inter_config_read(char *cfgName) {
@@ -5355,7 +5360,10 @@ void map_helpscreen(bool do_exit)
ShowInfo(" --grf-path <file> Alternative GRF path configuration.\n");
ShowInfo(" --inter-config <file> Alternative inter-server configuration.\n");
ShowInfo(" --log-config <file> Alternative logging configuration.\n");
- ShowInfo(" --script-check <file> Tests a script for errors, without running the server.\n");
+ ShowInfo(" --script-check Doesn't run the server, only tests the\n");
+ ShowInfo(" scripts passed through --load-script.\n");
+ ShowInfo(" --load-script <file> Loads an additional script (can be repeated).\n");
+ ShowInfo(" --load-plugin <name> Loads an additional plugin (can be repeated).\n");
HPM->arg_help();/* display help for commands implemented thru HPM */
if( do_exit )
exit(EXIT_SUCCESS);
@@ -5565,8 +5573,9 @@ void map_load_defaults(void) {
int do_init(int argc, char *argv[])
{
bool minimal = false;
- char *scriptcheck = NULL;
- int i;
+ bool scriptcheck = false;
+ int i, load_extras_count = 0;
+ char **load_extras = NULL;
#ifdef GCOLLECT
GC_enable_incremental();
@@ -5579,7 +5588,21 @@ int do_init(int argc, char *argv[])
HPM->load_sub = HPM_map_plugin_load_sub;
HPM->symbol_defaults_sub = map_hp_symbols;
HPM->grabHPDataSub = HPM_map_grabHPData;
- HPM->config_read();
+ for( i = 1; i < argc; i++ ) {
+ const char* arg = argv[i];
+ if( strcmp(arg, "--load-plugin") == 0 ) {
+ if( map->arg_next_value(arg, i, argc, true) ) {
+ RECREATE(load_extras, char *, ++load_extras_count);
+ load_extras[load_extras_count-1] = argv[++i];
+ }
+ }
+ }
+ HPM->config_read((const char * const *)load_extras, load_extras_count);
+ if (load_extras) {
+ aFree(load_extras);
+ load_extras = NULL;
+ load_extras_count = 0;
+ }
HPM->event(HPET_PRE_INIT);
@@ -5627,8 +5650,15 @@ int do_init(int argc, char *argv[])
} else if( strcmp(arg, "script-check") == 0 ) {
map->minimal = true;
runflag = CORE_ST_STOP;
+ scriptcheck = true;
+ } else if( strcmp(arg, "load-plugin") == 0 ) {
if( map->arg_next_value(arg, i, argc, true) )
- scriptcheck = argv[++i];
+ i++;
+ } else if( strcmp(arg, "load-script") == 0 ) {
+ if( map->arg_next_value(arg, i, argc, true) ) {
+ RECREATE(load_extras, char *, ++load_extras_count);
+ load_extras[load_extras_count-1] = argv[++i];
+ }
} else {
ShowError("Unknown option '%s'.\n", argv[i]);
exit(EXIT_FAILURE);
@@ -5656,7 +5686,7 @@ int do_init(int argc, char *argv[])
map->config_read_sub(map->MAP_CONF_NAME);
// loads npcs
- map->reloadnpc(false);
+ map->reloadnpc(false, (const char * const *)load_extras, load_extras_count);
chrif->checkdefaultlogin();
@@ -5766,9 +5796,19 @@ int do_init(int argc, char *argv[])
vending->init(minimal);
if (scriptcheck) {
- if (npc->parsesrcfile(scriptcheck, false) == 0)
- exit(EXIT_SUCCESS);
- exit(EXIT_FAILURE);
+ bool failed = load_extras_count > 0 ? false : true;
+ for (i = 0; i < load_extras_count; i++) {
+ if (npc->parsesrcfile(load_extras[i], false) != 0)
+ failed = true;
+ }
+ if (failed)
+ exit(EXIT_FAILURE);
+ exit(EXIT_SUCCESS);
+ }
+ if (load_extras) {
+ aFree(load_extras);
+ load_extras = NULL;
+ load_extras_count = 0;
}
if( minimal ) {
diff --git a/src/map/map.h b/src/map/map.h
index 270931689..c1eaeb40d 100644
--- a/src/map/map.h
+++ b/src/map/map.h
@@ -992,7 +992,7 @@ struct map_interface {
struct mob_data * (*getmob_boss) (int16 m);
struct mob_data * (*id2boss) (int id);
// reload config file looking only for npcs
- void (*reloadnpc) (bool clear);
+ void (*reloadnpc) (bool clear, const char * const *extra_scripts, int extra_scripts_count);
int (*check_dir) (int s_dir,int t_dir);
uint8 (*calc_dir) (struct block_list *src,int16 x,int16 y);
diff --git a/src/map/script.c b/src/map/script.c
index 01a7e6410..d3d98ad06 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 {
diff --git a/src/plugins/HPMHooking/HPMHooking.Hooks.inc b/src/plugins/HPMHooking/HPMHooking.Hooks.inc
index 78987f81a..396b241b0 100644
--- a/src/plugins/HPMHooking/HPMHooking.Hooks.inc
+++ b/src/plugins/HPMHooking/HPMHooking.Hooks.inc
@@ -35401,13 +35401,13 @@ struct mob_data* HP_map_id2boss(int id) {
}
return retVal___;
}
-void HP_map_reloadnpc(bool clear) {
+void HP_map_reloadnpc(bool clear, const char *const *extra_scripts, int extra_scripts_count) {
int hIndex = 0;
if( HPMHooks.count.HP_map_reloadnpc_pre ) {
- void (*preHookFunc) (bool *clear);
+ void (*preHookFunc) (bool *clear, const char *const *extra_scripts, int *extra_scripts_count);
for(hIndex = 0; hIndex < HPMHooks.count.HP_map_reloadnpc_pre; hIndex++ ) {
preHookFunc = HPMHooks.list.HP_map_reloadnpc_pre[hIndex].func;
- preHookFunc(&clear);
+ preHookFunc(&clear, extra_scripts, &extra_scripts_count);
}
if( *HPMforce_return ) {
*HPMforce_return = false;
@@ -35415,13 +35415,13 @@ void HP_map_reloadnpc(bool clear) {
}
}
{
- HPMHooks.source.map.reloadnpc(clear);
+ HPMHooks.source.map.reloadnpc(clear, extra_scripts, extra_scripts_count);
}
if( HPMHooks.count.HP_map_reloadnpc_post ) {
- void (*postHookFunc) (bool *clear);
+ void (*postHookFunc) (bool *clear, const char *const *extra_scripts, int *extra_scripts_count);
for(hIndex = 0; hIndex < HPMHooks.count.HP_map_reloadnpc_post; hIndex++ ) {
postHookFunc = HPMHooks.list.HP_map_reloadnpc_post[hIndex].func;
- postHookFunc(&clear);
+ postHookFunc(&clear, extra_scripts, &extra_scripts_count);
}
}
return;
diff --git a/tools/HPMHookGen/HPMHookGen.pl b/tools/HPMHookGen/HPMHookGen.pl
index b035687e2..e83d5d9a0 100755
--- a/tools/HPMHookGen/HPMHookGen.pl
+++ b/tools/HPMHookGen/HPMHookGen.pl
@@ -138,7 +138,7 @@ sub parse($$) {
}
last; # No other modifiers
}
- if ($current =~ /^\s*(\w+)([*\s]*)(\w*)\s*((?:\[\])?)$/) { # Variable type and name
+ if ($current =~ /^\s*(\w+)((?:const|[*\s])*)(\w*)\s*((?:\[\])?)$/) { # Variable type and name
$type1 .= trim($1);
$indir = trim($2 // '');
$var = trim($3 // '');
@@ -147,7 +147,7 @@ sub parse($$) {
} else { # Unsupported
$notes .= "\n/* Error: Unhandled var type '$current' */";
print "Error: Unhandled var type '$current'\n";
- push(@args, {$current});
+ push(@args, { var => $current });
next;
}
}